diff --git a/addons/explosives/XEH_PREP.hpp b/addons/explosives/XEH_PREP.hpp index b43953d8fd1..17558ee54c4 100644 --- a/addons/explosives/XEH_PREP.hpp +++ b/addons/explosives/XEH_PREP.hpp @@ -2,6 +2,7 @@ PREP(addCellphoneIED); PREP(addClacker); PREP(addDetonateActions); +PREP(addDetonateHandler); PREP(addExplosiveActions); PREP(addToSpeedDial); PREP(addTransmitterActions); diff --git a/addons/explosives/XEH_preInit.sqf b/addons/explosives/XEH_preInit.sqf index 65bebfd3214..3a4d9a5aea8 100644 --- a/addons/explosives/XEH_preInit.sqf +++ b/addons/explosives/XEH_preInit.sqf @@ -25,4 +25,6 @@ if (isServer) then { GVAR(explosivesOrientations) = [] }; +GVAR(detonationHandlers) = []; + ADDON = true; diff --git a/addons/explosives/functions/fnc_addDetonateActions.sqf b/addons/explosives/functions/fnc_addDetonateActions.sqf index f88abc29d35..5b61de01f49 100644 --- a/addons/explosives/functions/fnc_addDetonateActions.sqf +++ b/addons/explosives/functions/fnc_addDetonateActions.sqf @@ -43,7 +43,7 @@ _explosivesList = []; {(_this select 2) call FUNC(detonateExplosive);}, {true}, {}, - [_unit,_range,_x] + [_unit,_range,_x,_detonator] ] call EFUNC(interact_menu,createAction), [], _unit @@ -62,7 +62,7 @@ if (_detonator != "ACE_DeadManSwitch") then { {(_this select 2) call FUNC(detonateExplosiveAll);}, {true}, {}, - [_unit,_range,_explosivesList] + [_unit,_range,_explosivesList, _detonator] ] call EFUNC(interact_menu,createAction), [], _unit diff --git a/addons/explosives/functions/fnc_addDetonateHandler.sqf b/addons/explosives/functions/fnc_addDetonateHandler.sqf new file mode 100644 index 00000000000..2058b245027 --- /dev/null +++ b/addons/explosives/functions/fnc_addDetonateHandler.sqf @@ -0,0 +1,24 @@ +/* + * Author: PabstMirror + * Add a explosive detonation handler. + * Should be called on all machines. + * Code needs to return BOOL: true(allowed) / false(blocked) + * See https://ace3mod.com/wiki/framework/explosives-framework.html for an example. + * + * Arguments: + * 0: Code + * - Passed [Unit, MaxRange , Explosive , FuzeTime , TriggerItem ] + * + * Return Value: + * None + * + * Example: + * [{false}] call ace_explosives_fnc_addDetonateHandler; + * + * Public: Yes + */ +#include "script_component.hpp" + +params [["_code", {true}, [{}]]]; + +GVAR(detonationHandlers) pushBack _code; diff --git a/addons/explosives/functions/fnc_defuseExplosive.sqf b/addons/explosives/functions/fnc_defuseExplosive.sqf index b98b992f8e7..a6d0e82a6b8 100644 --- a/addons/explosives/functions/fnc_defuseExplosive.sqf +++ b/addons/explosives/functions/fnc_defuseExplosive.sqf @@ -21,7 +21,7 @@ TRACE_2("params",_unit,_explosive); if (GVAR(ExplodeOnDefuse) && {(random 1.0) < (getNumber (ConfigFile >> "CfgAmmo" >> typeOf _explosive >> QGVAR(explodeOnDefuseChance)))}) exitWith { TRACE_1("exploding on defuse",_explosive); - [_unit, -1, [_explosive, 1], true] call FUNC(detonateExplosive); + [_unit, -1, [_explosive, 1], "#ExplodeOnDefuse"] call FUNC(detonateExplosive); [QGVAR(explodeOnDefuse), [_explosive, _unit]] call CBA_fnc_globalEvent; }; diff --git a/addons/explosives/functions/fnc_detonateExplosive.sqf b/addons/explosives/functions/fnc_detonateExplosive.sqf index 0b7f9f3fa46..822a04aeaf8 100644 --- a/addons/explosives/functions/fnc_detonateExplosive.sqf +++ b/addons/explosives/functions/fnc_detonateExplosive.sqf @@ -8,28 +8,35 @@ * 2: Explosive * 0: Explosive * 1: Fuse time + * 3: Trigger Item Classname * * Return Value: * None * * Example: - * [player, 100, [Explosive, 1]] call ACE_Explosives_fnc_detonateExplosive; // has to be within range - * [player, -1, [Explosive, 1]] call ACE_Explosives_fnc_detonateExplosive; // range ignored. + * [player, 100, [Explosive, 1], "ACE_Clacker"] call ACE_Explosives_fnc_detonateExplosive; // has to be within range + * [player, -1, [Explosive, 1], "ACE_Cellphone"] call ACE_Explosives_fnc_detonateExplosive; // range ignored. * * Public: Yes */ #include "script_component.hpp" -params ["_unit", "_range", "_item"]; -TRACE_3("params",_unit,_range,_item); +params ["_unit", "_range", "_item", ["_triggerClassname", "#unknown", [""]]]; +TRACE_4("detonateExplosive",_unit,_range,_item,_triggerClassname); private ["_result", "_ignoreRange", "_pos"]; _ignoreRange = (_range == -1); -_result = true; - if (!_ignoreRange && {(_unit distance (_item select 0)) > _range}) exitWith {TRACE_1("out of range",_range); false}; +_result = true; +{ + // Pass [Unit, MaxRange , Explosive , FuzeTime , TriggerItem ] + private _handlerResult = [_unit, _range, _item select 0, _item select 1, _triggerClassname] call _x; + if (_handlerResult isEqualTo false) then {TRACE_1("Handler Failed",_forEachIndex); _result = false}; +} forEach GVAR(detonationHandlers); +if (!_result) exitWith {false}; + if (getNumber (ConfigFile >> "CfgAmmo" >> typeOf (_item select 0) >> "TriggerWhenDestroyed") == 0) then { private ["_exp", "_previousExp"]; _previousExp = _item select 0; diff --git a/addons/explosives/functions/fnc_detonateExplosiveAll.sqf b/addons/explosives/functions/fnc_detonateExplosiveAll.sqf index 377dc0b93aa..468183a0031 100644 --- a/addons/explosives/functions/fnc_detonateExplosiveAll.sqf +++ b/addons/explosives/functions/fnc_detonateExplosiveAll.sqf @@ -8,20 +8,21 @@ * 2: Explosives to detonate * 0: Explosive * 1: Fuse time + * 3: Trigger Item Classname * * Return Value: * None * * Example: - * [player, -1, [[c4,0.5]]] call ACE_Explosives_fnc_detonateExplosiveAll; + * [player, -1, [[c4,0.5]], "ACE_Clacker"] call ACE_Explosives_fnc_detonateExplosiveAll; * * Public: No */ #include "script_component.hpp" -params ["_unit", "_range", "_explosivesList"]; -TRACE_3("Params",_unit,_range,_explosivesList); +params ["_unit", "_range", "_explosivesList", "_triggerClassname"]; +TRACE_4("Params",_unit,_range,_explosivesList,_triggerClassname); { - [_unit,_range,_x] call FUNC(detonateExplosive); + [_unit,_range,_x,_triggerClassname] call FUNC(detonateExplosive); } forEach _explosivesList; diff --git a/addons/explosives/functions/fnc_dialPhone.sqf b/addons/explosives/functions/fnc_dialPhone.sqf index e205f9b3810..7e715c2ac7b 100644 --- a/addons/explosives/functions/fnc_dialPhone.sqf +++ b/addons/explosives/functions/fnc_dialPhone.sqf @@ -41,6 +41,6 @@ if (_unit == ace_player) then { playSound3D [QUOTE(PATHTO_R(Data\Audio\Cellphone_Ring.wss)),objNull, false, getPosASL (_this select 1),3.16228,1,75]; (_this select 0) setVariable [QGVAR(Dialing), false, true]; }, [_unit,_explosive select 0], 0.25 * (count _arr - 4)] call CBA_fnc_waitAndExecute; - [_explosive select 0,(0.25 * (count _arr - 1)) + (_explosive select 2)] call FUNC(startTimer); + [_explosive select 0,(0.25 * (count _arr - 1)) + (_explosive select 2), "ACE_Cellphone"] call FUNC(startTimer); }; }; diff --git a/addons/explosives/functions/fnc_dialingPhone.sqf b/addons/explosives/functions/fnc_dialingPhone.sqf index aa20ebf4b04..9cafa01a5eb 100644 --- a/addons/explosives/functions/fnc_dialingPhone.sqf +++ b/addons/explosives/functions/fnc_dialingPhone.sqf @@ -31,7 +31,7 @@ private _explosive = [_code] call FUNC(getSpeedDialExplosive); if (_i >= (count _arr + 2)) then { [_pfID] call CALLSTACK(CBA_fnc_removePerFrameHandler); if ((count _explosive) > 0) then { - [_unit, -1, [_explosive select 0, _explosive select 2]] call FUNC(detonateExplosive); + [_unit, -1, [_explosive select 0, _explosive select 2], "ACE_Cellphone"] call FUNC(detonateExplosive); }; _unit setVariable [QGVAR(Dialing), false, true]; if (_unit == ace_player) then { diff --git a/addons/explosives/functions/fnc_onIncapacitated.sqf b/addons/explosives/functions/fnc_onIncapacitated.sqf index 96949e77194..6f9a9f498a7 100644 --- a/addons/explosives/functions/fnc_onIncapacitated.sqf +++ b/addons/explosives/functions/fnc_onIncapacitated.sqf @@ -26,7 +26,7 @@ private _range = getNumber (configFile >> "CfgWeapons" >> "ACE_DeadManSwitch" >> private _deadman = [_unit, "DeadManSwitch"] call FUNC(getPlacedExplosives); TRACE_2("placed",_deadman,_range); { - [_unit, _range, _x, true] call FUNC(detonateExplosive); + [_unit, _range, _x, "ACE_DeadManSwitch"] call FUNC(detonateExplosive); } forEach _deadman; //Handle deadman connected to explosive in inventory @@ -47,5 +47,5 @@ if (_connectedInventoryExplosive != "") then { private _explosive = createVehicle [_ammo, (getPos _unit), [], 0, "NONE"]; _explosive setPosASL (getPosASL _unit); - [_unit, -1, [_explosive, 0.5]] call FUNC(detonateExplosive); //Explode, ignoring range, with a 0.5 second delay + [_unit, -1, [_explosive, 0.5], "ACE_DeadManSwitch"] call FUNC(detonateExplosive); //Explode, ignoring range, with a 0.5 second delay }; diff --git a/addons/explosives/functions/fnc_scriptedExplosive.sqf b/addons/explosives/functions/fnc_scriptedExplosive.sqf index 6a554ac09c9..ff7a2ca1a02 100644 --- a/addons/explosives/functions/fnc_scriptedExplosive.sqf +++ b/addons/explosives/functions/fnc_scriptedExplosive.sqf @@ -6,6 +6,7 @@ * Arguments: * 0: Explosives objects to detonate * 1: Fuze delay (for each explosive; use negative number for random time up to value) + * 2: Trigger Item Classname * * Return Value: * None @@ -18,7 +19,7 @@ */ #include "script_component.hpp" -params [["_explosiveArr", [], [[], objNull]], ["_fuzeTime", 0, [0]]]; +params [["_explosiveArr", [], [[], objNull]], ["_fuzeTime", 0, [0]], ["_triggerClassname", "#scripted", [""]]]; if (_explosiveArr isEqualType objNull) then { _explosiveArr = [_explosiveArr]; @@ -26,5 +27,5 @@ if (_explosiveArr isEqualType objNull) then { { private _detTime = if (_fuzeTime < 0) then {random abs _fuzeTime} else {_fuzeTime}; - [objNull, -1, [_x, _detTime]] call FUNC(detonateExplosive); + [objNull, -1, [_x, _detTime], _triggerClassname] call FUNC(detonateExplosive); } forEach _explosiveArr; diff --git a/addons/explosives/functions/fnc_startTimer.sqf b/addons/explosives/functions/fnc_startTimer.sqf index 1f529d9765c..6694d5dc0d7 100644 --- a/addons/explosives/functions/fnc_startTimer.sqf +++ b/addons/explosives/functions/fnc_startTimer.sqf @@ -5,6 +5,7 @@ * Arguments: * 0: Explosive * 1: Time till detonate + * 2: Trigger Item Classname * * Return Value: * None @@ -16,13 +17,13 @@ */ #include "script_component.hpp" -params ["_explosive", "_delay"]; -TRACE_2("params",_explosive,_delay); +params ["_explosive", "_delay", ["_triggerClassname", "#timer", [""]]]; +TRACE_3("startTimer",_explosive,_delay,_triggerClassname); [{ - params ["_explosive"]; + params ["_explosive", "_triggerClassname"]; TRACE_1("Explosive Going Boom",_explosive); if (!isNull _explosive) then { - [_explosive, -1, [_explosive, 0]] call FUNC(detonateExplosive); + [_explosive, -1, [_explosive, 0], _triggerClassname] call FUNC(detonateExplosive); }; -}, [_explosive], _delay] call CBA_fnc_waitAndExecute; +}, [_explosive, _triggerClassname], _delay] call CBA_fnc_waitAndExecute; diff --git a/docs/wiki/framework/explosives-framework.md b/docs/wiki/framework/explosives-framework.md index caa7f6b8129..2d5edebb5e5 100644 --- a/docs/wiki/framework/explosives-framework.md +++ b/docs/wiki/framework/explosives-framework.md @@ -170,3 +170,34 @@ Name | Use 0 | `player` | Unit explosive will connect to 1 | `claymore1` | Explosive object that will be connected 2 | `"ACE_Clacker"` | Detonator type class name + +#### 5.3 Detonation Handler. + +Detonation Handlers are called when something attempts to trigger an explosive. They can be used to block the detonation. + +These are only used for script based triggers like clackers, cellphone and timers (anything that uses `detonateExplosive`). +Sensor based triggers like AT Mines, Tripwires are uneffected. +All added handlers will be called, if ANY one returns false, the detonation will be blocked. + +`[{CODE}] call ace_explosives_fnc_addDetonateHandler;` + +CODE will be passed `[Unit, MaxRange , Explosive , FuzeTime , TriggerItem ]` and should return a bool: true(allowed) / false(blocked) + +#### 5.3.1 Example + +Jammer that blocks RF triggers: + +```cpp +[{ + params ["_unit", "_range", "_explosive", "_fuzeTime", "_triggerItem"]; + if (_triggerItem == "ace_cellphone") exitWith { systemChat "Blocking Cell Phone"; false }; // always block cell phones + if (_triggerItem == "ace_m26_clacker") exitWith { + _range = _range / 1000; + private _actualRange = _unit distance _explosive; + systemChat format ["Limited Range For RF Clacker [%1m / %2m]", _actualRange toFixed 1, _range toFixed 1]; + (_actualRange < _range) // return bool + }; + // allow anything else (like timers / wired clackers) + true +}] call ace_explosives_fnc_addDetonateHandler; +```