-
Notifications
You must be signed in to change notification settings - Fork 108
/
Copy pathfn_OnKilled.sqf
370 lines (291 loc) · 9.59 KB
/
fn_OnKilled.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
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
/*
DMS_fnc_OnKilled
Created by eraser1 and Defent
Influenced by WAI
Usage:
[
_killedUnit,
_killer
] call DMS_fnc_OnKilled;
***Designed for use with the ArmA "MPKilled" EH. This function should not be explicitly called otherwise.***
*/
if (DMS_DEBUG) then
{
(format ["OnKilled :: Logging AI death with parameters: %1",_this]) call DMS_fnc_DebugLog;
};
params
[
"_unit",
"_killer"
];
private _side = _unit getVariable ["DMS_AI_Side", "bandit"];
private _type = _unit getVariable ["DMS_AI_Type", "soldier"];
private _launcher = secondaryWeapon _unit;
private _launcherVar = _unit getVariable ["DMS_AI_Launcher",""];
private _playerObj = objNull;
_unit call ([missionNamespace getVariable [_unit getVariable ["DMS_AI_CustomOnKilledFnc",""],{}]] param [0,{},[{}]]);
// Some of the previously used functions work with non-local argument. Some don't. BIS is annoying
private _removeAll =
{
{_this removeWeaponGlobal _x;} forEach (weapons _this);
{_this unlinkItem _x;} forEach (assignedItems _this);
{_this removeItem _x;} forEach (items _this);
removeAllItemsWithMagazines _this;
removeHeadgear _this;
removeUniform _this;
removeVest _this;
removeBackpackGlobal _this;
};
moveOut _unit;
_unit removeAllEventHandlers "HandleDamage";
_unit enableSimulationGlobal true;
// Remove gear according to configs
if ((_unit getVariable ["DMS_clear_AI_body",DMS_clear_AI_body]) && {(random 100) <= (_unit getVariable ["DMS_clear_AI_body_chance",DMS_clear_AI_body_chance])}) then
{
_unit call _removeAll;
};
if ((_unit getVariable ["DMS_ai_remove_launchers",DMS_ai_remove_launchers]) && {(_launcherVar != "") || {_launcher != ""}}) then
{
// Because arma is stupid sometimes
if (_launcher isEqualTo "") then
{
_launcher = _launcherVar;
diag_log "sneaky launchers...";
_unit spawn
{
uiSleep 0.5;
{
_holder = _x;
{
if (_x isKindOf ["LauncherCore", configFile >> "CfgWeapons"]) exitWith
{
deleteVehicle _holder;
diag_log "gotcha";
};
} forEach (weaponCargo _holder);
} forEach (nearestObjects [_this, ["GroundWeaponHolder","WeaponHolderSimulated"], 5]);
};
};
_unit removeWeaponGlobal _launcher;
{
if (_x isKindOf ["CA_LauncherMagazine", configFile >> "CfgMagazines"]) then
{
_unit removeMagazineGlobal _x;
};
} forEach (magazines _unit);
};
if (_unit getVariable ["DMS_RemoveNVG",DMS_RemoveNVG]) then
{
_unit unlinkItem "NVGoggles";
};
private _grp = group _unit;
private _grpUnits = (units _grp) - [_unit];
// Give the AI a new leader if the killed unit was the leader
if (!(_grpUnits isEqualTo []) && {(leader _grp) isEqualTo _unit}) then
{
_grp selectLeader (selectRandom _grpUnits);
};
private _av = _unit getVariable ["DMS_AssignedVeh",objNull];
if (!isNull _av) then
{
_av enableSimulationGlobal true;
// Determine whether or not the vehicle has any active crew remaining.
private _memCount = {[(alive _x),false] select (_unit isEqualTo _x);} count (crew _av);
// Destroy the vehicle and add it to cleanup if there are no active crew members of the vehicle.
if (_memCount isEqualTo 0) then
{
/*
This is some pretty funky code because this is about the fastest way to do the task.
An "if-statement" inside another "if-statement" is almost as fast, but it isn't as slick ;)
*/
if
(
call
([
{ (random 100)<(_av getVariable ["DMS_DestructionChance",DMS_AI_destroyVehicleChance]) },
{ DMS_AI_destroyStaticWeapon && {(random 100)<(_av getVariable ["DMS_DestructionChance",DMS_AI_destroyStaticWeapon_chance])} }
] select (_av isKindOf "StaticWeapon"))
) then
{
_av setDamage [1, false];
_av setVariable ["ExileDiedAt",time];
[if (_av isKindOf "Air") then {30} else {5}, {_this enableSimulationGlobal false}, _av, false, false] call ExileServer_system_thread_addTask;
if (DMS_DEBUG) then
{
(format["OnKilled :: Destroying used AI vehicle %1, and disabling simulation.",typeOf _av]) call DMS_fnc_DebugLog;
};
}
else
{
if (local _av) then
{
_av lock 1;
}
else
{
[_av, 1] remoteExecCall ["lock", _av];
};
_av call ExileServer_system_simulationMonitor_addVehicle;
_av setVariable ["ExileMoney",0,true];
_av setVariable ["ExileIsPersistent", false];
_av addMPEventHandler ["MPKilled", { if (isServer) then {_this call ExileServer_object_vehicle_event_onMPKilled;};}];
_av addEventHandler ["GetIn", {_this call ExileServer_object_vehicle_event_onGetIn}];
if (!isNil "AVS_Version") then
{
_av call AVS_fnc_sanitizeVehicle;
};
if (DMS_DEBUG) then
{
(format["OnKilled :: Unlocking used AI vehicle (%1).",typeOf _av]) call DMS_fnc_DebugLog;
};
};
}
else
{
// Only check for this stuff for ground vehicles that have guns...
if ((_av isKindOf "LandVehicle") && {(count (weapons _av))>0}) then
{
private _gunner = gunner _av;
private _driver = driver _av;
// The fact that I have to do this in the FUCKING ONKILLED EVENTHANDLER is a testament to why ArmA will make me die prematurely
private _gunnerIsAlive = alive _gunner;
private _driverIsAlive = alive _driver;
if (_unit isEqualTo _gunner) then
{
_gunnerIsAlive = false;
};
if (_unit isEqualTo _driver) then
{
_driverIsAlive = false;
};
// If the gunner is dead but the driver is alive, then the driver becomes the gunner.
// Helps with troll AI vehicles driving around aimlessly after the gunner is shot off. More realistic imo
if (!_gunnerIsAlive && {_driverIsAlive}) then
{
[_driver,_av,_killer] spawn
{
params
[
"_driver",
"_av",
"_killer"
];
private _grp = group _driver;
private _owner = groupOwner _grp;
_grp setVariable ["DMS_LockLocality",true];
// The AI has to be local in order for these commands to work, so I reset locality, just because it's really difficult to deal with otherwise
if !(_owner in [2,0]) then
{
diag_log format ["DMS Seat Switcher :: Temporarily setting owner of %1 to server from %2. Success: %3",_grp,_owner,_grp setGroupOwner 2];
};
uiSleep 5+(random 3); // 5 to 8 seconds delay after gunner death
if !(alive _driver) exitWith {};
unassignVehicle _driver;
moveOut _driver;
_driver disableCollisionWith _av;
_av setVehicleAmmoDef 1;
waitUntil
{
unassignVehicle _driver;
doGetOut _driver;
moveOut _driver;
(vehicle _driver)==_driver
};
_driver assignAsGunner _av;
[_driver] orderGetIn true;
uiSleep 1.5;
if !(alive _driver) exitWith {};
_driver moveInGunner _av;
_driver enableCollisionWith _av;
if (DMS_DEBUG) then
{
(format["OnKilled :: Switched driver of AI Vehicle (%1) to gunner.",typeOf _av]) call DMS_fnc_DebugLog;
};
if !(_owner in [2,0]) then
{
private _start = time;
// Controlling AI... yes. I have to do this
waitUntil
{
_driver assignAsGunner _av;
[_driver] orderGetIn true;
_driver moveInGunner _av;
(((gunner _av) isEqualTo _driver) || {(time-_start)>30})
};
uiSleep 3;
_start = time;
waitUntil
{
_driver assignAsGunner _av;
[_driver] orderGetIn true;
_driver moveInGunner _av;
(((gunner _av) isEqualTo _driver) || {(time-_start)>30})
};
_driver doTarget _killer;
_driver doSuppressiveFire _killer;
uiSleep 15;
diag_log format ["DMS Seat Switcher :: Resetting ownership of %1 to %2. Success: %3",_grp,_owner,_grp setGroupOwner _owner];
};
_grp setVariable ["DMS_LockLocality",false];
};
};
};
};
};
private _roadKilled = false;
if (isPlayer _killer) then
{
private _veh = vehicle _killer;
_playerObj = _killer;
// Fix for players killing AI from mounted vehicle guns
if (!(_killer isKindOf "Exile_Unit_Player") && {!isNull (gunner _killer)}) then
{
_playerObj = gunner _killer;
};
if (!(_veh isEqualTo _killer) && {(driver _veh) isEqualTo _killer} && {(_killer distance _unit)<10}) then
{
_playerObj = driver _veh;
_roadKilled = true;
if (_unit getVariable ["DMS_explode_onRoadkill",DMS_explode_onRoadkill]) then
{
private _boom = createVehicle ["SLAMDirectionalMine_Wire_Ammo", [0,0,100], [], 0, "CAN_COLLIDE"];
_boom setPosATL (getPosATL _playerObj);
_boom setDamage 1;
if (DMS_DEBUG) then
{
(format ["OnKilled :: %1 roadkilled an AI! Creating mine at the roadkilled AI's position!",name _killer]) call DMS_fnc_DebugLog;
};
};
// Remove gear from roadkills if configured to do so
if ((_unit getVariable ["DMS_remove_roadkill",DMS_remove_roadkill]) && {(random 100) <= (_unit getVariable ["DMS_remove_roadkill_chance",DMS_remove_roadkill_chance])}) then
{
_unit call _removeAll;
};
};
_unit setVariable ["DMS_KillerID",owner _playerObj];
// Reveal the killer to the AI units
if (_unit getVariable ["DMS_ai_share_info",DMS_ai_share_info]) then
{
private _revealAmount = 3;
private _muzzle = currentMuzzle _playerObj;
if (_muzzle isEqualType "") then
{
private _silencer = _playerObj weaponAccessories _muzzle select 0;
if (!isNil "_silencer" && {_silencer != ""}) then
{
_revealAmount = 1.5;
};
};
private _shareInfoDistance = _unit getVariable ["DMS_ai_share_info_distance",DMS_ai_share_info_distance];
{
if ((_x distance2D _unit) <= _shareInfoDistance) then
{
_x reveal [_killer, _revealAmount];
};
} forEach _grpUnits;
};
};
[_playerObj, _unit, _side, _type, _roadKilled] call DMS_fnc_PlayerAwardOnAIKill;
// Let Exile handle the AI Body cleanup.
_unit setVariable ["ExileDiedAt",time];
_unit setVariable ["DMS_KillerObj",[_playerObj,_killer] select (isNull _playerObj)];