-
Notifications
You must be signed in to change notification settings - Fork 42
Expand file tree
/
Copy pathfnc_brainVehicle.sqf
More file actions
375 lines (324 loc) · 13.8 KB
/
fnc_brainVehicle.sqf
File metadata and controls
375 lines (324 loc) · 13.8 KB
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
#include "script_component.hpp"
/*
* Author: nkenny
* handles vehicle brain
*
* Arguments:
* 0: unit doing the evaluation <OBJECT>
* 2: current action queue <ARRAY>
*
* Return Value:
* timeout and danger result for FSM
*
* Example:
* [bob, []] call lambs_danger_fnc_brainVehicle;
*
* Public: No
*/
params ["_unit", ["_queue", []]];
// timeout
private _timeout = time + 1;
// commander
private _vehicle = vehicle _unit;
if !((effectiveCommander _vehicle) isEqualTo _unit && {_unit call EFUNC(main,isAlive)}) exitWith {
[_timeout, -2, getPosWorld _vehicle, time + GVAR(dangerUntil), objNull]
};
// no queue
if (_queue isEqualTo []) then {_queue pushBack [10, getPosWorld _vehicle, time + GVAR(dangerUntil), assignedTarget _unit];};
// modify priorities ~ consider adding vehicle specific changes!
private _priorities = _unit call FUNC(brainAdjust);
// pick the most relevant danger cause
private _priority = -1;
private _index = -1;
{
private _cause = _x select 0;
if ((_priorities select _cause) > _priority) then {
_index = _forEachIndex;
_priority = _priorities select _cause;
};
} forEach _queue;
// select cause
private _causeArray = _queue select _index;
_causeArray params ["_cause", "_dangerPos", "", "_dangerCausedBy"]; // "_dangerUntil" may be re-implemented in the future ~ nkenny
// debug variable
_unit setVariable [QEGVAR(main,FSMDangerCauseData), _causeArray, EGVAR(main,debug_functions)];
// is it an attack?
private _attack = _cause in [DANGER_ENEMYDETECTED, DANGER_ENEMYNEAR, DANGER_HIT, DANGER_CANFIRE, DANGER_BULLETCLOSE] && {(side _dangerCausedBy) isNotEqualTo (side _unit)} && {!isNull _dangerCausedBy};
// update dangerPos if attacking. Check that the position is not too far above, or below ground.
if (_attack) then {
_dangerPos = _unit getHideFrom _dangerCausedBy;
if (_dangerPos isEqualTo [0, 0, 0]) exitWith {_attack = false;};
_dangerPos = ASLToAGL (ATLToASL _dangerPos);
if ((_dangerPos select 2) > 6 || {(_dangerPos select 2) < 2}) then {_dangerPos set [2, 1]};
};
// vehicle type ~ Artillery
private _artillery = _vehicle getVariable [QEGVAR(main,isArtillery), getNumber (configOf _vehicle >> "artilleryScanner") > 0];
if (_artillery) exitWith {
_vehicle setVariable [QEGVAR(main,isArtillery), true];
// enemies within 12-30m may cause crew to disembark!
if (
_attack
&& {_dangerCausedBy distance _vehicle < (12 + random 18)}
&& {currentCommand _unit isEqualTo ""}
&& {!(_vehicle isKindOf "Tank" && {count (allTurrets [_vehicle, false]) > 1})}
) then {
private _vehicleCrew = crew _vehicle;
_vehicleCrew orderGetIn false;
{
_x setSuppression 0.94; // to prevent instant laser aim on exiting vehicle
} forEach _vehicleCrew; // There may be more than one unit in vehicle
[_unit, "Combat", "Eject", 125] call EFUNC(main,doCallout);
};
// mortars fire rounds
private _mortarTime = _vehicle getVariable [QEGVAR(main,mortarTime), 0];
if (_attack && {_vehicle isKindOf "StaticMortar"} && {unitReady _vehicle} && {_mortarTime < time}) then {
// delay
_timeout = _timeout + 2;
_vehicle doWatch _dangerPos;
// check ammo & range
private _ammo = getArtilleryAmmo [_vehicle];
private _shell = _ammo param [0, ""];
if (_shell isEqualTo "") exitWith {};
private _flareIndex = _ammo findIf {"flare" in (toLower _x)};
private _smokeIndex = _ammo findIf {"smoke" in (toLower _x)};
// check friendlies
private _dangerRound = false;
private _repeatRounds = true;
if ( RND(0.8) || { ([_unit, _dangerPos, 150] call EFUNC(main,findNearbyFriendlies)) isNotEqualTo [] } ) then {
if (_smokeIndex isNotEqualTo -1) then {
_shell = _ammo select _smokeIndex;
_repeatRounds = RND(0.5);
} else {
_dangerRound = true;
};
};
// check night
if ( RND(0.2) && { _unit call EFUNC(main,isNight) } && { _flareIndex isNotEqualTo -1 } ) then {
_dangerPos = _dangerPos getPos [-50 + random 100, (_vehicle getDir _dangerPos) - 45 + random 90];
_shell = _ammo select _flareIndex;
_dangerRound = false;
_repeatRounds = false;
};
// check for issues
if ( _dangerRound || !( _dangerPos inRangeOfArtillery [[_vehicle], _shell] ) ) exitWith {};
// execute fire command
_vehicle commandArtilleryFire [_dangerPos getPos [30 + random 80, (_dangerPos getDir _vehicle) - 10 + random 20], _shell, 1 + random 2];
_vehicle setVariable [QEGVAR(main,mortarTime), time + 24 + random 6];
_unit setVariable [QEGVAR(main,currentTask), "Mortar Fire", EGVAR(main,debug_functions)];
if (_repeatRounds) then {
[
{
params [["_vehicle", objNull], ["_dangerPos", [0, 0, 0]], ["_shell", ""]];
if (canFire _vehicle && unitReady _vehicle) then {
_vehicle commandArtilleryFire [_dangerPos, _shell, ( 2 + random 1 ) min ((gunner _vehicle) ammo (currentMuzzle (gunner _vehicle)))];
};
},
[_vehicle, _dangerPos, _shell],
18 + random 6
] call CBA_fnc_waitAndExecute;
};
};
[_timeout] + _causeArray
};
// variable
_vehicle setVariable [QEGVAR(main,isArtillery), false];
// vehicle type ~ Air
if (_vehicle isKindOf "Air") exitWith {
[_timeout + 2 + random 2] + _causeArray
};
// vehicle type ~ Static weapon
if (_vehicle isKindOf "StaticWeapon") exitWith {
// get out if enemy near OR out of ammunition
if ((count (magazines _vehicle)) isEqualTo 0 || {(_unit findNearestEnemy _dangerPos) distance _vehicle < (6 + random 15)}) then {
private _vehicleCrew = (crew _vehicle);
_vehicleCrew orderGetIn false;
[_unit, "Combat", "Eject"] call EFUNC(main,doCallout);
{
_x setSuppression 0.94; // to prevent instant laser aim on exiting vehicle
} forEach _vehicleCrew; // There may be more than one unit in vehicle
} else {
// suppression
if (_attack) then {
[_unit, _dangerPos] call EFUNC(main,doVehicleSuppress);
[{_this call EFUNC(main,doVehicleSuppress)}, [_unit, _dangerPos], 3] call CBA_fnc_waitAndExecute;
};
};
// end
[_timeout + random 4] + _causeArray
};
// update information
if (_cause in [DANGER_ENEMYNEAR, DANGER_SCREAM]) then {[_unit, _dangerCausedBy] call EFUNC(main,doShareInformation);};
// select turret ammunition
if (_attack && {!EGVAR(main,disableAutonomousMunitionSwitching) && {!(isNull _dangerCausedBy) && {
(_vehicle getVariable [QGVAR(warheadSwitchTimeout), -1]) < CBA_missionTime}}}) then {
_vehicle setVariable [QGVAR(warheadSwitchTimeout), CBA_missionTime + 15];
[{
params ["_vehicle", "_dangerCausedBy"];
private _enemyVic = vehicle _dangerCausedBy;
if (_enemyVic isKindOf "Tank" || {
_enemyVic isKindOf "Wheeled_APC_F"}) then {
[_vehicle, ["AP", "TANDEMHEAT"], true] call EFUNC(main,doSelectWarhead);
} else {
[_vehicle] call EFUNC(main,doSelectWarhead);
};
}, [_vehicle, _dangerCausedBy]] call CBA_fnc_directCall;
};
// vehicle type ~ Armoured vehicle
private _armored = _vehicle isKindOf "Tank" || {_vehicle isKindOf "Wheeled_APC_F"};
if (_armored && {!isNull _dangerCausedBy}) exitWith {
// delay + info
private _delay = 2 + random 3;
private _validTarget = (side _unit) isNotEqualTo (side _dangerCausedBy);
private _distance = _vehicle distance _dangerCausedBy;
// keep cargo aboard!
_vehicle setUnloadInCombat [false, false];
// foot infantry support ~ unload
private _group = group _vehicle;
private _cargo = ((fullCrew [_vehicle, "cargo"]) apply {_x select 0});
_cargo append ((fullCrew [_vehicle, "turret"] select {_x select 4}) apply {_x select 0});
if (
_validTarget
&& {_cargo isNotEqualTo []}
&& {speed _vehicle < 10}
&& {_distance < 350}
&& {_unit knowsAbout _dangerCausedBy > 2 || {_distance < 220}}
&& {!(terrainIntersectASL [eyePos _vehicle, (eyePos _dangerCausedBy) vectorAdd [0, 0, 2]]) || {_distance < 200}}
) exitWith {
// use smoke if available
private _time = _vehicle getVariable [QEGVAR(main,smokescreenTime), 0];
if (RND(0.6) && {_time < time}) then {
(commander _vehicle) forceWeaponFire ["SmokeLauncher", "SmokeLauncher"];
_vehicle setVariable [QEGVAR(main,smokescreenTime), time + 30 + random 20];
};
// define enemy direction
_group setFormDir (_vehicle getDir _dangerCausedBy);
_cargo doMove _dangerPos;
// delayed unload
[
{
params [["_cargo", []], ["_side", east], ["_vehicle", objNull]];
{_x action ["Eject", _vehicle];} forEach _cargo;
[selectRandom _cargo, "Combat", "Dismount"] call EFUNC(main,doCallout);
_cargo allowGetIn false;
if (EGVAR(main,debug_functions)) then {["%1 %2 unloading %3 carried troops", _side, getText (configOf _vehicle >> "displayName"), count _cargo] call EFUNC(main,debugLog);};
},
[_cargo, side _group, _vehicle],
0.1
] call CBA_fnc_waitAndExecute;
// exit
[_timeout + _delay + 1] + _causeArray
};
// move into gunners seat ~ Enemy Detected, commander alive but gunner dead
private _slow = speed _vehicle < 20;
if (
RND(0.4)
&& {_slow}
&& {someAmmo _vehicle}
&& {_cause isEqualTo DANGER_ENEMYDETECTED}
&& {!alive (gunner _vehicle)}
&& {(commander _vehicle) call EFUNC(main,isAlive)}
) exitWith {
(commander _vehicle) assignAsGunner _vehicle;
[_timeout + 3] + _causeArray
};
// vehicle jink
private _oldDamage = _vehicle getVariable [QGVAR(vehicleDamage), 0];
if (_slow && _validTarget && {_distance < (12 + random 15) || {damage _vehicle > _oldDamage}} && {(driver _vehicle) call EFUNC(main,isAlive)}) exitWith {
_vehicle setVariable [QGVAR(vehicleDamage), damage _vehicle];
[_unit] call EFUNC(main,doVehicleJink);
[_timeout + _delay] + _causeArray
};
// tank assault
if (_attack && {_slow} && {(getUnitState _unit) isEqualTo "OK"}) then {
// rotate
private _rotate = [_vehicle, _dangerPos] call EFUNC(main,doVehicleRotate);
// assault
if (!_rotate && {_distance < 750} && {_dangerCausedBy isKindOf "CAManBase"} && {(gunner _vehicle) call EFUNC(main,isAlive)}) then {
[
{_this call EFUNC(main,doVehicleAssault)},
[_unit, _dangerPos, _dangerCausedBy],
_delay - 1.5
] call CBA_fnc_waitAndExecute;
};
};
// timeout
[_timeout + _delay] + _causeArray
};
// vehicle type ~ Armed Car
private _car = _vehicle isKindOf "Car_F" && {([typeOf _vehicle, false] call BIS_fnc_allTurrets) isNotEqualTo []};
if (_car) exitWith {
// speed
private _delay = 0;
private _slow = speed _vehicle < 30;
// move into gunners seat ~ 30-90 meters and Enemy Detected
if (
_slow
&& {canUnloadInCombat _vehicle}
&& {someAmmo _vehicle}
&& {_cause isEqualTo DANGER_ENEMYDETECTED}
&& {_vehicle distanceSqr _dangerPos < (900 + random 3600)}
&& {!alive (gunner _vehicle)}
) exitWith {
_unit action ["Eject", _vehicle];
_unit assignAsGunner _vehicle;
[
{
params ["_unit", "_vehicle"];
if (_unit call EFUNC(main,isAlive)) then {
[_unit, "Stealth", "Eject"] call EFUNC(main,doCallout);
_unit setDir (_unit getDir _vehicle);
_unit action ["getInGunner", _vehicle];
};
}, [_unit, _vehicle], 0.9
] call CBA_fnc_waitAndExecute;
[_timeout + 3] + _causeArray
};
// escape ~ if enemy within 15-50 meters or explosions are nearby!
if (
_slow
&& {(side _dangerCausedBy) isNotEqualTo (side _unit)}
&& {_cause isEqualTo DANGER_EXPLOSION || {_vehicle distanceSqr _dangerCausedBy < (225 + random 1225)}}
&& {(driver _vehicle) call EFUNC(main,isAlive)}
) exitWith {
[_unit] call EFUNC(main,doVehicleJink);
[_timeout + 3] + _causeArray
};
// look toward danger
if (
_attack
&& {_vehicle knowsAbout _dangerCausedBy > 3}
&& {(gunner _vehicle) call EFUNC(main,isAlive)}
) then {_vehicle doWatch (AGLToASL _dangerPos);};
// suppression
if (_attack && {_slow}) then {
[_unit, _dangerPos vectorAdd [0, 0, random 1]] call EFUNC(main,doVehicleSuppress);
[{_this call EFUNC(main,doVehicleSuppress)}, [_unit, _dangerPos vectorAdd [0, 0, random 2]], 3] call CBA_fnc_waitAndExecute;
_delay = random 4;
};
// end
[_timeout + _delay] + _causeArray
};
// vehicle type ~ Unarmed car
if (_vehicle isKindOf "Car_F" && {!someAmmo _vehicle}) then {
// speed
private _stopped = speed _vehicle < 2;
// is static and a driver and enemy near and a threat - enemy within 10-35 meters
if (
_stopped
&& {!isNull (driver _vehicle)}
&& {canUnloadInCombat _vehicle}
&& {_cause isEqualTo DANGER_ENEMYDETECTED}
&& {_vehicle distanceSqr _dangerCausedBy < (100 + random 225)}
) then {
private _driver = driver _vehicle;
_driver action ["Eject", _vehicle];
_driver setSuppression 0.94; // to prevent instant laser aim on exiting vehicle
[_driver, "Combat", "Eject"] call EFUNC(main,doCallout);
};
};
// Make leadership assessment as infantry
if (_unit call FUNC(isLeader)) then {
[_unit, _dangerCausedBy] call FUNC(tactics);
};
// end
[_timeout] + _causeArray