2018-09-17 19:19:29 +00:00
|
|
|
#include "script_component.hpp"
|
2018-02-24 17:44:57 +00:00
|
|
|
/*
|
|
|
|
* Author: mharis001
|
|
|
|
* Zeus module function to make unit a suicide bomber.
|
|
|
|
*
|
|
|
|
* Arguments:
|
|
|
|
* 0: Unit that is suicide bomber <OBJECT>
|
|
|
|
* 1: Activation side <SIDE> (default: west)
|
|
|
|
* 2: Activation radius <NUMBER> (default: 10)
|
|
|
|
* 3: Explosion size (0 - Small, 1 - Medium, 2 - Large) <NUMBER> (default: 0)
|
|
|
|
* 4: Auto seek <BOOL> (default: false)
|
|
|
|
*
|
|
|
|
* Return Value:
|
|
|
|
* None
|
|
|
|
*
|
|
|
|
* Example:
|
|
|
|
* [unit, west, 10, 0, true] call ace_zeus_fnc_moduleSuicideBomber
|
|
|
|
*
|
|
|
|
* Public: No
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define EXPLOSIVES ["R_TBG32V_F", "M_Mo_120mm_AT", "Bo_GBU12_LGB"]
|
|
|
|
#define DISTANCE_FAR 15
|
|
|
|
#define DISTANCE_CLOSE 2
|
|
|
|
#define MOVE_TIME 10
|
2018-05-04 15:35:28 +00:00
|
|
|
#define SCANNING_PERIOD 1
|
|
|
|
|
|
|
|
#ifdef DEBUG_MODE_FULL
|
|
|
|
#define SCANNING_PERIOD 0
|
|
|
|
#endif
|
2018-02-24 17:44:57 +00:00
|
|
|
|
|
|
|
TRACE_1("params",_this);
|
|
|
|
|
|
|
|
if (isNull (_this select 0)) exitWith {};
|
|
|
|
|
|
|
|
// Prevent another suicide bomber module being attached
|
|
|
|
_unit setVariable [QGVAR(suicideBomber), true, true];
|
|
|
|
|
|
|
|
// One time behaviour changes
|
|
|
|
if (_autoSeek) then {
|
|
|
|
[QEGVAR(ai,setUnitPos), [_unit, "UP"], _unit] call CBA_fnc_targetEvent;
|
|
|
|
[QEGVAR(ai,setSpeedMode), [_unit, "FULL"], _unit] call CBA_fnc_targetEvent;
|
|
|
|
[QEGVAR(ai,setBehaviour), [[_unit], "CARELESS"], _unit] call CBA_fnc_targetEvent;
|
|
|
|
[QEGVAR(ai,setCombatMode), [_unit, "BLUE"], _unit] call CBA_fnc_targetEvent;
|
|
|
|
[QEGVAR(ai,AISection), [[_unit], ["TARGET", "AUTOTARGET"], false], _unit] call CBA_fnc_targetEvent;
|
|
|
|
[QEGVAR(ai,allowFleeing), [_unit, 0], _unit] call CBA_fnc_targetEvent;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Run PFH to make unit a suicide bomber
|
|
|
|
[{
|
|
|
|
params ["_args", "_pfhID"];
|
|
|
|
_args params [["_unit", objNull], ["_activationSide", west], ["_activationRadius", 10], ["_explosionSize", 0], ["_autoSeek", false]];
|
|
|
|
|
|
|
|
// Unit deleted or killed
|
|
|
|
if (isNull _unit || {!alive _unit}) exitWith {
|
|
|
|
[_pfhID] call CBA_fnc_removePerFrameHandler;
|
|
|
|
LOG("Unit deleted or killed, PFH removed");
|
|
|
|
};
|
|
|
|
|
2018-05-04 16:57:38 +00:00
|
|
|
if (!([_unit] call EFUNC(common,isAwake))) exitWith {};
|
|
|
|
|
2018-02-24 17:44:57 +00:00
|
|
|
// Detonation
|
|
|
|
private _nearObjects = (_unit nearObjects _activationRadius) select {side _x == _activationSide && {_x != _unit} && {alive _x}};
|
|
|
|
if !(_nearObjects isEqualTo []) then {
|
2018-05-04 15:36:08 +00:00
|
|
|
createVehicle [EXPLOSIVES select _explosionSize, _unit, [], 0, "CAN_COLLIDE"];
|
2018-02-24 17:44:57 +00:00
|
|
|
[_pfhID] call CBA_fnc_removePerFrameHandler;
|
|
|
|
LOG("Explosion created, PFH removed");
|
|
|
|
};
|
|
|
|
|
|
|
|
// Auto Seek
|
|
|
|
if (!_autoSeek) exitWith {};
|
|
|
|
|
|
|
|
private _memory = _unit getVariable [QGVAR(suicideBomber_memory), [nil, CBA_missionTime]];
|
|
|
|
_memory params ["_lastMove", "_lastTime"];
|
|
|
|
|
2018-05-04 15:35:28 +00:00
|
|
|
private _range = 100 + 100 * (_unit skillFinal "spotDistance"); // 100-200
|
|
|
|
private _nearestObjects = nearestObjects [_unit, [], _range] select {side _x == _activationSide && {_x != _unit} && {alive _x}};
|
2018-02-24 17:44:57 +00:00
|
|
|
|
|
|
|
#ifdef DEBUG_MODE_FULL
|
2020-02-11 22:47:36 +00:00
|
|
|
if (!isNil "_lastMove") then {
|
2018-02-24 17:44:57 +00:00
|
|
|
drawLine3D [_unit modelToWorldVisual [0, 0, 1], _lastMove, [1, 0, 0, 1]];
|
|
|
|
};
|
|
|
|
for "_i" from 0 to 35 do {
|
|
|
|
drawLine3D [(_unit getRelPos [_range, _i * 10]) vectorAdd [0, 0, 1], (_unit getRelPos [_range, (_i + 1) * 10]) vectorAdd [0, 0, 1], [0, 1, 0, 1]];
|
|
|
|
};
|
|
|
|
for "_i" from 0 to 35 do {
|
|
|
|
drawLine3D [(_unit getRelPos [_activationRadius, _i * 10]) vectorAdd [0, 0, 1], (_unit getRelPos [_activationRadius, (_i + 1) * 10]) vectorAdd [0, 0, 1], [0, 0, 1, 1]];
|
|
|
|
};
|
|
|
|
for "_i" from 0 to 359 do {
|
|
|
|
if (_i >= linearConversion [_lastTime - MOVE_TIME, _lastTime, CBA_missionTime, 0, 359, true]) then {
|
|
|
|
drawLine3D [(_unit getRelPos [2, _i]) vectorAdd [0, 0, 1], (_unit getRelPos [2, _i + 1]) vectorAdd [0, 0, 1], [1, 1, 0, 1]];
|
|
|
|
};
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (_nearestObjects isEqualTo []) exitWith {};
|
|
|
|
|
|
|
|
// Get relative position close to target to avoid bug where AI wont path to a certain position
|
|
|
|
private _moveToPos = (_nearestObjects select 0) getPos [1, random 360];
|
|
|
|
|
|
|
|
if (isNil "_lastMove" || // No move given yet
|
2018-05-04 15:35:28 +00:00
|
|
|
{_lastMove distance _moveToPos > DISTANCE_FAR} || // New target is too far from last move
|
|
|
|
{_lastMove distance _unit < DISTANCE_CLOSE} || // Unit has reached last move
|
|
|
|
{CBA_missionTime >= _lastTime} // Too much time passed between last move (also acts as a fail-safe if unit gets stuck)
|
|
|
|
) then {
|
2018-02-24 17:44:57 +00:00
|
|
|
[QEGVAR(ai,doMove), [[[_unit, _moveToPos]]], _unit] call CBA_fnc_targetEvent;
|
|
|
|
_unit setVariable [QGVAR(suicideBomber_memory), [_moveToPos, CBA_missionTime + MOVE_TIME]];
|
|
|
|
TRACE_2("Moving unit",_moveToPos,CBA_missionTime);
|
|
|
|
};
|
2018-05-04 15:35:28 +00:00
|
|
|
}, SCANNING_PERIOD, _this] call CBA_fnc_addPerFrameHandler;
|