Jump to content

Arma 3 - Tiny Functions Set


Donnovan

Recommended Posts

Here i will release some usefull functions i use on my scripts.
 
===================================================

Function 1: Find spot on map with a specific player density

===================================================

donn_fc_findDensitySpot = {
	if (count playableUnits == 0) exitWith {};
	_playableUnits = [];
	{
		_playableUnits = _playableUnits + [[(getPosATL _x) select 0,(getPosATL _x) select 1,0]];
	} forEach playableUnits;
	_mapX = _this select 0;
	_mapY = _this select 0;
	_density = _this select 1;
	_central = [_mapX/2,_mapY/2,0];
	_gridX_cnt = 16;
	_gridY_cnt = 16;
	_gridSize = (_this select 0)/16 - 0.001;
	_result = [];
	_distMax = 0;
	_distMin = 10^8;
	for "_xCnt" from -(_gridX_cnt/2) to (_gridX_cnt/2) do {
		for "_yCnt" from -(_gridY_cnt/2) to (_gridY_cnt/2) do {
			_pointX = (_central select 0) + _xCnt * _gridSize;
			_pointY = (_central select 1) + _yCnt * _gridSize;
			_point = [_pointX,_pointY,0];
			if !(surfaceIsWater _point) then {
				_distSum = 0;
				{
					_playerPos = _x;
					_distSum	= _distSum + (_point distance _playerPos);
				} forEach _playableUnits;
				_result = _result + [[_point,_distSum]];
				_distMax = _distMax max _distSum;
				_distMin = _distMin min _distSum;
			};
		};
	};
	_goal = _distMin + (_distMax - _distMin) * (1 - _density);
	_rMin = 10^8;
	_tolerance = (_distMax - _distMin) * 0.05;
	_returnOpt = [];
	_returnTol = [];
	{
		_dist = _x select 1;
		_error = abs (_dist - _goal);
		if (_error < _rMin) then {
			_returnOpt = _x;
			_rMin = _error;
		};
		if (_error <= _tolerance) then {
			_returnTol = _returnTol + [_x];
		};
	} forEach _result;
	_return = _returnOpt;
	if (count _returnTol > 0) then {
		_return = _returnTol call BIS_fnc_selectRandom;
	};
	_return select 0
};

Status: tested.
 
Syntax: result = [map_size, density] call donn_fc_findDensitySpot;
[map_size] is a number, the size of the map (15360 for Chernarus, for example).
[density]: is a number, its the player density of the spot to be found, 0 is minimum density and 1 is maximum density.
[result]: is a 3D position, [x,y,z], the spot with the desired player density or with the nearest player density.
 
Example 1: _spawnPos = [15360, 0.4] call donn_fc_findDensitySpot;
Example 2: _moveToPos = [15360, 1] call donn_fc_findDensitySpot;
 
Considerations: If more than one spot is found, one is selected randonly. If no spot is found, the one with the nearest density will be selected.
 
How it works: a 16 x 16 grid is put over the map. All 256 points of this grid have it distance calculated to every player. Those distances are sum giving the point a player density measurement. Low player density points have high value (they are far from players: sum of big distances) and high player density points have low values (they are near players: sum of small distances).

 

====================

Function 2: Fake getDir

====================

