diff --git a/addons/common/XEH_preInit.sqf b/addons/common/XEH_preInit.sqf index 64a06a0f8c..3d1d5164df 100644 --- a/addons/common/XEH_preInit.sqf +++ b/addons/common/XEH_preInit.sqf @@ -110,6 +110,7 @@ PREP(removeCameraEventHandler); PREP(removeCustomEventHandler); PREP(removeMapMarkerCreatedEventHandler); PREP(removeScrollWheelEventHandler); +PREP(removeSpecificMagazine); PREP(restoreVariablesJIP); PREP(revertKeyCodeLocalized); PREP(sanitizeString); diff --git a/addons/common/functions/fnc_removeSpecificMagazine.sqf b/addons/common/functions/fnc_removeSpecificMagazine.sqf new file mode 100644 index 0000000000..7f29cf979c --- /dev/null +++ b/addons/common/functions/fnc_removeSpecificMagazine.sqf @@ -0,0 +1,69 @@ +/* + * Author: CAA-Picard + * Removes a magazine from the unit that has an specific ammo count + * + * Argument: + * 0: Player + * 1: Magazine + * 2: Ammo count + * + * Return value: + * None + */ +#include "script_component.hpp" + +EXPLODE_3_PVT(_this,_player,_magazineType,_ammoCount); + +private ["_magazines","_index","_isRemoved"]; +_isRemoved = false; + +// Check uniform +_magazines = [magazinesAmmoCargo uniformContainer _player, {_this select 0 == _magazineType}] call FUNC(filter); +_index = _magazines find [_magazineType,_ammoCount]; +if (_index > -1) exitWith { + { + _player removeItemFromUniform (_x select 0); + } forEach _magazines; + + { + if (!_isRemoved && (_x isEqualTo [_magazineType,_ammoCount])) then { + _isRemoved = true; + } else { + (uniformContainer _player) addMagazineAmmoCargo [_x select 0, 1, _x select 1]; + }; + } forEach _magazines; +}; + +// Check vest +_magazines = [magazinesAmmoCargo vestContainer _player, {_this select 0 == _magazineType}] call FUNC(filter); +_index = _magazines find [_magazineType,_ammoCount]; +if (_index > -1) exitWith { + { + _player removeItemFromVest (_x select 0); + } forEach _magazines; + + { + if (!_isRemoved && (_x isEqualTo [_magazineType,_ammoCount])) then { + _isRemoved = true; + } else { + (vestContainer _player) addMagazineAmmoCargo [_x select 0, 1, _x select 1]; + }; + } forEach _magazines; +}; + +// Check backpack +_magazines = [magazinesAmmoCargo backpackContainer _player, {_this select 0 == _magazineType}] call FUNC(filter); +_index = _magazines find [_magazineType,_ammoCount]; +if (_index > -1) exitWith { + { + _player removeItemFromBackpack (_x select 0); + } forEach _magazines; + + { + if (!_isRemoved && (_x isEqualTo [_magazineType,_ammoCount])) then { + _isRemoved = true; + } else { + (backpackContainer _player) addMagazineAmmoCargo [_x select 0, 1, _x select 1]; + }; + } forEach _magazines; +}; diff --git a/addons/reload/CfgMagazines.hpp b/addons/reload/CfgMagazines.hpp new file mode 100644 index 0000000000..6811a49494 --- /dev/null +++ b/addons/reload/CfgMagazines.hpp @@ -0,0 +1,12 @@ +class CfgMagazines { + + class CA_Magazine; + class 150Rnd_762x51_Box : CA_Magazine { + ACE_isBelt = 1; + }; + + class 100Rnd_65x39_caseless_mag; + class 200Rnd_65x39_cased_Box : 100Rnd_65x39_caseless_mag { + ACE_isBelt = 1; + }; +}; \ No newline at end of file diff --git a/addons/reload/CfgVehicles.hpp b/addons/reload/CfgVehicles.hpp new file mode 100644 index 0000000000..8524ca5186 --- /dev/null +++ b/addons/reload/CfgVehicles.hpp @@ -0,0 +1,19 @@ +class CfgVehicles { + class Man; + class CAManBase: Man { + class ACE_Actions { + class ACE_WeaponsActions { + selection = "weapon"; + displayName = "Weapon"; + distance = 2; + condition = QUOTE([ARR_2(_player, _target)] call FUNC(canLinkBelt)); + class ACE_LinkBelt { + displayName = "$STR_ACE_Reload_LinkBelt"; + distance = 2; + condition = QUOTE([ARR_2(_player, _target)] call FUNC(canLinkBelt)); + statement = QUOTE([ARR_2(_player, _target)] call FUNC(startLinkingBelt)); + }; + }; + }; + }; +}; diff --git a/addons/reload/XEH_postInit.sqf b/addons/reload/XEH_postInit.sqf index d40e5e0442..887b673503 100644 --- a/addons/reload/XEH_postInit.sqf +++ b/addons/reload/XEH_postInit.sqf @@ -22,3 +22,48 @@ if !(hasInterface) exitWith {}; false, "keydown" ] call cba_fnc_registerKeybind; + + +// Listen for attempts to link ammo +["linkedAmmo", { + EXPLODE_3_PVT(_this,_receiver,_giver,_magazine); + diag_log "linkedAmmo"; + diag_log _this; + + private ["_magazineCfg","_magazineType"]; + _magazineType = currentMagazine _receiver; + _magazineCfg = configFile >> "CfgMagazines" >> _magazineType; + + // Return the magazine if it's the wrong type + if (_magazineType != (_magazine select 0)) exitWith { + ["returnedAmmo", [_giver], [_giver,_receiver,_magazine]] call EFUNC(common,targetEvent); + }; + + private ["_ammoCount","_ammoMissing","_ammoAdded","_ammoRemaining"]; + _ammoCount = _receiver ammo currentWeapon _receiver; + _ammoMissing = getNumber (_magazineCfg >> "count") - _ammoCount; + + // Return the magazine if the belt is full or empty + if ((_ammoCount == 0) || _ammoMissing == 0) exitWith { + ["returnedAmmo", [_giver], [_giver,_receiver,_magazine]] call EFUNC(common,targetEvent); + }; + + // Add the ammo + _ammoAdded = _ammoMissing min (_magazine select 1); + _receiver setAmmo [currentWeapon _receiver, _ammoCount + _ammoAdded]; + + if ((_magazine select 1) - _ammoAdded > 0) then { + ["returnedAmmo", [_giver], [_giver,_receiver,[_magazineType,(_magazine select 1) - _ammoAdded]]] call EFUNC(common,targetEvent); + }; + +}] call EFUNC(common,addEventhandler); + + +// Listen for returned magazines +["returnedAmmo", { + EXPLODE_3_PVT(_this,_receiver,_giver,_magazine); + diag_log "returnedAmmo"; + diag_log _this; + + _receiver addMagazine _magazine; +}] call EFUNC(common,addEventhandler); diff --git a/addons/reload/XEH_preInit.sqf b/addons/reload/XEH_preInit.sqf index b5c8e45d35..f0e19f9379 100644 --- a/addons/reload/XEH_preInit.sqf +++ b/addons/reload/XEH_preInit.sqf @@ -2,6 +2,8 @@ ADDON = false; +PREP(canLinkBelt); PREP(checkAmmo); +PREP(startLinkingBelt); ADDON = true; diff --git a/addons/reload/config.cpp b/addons/reload/config.cpp index 6e0c14049d..dece04224a 100644 --- a/addons/reload/config.cpp +++ b/addons/reload/config.cpp @@ -12,6 +12,10 @@ class CfgPatches { }; }; +#include "CfgVehicles.hpp" + +#include "CfgMagazines.hpp" + #include "CfgEventHandlers.hpp" #include "CfgActions.hpp" diff --git a/addons/reload/functions/fnc_canLinkBelt.sqf b/addons/reload/functions/fnc_canLinkBelt.sqf new file mode 100644 index 0000000000..4b576865f1 --- /dev/null +++ b/addons/reload/functions/fnc_canLinkBelt.sqf @@ -0,0 +1,41 @@ +/* + * Author: CAA-Picard + * Check if the target has an MG equiped with belt system that the player can link + * + * Argument: + * 0: Player + * 1: Target + * + * Return value: + * Can link belt + */ +#include "script_component.hpp" + +EXPLODE_2_PVT(_this,_player,_target); + +if (vehicle _target != _target) exitWith {false}; + +private ["_magazineCfg","_magazineType"]; +_magazineType = currentMagazine _target; +_magazineCfg = configFile >> "CfgMagazines" >> _magazineType; +if (getNumber (_magazineCfg >> "ACE_isBelt") == 0) exitWith {false}; + +// Check if the ammo is not empty or full +private "_ammoCount"; +_ammoCount = _target ammo currentWeapon _target; + +// Exit if the belt is full or empty +if ((_ammoCount == 0) || (getNumber (_magazineCfg >> "count") - _ammoCount) == 0) exitWith {false}; + +// Check if the player has any of the same same magazines +// Calculate max ammo +private "_maxAmmo"; +_maxAmmo = 0; + +{ + diag_log "filtered:"; + diag_log _x; + _maxAmmo = _maxAmmo max (_x select 1); +} forEach ([magazinesAmmo _player, {_this select 0 == _magazineType}] call EFUNC(common,filter)); + +_maxAmmo > 0 diff --git a/addons/reload/functions/fnc_startLinkingBelt.sqf b/addons/reload/functions/fnc_startLinkingBelt.sqf new file mode 100644 index 0000000000..142f38b7b5 --- /dev/null +++ b/addons/reload/functions/fnc_startLinkingBelt.sqf @@ -0,0 +1,68 @@ +/* + * Author: CAA-Picard + * Start linking the belt + * + * Argument: + * 0: Player + * 1: Target + * + * Return value: + * None + */ +#include "script_component.hpp" + +EXPLODE_2_PVT(_this,_player,_target); + +if (vehicle _target != _target) exitWith {false}; + +private ["_magazineCfg","_magazineType"]; +_magazineType = currentMagazine _target; +_magazineCfg = configFile >> "CfgMagazines" >> _magazineType; +if (getNumber (_magazineCfg >> "ACE_isBelt") == 0) exitWith {false}; + +// Check if the ammo is not empty or full +private "_ammoCount"; +_ammoCount = _target ammo currentWeapon _target; + +// Exit if the belt is full or empty +if ((_ammoCount == 0) || (getNumber (_magazineCfg >> "count") - _ammoCount) == 0) exitWith {false}; + +// Check if the player has any of the same same magazines +// Calculate max ammo it can link +private "_maxAmmo"; +_maxAmmo = 0; + +{ + _maxAmmo = _maxAmmo max (_x select 1); +} forEach ([magazinesAmmo _player, {_this select 0 == _magazineType}] call EFUNC(common,filter)); + +if (_maxAmmo == 0) exitWith {}; + +// Condition to call each frame +_condition = { + EXPLODE_2_PVT((_this select 0),_player,_target); + ([_player, _target] call EFUNC(common,canInteract)) && ((_player distance _target) < 3) && ((speed _target) < 1) +}; + +_onFinish = { + EXPLODE_3_PVT((_this select 0),_player,_target,_magazine); + + // Raise event on remote unit + ["linkedAmmo", [_target], [_target, _player, _magazine]] call EFUNC(common,targetEvent); +}; + +_onFailure = { + EXPLODE_3_PVT((_this select 0),_player,_target,_magazine); + [_caller, "AmovPknlMstpSrasWrflDnon", 1] call EFUNC(common,doAnimation); + + // Add back the magazine with the former ammo count + _player addMagazine _magazine; +}; + +[_player, "AinvPknlMstpSnonWnonDr_medic5", 0] call EFUNC(common,doAnimation); + +// Remove the magazine with maximum remaining ammo +[_player, _magazineType, _maxAmmo] call EFUNC(common,removeSpecificMagazine); + +// Call progress bar +[4, [_player, _target, [_magazineType, _maxAmmo]], _onFinish, _onFailure, (localize "STR_ACE_Reload_LinkingBelt"), _condition] call EFUNC(common,progressBar); diff --git a/addons/reload/stringtable.xml b/addons/reload/stringtable.xml index 1f39b0e743..18af718873 100644 --- a/addons/reload/stringtable.xml +++ b/addons/reload/stringtable.xml @@ -26,5 +26,11 @@ Munições Боеприпасы + + Link belt + + + Linking belt... +