diff --git a/addons/disarming/$PBOPREFIX$ b/addons/disarming/$PBOPREFIX$ new file mode 100644 index 0000000000..47b746cf19 --- /dev/null +++ b/addons/disarming/$PBOPREFIX$ @@ -0,0 +1 @@ +z\ace\addons\disarming \ No newline at end of file diff --git a/addons/disarming/CfgEventHandlers.hpp b/addons/disarming/CfgEventHandlers.hpp new file mode 100644 index 0000000000..e75956f440 --- /dev/null +++ b/addons/disarming/CfgEventHandlers.hpp @@ -0,0 +1,11 @@ +class Extended_PreInit_EventHandlers { + class ADDON { + init = QUOTE(call COMPILE_FILE(XEH_preInit)); + }; +}; + +class Extended_PostInit_EventHandlers { + class ADDON { + init = QUOTE(call COMPILE_FILE(XEH_postInit)); + }; +}; diff --git a/addons/disarming/CfgVehicles.hpp b/addons/disarming/CfgVehicles.hpp new file mode 100644 index 0000000000..e7fbb92aa1 --- /dev/null +++ b/addons/disarming/CfgVehicles.hpp @@ -0,0 +1,53 @@ +class CfgVehicles { + class Man; + class CAManBase: Man { + class ACE_Actions { + class ACE_Disarm { + displayName = "Disarm >>"; + distance = 3; + condition = QUOTE([ARR_2(_player, _target)] call FUNC(canDisarm)); + statement = ""; + showDisabled = 0; + priority = 3.2; + // icon = PATHTOF(UI\team\team_management_ca.paa); + subMenu[] = {"ACE_Disarm", 0}; + // hotkey = "M"; + enableInside = 0; + + class ACE_removeWeapons { + displayName = "Remove Weapons"; + distance = 3; + condition = QUOTE([ARR_3(_player, _target, 'weapons')] call FUNC(canDisarm)); + statement = QUOTE([ARR_3(_player, _target, 'weapons')] call FUNC(startDisarmCaller)); + exceptions[] = {}; + showDisabled = 1; + priority = 2.4; + // icon = QUOTE(PATHTOF(UI\handcuff_ca.paa)); + // hotkey = "C"; + }; + class ACE_removeBackpack { + displayName = "Remove Backpack"; + distance = 3; + condition = QUOTE([ARR_3(_player, _target, 'backpack')] call FUNC(canDisarm)); + statement = QUOTE([ARR_3(_player, _target, 'backpack')] call FUNC(startDisarmCaller)); + exceptions[] = {}; + showDisabled = 1; + priority = 2.4; + // icon = QUOTE(PATHTOF(UI\handcuff_ca.paa)); + // hotkey = "C"; + }; + class ACE_removeUniform { + displayName = "Remove Uniform"; + distance = 3; + condition = QUOTE([ARR_3(_player, _target, 'uniform')] call FUNC(canDisarm)); + statement = QUOTE([ARR_3(_player, _target, 'uniform')] call FUNC(startDisarmCaller)); + exceptions[] = {}; + showDisabled = 1; + priority = 2.4; + // icon = QUOTE(PATHTOF(UI\handcuff_ca.paa)); + // hotkey = "C"; + }; + }; + }; + }; +}; diff --git a/addons/disarming/CfgWeapons.hpp b/addons/disarming/CfgWeapons.hpp new file mode 100644 index 0000000000..404ef4aa76 --- /dev/null +++ b/addons/disarming/CfgWeapons.hpp @@ -0,0 +1,14 @@ +class CfgWeapons { + class ACE_ItemCore; + class InventoryItem_Base_F; + + class ACE_DebugPotato: ACE_ItemCore { + displayName = "ACE Potato (debug)"; + descriptionShort = "Glorious Potato
If you see this in game it means someone fucked up"; + picture = QUOTE(PATHTOF(UI\potato_ca.paa)); + scope = 1; + class ItemInfo: InventoryItem_Base_F { + mass = 1; + }; + }; +}; diff --git a/addons/disarming/README.md b/addons/disarming/README.md new file mode 100644 index 0000000000..3938720f08 --- /dev/null +++ b/addons/disarming/README.md @@ -0,0 +1,14 @@ +ace_captives +============ + +Allows taking people captive/handcuffed + +####Items: +`ACE_CableTie` - adds ability to take someone captive + + +## Maintainers + +The people responsible for merging changes to this component or answering potential questions. + +- [PabstMirror](https://github.com/PabstMirror) diff --git a/addons/disarming/UI/potato_ca.paa b/addons/disarming/UI/potato_ca.paa new file mode 100644 index 0000000000..00757d8ed3 Binary files /dev/null and b/addons/disarming/UI/potato_ca.paa differ diff --git a/addons/disarming/XEH_postInit.sqf b/addons/disarming/XEH_postInit.sqf new file mode 100644 index 0000000000..a2397235c7 --- /dev/null +++ b/addons/disarming/XEH_postInit.sqf @@ -0,0 +1,4 @@ +#include "script_component.hpp" + +["Disarm", {_this call FUNC(startDisarmTarget)}] call EFUNC(common,addEventHandler); +["DisarmFinished", {_this call FUNC(finishDisarmCaller)}] call EFUNC(common,addEventHandler); diff --git a/addons/disarming/XEH_preInit.sqf b/addons/disarming/XEH_preInit.sqf new file mode 100644 index 0000000000..7078bdb74a --- /dev/null +++ b/addons/disarming/XEH_preInit.sqf @@ -0,0 +1,12 @@ +#include "script_component.hpp" + +ADDON = false; + +PREP(canDisarm); +PREP(disarmDropItems); +PREP(finishDisarmCaller); +PREP(finishDisarmTarget); +PREP(startDisarmCaller); +PREP(startDisarmTarget); + +ADDON = true; diff --git a/addons/disarming/config.cpp b/addons/disarming/config.cpp new file mode 100644 index 0000000000..b54e52e57e --- /dev/null +++ b/addons/disarming/config.cpp @@ -0,0 +1,18 @@ +#include "script_component.hpp" + +class CfgPatches { + class ADDON { + units[] = {}; + weapons[] = {"ACE_DebugPotato"}; + requiredVersion = REQUIRED_VERSION; + requiredAddons[] = {"ACE_Interaction"}; + author[] = {"PabstMirror"}; + authorUrl = "https://github.com/PabstMirror/"; + VERSION_CONFIG; + }; +}; + +#include "CfgEventHandlers.hpp" +#include "CfgVehicles.hpp" +#include "CfgWeapons.hpp" + diff --git a/addons/disarming/functions/fnc_canDisarm.sqf b/addons/disarming/functions/fnc_canDisarm.sqf new file mode 100644 index 0000000000..bb654b3dd8 --- /dev/null +++ b/addons/disarming/functions/fnc_canDisarm.sqf @@ -0,0 +1,32 @@ +/* + * Author: PabstMirror + * Checks the conditions for being able to disarm + * + * Arguments: + * 0: caller (player) + * 1: target + * 2: type of disarm + * + * Return Value: + * The return value + * + * Example: + * TODO + * + * Public: No + */ +#include "script_component.hpp" + +PARAMS_2(_caller,_target); +DEFAULT_PARAM(2,_type,""); + +if (false) exitWith {false}; + +_returnValue = true; + +switch (_type) do { + + +}; + +_returnValue diff --git a/addons/disarming/functions/fnc_disarmDropItems.sqf b/addons/disarming/functions/fnc_disarmDropItems.sqf new file mode 100644 index 0000000000..c4e093ec05 --- /dev/null +++ b/addons/disarming/functions/fnc_disarmDropItems.sqf @@ -0,0 +1,209 @@ +#include "script_component.hpp" + +#define TIME_MAX_WAIT 5 +#define DUMMY_ITEM "ACE_DebugPotato" +#define UNIQUE_MAGAZINES ["ACE_key_customKeyMagazine"] + +PARAMS_3(_caller,_target,_listOfItemsToRemove); +DEFAULT_PARAM(3,_doNotDropAmmo,false); //By default units drop all weapon mags when dropping a weapon + +_fncSumArray = { + _return = 0; + {_return = _return + _x;} forEach (_this select 0); + _return +}; + +//Sanity Check +if (_doNotDropAmmo && {({_x in _listOfItemsToRemove} count (magazines _target)) > 0}) exitWith { + [_caller, _target, "magazines and _doNotDropAmmo error"] call FUNC(finishDisarmTarget); +}; + +_holder = objNull; +{ + if ((_x getVariable [QGVAR(disarmUnit), objNull]) == _target) exitWith { + _holder = _x; + }; +} forEach ((getpos _target) nearObjects ["WeaponHolderSimulated", 3]); + +if (isNull _holder) then { + _dropPos = _target modelToWorld [-0.75, 0.75, 0]; + _dropPos set [2, 0]; + _holder = createVehicle ["WeaponHolderSimulated", _dropPos, [], 0, "CAN_COLLIDE"]; + _holder setVariable [QGVAR(disarmUnit), _target]; +}; + +//Verify holder created +if (isNull _holder) exitWith { + [_caller, _target, "Create Holder"] call FUNC(finishDisarmTarget); +}; + + +//Remove Magazines +_targetMagazinesStart = magazinesAmmo _target; +_holderMagazinesStart = magazinesAmmoCargo _holder; + +{ + EXPLODE_2_PVT(_x,_xClassname,_xAmmo); + if ((_xClassname in _listOfItemsToRemove) && {!(_xClassname in UNIQUE_MAGAZINES)}) then { + _holder addMagazineAmmoCargo [_xClassname, 1, _xAmmo]; + _target removeMagazine _xClassname; + }; +} forEach _targetMagazinesStart; + +_targetMagazinesEnd = magazinesAmmo _target; +_holderMagazinesEnd = magazinesAmmoCargo _holder; + +//Verify Mags dropped from unit: +if ( ({(_x select 0) in _listOfItemsToRemove} count _targetMagazinesEnd) != 0) exitWith { + [_caller, _target, "Didn't Remove Magazines"] call FUNC(finishDisarmTarget); +}; +//Verify holder has mags unit had (lazy count for now) +if (((count _targetMagazinesEnd) - (count _targetMagazinesStart)) != ((count _holderMagazinesEnd) - (count _holderMagazinesStart))) exitWith { + [_caller, _target, "Crate Magazines"] call FUNC(finishDisarmTarget); +}; + + +//Remove Items, Assigned Items and NVG +_holderItemsStart = getitemCargo _holder; +_targetItemsStart = ((assignedItems _target) + (items _target) + [hmd _target] + [headgear _target]); + +_addToCrateClassnames = []; +_addToCrateCount = []; +{ + if (_x in _listOfItemsToRemove) then { + if (_x in (items _target)) then { + _target removeItem _x; + } else { + _target unlinkItem _x; + }; + _index = _addToCrateClassnames find _x; + if (_index != -1) then { + _addToCrateCount set [_index, ((_addToCrateCount select _index) + 1)]; + } else { + _addToCrateClassnames pushBack _x; + _addToCrateCount pushBack 1; + }; + }; +} forEach _targetItemsStart; + +//Add the items to the holder (combined to reduce addItemCargoGlobal calls) +{ + _holder addItemCargoGlobal [(_addToCrateClassnames select _forEachIndex), (_addToCrateCount select _forEachIndex)]; +} forEach _addToCrateClassnames; + +_holderItemsEnd = getitemCargo _holder; +_targetItemsEnd = ((assignedItems _target) + (items _target) + [hmd _target] + [headgear _target]); + +//Verify Items Added (lazy count) +if (((count _targetItemsEnd) - (count _targetItemsStart)) != ([_addToCrateCount] call _fncSumArray)) exitWith { + [_caller, _target, "Items Not Removed From Player"] call FUNC(finishDisarmTarget); +}; +if ((([_holderItemsEnd select 1] call _fncSumArray) - ([_holderItemsStart select 1] call _fncSumArray)) != ([_addToCrateCount] call _fncSumArray)) exitWith { + [_caller, _target, "Items Not Added to Holder"] call FUNC(finishDisarmTarget); +}; + + +//If holder is still empty, it will be 'garbage collected' while we wait for the drop 'action' to take place +//So add a dummy item and just remove at the end +_holderIsEmpty = (([_holderItemsEnd select 1] call _fncSumArray) + (count _holderMagazinesEnd)) == 0; +if (_holderIsEmpty) then { + systemChat "Empty: making dummy"; + _holder addItemCargoGlobal [DUMMY_ITEM, 1]; +}; + +systemChat format ["PFEh start %1", time]; +//Start the PFEH to do the actions (which could take >1 frame) +[{ + PARAMS_2(_args,_pfID); + EXPLODE_8_PVT(_args,_caller,_target,_listOfItemsToRemove,_holder,_holderIsEmpty,_maxWaitTime,_doNotDropAmmo,_startingMagazines); + + _needToRemoveWeapon = ({_x in _listOfItemsToRemove} count (weapons _target)) > 0; + _needToRemoveMagazines = ({_x in _listOfItemsToRemove} count (magazines _target)) > 0; + _needToRemoveBackpack = ((backPack _target) != "") && {(backPack _target) in _listOfItemsToRemove}; + _needToRemoveVest = ((vest _target) != "") && {(vest _target) in _listOfItemsToRemove}; + _needToRemoveUniform = ((uniform _target) != "") && {(uniform _target) in _listOfItemsToRemove}; + + // systemChat format ["%1 - (%2 %3 %4 %5)", time, _maxWaitTime, _needToRemoveWeapon, _needToRemoveMagazines, _needToRemoveBackpack]; + + if ((time < _maxWaitTime) && {_needToRemoveWeapon || _needToRemoveMagazines || _needToRemoveBackpack}) then { + //action drop weapons (keeps loaded magazine and attachements) + { + if (_x in _listOfItemsToRemove) then { + _target action ["DropWeapon", _holder, _x]; + }; + } forEach (weapons _target); + + //Drop magazine (keeps unique ID) + { + if (_x in _listOfItemsToRemove) then { + _target action ["DropMagazine", _holder, _x]; + }; + } forEach (magazines _target); + + //Drop backpack (Keeps variables for ACRE/TFR) + if (_needToRemoveBackpack) then {_target action ["DropBag", _holder, (backPack _target)];}; + } else { + systemChat format ["PFEh done %1", time]; + //Exit PFEH + [_pfID] call CBA_fnc_removePerFrameHandler; + + + if (_doNotDropAmmo) then { + _error = false; + + _magsToPickup = +_startingMagazines; + { + _index = _magsToPickup find _x; + if (_index == -1) exitWith {_error = true; ERROR("More mags than when we started?")}; + _magsToPickup deleteAt _index; + } forEach (magazinesAmmo _target); + + _magazinesInHolder = magazinesAmmoCargo _holder; + { + _index = _magazinesInHolder find _x; + if (_index == -1) exitWith {_error = true; ERROR("Missing mag not in holder")}; + _magazinesInHolder deleteAt _index; + } forEach _magsToPickup; + + //No Error (all the ammo in the container is ammo we should have); + if ((!_error) && {_magazinesInHolder isEqualTo []}) then { + { + _target addMagazine _x; + } forEach (magazinesAmmoCargo _holder); + clearMagazineCargoGlobal _holder; + }; + }; + + //If we added a dummy item, remove it now + if (_holderIsEmpty && {!((getItemCargo _holder) isEqualTo [[DUMMY_ITEM],[1]])}) exitWith { + [_caller, _target, "Holder should only have dummy item"] call FUNC(finishDisarmTarget); + }; + if (_holderIsEmpty) then { + systemChat "Debug: Deleting Dummy"; + clearItemCargoGlobal _holder; + }; + + //Verify we didn't timeout waiting on drop action + if (time >= _maxWaitTime) exitWith { + [_caller, _target, "Drop Actions Timeout"] call FUNC(finishDisarmTarget); + }; + + if (_needToRemoveVest && {!((vestItems _target) isEqualTo [])}) exitWith { + [_caller, _target, "Vest Not Empty"] call FUNC(finishDisarmTarget); + }; + if (_needToRemoveVest) then { + removeVest _target; + _holder addItemCargoGlobal [(vest _target), 1]; + }; + if (_needToRemoveUniform && {!((uniformItems _target) isEqualTo [])}) exitWith { + [_caller, _target, "Uniform Not Empty"] call FUNC(finishDisarmTarget); + }; + if (_needToRemoveUniform) then { + removeUniform _target; + _holder addItemCargoGlobal [(uniform _target), 1]; + }; + + [_caller, _target, "Victory"] call FUNC(finishDisarmTarget); + }; + +}, 0.0, [_caller,_target, _listOfItemsToRemove, _holder, _holderIsEmpty, (time + TIME_MAX_WAIT), _doNotDropAmmo, _targetMagazinesEnd]] call CBA_fnc_addPerFrameHandler; diff --git a/addons/disarming/functions/fnc_finishDisarmCaller.sqf b/addons/disarming/functions/fnc_finishDisarmCaller.sqf new file mode 100644 index 0000000000..555555d8fe --- /dev/null +++ b/addons/disarming/functions/fnc_finishDisarmCaller.sqf @@ -0,0 +1,23 @@ +/* + * Author: PabstMirror + * TODO + * + * Arguments: + * 0: caller (player) + * 1: target + * 1: type of disarm + * + * Return Value: + * The return value + * + * Example: + * + * + * Public: No + */ +#include "script_component.hpp" + + +PARAMS_3(_caller,_target,_errorMsg); + +systemChat format ["Debug-Caller: Disarm finished with code [%1]", _errorMsg]; \ No newline at end of file diff --git a/addons/disarming/functions/fnc_finishDisarmTarget.sqf b/addons/disarming/functions/fnc_finishDisarmTarget.sqf new file mode 100644 index 0000000000..b65e5f053c --- /dev/null +++ b/addons/disarming/functions/fnc_finishDisarmTarget.sqf @@ -0,0 +1,25 @@ +/* + * Author: PabstMirror + * TODO + * + * Arguments: + * 0: caller (player) + * 1: target + * 1: type of disarm + * + * Return Value: + * The return value + * + * Example: + * finishDisarmTarget + * + * Public: No + */ +#include "script_component.hpp" + + +PARAMS_3(_caller,_target,_errorMsg); + +systemChat format ["Debug-Target: Disarm finished with code [%1]", _errorMsg]; + +["DisarmFinished", [_caller], [_caller, _target, _errorMsg]] call EFUNC(common,targetEvent); diff --git a/addons/disarming/functions/fnc_startDisarmCaller.sqf b/addons/disarming/functions/fnc_startDisarmCaller.sqf new file mode 100644 index 0000000000..43fa586b22 --- /dev/null +++ b/addons/disarming/functions/fnc_startDisarmCaller.sqf @@ -0,0 +1,22 @@ +/* + * Author: PabstMirror + * Starts the disarming process from the caller + * + * Arguments: + * 0: caller (player) + * 1: target + * 2: type of disarm + * + * Return Value: + * None + * + * Example: + * TODO + * + * Public: No + */ +#include "script_component.hpp" + +PARAMS_3(_caller,_target,_type); + +["Disarm", [_target], [_caller,_target,_type]] call EFUNC(common,targetEvent); diff --git a/addons/disarming/functions/fnc_startDisarmTarget.sqf b/addons/disarming/functions/fnc_startDisarmTarget.sqf new file mode 100644 index 0000000000..9a7526856d --- /dev/null +++ b/addons/disarming/functions/fnc_startDisarmTarget.sqf @@ -0,0 +1,38 @@ +/* + * Author: PabstMirror + * Starts disarming the target from the target + * Generates the specific list of items that should be removed from a disarm type + * + * Arguments: + * 0: caller (player) + * 1: target + * 1: type of disarm + * + * Return Value: + * None + * + * Example: + * + * + * Public: No + */ +#include "script_component.hpp" + +PARAMS_3(_caller,_target,_type); + +_listOfItemsToRemove = []; +_doNotDropAmmo = false; + +switch (toLower _type) do { +case ("backpack"): { + _listOfItemsToRemove pushBack (backpack _target); +}; +case ("weapons"): { + _listOfItemsToRemove = _listOfItemsToRemove + (weapons _target); + _doNotDropAmmo = true; +}; + + +}; + +[_caller, _target, _listOfItemsToRemove, _doNotDropAmmo] call FUNC(disarmDropItems); diff --git a/addons/disarming/functions/script_component.hpp b/addons/disarming/functions/script_component.hpp new file mode 100644 index 0000000000..38e082ee0e --- /dev/null +++ b/addons/disarming/functions/script_component.hpp @@ -0,0 +1 @@ +#include "\z\ace\addons\disarming\script_component.hpp" \ No newline at end of file diff --git a/addons/disarming/script_component.hpp b/addons/disarming/script_component.hpp new file mode 100644 index 0000000000..78315f5071 --- /dev/null +++ b/addons/disarming/script_component.hpp @@ -0,0 +1,12 @@ +#define COMPONENT disarming +#include "\z\ace\addons\main\script_mod.hpp" + +#ifdef DEBUG_ENABLED_DISARMING + #define DEBUG_MODE_FULL +#endif + +#ifdef DEBUG_SETTINGS_DISARMING + #define DEBUG_SETTINGS DEBUG_SETTINGS_DISARMING +#endif + +#include "\z\ace\addons\main\script_macros.hpp" \ No newline at end of file diff --git a/addons/disarming/stringtable.xml b/addons/disarming/stringtable.xml new file mode 100644 index 0000000000..893221713e --- /dev/null +++ b/addons/disarming/stringtable.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file