2023-09-12 18:58:10 +00:00
#include "..\script_component.hpp"
2015-02-27 21:23:46 +00:00
/*
* Author: PabstMirror
2015-08-09 03:18:26 +00:00
*
2015-03-21 01:17:49 +00:00
* Makes a unit drop items
2015-02-27 21:23:46 +00:00
*
* Arguments:
2017-09-22 15:33:08 +00:00
* 0: Caller (player) <OBJECT>
* 1: Target <OBJECT>
* 2: Classnames <ARRAY>
* 3: Do Not Drop Ammo <BOOL> (default: false)
2015-02-27 21:23:46 +00:00
*
* Return Value:
2017-06-08 13:31:51 +00:00
* None
2015-02-27 21:23:46 +00:00
*
* Example:
* [player, cursorTarget, ["ace_bandage"]] call ace_disarming_fnc_disarmDropItems
*
* Public: No
*/
2015-02-11 01:55:53 +00:00
#define TIME_MAX_WAIT 5
2015-08-09 03:18:26 +00:00
params ["_caller", "_target", "_listOfItemsToRemove", ["_doNotDropAmmo", false, [false]]]; //By default units drop all weapon mags when dropping a weapon
2015-02-11 01:55:53 +00:00
2017-10-10 14:39:59 +00:00
private _fncSumArray = {
private _return = 0;
2015-08-09 03:18:26 +00:00
{_return = _return + _x;} count (_this select 0);
2015-02-11 01:55:53 +00:00
_return
};
2015-02-27 21:23:46 +00:00
//Sanity Checks
2024-06-18 14:08:03 +00:00
if !([_target] call FUNC(canBeDisarmed)) exitWith {
2015-02-27 21:23:46 +00:00
[_caller, _target, "Debug: Cannot disarm target"] call FUNC(eventTargetFinish);
};
2015-02-11 01:55:53 +00:00
if (_doNotDropAmmo && {({_x in _listOfItemsToRemove} count (magazines _target)) > 0}) exitWith {
2015-02-27 21:23:46 +00:00
[_caller, _target, "Debug: Trying to drop magazine with _doNotDropAmmo flag"] call FUNC(eventTargetFinish);
2015-02-11 01:55:53 +00:00
};
2017-10-10 14:39:59 +00:00
private _holder = objNull;
2015-03-21 01:17:49 +00:00
2023-10-09 17:58:49 +00:00
// if _target is in a vehicle, use vehicle inventory as container
if (!isNull objectParent _target) then {
_holder = objectParent _target;
};
2015-03-21 01:17:49 +00:00
//If not dropping ammo, don't use an existing container
2015-02-27 21:23:46 +00:00
if (!_doNotDropAmmo) then {
{
if ((_x getVariable [QGVAR(disarmUnit), objNull]) == _target) exitWith {
_holder = _x;
};
2024-04-04 11:15:26 +00:00
} forEach ((getpos _target) nearObjects [DISARM_CONTAINER, 3]);
2015-02-27 21:23:46 +00:00
};
2015-02-11 01:55:53 +00:00
2015-04-04 05:52:21 +00:00
//Create a new weapon holder
2015-02-11 01:55:53 +00:00
if (isNull _holder) then {
2017-10-10 14:39:59 +00:00
private _dropPos = _target modelToWorld [0.4, 0.75, 0]; //offset someone unconscious isn't lying over it
2015-03-21 01:17:49 +00:00
_dropPos set [2, ((getPosASL _target) select 2)];
_holder = createVehicle [DISARM_CONTAINER, _dropPos, [], 0, "CAN_COLLIDE"];
_holder setPosASL _dropPos;
2015-02-28 00:56:15 +00:00
_holder setVariable [QGVAR(disarmUnit), _target, true];
2015-02-11 01:55:53 +00:00
};
//Verify holder created
if (isNull _holder) exitWith {
2015-02-27 21:23:46 +00:00
[_caller, _target, "Debug: Null Holder"] call FUNC(eventTargetFinish);
2015-02-11 01:55:53 +00:00
};
2015-10-21 20:52:21 +00:00
//Make sure only one drop operation at a time (using PFEH system as a queue)
2015-02-27 21:23:46 +00:00
if (_holder getVariable [QGVAR(holderInUse), false]) exitWith {
[{
_this call FUNC(disarmDropItems);
2016-05-22 13:27:24 +00:00
}, _this] call CBA_fnc_execNextFrame;
2015-02-27 21:23:46 +00:00
};
_holder setVariable [QGVAR(holderInUse), true];
2015-02-11 01:55:53 +00:00
//Remove Magazines
2017-10-10 14:39:59 +00:00
private _targetMagazinesStart = magazinesAmmo _target;
private _holderMagazinesStart = magazinesAmmoCargo _holder;
2015-02-11 01:55:53 +00:00
{
2017-10-10 14:39:59 +00:00
_x params ["_xClassname", "_xAmmo"];
2015-05-09 22:08:47 +00:00
if ((_xClassname in _listOfItemsToRemove) && {(getNumber (configFile >> "CfgMagazines" >> _xClassname >> "ACE_isUnique")) == 0}) then {
2015-02-11 01:55:53 +00:00
_holder addMagazineAmmoCargo [_xClassname, 1, _xAmmo];
_target removeMagazine _xClassname;
};
} forEach _targetMagazinesStart;
2017-10-10 14:39:59 +00:00
private _targetMagazinesEnd = magazinesAmmo _target;
private _holderMagazinesEnd = magazinesAmmoCargo _holder;
2015-02-11 01:55:53 +00:00
//Verify Mags dropped from unit:
2015-05-09 22:08:47 +00:00
if (({((_x select 0) in _listOfItemsToRemove) && {(getNumber (configFile >> "CfgMagazines" >> (_x select 0) >> "ACE_isUnique")) == 0}} count _targetMagazinesEnd) != 0) exitWith {
2015-02-27 21:23:46 +00:00
_holder setVariable [QGVAR(holderInUse), false];
[_caller, _target, "Debug: Didn't Remove Magazines"] call FUNC(eventTargetFinish);
2015-02-11 01:55:53 +00:00
};
2015-04-04 05:52:21 +00:00
//Verify holder has mags unit had
2024-06-18 14:08:03 +00:00
if !([_targetMagazinesStart, _targetMagazinesEnd, _holderMagazinesStart, _holderMagazinesEnd] call FUNC(verifyMagazinesMoved)) then {
2015-02-27 21:23:46 +00:00
_holder setVariable [QGVAR(holderInUse), false];
[_caller, _target, "Debug: Crate Magazines not in holder"] call FUNC(eventTargetFinish);
2015-02-11 01:55:53 +00:00
};
//Remove Items, Assigned Items and NVG
2017-10-10 14:39:59 +00:00
private _holderItemsStart = getitemCargo _holder;
private _targetItemsStart = (assignedItems _target) + (items _target) - (weapons _target);
2015-02-28 00:38:23 +00:00
if ((headgear _target) != "") then {_targetItemsStart pushBack (headgear _target);};
if ((goggles _target) != "") then {_targetItemsStart pushBack (goggles _target);};
2015-02-11 01:55:53 +00:00
2017-10-10 14:39:59 +00:00
private _addToCrateClassnames = [];
private _addToCrateCount = [];
2015-02-11 01:55:53 +00:00
{
if (_x in _listOfItemsToRemove) then {
if (_x in (items _target)) then {
_target removeItem _x;
} else {
_target unlinkItem _x;
};
2017-10-10 14:39:59 +00:00
private _index = _addToCrateClassnames find _x;
2015-02-11 01:55:53 +00:00
if (_index != -1) then {
_addToCrateCount set [_index, ((_addToCrateCount select _index) + 1)];
} else {
_addToCrateClassnames pushBack _x;
_addToCrateCount pushBack 1;
};
};
2015-08-15 01:13:41 +00:00
} forEach _targetItemsStart;
2015-02-11 01:55:53 +00:00
//Add the items to the holder (combined to reduce addItemCargoGlobal calls)
{
_holder addItemCargoGlobal [(_addToCrateClassnames select _forEachIndex), (_addToCrateCount select _forEachIndex)];
} forEach _addToCrateClassnames;
2017-10-10 14:39:59 +00:00
private _holderItemsEnd = getitemCargo _holder;
private _targetItemsEnd = (assignedItems _target) + (items _target) - (weapons _target);
2015-02-28 00:38:23 +00:00
if ((headgear _target) != "") then {_targetItemsEnd pushBack (headgear _target);};
if ((goggles _target) != "") then {_targetItemsEnd pushBack (goggles _target);};
2015-02-11 01:55:53 +00:00
2015-03-17 19:43:50 +00:00
//Verify Items Added
2015-02-11 20:37:18 +00:00
if (((count _targetItemsStart) - (count _targetItemsEnd)) != ([_addToCrateCount] call _fncSumArray)) exitWith {
2015-02-27 21:23:46 +00:00
_holder setVariable [QGVAR(holderInUse), false];
[_caller, _target, "Debug: Items Not Removed From Player"] call FUNC(eventTargetFinish);
2015-02-11 01:55:53 +00:00
};
if ((([_holderItemsEnd select 1] call _fncSumArray) - ([_holderItemsStart select 1] call _fncSumArray)) != ([_addToCrateCount] call _fncSumArray)) exitWith {
2015-02-27 21:23:46 +00:00
_holder setVariable [QGVAR(holderInUse), false];
[_caller, _target, "Debug: Items Not Added to Holder"] call FUNC(eventTargetFinish);
2015-02-11 01:55:53 +00:00
};
2015-05-09 19:41:46 +00:00
//Script drop uniforms/vest if empty
if (((uniform _target) != "") && {(uniform _target) in _listOfItemsToRemove} && {(uniformItems _target) isEqualTo []}) then {
_holder addItemCargoGlobal [(uniform _target), 1];
removeUniform _target;
};
if (((vest _target) != "") && {(vest _target) in _listOfItemsToRemove} && {(vestItems _target) isEqualTo []}) then {
_holder addItemCargoGlobal [(vest _target), 1];
removeVest _target;
};
2015-02-11 01:55:53 +00:00
//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
2017-10-10 14:39:59 +00:00
private _holderIsEmpty = ([_holder] call FUNC(getAllGearContainer)) isEqualTo [[],[]];
2015-02-11 01:55:53 +00:00
if (_holderIsEmpty) then {
2015-04-04 05:52:21 +00:00
TRACE_1("Debug: adding dummy item to holder",_holder);
2015-02-11 01:55:53 +00:00
_holder addItemCargoGlobal [DUMMY_ITEM, 1];
};
//Start the PFEH to do the actions (which could take >1 frame)
[{
2017-10-10 14:39:59 +00:00
params ["_args", "_pfID"];
_args params ["_caller", "_target", "_listOfItemsToRemove", "_holder", "_holderIsEmpty", "_maxWaitTime", "_doNotDropAmmo", "_startingMagazines"];
2015-02-11 01:55:53 +00:00
2017-10-10 14:39:59 +00:00
private _needToRemoveWeapon = ({_x in _listOfItemsToRemove} count (weapons _target)) > 0;
private _needToRemoveMagazines = ({_x in _listOfItemsToRemove} count (magazines _target)) > 0;
private _needToRemoveBackpack = ((backPack _target) != "") && {(backPack _target) in _listOfItemsToRemove};
private _needToRemoveVest = ((vest _target) != "") && {(vest _target) in _listOfItemsToRemove};
private _needToRemoveUniform = ((uniform _target) != "") && {(uniform _target) in _listOfItemsToRemove};
2015-02-11 01:55:53 +00:00
2016-03-02 10:01:39 +00:00
if ((CBA_missionTime < _maxWaitTime) && {[_target] call FUNC(canBeDisarmed)} && {_needToRemoveWeapon || _needToRemoveMagazines || _needToRemoveBackpack}) then {
2015-02-11 01:55:53 +00:00
//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 {
[_pfID] call CBA_fnc_removePerFrameHandler;
if (_doNotDropAmmo) then {
2017-10-10 14:39:59 +00:00
private _error = false;
2015-02-11 01:55:53 +00:00
2017-10-10 14:39:59 +00:00
private _magsToPickup = +_startingMagazines;
2015-02-11 01:55:53 +00:00
{
2017-10-10 14:39:59 +00:00
private _index = _magsToPickup find _x;
2015-02-11 01:55:53 +00:00
if (_index == -1) exitWith {_error = true; ERROR("More mags than when we started?")};
_magsToPickup deleteAt _index;
} forEach (magazinesAmmo _target);
2017-10-10 14:39:59 +00:00
private _magazinesInHolder = magazinesAmmoCargo _holder;
2015-02-11 01:55:53 +00:00
{
2017-10-10 14:39:59 +00:00
private _index = _magazinesInHolder find _x;
2015-02-11 01:55:53 +00:00
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
2021-02-27 17:05:05 +00:00
if (_holderIsEmpty && {(getItemCargo _holder) isNotEqualTo [[DUMMY_ITEM],[1]]}) exitWith {
2015-02-27 21:23:46 +00:00
_holder setVariable [QGVAR(holderInUse), false];
[_caller, _target, "Debug: Holder should only have dummy item"] call FUNC(eventTargetFinish);
2015-02-11 01:55:53 +00:00
};
if (_holderIsEmpty) then {
2015-04-04 05:52:21 +00:00
TRACE_1("Debug: removing dummy item from holder",_holder);
2015-02-11 01:55:53 +00:00
clearItemCargoGlobal _holder;
};
//Verify we didn't timeout waiting on drop action
2016-03-02 10:01:39 +00:00
if (CBA_missionTime >= _maxWaitTime) exitWith {
2015-02-27 21:23:46 +00:00
_holder setVariable [QGVAR(holderInUse), false];
[_caller, _target, "Debug: Drop Actions Timeout"] call FUNC(eventTargetFinish);
2015-02-11 01:55:53 +00:00
};
2015-03-17 19:43:50 +00:00
//If target lost disarm status:
2024-06-18 14:08:03 +00:00
if !([_target] call FUNC(canBeDisarmed)) exitWith {
2015-03-17 19:43:50 +00:00
_holder setVariable [QGVAR(holderInUse), false];
[_caller, _target, "Debug: Target cannot be disarmed"] call FUNC(eventTargetFinish);
};
2021-02-27 17:05:05 +00:00
if (_needToRemoveVest && {(vestItems _target) isNotEqualTo []}) exitWith {
2015-02-27 21:23:46 +00:00
_holder setVariable [QGVAR(holderInUse), false];
[_caller, _target, "Debug: Vest Not Empty"] call FUNC(eventTargetFinish);
2015-02-11 01:55:53 +00:00
};
if (_needToRemoveVest) then {
_holder addItemCargoGlobal [(vest _target), 1];
2015-03-21 01:47:34 +00:00
removeVest _target;
2015-02-11 01:55:53 +00:00
};
2021-02-27 17:05:05 +00:00
if (_needToRemoveUniform && {(uniformItems _target) isNotEqualTo []}) exitWith {
2015-02-27 21:23:46 +00:00
_holder setVariable [QGVAR(holderInUse), false];
[_caller, _target, "Debug: Uniform Not Empty"] call FUNC(eventTargetFinish);
2015-02-11 01:55:53 +00:00
};
if (_needToRemoveUniform) then {
_holder addItemCargoGlobal [(uniform _target), 1];
2015-03-21 01:47:34 +00:00
removeUniform _target;
2015-02-11 01:55:53 +00:00
};
2015-02-27 21:23:46 +00:00
_holder setVariable [QGVAR(holderInUse), false];
2015-02-28 00:38:23 +00:00
[_caller, _target, ""] call FUNC(eventTargetFinish);
2015-02-11 01:55:53 +00:00
};
2016-03-02 10:01:39 +00:00
}, 0.0, [_caller,_target, _listOfItemsToRemove, _holder, _holderIsEmpty, (CBA_missionTime + TIME_MAX_WAIT), _doNotDropAmmo, _targetMagazinesEnd]] call CBA_fnc_addPerFrameHandler;