donn_vecDir = {
	private ["_pnt1","_pnt2","_vec","_vecX","_vecY","_magnitude","_asin1","_asin2","_acos1","_acos2","_asin1r","_asin2r","_acos1r","_acos2r","_calcDir"];
	_pnt1 = _this select 0;
	_pnt2 = _this select 1;
	_vec = [(_pnt2 select 0) - (_pnt1 select 0), (_pnt2 select 1) - (_pnt1 select 1)];
	_vecX = _vec select 0;
	_vecY = _vec select 1;
	_magnitude = sqrt(_vecX^2 + _vecY^2);

	_asin1 = asin (_vecX/_magnitude);
	_asin2 = 180 - _asin1;
	_acos1 = acos (_vecY/_magnitude);
	_acos2 = -_acos1;
	
	_asin1 = (_asin1 + 360) mod 360;
	_asin2 = (_asin2 + 360) mod 360;
	_acos1 = (_acos1 + 360) mod 360;
	_acos2 = (_acos2 + 360) mod 360;
	
	_asin1r = (round (_asin1 * 100))/100;
	_asin2r = (round (_asin2 * 100))/100;
	_acos1r = (round (_acos1 * 100))/100;
	_acos2r = (round (_acos2 * 100))/100;

	_calcDir = 0;
	if (_asin1r == _acos1r) then {_calcDir = _asin1};
	if (_asin1r == _acos2r) then {_calcDir = _asin1};
	if (_asin2r == _acos1r) then {_calcDir = _asin2};
	if (_asin2r == _acos2r) then {_calcDir = _asin2};
	_calcDir = _calcDir mod 360;
	_calcDir
};

Status: tested.

 

Introduction: find a dir based in two points or in one vector. Result is similar to getDir, but the input is not an object.
 
Syntax 1 (find dir with two points): _dir = [_point1,_point2] call donn_vecDir;
[_point1]: is a 3D position, [x,y,z], the position of the fake object.
[_point2]: is a 3D position, [x,y,z], the point that the fake object is facing.
[_dir]: is a number, its the angle (0 - 360) of an object positioned in _point1 and facing _point2 direction.

 

Syntax 2 (if instead of 2 points you have one vector): _dir = [[0, 0, 0], _vector] call donn_vecDir;

[_vector]: is a vector, [x,y,z], like, for example, the velocity vector returned by the BI function velocity.
[_dir]: is a number, its the angle (0 - 360) of the vector "_vector".

 
Example 1:

_unit setDir ([getPos _unit, _towerPos] call donn_vecDir);

//Make a unit face the tower in _towerPos.

 

Example 2:

//In a drifiting car

_carDir1 = getDir _car; //The direction of the car model

_carDir2 = [[0, 0, 0], velocity _car] call donn_vecDir; //The direction of the car movement

// _carDir1 is not equal to _carDir2

 

Considerations: This was used in one of my Arma 2 scripts, may be Arma 3 already have something similar, if you know, please tell me. Thankyou.

Link to comment
Share on other sites

That would come n handy for some mission systems for when the mission is complete.When the mission marker respawns it can be placed away from players so they have to travel.And so missions don't spawn next to players to.

 

Is it possible to give it an array of mission markers so missions don't spawn too close to each other?

 

 

Greettz  - WArGaSM

Link to comment
Share on other sites

Donnovan, you can easily speed up your script by not using arbitrary calculations to calculate something like for exmple 

_rMin = 10^8;

The answer will always be 100000000 in this case. Also there is a command to check the power of (x), to make it more neat. 

https://community.bistudio.com/wiki/exp

 

You've also wound up the calculations a lot. I don't see why you'd complicate it this much. 

_error = abs (_dist - _goal);

Why are you checking the absolute value here? It only checks how far your sum is from 0. Negative 6 is 6 away from zero, but so is also positive 6. This becomes very unreliable when using distances etc imo since it's often relied on a set pos. -5040 is very different from +5040. I know that distance is always positive but it may mess up a bit.

 

I'm not trying to be a dick here but this could cause some performance issues, is all im trying to say.

 

https://community.bistudio.com/wiki/Math_Commands

Link to comment
Share on other sites

The performance hit is because it mess with a array with 256 3D positions.

If not the slow array problem, could use 64 x 64 grid (4096 3D positions).

One good thing is that Arma 3 don't give unlimited priority to the function, so you will not have server slow down due to use of it, but it can take more time to finish.

For normal use (1 - 100 players) i believe there in no performance problem.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Advertisement
  • Discord

×
×
  • Create New...