-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathfn_findSafePos.sqf
147 lines (116 loc) · 4.93 KB
/
fn_findSafePos.sqf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/*
Author:
Joris-Jan van 't Land, optimised by Killzone_Kid, patched by jmlane.
Description:
Function to generate position in the world according to several parameters.
Parameters:
0: (Optional) ARRAY - center position
Note: passing [] (empty Array), the world's "safePositionAnchor" entry will be used.
1: (Optional) NUMBER - minimum distance from the center position
2: (Optional) NUMBER - maximum distance from the center position
Note: passing -1, the world's "safePositionRadius" entry will be used.
3: (Optional) NUMBER - minimum distance from the nearest object
4: (Optional) NUMBER - water mode
0 - cannot be in water
1 - can either be in water or not
2 - must be in water
5: (Optional) NUMBER - maximum terrain gradient (hill steepness)
6: (Optional) NUMBER - shore mode:
0 - does not have to be at a shore
1 - must be at a shore
7: (Optional) ARRAY - black listed areas in format [area1, area2, area3, ...areaN], where area is:
ARRAY - array in format [topLeftCorner, bottomRightCorner]
or
OBJECT - trigger area
STRING - marker area
LOCATION - location area
ARRAY - array in format [center, distance] or [center, [a, b, angle, rect]] or [center, [a, b, angle, rect, height]]
8: (Optional) ARRAY - array in format [landPosition, seaPosition], where:
landPosition: ARRAY - in format [x,y] or [x,y,z] - default position on land
seaPosition: ARRAY - in format [x,y] or [x,y,z] - default position on water
Returns:
ARRAY - position solution
*/
#define MAX_TRIES 3000
scopeName "main";
params [
["_checkPos",[]],
["_minDistance",0],
["_maxDistance",-1],
["_objectProximity",0],
["_waterMode",0],
["_maxGradient",0],
["_shoreMode",0],
["_posBlacklist",[]],
["_defaultPos",[]]
];
// support object for center pos as well
if (_checkPos isEqualType objNull) then {_checkPos = getPos _checkPos};
/// --- validate input
if !([_checkPos,_minDistance,_maxDistance,_objectProximity,_waterMode,_maxGradient,_shoreMode,_posBlacklist,_defaultPos] isEqualTypeParams [[],0,0,0,0,0,0,[],[]]) exitWith {[[_checkPos,_minDistance,_maxDistance,_objectProximity,_waterMode,_maxGradient,_shoreMode,_posBlacklist,_defaultPos], "isEqualTypeParams", [[],0,0,0,0,0,0,[],[]]] call (missionNamespace getVariable "BIS_fnc_errorParamsType")};
private _defaultMaxDistance = worldSize / 2;
private _defaultCenterPos = [_defaultMaxDistance, _defaultMaxDistance, 0];
private _fnc_defaultPos =
{
_defaultPos = _defaultPos param [parseNumber _this, []];
if !(_defaultPos isEqualTo []) exitWith {_defaultPos};
_defaultPos = getArray (configFile >> "CfgWorlds" >> worldName >> "Armory" >> ["positionStart", "positionStartWater"] select _this);
if !(_defaultPos isEqualTo []) exitWith {_defaultPos};
_defaultPos = getArray (configFile >> "CfgWorlds" >> worldName >> "centerPosition");
if !(_defaultPos isEqualTo []) exitWith {_defaultPos};
_defaultCenterPos
};
if (_checkPos isEqualTo []) then
{
_checkPos = getArray (configFile >> "CfgWorlds" >> worldName >> "safePositionAnchor");
if (_checkPos isEqualTo []) then {_checkPos = _defaultCenterPos};
};
if (_maxDistance < 0) then
{
_maxDistance = getNumber (configFile >> "CfgWorlds" >> worldName >> "safePositionRadius");
if (_maxDistance <= 0) then {_maxDistance = _defaultMaxDistance};
};
private _checkProximity = _objectProximity > 0;
private _checkBlacklist = !(_posBlacklist isEqualTo []);
_shoreMode = _shoreMode != 0;
if (_checkBlacklist) then
{
_posBlacklist = _posBlacklist apply
{
// top-left, bottom-right coordinates
if (_x isEqualTypeParams [[],[]] && {count (_x select 1) < 4}) then
{
diag_log format ["findSafePos BUG!", _x];
_x select 0 params [["_x0", 0], ["_y0", 0]];
_x select 1 params [["_x1", 0], ["_y1", 0]];
private _a = (_x1 - _x0) / 2;
private _b = (_y0 - _y1) / 2;
[[_x0 + _a, _y0 - _b], abs _a, abs _b, 0, true]
}
else
{
// other area compatible formats
_x call BIS_fnc_getArea
};
};
};
private _off = (_minDistance / _maxDistance) ^ 2;
private _rem = 1 - _off;
private _gradientRadius = 1 max _objectProximity * 0.1;
for "_i" from 1 to MAX_TRIES do
{
_checkPos getPos [_maxDistance * sqrt (_off + random _rem), random 360] call
{
// position is roughly suitable
if (_this isFlatEmpty [-1, -1, _maxGradient, _gradientRadius, _waterMode, _shoreMode] isEqualTo []) exitWith {};
// away from other objects
if (_checkProximity && {!(nearestTerrainObjects [_this, [], _objectProximity, false, true] isEqualTo [])}) exitWith {};
// not inside something
if !(lineIntersectsSurfaces [AGLtoASL _this, AGLtoASL _this vectorAdd [0, 0, 50], objNull, objNull, false, 1, "GEOM", "NONE"] isEqualTo []) exitWith {};
// not in blacklist
if (_checkBlacklist && {{if (_this inArea _x) exitWith {true}; false} forEach _posBlacklist}) exitWith {};
_this select [0, 2] breakOut "main";
};
};
// search failed, try default position
(_waterMode != 0) call _fnc_defaultPos