diff --git a/addons/common/XEH_PREP.hpp b/addons/common/XEH_PREP.hpp index 323f2c1d0d4..469e9dfc5d1 100644 --- a/addons/common/XEH_PREP.hpp +++ b/addons/common/XEH_PREP.hpp @@ -44,6 +44,7 @@ PREP(displayText); PREP(displayTextPicture); PREP(displayTextStructured); PREP(doAnimation); +PREP(doArtilleryFire); PREP(doGesture); PREP(dummy); PREP(dropBackpack); diff --git a/addons/common/functions/fnc_doArtilleryFire.sqf b/addons/common/functions/fnc_doArtilleryFire.sqf new file mode 100644 index 00000000000..8cb75b78350 --- /dev/null +++ b/addons/common/functions/fnc_doArtilleryFire.sqf @@ -0,0 +1,74 @@ +#include "script_component.hpp" +/* + * Author: LinkIsGrim, mharris001 + * Wrapper for engine doArtilleryFire, fires barrage one round at a time. + * Handles and accepts CSW carry magazines. + * + * Arguments: + * 0: Vehicle, gunner must be local + * 1: Target + * 2: Magazine Type + * 3: Rounds to fire + * 4: Spread around target position, in meters (default: 0) + * + * Return Value: + * Barrage Started + * + * Example: + * [cursorObject, [0, 0, 0], "8Rnd_82mm_Mo_shells", 2, 25] call ace_common_fnc_doArtilleryFire + * + * Public: Yes + */ +params [["_vehicle", objNull, [objNull]], ["_position", [0, 0, 0], [[], objNull, ""], 3], ["_magazine", "", [""]], ["_rounds", 0, [0]], ["_spread", 0, [0]]]; + +if (isNull _vehicle || {_rounds isEqualTo 0} || {_magazine isEqualTo ""} || {!(_vehicle turretLocal [0])} || {isNull (gunner _vehicle)}) exitWith {false}; + +if (_position isEqualType objNull) then { + _position = ASLtoAGL getPosASL _position; +}; + +if (_position isEqualType "") then { + _position = [_position, true] call CBA_fnc_mapGridToPos; +}; + +// Magazine must be configCase +_magazine = configName (configFile >> "CfgMagazines" >> _magazine); +if (_magazine isEqualTo "") exitWith {false}; + +if (["ace_csw"] call EFUNC(common,isModLoaded)) then { + [_vehicle, _magazine] call EFUNC(csw,handleDoArtilleryFire) params ["_cswHandled", "_newMagazine"]; + if !(_cswHandled) exitWith {false}; + _magazine = _newMagazine; +}; + +if !(_position inRangeOfArtillery [[_vehicle], _magazine]) exitWith {false}; + +_vehicle doWatch _position; + +[{ + params ["_vehicle", "_position", "_magazine", "_roundsLeft", "_spread", "_lastFired"]; + if (CBA_missionTime - _lastFired > 30) exitWith {true}; + + (weaponState [_vehicle, [0]]) params ["", "", "", "_loadedMag", "_ammoCount", "_roundReloadPhase", "_magazineReloadPhase"]; + if ( + _loadedMag isEqualTo _magazine && + {_ammoCount > 0} && + {_roundReloadPhase isEqualTo 0} && + {_magazineReloadPhase isEqualTo 0} && + {unitReady _vehicle} + ) then { + _vehicle doArtilleryFire [[_position, _spread] call CBA_fnc_randPos, _magazine, 1]; + _roundsLeft = _roundsLeft - 1; + _this set [3, _roundsLeft]; + _this set [5, CBA_missionTime]; + }; + + if (_roundsLeft <= 0 || {!alive _vehicle} || {!alive (gunner _vehicle)} || {objectParent (gunner _vehicle) isNotEqualTo _vehicle}) exitWith { + [QGVAR(doArtilleryFireComplete), [_vehicle, _magazine, _roundsLeft]] call CBA_fnc_globalEvent; + [{_this doWatch objNull}, _vehicle, 5] call CBA_fnc_waitAndExecute; + true + }; + false +}, {}, [_vehicle, _position, _magazine, _rounds, _spread, CBA_missionTime]] call CBA_fnc_waitUntilAndExecute; + +true diff --git a/addons/csw/XEH_PREP.hpp b/addons/csw/XEH_PREP.hpp index 5966578aca5..d2a05e5c895 100644 --- a/addons/csw/XEH_PREP.hpp +++ b/addons/csw/XEH_PREP.hpp @@ -4,6 +4,7 @@ PREP(aceRearmGetCarryMagazines); PREP(ai_handleFired); PREP(ai_handleGetIn); +PREP(ai_switchMagazine); PREP(ai_reload); PREP(assemble_canDeployTripod); @@ -19,7 +20,12 @@ PREP(assemble_pickupWeapon); PREP(canGetIn); PREP(getIn); +PREP(compatibleMagazines); +PREP(getAvailableAmmo); PREP(getCarryMagazine); +PREP(getNearbySources); +PREP(getSourceCompatibleMagazines); +PREP(handleDoArtilleryFire); PREP(proxyWeapon); PREP(reload_actionsLoad); @@ -32,6 +38,7 @@ PREP(reload_handleAddTurretMag); PREP(reload_handleRemoveTurretMag); PREP(reload_handleReturnAmmo); PREP(reload_loadMagazine); +PREP(unloadMagazines); PREP(staticWeaponInit); PREP(staticWeaponInit_unloadExtraMags); diff --git a/addons/csw/XEH_postInit.sqf b/addons/csw/XEH_postInit.sqf index fddac693858..c1525dc4ea6 100644 --- a/addons/csw/XEH_postInit.sqf +++ b/addons/csw/XEH_postInit.sqf @@ -1,7 +1,5 @@ #include "script_component.hpp" -GVAR(vehicleMagCache) = createHashMap; - ["CBA_settingsInitialized", { TRACE_3("settingsInit",GVAR(defaultAssemblyMode),GVAR(handleExtraMagazines),GVAR(ammoHandling)); ["StaticWeapon", "init", LINKFUNC(staticWeaponInit), true, [], true] call CBA_fnc_addClassEventHandler; @@ -18,8 +16,14 @@ GVAR(vehicleMagCache) = createHashMap; [QGVAR(addTurretMag), LINKFUNC(reload_handleAddTurretMag)] call CBA_fnc_addEventHandler; [QGVAR(removeTurretMag), LINKFUNC(reload_handleRemoveTurretMag)] call CBA_fnc_addEventHandler; [QGVAR(returnAmmo), LINKFUNC(reload_handleReturnAmmo)] call CBA_fnc_addEventHandler; +[QGVAR(ai_reload), LINKFUNC(ai_reload)] call CBA_fnc_addEventHandler; +[QEGVAR(common,doArtilleryFireComplete), { + params ["_vehicle"]; + if !(local _vehicle) exitWith {}; + _vehicle setVariable [QGVAR(forcedMag), nil, true]; +}] call CBA_fnc_addEventHandler; #ifdef DEBUG_MODE_FULL call compile preprocessFileLineNumbers QPATHTOF(dev\checkStaticWeapons.sqf); diff --git a/addons/csw/XEH_preInit.sqf b/addons/csw/XEH_preInit.sqf index 6ecb2a0c2fb..a95f9746217 100644 --- a/addons/csw/XEH_preInit.sqf +++ b/addons/csw/XEH_preInit.sqf @@ -9,6 +9,8 @@ PREP_RECOMPILE_END; #include "initSettings.sqf" GVAR(initializedStaticTypes) = []; +GVAR(vehicleMagCache) = createHashMap; +GVAR(compatibleMagsCache) = createHashMap; +GVAR(compatibleVehicleMagsCache) = createHashMap; ADDON = true; - diff --git a/addons/csw/functions/fnc_aceRearmGetCarryMagazines.sqf b/addons/csw/functions/fnc_aceRearmGetCarryMagazines.sqf index ac51d03347e..ac833d64fd4 100644 --- a/addons/csw/functions/fnc_aceRearmGetCarryMagazines.sqf +++ b/addons/csw/functions/fnc_aceRearmGetCarryMagazines.sqf @@ -4,7 +4,7 @@ * Helper function for ace_rearm; Gets magazines that should be loaded by csw * * Arguments: - * 0: Vehicle + * 0: CSW * 1: Specific Turret or pass bool to check all turrets (default: true) * * Return Value: diff --git a/addons/csw/functions/fnc_ai_handleFired.sqf b/addons/csw/functions/fnc_ai_handleFired.sqf index 668a425b50f..8bec4329c27 100644 --- a/addons/csw/functions/fnc_ai_handleFired.sqf +++ b/addons/csw/functions/fnc_ai_handleFired.sqf @@ -12,12 +12,12 @@ * Public: No */ -params ["_staticWeapon", "_weapon", "_muzzle", "_mode", "_ammo", "_magazine", "_projectile", "_gunner"]; -TRACE_8("firedEH:",_staticWeapon,_weapon,_muzzle,_mode,_ammo,_magazine,_projectile,_gunner); +params ["_vehicle", "_weapon", "_muzzle", "_mode", "_ammo", "_magazine", "_projectile", "_gunner"]; +TRACE_8("firedEH:",_vehicle,_weapon,_muzzle,_mode,_ammo,_magazine,_projectile,_gunner); if ((!local _gunner) || {[_gunner] call EFUNC(common,isPlayer)}) exitWith {}; -if (someAmmo _staticWeapon) exitWith {}; +if (someAmmo _vehicle) exitWith {}; -TRACE_2("need ammo",someAmmo _staticWeapon,magazinesAllTurrets _staticWeapon); +TRACE_2("need ammo",someAmmo _vehicle,magazinesAllTurrets _vehicle); -[_staticWeapon, _gunner, _weapon, _magazine] call FUNC(ai_reload); +[_vehicle, _gunner] call FUNC(ai_reload); diff --git a/addons/csw/functions/fnc_ai_handleGetIn.sqf b/addons/csw/functions/fnc_ai_handleGetIn.sqf index 2906a01d1e8..af74d14a64c 100644 --- a/addons/csw/functions/fnc_ai_handleGetIn.sqf +++ b/addons/csw/functions/fnc_ai_handleGetIn.sqf @@ -1,7 +1,7 @@ #include "script_component.hpp" /* - * Author: Grim - * Handles AI GetIn on an empty weapon + * Author: LinkIsGrim + * Handles AI GetIn on an empty CSW * * Arguments: * GetIn EH @@ -11,12 +11,10 @@ * * Public: No */ -params ["_staticWeapon", "_role", "_gunner"]; -TRACE_3("getInEH:",_staticWeapon,_role,_gunner); +params ["_vehicle", "_role", "_gunner", "_turret"]; +TRACE_3("getInEH:",_vehicle,_role,_gunner); if ((!local _gunner) || {[_gunner] call EFUNC(common,isPlayer)}) exitWith {}; -if (someAmmo _staticWeapon) exitWith {}; +if (someAmmo _vehicle) exitWith {}; -TRACE_2("need ammo",someAmmo _staticWeapon,magazinesAllTurrets _staticWeapon); - -[_staticWeapon, _gunner, currentWeapon _staticWeapon] call FUNC(ai_reload); +[_vehicle, _gunner] call FUNC(ai_reload); diff --git a/addons/csw/functions/fnc_ai_reload.sqf b/addons/csw/functions/fnc_ai_reload.sqf index 47e5d1ee6fe..8c37895e0a6 100644 --- a/addons/csw/functions/fnc_ai_reload.sqf +++ b/addons/csw/functions/fnc_ai_reload.sqf @@ -1,95 +1,72 @@ #include "script_component.hpp" /* - * Author: PabstMirror, modified by Grim + * Author: PabstMirror, LinkIsGrim * Handles AI reloading * * Arguments: - * 0: Static Weapon + * 0: CSW * 1: Gunner - * 2: Weapon - * 3: Magazine (default: "") + * 2: Skip reload time (default: false) + * 3: Clear forced magazine after reloading (default: true) * * Return Value: * None * * Public: No */ -params ["_staticWeapon", "_gunner", "_weapon", ["_magazine", ""]]; +params ["_vehicle", "_gunner", ["_instantReload", false], ["_clearForcedMag", false]]; +TRACE_3("AI reload",_vehicle,_gunner,_instantReload); -private _turretPath = [_gunner] call EFUNC(common,getTurretIndex); -private _reloadSource = objNull; -private _reloadMag = ""; -private _reloadNeededAmmo = -1; +// API, used for ai_switchMagazine +private _forcedMag = _vehicle getVariable [QGVAR(forcedMag), ""]; +private _turretIndex = [_gunner] call EFUNC(common,getTurretIndex); +if (_turretIndex isEqualTo []) then { + _turretIndex = [0]; +}; -private _cfgMagGroups = configFile >> QGVAR(groups); +// If this is called while CSW has ammo, unload mags in gunner's turret +if (someAmmo _vehicle) then {[_vehicle, _turretIndex] call FUNC(unloadMagazines)}; -private _nearSupplies = [_gunner] + ((_staticWeapon nearSupplies 10) select { - isNull (group _x) || - {!([_x] call EFUNC(common,isPlayer)) && {[side group _gunner, side group _x] call BIS_fnc_sideIsFriendly}} -}); +private _loadableMagazines = [_vehicle, _gunner, true] call FUNC(reload_getLoadableMagazines); +if (_loadableMagazines isEqualTo []) exitWith {TRACE_1("could not find reloadable mag",_vehicle)}; -// Find if there is anything we can reload with +private _bestAmmo = 0; +private _magazineInfo = []; { - scopeName "findSource"; - private _xSource = _x; - - private _cswMagazines = []; - { - _cswMagazines pushBackUnique _x; - } forEach ((magazineCargo _xSource) select {isClass (_cfgMagGroups >> _x)}); - TRACE_2("",_xSource,_cswMagazines); - - private _compatibleMags = [_weapon] call CBA_fnc_compatibleMagazines; - if (_magazine != "") then { - _compatibleMags insert [0, [_magazine]]; + _x params ["_xMag", "", "", "", "", "_ammo"]; + if (_forcedMag isNotEqualTo "" && {_xMag != _forcedMag}) then {continue}; + if (_ammo > _bestAmmo) then { + _bestAmmo = _ammo; + _magazineInfo = _x; }; +} forEach _loadableMagazines; - { - private _xWeaponMag = _x; - { - if ((getNumber (_cfgMagGroups >> _x >> _xWeaponMag)) == 1) then { - private _loadInfo = [_staticWeapon, _turretPath, _x, _xSource] call FUNC(reload_canLoadMagazine); - if (_loadInfo select 0) then { - _reloadMag = _x; - _reloadSource = _xSource; - _reloadNeededAmmo = _loadInfo select 2; - TRACE_3("found mag",_reloadMag,_reloadSource,_x); - breakOut "findSource"; - }; - }; - } forEach _cswMagazines; - } forEach _compatibleMags; -} forEach _nearSupplies; -if (_reloadMag == "") exitWith {TRACE_1("could not find mag",_reloadMag);}; +if (_clearForcedMag) then { + _vehicle setVariable [QGVAR(forcedMag), nil, true]; +}; -// Figure out what we can add from the magazines we have -private _bestAmmoToSend = -1; -{ - _x params ["_xMag", "_xAmmo"]; - TRACE_2("",_xMag,_xAmmo); - if (_xMag == _reloadMag) then { - if ((_bestAmmoToSend == -1) || {(_xAmmo > _bestAmmoToSend) && {_xAmmo <= _reloadNeededAmmo}}) then { - _bestAmmoToSend = _xAmmo; - }; - }; -} forEach (if (_reloadSource isKindOf "CAManBase") then {magazinesAmmo _reloadSource} else {magazinesAmmoCargo _reloadSource}); -TRACE_4("",_reloadSource,_reloadMag,_reloadNeededAmmo,_bestAmmoToSend); -if (_bestAmmoToSend == -1) exitWith {ERROR("No ammo");}; +if (_magazineInfo isEqualTo []) exitWith {}; +_magazineInfo params ["_carryMag", "_turretPath", "_loadInfo", "_magSource", "", "_ammo"]; // Remove the mag from the source -[_reloadSource, _reloadMag, _bestAmmoToSend] call EFUNC(common,removeSpecificMagazine); +[_magSource, _carryMag, _ammo] call EFUNC(common,removeSpecificMagazine); -private _timeToLoad = 1; -if (!isNull(configOf _staticWeapon >> QUOTE(ADDON) >> "ammoLoadTime")) then { - _timeToLoad = getNumber(configOf _staticWeapon >> QUOTE(ADDON) >> "ammoLoadTime"); +// AI never returns ammo and removes the magazine before reloading, so we can skip distance and weaponHolder checks +private _eventParams = [_vehicle, _turretPath, objNull, _carryMag, _ammo, _gunner]; + +if (_instantReload) exitWith { + TRACE_1("calling addTurretMag event: instant AI reload",_this); + [QGVAR(addTurretMag), _eventParams] call CBA_fnc_globalEvent; }; +private _timeToLoad = GET_NUMBER(configOf _vehicle >> QUOTE(ADDON) >> "ammoLoadTime", 1); + TRACE_1("Reloading in progress",_timeToLoad); [{ - params ["_staticWeapon", "_turretPath", "_gunner", "_reloadMag", "_bestAmmoToSend"]; - if ((!alive _staticWeapon) || {!alive _gunner} || {(_staticWeapon distance _gunner) > 10}) exitWith {TRACE_1("invalid state",_this);}; + params ["_vehicle", "", "", "", "", "_gunner"]; + if !(alive _vehicle && {alive _gunner}) exitWith {TRACE_2("invalid state",alive _vehicle,alive _gunner);}; // Reload the static weapon - TRACE_5("calling addTurretMag event",_staticWeapon,_turretPath,_gunner,_reloadMag,_bestAmmoToSend); + TRACE_1("calling addTurretMag event: AI reload",_this); [QGVAR(addTurretMag), _this] call CBA_fnc_globalEvent; -}, [_staticWeapon, _turretPath, _gunner, _reloadMag, _bestAmmoToSend], _timeToLoad] call CBA_fnc_waitAndExecute; +}, _eventParams, _timeToLoad] call CBA_fnc_waitAndExecute; diff --git a/addons/csw/functions/fnc_ai_switchMagazine.sqf b/addons/csw/functions/fnc_ai_switchMagazine.sqf new file mode 100644 index 00000000000..0c1f58ef484 --- /dev/null +++ b/addons/csw/functions/fnc_ai_switchMagazine.sqf @@ -0,0 +1,39 @@ +#include "script_component.hpp" +/* + * Author: LinkIsGrim + * Handles AI magazine switching + * Magazine must be compatible and available, use ace_csw_fnc_getAvailableAmmo + * + * Arguments: + * 0: CSW + * 1: Carry Magazine + * 2: Turret Path (default: [0]) + * 3: Skip reload time (default: false) + * 4: Clear forced magazine after reloading (default: true) + * + * Return Value: + * Successful + * + * Example: + * [cursorTarget, "ACE_csw_100Rnd_127x99_mag_red", [0]] call ace_csw_fnc_ai_switchMagazine + * + * Public: Yes + */ +params [["_vehicle", objNull, [objNull]], ["_carryMag", "", [""]], ["_turretPath", [0], [[0]]], ["_instantReload", false, [false]], ["_clearForcedMag", true, [true]]]; + +if !(alive _vehicle && {!isNull (_vehicle turretUnit _turretPath)} && {!(isNull _vehicle)}) exitWith {false}; + +// must be config case +_carryMag = configName (configFile >> "CfgMagazines" >> _carryMag); +if (_carryMag isEqualTo "") exitWith {false}; + +private _availableMags = [_vehicle] call FUNC(getAvailableAmmo); +if !(_carryMag in _availableMags) exitWith {false}; + +_vehicle setVariable [QGVAR(forcedMag), _carryMag, true]; + +private _gunner = _vehicle turretUnit _turretPath; + +[QGVAR(ai_reload), [_vehicle, _gunner, _instantReload, _clearForcedMag], _gunner] call CBA_fnc_targetEvent; + +true diff --git a/addons/csw/functions/fnc_assemble_canPickupWeapon.sqf b/addons/csw/functions/fnc_assemble_canPickupWeapon.sqf index 9736fb97dde..139d1106bc8 100644 --- a/addons/csw/functions/fnc_assemble_canPickupWeapon.sqf +++ b/addons/csw/functions/fnc_assemble_canPickupWeapon.sqf @@ -4,7 +4,7 @@ * If the CSW is mounted or in use this will not allow you to dismount the weapon * * Arguments: - * 0: Static Weapon + * 0: CSW * * Return Value: * Can Dismount @@ -15,12 +15,11 @@ * Public: No */ -params ["_staticWeapon"]; +params ["_vehicle"]; // Assembly mode: [0=disabled, 1=enabled, 2=enabled&unload, 3=default] -private _assemblyMode = [false, true, true, GVAR(defaultAssemblyMode)] select (_staticWeapon getVariable [QGVAR(assemblyMode), 3]); -private _notCrewed = (crew _staticWeapon) isEqualTo []; -private _deadCrew = !(alive (gunner _staticWeapon)); // need to eject body??? +private _assemblyMode = [false, true, true, GVAR(defaultAssemblyMode)] select (_vehicle getVariable [QGVAR(assemblyMode), 3]); +private _notCrewed = (crew _vehicle) isEqualTo []; +private _deadCrew = !(alive (gunner _vehicle)); // need to eject body??? _assemblyMode && {_notCrewed || _deadCrew} - diff --git a/addons/csw/functions/fnc_assemble_pickupWeapon.sqf b/addons/csw/functions/fnc_assemble_pickupWeapon.sqf index 9b17fcaf732..f5ce64d3062 100644 --- a/addons/csw/functions/fnc_assemble_pickupWeapon.sqf +++ b/addons/csw/functions/fnc_assemble_pickupWeapon.sqf @@ -4,7 +4,7 @@ * Dismounts the weapon from the tripod and drops its backpack beside * * Arguments: - * 0: Static Weapon + * 0: CSW * * Return Value: * None @@ -16,26 +16,26 @@ */ [{ - params ["_staticWeapon", "_player"]; - TRACE_2("assemble_pickupWeapon",_staticWeapon,_player); + params ["_vehicle", "_player"]; + TRACE_2("assemble_pickupWeapon",_vehicle,_player); - private _onDisassembleFunc = getText(configOf _staticWeapon >> QUOTE(ADDON) >> "disassembleFunc"); - private _carryWeaponClassname = getText(configOf _staticWeapon >> QUOTE(ADDON) >> "disassembleWeapon"); - private _turretClassname = getText(configOf _staticWeapon >> QUOTE(ADDON) >> "disassembleTurret"); + private _onDisassembleFunc = getText(configOf _vehicle >> QUOTE(ADDON) >> "disassembleFunc"); + private _carryWeaponClassname = getText(configOf _vehicle >> QUOTE(ADDON) >> "disassembleWeapon"); + private _turretClassname = getText(configOf _vehicle >> QUOTE(ADDON) >> "disassembleTurret"); private _pickupTime = getNumber(configFile >> "CfgWeapons" >> _carryWeaponClassname >> QUOTE(ADDON) >> "pickupTime"); - TRACE_4("",typeOf _staticWeapon,_carryWeaponClassname,_turretClassname,_pickupTime); + TRACE_4("",typeOf _vehicle,_carryWeaponClassname,_turretClassname,_pickupTime); if (!isClass (configFile >> "CfgWeapons" >> _carryWeaponClassname)) exitWith {ERROR_1("bad weapon classname [%1]",_carryWeaponClassname);}; // Turret classname can equal nothing if the deploy bag is the "whole" weapon. e.g Kornet, Metis, other ATGMs if ((_turretClassname isNotEqualTo "") && {!isClass (configFile >> "CfgVehicles" >> _turretClassname)}) exitWith {ERROR_1("bad turret classname [%1]",_turretClassname);}; private _onFinish = { params ["_args"]; - _args params ["_staticWeapon", "_player", "_carryWeaponClassname", "_turretClassname", "_onDisassembleFunc"]; - TRACE_4("disassemble finish",_staticWeapon,_player,_carryWeaponClassname,_turretClassname); + _args params ["_vehicle", "_player", "_carryWeaponClassname", "_turretClassname", "_onDisassembleFunc"]; + TRACE_4("disassemble finish",_vehicle,_player,_carryWeaponClassname,_turretClassname); - private _weaponPos = getPosATL _staticWeapon; + private _weaponPos = getPosATL _vehicle; _weaponPos set [2, (_weaponPos select 2) + 0.1]; - private _weaponDir = getDir _staticWeapon; + private _weaponDir = getDir _vehicle; private _carryWeaponMag = ""; private _carryWeaponMags = getArray (configFile >> "CfgWeapons" >> _carryWeaponClassname >> "magazines") apply {toLower _x}; @@ -54,7 +54,7 @@ TRACE_2("Removing ammo",_xMag,_carryMag); [_player, _carryMag, _xAmmo] call FUNC(reload_handleReturnAmmo); }; - } forEach (magazinesAllTurrets _staticWeapon); + } forEach (magazinesAllTurrets _vehicle); if (_turretClassname isNotEqualTo "") then { private _cswTripod = createVehicle [_turretClassname, [0, 0, 0], [], 0, "NONE"]; @@ -66,7 +66,7 @@ _cswTripod setVelocity [0, 0, -0.05]; _cswTripod setVectorUp (surfaceNormal _weaponPos); }, [_cswTripod, _weaponDir, _weaponPos]] call CBA_fnc_execNextFrame; - [_cswTripod, _staticWeapon] call (missionNamespace getVariable _onDisassembleFunc); + [_cswTripod, _vehicle] call (missionNamespace getVariable _onDisassembleFunc); }; [{ @@ -89,16 +89,16 @@ }, [_player, _weaponPos, _carryWeaponClassname, _carryWeaponMag]] call CBA_fnc_execNextFrame; LOG("delete weapon"); - deleteVehicle _staticWeapon; + deleteVehicle _vehicle; LOG("end"); }; private _condition = { params ["_args"]; - _args params ["_staticWeapon"]; - ((crew _staticWeapon) isEqualTo []) && (alive _staticWeapon) + _args params ["_vehicle"]; + ((crew _vehicle) isEqualTo []) && (alive _vehicle) }; - [TIME_PROGRESSBAR(_pickupTime), [_staticWeapon, _player, _carryWeaponClassname, _turretClassname, _onDisassembleFunc], _onFinish, {}, localize LSTRING(DisassembleCSW_progressBar), _condition] call EFUNC(common,progressBar); + [TIME_PROGRESSBAR(_pickupTime), [_vehicle, _player, _carryWeaponClassname, _turretClassname, _onDisassembleFunc], _onFinish, {}, localize LSTRING(DisassembleCSW_progressBar), _condition] call EFUNC(common,progressBar); }, _this] call CBA_fnc_execNextFrame; diff --git a/addons/csw/functions/fnc_canGetIn.sqf b/addons/csw/functions/fnc_canGetIn.sqf index 052f48f8b0d..73a170ab8ee 100644 --- a/addons/csw/functions/fnc_canGetIn.sqf +++ b/addons/csw/functions/fnc_canGetIn.sqf @@ -1,10 +1,10 @@ #include "script_component.hpp" /* * Author:Dani (TCVM) - * Checks if the player can get in the weapon + * Checks if the player can get in the CSW * * Arguments: - * 0: Static Weapon + * 0: CSW * * Return Value: * None @@ -20,9 +20,9 @@ if ((missionNamespace getVariable [QEGVAR(quickmount,enabled), false]) && {(miss false }; -params ["_staticWeapon"]; +params ["_vehicle"]; -alive _staticWeapon -&& {!(alive (gunner _staticWeapon))} -&& {(locked _staticWeapon) < 2} -&& {0.3 < ((vectorUp _staticWeapon) select 2)} +alive _vehicle +&& {!(alive (gunner _vehicle))} +&& {(locked _vehicle) < 2} +&& {0.3 < ((vectorUp _vehicle) select 2)} diff --git a/addons/csw/functions/fnc_compatibleMagazines.sqf b/addons/csw/functions/fnc_compatibleMagazines.sqf new file mode 100644 index 00000000000..2c8e3a090b4 --- /dev/null +++ b/addons/csw/functions/fnc_compatibleMagazines.sqf @@ -0,0 +1,46 @@ +#include "script_component.hpp" +/* + * Author: LinkIsGrim + * Gets all carry magazines that can be loaded into a CSW, includes weapons added by script + * + * Arguments: + * 0: CSW + * + * Return Value: + * Compatible Magazines + * Magazine classname + * Nothing + * + * Example: + * [cursorObject] call ace_csw_fnc_compatibleMagazines + * + * Public: Yes + */ +params [["_csw", objNull, [objNull]]]; + +if !((typeOf _csw) in GVAR(initializedStaticTypes)) exitWith {createHashMap}; + +// fast exit for csw with single weapon, most common scenario +if (count allTurrets _csw isEqualTo 1 && {count weapons _csw isEqualTo 1}) exitWith { + GVAR(compatibleMagsCache) get ((weapons _csw) select 0) // return +}; + +private _weapons = []; + +{ + private _turret = _x; + { + _weapons pushBackUnique _x; + } forEach (_csw weaponsTurret _turret); +} forEach (allTurrets _csw); + +if (_weapons isEqualTo []) exitWith {[]}; + +private _carryMagazines = createHashMap; // hashmap for constant lookup +{ + private _weapon = _x; + if !(_weapon in GVAR(compatibleMagsCache)) then {continue}; + _carryMagazines merge [GVAR(compatibleMagsCache) get _weapon, true]; +} forEach _weapons; + +_carryMagazines // return diff --git a/addons/csw/functions/fnc_getAvailableAmmo.sqf b/addons/csw/functions/fnc_getAvailableAmmo.sqf new file mode 100644 index 00000000000..3eb65589f27 --- /dev/null +++ b/addons/csw/functions/fnc_getAvailableAmmo.sqf @@ -0,0 +1,61 @@ +#include "script_component.hpp" +/* + * Author: LinkIsGrim + * Gets available ammo for a CSW + * + * Arguments: + * 0: CSW + * 1: Only loaded magazines (default: false) + * 2: Skip ammo from vehicles (default: true) + * 3: Include CSW crew (default: true) + * + * Return Value: + * Available Ammo + * Magazine classname + * Total Ammo + * + * Example: + * [cursorObject] call ace_csw_fnc_getAvailableAmmo + * + * Public: Yes + */ +params [["_vehicle", objNull, [objNull]], ["_onlyLoaded", false, [false]], ["_skipVehicles", true, [true]], ["_includeCrew", true, [true]]]; + +if (isNull _vehicle) exitWith {createHashMap}; + +private _availableMagazines = createHashMap; + +private _fnc_addAmmo = { + params ["_magazine", "_ammo"]; + if !(_magazine in _availableMagazines) then { + _availableMagazines set [_magazine, _ammo]; + } else { + _availableMagazines set [_magazine, (_availableMagazines get _magazine) + _ammo]; + }; +}; + +{ + _x params ["_xMag", "", "_xAmmo"]; + + if (_xAmmo <= 0) then {continue}; + + private _carryMag = _xMag call FUNC(getCarryMagazine); + if (_carryMag isEqualTo "") then {continue}; + + [_carryMag, _xAmmo] call _fnc_addAmmo +} forEach (magazinesAllTurrets _vehicle); + +if (_onlyLoaded) exitWith {_availableMagazines}; + +[QGVAR(clearNearbySourcesCache), []] call CBA_fnc_localEvent; +private _sources = [_vehicle, _skipVehicles, _includeCrew] call FUNC(getNearbySources); +if (_sources isEqualTo []) exitWith {_availableMagazines}; + +{ + private _source = _x; + { + _x call _fnc_addAmmo + } forEach ([_source, _vehicle] call FUNC(getSourceCompatibleMagazines)); +} forEach _sources; + +_availableMagazines // return diff --git a/addons/csw/functions/fnc_getCarryMagazine.sqf b/addons/csw/functions/fnc_getCarryMagazine.sqf index 4535512e2db..402cf866a8f 100644 --- a/addons/csw/functions/fnc_getCarryMagazine.sqf +++ b/addons/csw/functions/fnc_getCarryMagazine.sqf @@ -12,10 +12,10 @@ * Example: * "1Rnd_GAT_missiles" call ace_csw_fnc_getCarryMagazine * - * Public: No + * Public: Yes */ -params ["_vehicleMag"]; +params [["_vehicleMag", "", [""]]]; private _carryMag = GVAR(vehicleMagCache) get _vehicleMag; if (isNil "_carryMag") then { diff --git a/addons/csw/functions/fnc_getIn.sqf b/addons/csw/functions/fnc_getIn.sqf index 9a11553ce99..75485d1025c 100644 --- a/addons/csw/functions/fnc_getIn.sqf +++ b/addons/csw/functions/fnc_getIn.sqf @@ -6,7 +6,7 @@ * the gun and can't be acssesed from the back, I am implementing this to get around that issue. * * Arguments: - * 0: Static Weapon + * 0: CSW * 1: Unit * * Return Value: @@ -18,7 +18,7 @@ * Public: No */ -params ["_staticWeapon", "_player"]; -TRACE_2("getIn",_staticWeapon,_player); +params ["_vehicle", "_player"]; +TRACE_2("getIn",_vehicle,_player); -_player moveInTurret [_staticWeapon, [0]]; +_player moveInTurret [_vehicle, [0]]; diff --git a/addons/csw/functions/fnc_getNearbySources.sqf b/addons/csw/functions/fnc_getNearbySources.sqf new file mode 100644 index 00000000000..4fb98d11175 --- /dev/null +++ b/addons/csw/functions/fnc_getNearbySources.sqf @@ -0,0 +1,51 @@ +#include "script_component.hpp" +/* + * Author: LinkIsGrim + * Gets available ammo sources for loading a CSW + * + * Arguments: + * 0: Unit or vehicle attempting to load + * 1: Skip vehicle sources (default: false) + * 2: Include CSW crew (default: false) + * + * Return Value: + * Ammo sources + * + * Example: + * [player] call ace_csw_fnc_getNearbySources + * + * Public: No + */ +[_this, { + params ["_unit", ["_skipVehicles", false], ["_includeCrew", false]]; + private _nearSupplies = (_unit nearSupplies 5) select { + isNull (group _x) || + {!([_x] call EFUNC(common,isPlayer)) && {[side group _unit, side group _x] call BIS_fnc_sideIsFriendly}} + }; + + if (_includeCrew) then { + _nearSupplies append (crew _unit); + }; + + if (_skipVehicles) then { + _nearSupplies = _nearSupplies select { + private _source = _x; + (["Ship", "Car", "Air", "Tank"] findIf {_source isKindOf _x}) == -1 + }; + }; + + _nearSupplies pushBackUnique _unit; + { + if (_x isKindOf "CAManBase") then { + _nearSupplies append [uniformContainer _x, vestContainer _x, backpackContainer _x]; + continue; + }; + + { + _x params ["", "_container"]; + _nearSupplies pushBack _container; + } forEach (everyContainer _x); + } forEach _nearSupplies; + + _nearSupplies select {!(_x isKindOf "CAManBase")} // return +}, _this select 0, QGVAR(nearbySourcesCache), NEARBY_SOURCES_CACHE_EXPIRY, QGVAR(clearNearbySourcesCache)] call EFUNC(common,cachedCall); diff --git a/addons/csw/functions/fnc_getSourceCompatibleMagazines.sqf b/addons/csw/functions/fnc_getSourceCompatibleMagazines.sqf new file mode 100644 index 00000000000..b6786ae128a --- /dev/null +++ b/addons/csw/functions/fnc_getSourceCompatibleMagazines.sqf @@ -0,0 +1,37 @@ +#include "script_component.hpp" +/* + * Author: LinkIsGrim + * Gets compatible magazines to load a CSW from a magazine source + * + * Arguments: + * 0: Magazine Source + * 1: CSW (default: objNull) + * + * Return Value: + * Magazines + * Magazine classname + * Magazine ammo + * + * Example: + * [backpackContainer player, cursorObject] call ace_csw_fnc_getSourceCompatibleMagazines + * + * Public: Yes + */ +params [["_source", objNull, [objNull]], ["_csw", objNull, [objNull]]]; + +if (isNull _source || {isNull _csw}) exitWith {[]}; + +if !(typeOf _csw in GVAR(initializedStaticTypes)) exitWith {[]}; + +private _magazines = magazinesAmmoCargo _source; + +if (_magazines isEqualTo []) exitWith {[]}; + +private _compatibleMagazines = [_csw] call FUNC(compatibleMagazines); + +private _return = _magazines select {(_x select 0) in _compatibleMagazines}; + +// sort by ammo count, highest to lowest +_return sort false; + +_return diff --git a/addons/csw/functions/fnc_handleDoArtilleryFire.sqf b/addons/csw/functions/fnc_handleDoArtilleryFire.sqf new file mode 100644 index 00000000000..518f87377f7 --- /dev/null +++ b/addons/csw/functions/fnc_handleDoArtilleryFire.sqf @@ -0,0 +1,42 @@ +#include "script_component.hpp" +/* + * Author: LinkIsGrim + * CSW compatibility for ace_artillerytables_fnc_doArtilleryFire + * + * Arguments: + * 0: Vehicle + * 1: Magazine Classname + * + * Return Value: + * CSW Handled + * CSW Handled + * Vehicle Magazine + * + * Public: No + */ +params ["_vehicle", "_magazine"]; + +if !((typeOf _vehicle) in GVAR(initializedStaticTypes)) exitWith {[true, _magazine]}; + +// Solve this before exiting, a carry mag can still be passed to a disabled CSW +private _carryMag = _magazine; +private _isCarryMag = isClass (configFile >> QGVAR(groups) >> _carryMag); + +if (_isCarryMag) then { + _magazine = [_vehicle, [0], _carryMag] call FUNC(reload_getVehicleMagazine); +} else { + _carryMag = [_magazine] call FUNC(getCarryMagazine); +}; + +// Assembly mode: [0=disabled, 1=enabled, 2=enabled&unload, 3=default] +private _assemblyMode = [false, true, true, GVAR(defaultAssemblyMode)] select (_vehicle getVariable [QGVAR(assemblyMode), 3]); + +// Not using CSW systems +if (!_assemblyMode) exitWith {[true, _magazine]}; + +// Ammo Handling disabled for AI +if (GVAR(ammoHandling) < 2) exitWith {[false, _magazine]}; + +private _canSwitch = [_vehicle, _carryMag, [0], true, false] call FUNC(ai_switchMagazine); + +[_canSwitch, _magazine] // return diff --git a/addons/csw/functions/fnc_proxyWeapon.sqf b/addons/csw/functions/fnc_proxyWeapon.sqf index e4449bbbce4..bd49e3f3ddf 100644 --- a/addons/csw/functions/fnc_proxyWeapon.sqf +++ b/addons/csw/functions/fnc_proxyWeapon.sqf @@ -4,7 +4,7 @@ * Handles the use of proxy weapons to fix engine-reload times * * Arguments: - * 0: Weapon + * 0: CSW * 1: Turret * 2: Proxy weapon needed * 2: Weapon should be emptied @@ -18,26 +18,37 @@ * Public: No */ -params ["_staticWeapon", "_turret", "_needed", "_emptyWeapon"]; -TRACE_4("proxyWeapon",_staticWeapon,_turret,_needed,_emptyWeapon); +params ["_vehicle", "_turret", "_needed", "_emptyWeapon"]; +TRACE_4("proxyWeapon",_vehicle,_turret,_needed,_emptyWeapon); -if (_staticWeapon getVariable [format [QGVAR(proxyHandled_%1), _turret], false]) exitWith { TRACE_1("already handled",typeOf _staticWeapon); }; +if (_vehicle getVariable [format [QGVAR(proxyHandled_%1), _turret], false]) exitWith { TRACE_1("already handled",typeOf _vehicle); }; -private _proxyWeapon = getText (configOf _staticWeapon >> "ace_csw" >> "proxyWeapon"); +private _proxyWeapon = getText (configOf _vehicle >> "ace_csw" >> "proxyWeapon"); -TRACE_2("",typeOf _staticWeapon,_proxyWeapon); -if (_proxyWeapon == "") exitWith {}; +TRACE_2("",typeOf _vehicle,_proxyWeapon); +if (_proxyWeapon isEqualTo "") exitWith {}; -private _currentWeapon = (_staticWeapon weaponsTurret [0]) param [0, "#none"]; +private _currentWeapon = (_vehicle weaponsTurret [0]) param [0, "#none"]; if ((missionNamespace getVariable [_proxyWeapon, objNull]) isEqualType {}) then { // check if string is a function TRACE_1("Calling proxyWeapon function",_proxyWeapon); // This function may replace magazines or do other things to the static weapon - _proxyWeapon = [_staticWeapon, _turret, _currentWeapon, _needed, _emptyWeapon] call (missionNamespace getVariable _proxyWeapon); - _needed = _proxyWeapon != ""; + _proxyWeapon = [_vehicle, _turret, _currentWeapon, _needed, _emptyWeapon] call (missionNamespace getVariable _proxyWeapon); + _needed = _proxyWeapon isNotEqualTo "" && {_proxyWeapon isNotEqualTo _currentWeapon}; }; if (!_needed) exitWith { TRACE_2("not needed",_needed,_proxyWeapon); }; +// Config case for hashmap key +_proxyWeapon = configName (configFile >> "CfgWeapons" >> _proxyWeapon); +if (_proxyWeapon isEqualTo "") exitWith {ERROR_1("proxy weapon non-existent for [%1]", _currentWeapon)}; + +// Cache compatible magazines +if !(_proxyWeapon in GVAR(compatibleMagsCache)) then { + private _compatibleMagazines = compatibleMagazines _proxyWeapon; + GVAR(compatibleVehicleMagsCache) set [_proxyWeapon, _compatibleMagazines]; + GVAR(compatibleMagsCache) set [_proxyWeapon, (_compatibleMagazines apply {_x call FUNC(getCarryMagazine)}) createHashMapFromArray []]; +}; + TRACE_2("swapping to proxy weapon",_currentWeapon,_proxyWeapon); -_staticWeapon removeWeaponTurret [_currentWeapon, _turret]; -_staticWeapon addWeaponTurret [_proxyWeapon, _turret]; -_staticWeapon setVariable [format [QGVAR(proxyHandled_%1), _turret], true, true]; +_vehicle removeWeaponTurret [_currentWeapon, _turret]; +_vehicle addWeaponTurret [_proxyWeapon, _turret]; +_vehicle setVariable [format [QGVAR(proxyHandled_%1), _turret], true, true]; diff --git a/addons/csw/functions/fnc_reload_actionsLoad.sqf b/addons/csw/functions/fnc_reload_actionsLoad.sqf index d141da3d93b..7a1f49980e2 100644 --- a/addons/csw/functions/fnc_reload_actionsLoad.sqf +++ b/addons/csw/functions/fnc_reload_actionsLoad.sqf @@ -1,10 +1,10 @@ #include "script_component.hpp" /* * Author: PabstMirror - * Gets sub actions for what the player can load into the static weapon + * Gets sub actions for what the player can load into the CSW * * Arguments: - * 0: Static Weapon + * 0: CSW * 1: Player * * Return Value: @@ -23,9 +23,9 @@ private _loadableMagazines = [_vehicle, _player] call FUNC(reload_getLoadableMag private _statement = { params ["_target", "_player", "_params"]; - _params params ["_carryMag", "_turretPath", "", "_magSource"]; + _params params ["_carryMag", "_turretPath", "", "_magSource", "", "_ammo"]; - [_target, _turretPath, _carryMag, _magSource, _player] call FUNC(reload_loadMagazine); + [_target, _turretPath, _carryMag, _magSource, _player, _ammo] call FUNC(reload_loadMagazine); }; private _condition = { @@ -46,7 +46,7 @@ private _cfgMagazines = configFile >> "CfgMagazines"; // micro-optimization private _text = if (_isBeltLinking) then { format [localize LSTRING(actionLink), _displayName]; } else { - format [localize LSTRING(loadX), _displayName]; + format [localize LSTRING(actionLoad), _displayName]; }; private _action = [format ["load_%1", _forEachIndex], _text, _picture, _statement, _condition, {}, _x] call EFUNC(interact_menu,createAction); diff --git a/addons/csw/functions/fnc_reload_actionsUnload.sqf b/addons/csw/functions/fnc_reload_actionsUnload.sqf index 0f4e9cb7ded..118072b8c26 100644 --- a/addons/csw/functions/fnc_reload_actionsUnload.sqf +++ b/addons/csw/functions/fnc_reload_actionsUnload.sqf @@ -1,10 +1,10 @@ #include "script_component.hpp" /* * Author: PabstMirror - * Gets sub actions for what the player can unload from the static weapon + * Gets sub actions for what the player can unload from the CSW * * Arguments: - * 0: Target + * 0: CSW * 1: Player * * Return Value: @@ -64,7 +64,7 @@ private _cfgMagazines = configFile >> "CfgMagazines"; if (_carryMag == "") exitWith {}; private _displayName = getText (_cfgMagazines >> _carryMag >> "displayName"); - private _text = format [LLSTRING(unloadX), _displayName]; + private _text = format [LLSTRING(actionUnload), _displayName]; private _picture = getText (_cfgMagazines >> _carryMag >> "picture"); private _action = [format ["unload_%1", _forEachIndex], _text, _picture, _statement, _condition, {}, [_xMag, _xTurret, _carryMag]] call EFUNC(interact_menu,createAction); _actions pushBack [_action, [], _vehicle]; diff --git a/addons/csw/functions/fnc_reload_canLoadMagazine.sqf b/addons/csw/functions/fnc_reload_canLoadMagazine.sqf index 1fbd2e47080..851147ef772 100644 --- a/addons/csw/functions/fnc_reload_canLoadMagazine.sqf +++ b/addons/csw/functions/fnc_reload_canLoadMagazine.sqf @@ -1,13 +1,13 @@ #include "script_component.hpp" /* * Author: PabstMirror &Dani (TCVM) - * Tests if unit can load a magazine into a static weapon. + * Tests if unit can load a magazine into a CSW. * * Arguments: - * 0: Static Weapon + * 0: CSW * 1: Turret Path * 2: Carryable Magazine - * 3: Supplier + * 3: Supplier (default: objNull) * * Return Value: * [CanLoad, LoadedMag, AmmoNeeded, IsBeltLinking] @@ -24,16 +24,16 @@ params ["_vehicle", "_turret", "_carryMag", ["_magSource", objNull]]; private _return = [false, "", -2, false]; // Handle disassembled or deleted -if (!alive _vehicle) exitWith { _return }; -// Verify holder has carry magazine -if ( - (!isNull _magSource) && - {!((_magSource isKindOf "Bag_Base") || {_magSource isKindOf "ContainerSupply"})} && // hacky workaround for magazines within dropped backpacks - { - ((_vehicle distance _magSource) > 10) || - {((magazineCargo _magSource) findIf {_x == _carryMag}) == -1} - } -) exitWith { _return }; +if !(alive _vehicle) exitWith {TRACE_1("not alive",_vehicle);_return}; + +// objNull as mag source means we can skip these checks: used to just get magazine info to load in turret +if !(isNull _magSource) then { + // Verify holder has carry magazine + if !(_carryMag in (magazineCargo _magSource)) exitWith {TRACE_3("no carry mag",_magSource,_carryMag,magazineCargo _magSource);_return}; + + // Verify holder has not moved away from vehicle, with workaround for containers within containers + if ((_vehicle distance _magSource) > 5 && {(_vehicle distance (objectParent _magSource)) > 5}) exitWith {TRACE_1("too far","");_return}; +}; // solve config lookups private _cfgMagazines = configFile >> "CfgMagazines"; diff --git a/addons/csw/functions/fnc_reload_canUnloadMagazine.sqf b/addons/csw/functions/fnc_reload_canUnloadMagazine.sqf index 2ce6b6e591c..634eff0968e 100644 --- a/addons/csw/functions/fnc_reload_canUnloadMagazine.sqf +++ b/addons/csw/functions/fnc_reload_canUnloadMagazine.sqf @@ -1,10 +1,10 @@ #include "script_component.hpp" /* * Author: PabstMirror - * Tests if unit can unload a magazine from a static weapon. + * Tests if unit can unload a magazine from a CSW. * * Arguments: - * 0: Static Weapon + * 0: CSW * 1: Turret Path * 2: Player * 3: Carryable Magazine diff --git a/addons/csw/functions/fnc_reload_getLoadableMagazines.sqf b/addons/csw/functions/fnc_reload_getLoadableMagazines.sqf index 1419e7b16e6..6af3ee8b8e2 100644 --- a/addons/csw/functions/fnc_reload_getLoadableMagazines.sqf +++ b/addons/csw/functions/fnc_reload_getLoadableMagazines.sqf @@ -1,11 +1,12 @@ #include "script_component.hpp" /* - * Author: PabstMirror - * Gets magazines that the player is carrying that can be loaded into the static weapon + * Author: PabstMirror, LinkIsGrim + * Gets nearby magazines that can be loaded into the CSW * * Arguments: - * 0: Vehicle - * 1: Player + * 0: CSW + * 1: Unit + * 2: AI reloading, skip turret checks (default: false) * * Return Value: * Mags @@ -17,63 +18,48 @@ * Public: No */ -params ["_vehicle", "_player"]; +params ["_vehicle", "_unit", ["_aiReload", false]]; -private _magGroupsConfig = configFile >> QGVAR(groups); // so we don't solve in loop every time private _availableMagazines = createHashMap; // slower than array, still needed for setting source of magazine // filter enemy & player units while allowing pulling from friendly AI, crates, etc -private _nearSupplies = ((_vehicle nearSupplies 10) select { - isNull (group _x) || - {!([_x] call EFUNC(common,isPlayer)) && {[side group _player, side group _x] call BIS_fnc_sideIsFriendly}} -}); - -// backpacks/uniforms/etc need to be added manually. -// array can't be modified while iterating, use copy -{ - { - _x params ["_classname", "_container"]; - _nearSupplies pushBack _container; - } forEach (everyContainer _x); -} forEach ((+_nearSupplies) select {(everyContainer _x) isNotEqualTo []}); - -// add caller to list of sources -_nearSupplies = [_player] + _nearSupplies; +private _sources = [_unit] call FUNC(getNearbySources); { + // minor optimization: since mags are sorted by ammo count in FUNC(getSourceCompatibleMagazines), we only need to check the first mag of this type in this source + private _handledSourceMags = []; private _xSource = _x; - private _mags = magazineCargo _xSource; - { - _availableMagazines set [_x, _xSource]; - } forEach (_mags select {isClass (_magGroupsConfig >> _x)}); -} forEach _nearSupplies; + _x params ["_classname", "_ammo"]; + if (_classname in _handledSourceMags) then {continue}; + _handledSourceMags pushBack _classname; + + // select mag source with the highest ammo + if (_ammo > (_availableMagazines getOrDefault [_classname, [objNull, 0]]) select 1) then { + _availableMagazines set [_classname, [_xSource, _ammo]]; + }; + } forEach ([_x, _vehicle] call FUNC(getSourceCompatibleMagazines)); +} forEach _sources; -if (_availableMagazines isEqualTo createHashMap) exitWith { [] }; // fast exit if no available mags +if (_availableMagazines isEqualTo createHashMap) exitWith {[]}; // fast exit if no available mags private _loadInfo = []; private _return = []; +private _turretPath = [_unit] call EFUNC(common,getTurretIndex); + // Go through turrets and find weapons that we could reload +// We can skip checking all turrets if we're doing AI reloading { private _turretPath = _x; { - private _weapon = _x; - { - //IGNORE_PRIVATE_WARNING ["_x", "_y"]; - private _carryMag = _x; - private _magSource = _y; - private _carryGroup = _magGroupsConfig >> _carryMag; - { - if ( - ((getNumber (_carryGroup >> _x)) == 1) && - {_loadInfo = [_vehicle, _turretPath, _carryMag, _magSource] call FUNC(reload_canLoadMagazine); _loadInfo select 0} - ) exitWith { - _return pushBack [_carryMag, _turretPath, _loadInfo, _magSource]; - }; - } forEach ([_weapon] call CBA_fnc_compatibleMagazines); - } forEach _availableMagazines; - } forEach (_vehicle weaponsTurret _turretPath); -} forEach (allTurrets _vehicle); -// Note: these nested forEach's looks terrible, but most only have one element + //IGNORE_PRIVATE_WARNING ["_x", "_y"]; + private _carryMag = _x; + _y params ["_magSource", "_ammo"]; + _loadInfo = [_vehicle, _turretPath, _carryMag] call FUNC(reload_canLoadMagazine); + if (_loadInfo select 0) then { + _return pushBack [_carryMag, _turretPath, _loadInfo, _magSource, _unit, _ammo]; + }; + } forEach _availableMagazines; +} forEach ([(allTurrets _vehicle), [_turretPath]] select _aiReload); _return diff --git a/addons/csw/functions/fnc_reload_getVehicleMagazine.sqf b/addons/csw/functions/fnc_reload_getVehicleMagazine.sqf index f8053df3b97..3668469f9f3 100644 --- a/addons/csw/functions/fnc_reload_getVehicleMagazine.sqf +++ b/addons/csw/functions/fnc_reload_getVehicleMagazine.sqf @@ -4,7 +4,7 @@ * Finds the best vehicle magazines to create from a carryable magazine for a given weapon. * * Arguments: - * 0: Vehicle + * 0: CSW * 1: Turret * 2: Magazine that is carryable * diff --git a/addons/csw/functions/fnc_reload_handleAddTurretMag.sqf b/addons/csw/functions/fnc_reload_handleAddTurretMag.sqf index 8cdd9d29fee..0dee4ac31b9 100644 --- a/addons/csw/functions/fnc_reload_handleAddTurretMag.sqf +++ b/addons/csw/functions/fnc_reload_handleAddTurretMag.sqf @@ -5,12 +5,13 @@ * Called from a global event but only runs where turret is local * * Arguments: - * 0: Static Weapon + * 0: CSW * 1: Turret Path * 2: Source of magazine * 3: Vehicle Magazine * 4: Ammo in magazine - * 5: Unit or object to return ammo to + * 5: Unit that added the magazine + * 6: Object to return extra ammo (default: Unit that added the magazine) * * Return Value: * None @@ -21,8 +22,12 @@ * Public: No */ -params ["_vehicle", "_turret", "_magSource", "_carryMag", "_ammoReceived", ["_returnTo", _magSource]]; -TRACE_6("reload_handleAddTurretMag",_vehicle,_turret,_magSource,_carryMag,_ammoReceived,_returnTo); +params ["_vehicle", "_turret", "_magSource", "_carryMag", "_ammoReceived", "_unit"]; +private _returnTo = param [6, _unit]; +if (isNull _returnTo) then { + _returnTo = _vehicle; +}; +TRACE_7("reload_handleAddTurretMag",_vehicle,_turret,_magSource,_carryMag,_ammoReceived,_unit,_returnTo); TRACE_2("",local _vehicle, _vehicle turretLocal _turret); if (!(_vehicle turretLocal _turret)) exitWith {}; diff --git a/addons/csw/functions/fnc_reload_handleRemoveTurretMag.sqf b/addons/csw/functions/fnc_reload_handleRemoveTurretMag.sqf index c78c1414499..56f94619803 100644 --- a/addons/csw/functions/fnc_reload_handleRemoveTurretMag.sqf +++ b/addons/csw/functions/fnc_reload_handleRemoveTurretMag.sqf @@ -5,9 +5,9 @@ * Called from a global event but only runs where turret is local * * Arguments: - * 0: Static Weapon + * 0: CSW * 1: Turret Path - * 2: Magainze Unit Can Carry + * 2: Magazine Unit Can Carry * 3: Magazine To Remove From Static * 4: Unit or container to unload to * diff --git a/addons/csw/functions/fnc_reload_handleReturnAmmo.sqf b/addons/csw/functions/fnc_reload_handleReturnAmmo.sqf index 52a14903201..b6af8d3ea2f 100644 --- a/addons/csw/functions/fnc_reload_handleReturnAmmo.sqf +++ b/addons/csw/functions/fnc_reload_handleReturnAmmo.sqf @@ -18,13 +18,18 @@ */ params ["_unloadTo", "_carryMag", "_ammo"]; -TRACE_3("reload_handleReturnAmmo",_unloadTo,_carryMag,_ammo); +TRACE_4("reload_handleReturnAmmo",_unloadTo,typeOf _unloadTo,_carryMag,_ammo); private _carryMaxAmmo = getNumber (configFile >> "CfgMagazines" >> _carryMag >> "count"); private _fullMagazines = floor (_ammo / _carryMaxAmmo); private _bulletsRemaining = _ammo % _carryMaxAmmo; -if (_unloadTo isKindOf "CaManBase") then { +// get nearby units to clear cache +private _nearUnits = _unloadTo nearEntities ["CAManBase", 5]; + +private _unloadToUnit = _unloadTo isKindOf "CAManBase"; + +if (_unloadToUnit) then { while {(_fullMagazines > 0) && {[_unloadTo, _carryMag] call CBA_fnc_canAddItem}} do { _unloadTo addMagazine [_carryMag, _carryMaxAmmo]; _fullMagazines = _fullMagazines - 1; @@ -35,21 +40,38 @@ if (_unloadTo isKindOf "CaManBase") then { }; }; -if ((_fullMagazines == 0) && {_bulletsRemaining == 0}) exitWith {}; - -// Try to use existing container -private _container = _unloadTo getVariable [QGVAR(container), objNull]; -if ((_container distance _unloadTo) > 10) then { _container = objNull; }; -if (isNull _container) then { - _container = (nearestObjects [_unloadTo, [QGVAR(ammo_holder), "GroundWeaponHolder"], 10]) param [0, objNull]; +if ((_fullMagazines == 0) && {_bulletsRemaining == 0}) exitWith { + [QGVAR(clearNearbySourcesCache), [], _nearUnits] call CBA_fnc_targetEvent; }; +// Try to use object inventory or existing container +private _container = [_unloadTo, objNull] select _unloadToUnit; +if ((maxLoad _container) isEqualTo 0) then { + _container = _unloadTo getVariable [QGVAR(container), objNull]; + if ((_container distance _unloadTo) > 5) then { _container = objNull; }; + if (isNull _container) then { + _container = (nearestObjects [_unloadTo, [QGVAR(ammo_holder), "GroundWeaponHolder"], 5]) param [0, objNull]; + }; +}; if (isNull _container) then { // Create ammo storage container - private _weaponRelPos = _unloadTo getRelPos RELATIVE_DIRECTION(270); - _weaponRelPos set [2, ((getPosATL _unloadTo) select 2) + 0.05]; - _container = createVehicle [["GroundWeaponHolder", QGVAR(ammo_holder)] select GVAR(handleExtraMagazinesType), [0, 0, 0], [], 0, "NONE"]; + private _containerType = getText (configOf _unloadTo >> QUOTE(ADDON) >> "container"); + + // Use setting if container already created or not defined + if (_containerType isEqualTo "" || {!isNil {_unloadTo getVariable QGVAR(container)}}) then { + _containerType = ["GroundWeaponHolder", QGVAR(ammo_holder)] select GVAR(handleExtraMagazinesType); + }; + + _container = createVehicle [_containerType, [0, 0, 0], [], 0, "CAN_COLLIDE"]; + if ((loadAbs _container) isNotEqualTo 0) then { + clearItemCargoGlobal _container; + clearWeaponCargoGlobal _container; + clearBackpackCargoGlobal _container; + clearMagazineCargoGlobal _container; + }; + + private _weaponRelPos = (_unloadTo getRelPos RELATIVE_DIRECTION(270)) vectorAdd [0, 0, 0.05]; _unloadTo setVariable [QGVAR(container), _container, true]; _container setDir random [0, 180, 360]; _container setPosATL _weaponRelPos; @@ -59,7 +81,7 @@ if (isNull _container) then { TRACE_2("Creating NEW Container",_container,_weaponRelPos); }; -TRACE_3("adding to container",_container,_fullMagazines,_bulletsRemaining); +TRACE_4("adding to container",_container,typeOf _container,_fullMagazines,_bulletsRemaining); if (_fullMagazines > 0) then { _container addMagazineAmmoCargo [_carryMag, _fullMagazines, _carryMaxAmmo]; @@ -67,3 +89,5 @@ if (_fullMagazines > 0) then { if (_bulletsRemaining > 0) then { _container addMagazineAmmoCargo [_carryMag, 1, _bulletsRemaining]; }; + +[QGVAR(clearNearbySourcesCache), [], _nearUnits] call CBA_fnc_targetEvent; diff --git a/addons/csw/functions/fnc_reload_loadMagazine.sqf b/addons/csw/functions/fnc_reload_loadMagazine.sqf index 5cceb55113e..03f8cb86b76 100644 --- a/addons/csw/functions/fnc_reload_loadMagazine.sqf +++ b/addons/csw/functions/fnc_reload_loadMagazine.sqf @@ -1,10 +1,10 @@ #include "script_component.hpp" /* * Author: PabstMirror - * Loads a magazine into a static weapon from a magazine carried by or next to the player. + * Loads a magazine into a CSW from a magazine carried by or next to the player. * * Arguments: - * 0: Vehicle + * 0: CSW * 1: Turret * 2: Unit Carried Magazine * 3: Magazine source @@ -19,46 +19,41 @@ * Public: No */ -params ["_vehicle", "_turret", "_carryMag", "_magSource", "_unit"]; -TRACE_5("loadMagazine",_vehicle,_turret,_carryMag,_magSource,_unit); +params ["_vehicle", "_turret", "_carryMag", "_magSource", "_unit", "_ammo"]; +TRACE_6("loadMagazine",_vehicle,_turret,_carryMag,_magSource,_unit,_ammo); -private _timeToLoad = 1; -if (!isNull(configOf _vehicle >> QUOTE(ADDON) >> "ammoLoadTime")) then { - _timeToLoad = getNumber(configOf _vehicle >> QUOTE(ADDON) >> "ammoLoadTime"); -}; +private _timeToLoad = GET_NUMBER(configOf _vehicle >> QUOTE(ADDON) >> "ammoLoadTime", 1); private _displayName = format [localize LSTRING(loadX), getText (configFile >> "CfgMagazines" >> _carryMag >> "displayName")]; private _onFinish = { - (_this select 0) params ["_vehicle", "_turret", "_carryMag", "_magSource", "_unit"]; - TRACE_5("load progressBar finish",_vehicle,_turret,_carryMag,_magSource,_unit); + (_this select 0) params ["_vehicle", "_turret", "_carryMag", "_magSource", "_unit", "_ammo"]; + TRACE_6("load progressBar finish",_vehicle,_turret,_carryMag,_magSource,_unit,_ammo); - ([_vehicle, _turret, _carryMag, _magSource] call FUNC(reload_canLoadMagazine)) params ["", "", "_neededAmmo", ""]; + ([_vehicle, _turret, _carryMag] call FUNC(reload_canLoadMagazine)) params ["", "", "_neededAmmo", ""]; if (_neededAmmo <= 0) exitWith { ERROR_1("Can't load ammo - %1",_this); }; - // Figure out what we can add from the magazines we have - private _bestAmmoToSend = -1; - { - _x params ["_xMag", "_xAmmo"]; - if (_xMag == _carryMag) then { - if ((_bestAmmoToSend == -1) || {(_xAmmo > _bestAmmoToSend) && {_xAmmo <= _neededAmmo}}) then { - _bestAmmoToSend = _xAmmo; - }; - }; - } forEach (if (_magSource isKindOf "CAManBase") then {magazinesAmmo _magSource} else {magazinesAmmoCargo _magSource}); + [_magSource, _carryMag, _ammo] call EFUNC(common,removeSpecificMagazine); - if (_bestAmmoToSend == -1) exitWith {ERROR_2("No ammo [%1 - %2]?",_xMag,_bestAmmoToSend);}; - [_magSource, _carryMag, _bestAmmoToSend] call EFUNC(common,removeSpecificMagazine); - if (_bestAmmoToSend == 0) exitWith {}; + private _nearUnits = _vehicle nearEntities ["CAManBase", 5]; + [QGVAR(clearNearbySourcesCache), [], _nearUnits] call CBA_fnc_targetEvent; - TRACE_6("calling addTurretMag event",_vehicle,_turret,_magSource,_carryMag,_bestAmmoToSend, _unit); - [QGVAR(addTurretMag), [_vehicle, _turret, _magSource, _carryMag, _bestAmmoToSend, _unit]] call CBA_fnc_globalEvent; -}; + private _returnTo = _magSource; + // if we're pulling from a weaponHolder, return the ammo to the unit doing the action + // workaround for weaponHolders being recreated with removeSpecificMagazine, magazines will still get dropped if inventory is full + // TODO: remove after 2.14 + if (_magSource isKindOf "WeaponHolder") then { + _returnTo = _unit; + }; + + TRACE_6("calling addTurretMag event",_vehicle,_turret,_magSource,_carryMag,_ammo, _unit); + [QGVAR(addTurretMag), [_vehicle, _turret, _magSource, _carryMag, _ammo, _unit, _returnTo]] call CBA_fnc_globalEvent; +}; [ TIME_PROGRESSBAR(_timeToLoad), - [_vehicle, _turret, _carryMag, _magSource], + [_vehicle, _turret, _carryMag, _magSource, _unit, _ammo], _onFinish, {TRACE_1("load progressBar fail",_this);}, _displayName, diff --git a/addons/csw/functions/fnc_staticWeaponInit.sqf b/addons/csw/functions/fnc_staticWeaponInit.sqf index 6ddaa9d36a5..9b216d68670 100644 --- a/addons/csw/functions/fnc_staticWeaponInit.sqf +++ b/addons/csw/functions/fnc_staticWeaponInit.sqf @@ -1,10 +1,10 @@ #include "script_component.hpp" /* * Author: Dani (TCVM) - * Initializes weapon to disable weapon disassembling + * Initializes CSW to disable weapon disassembling * * Arguments: - * 0: Weapon + * 0: CSW * * Return Value: * None @@ -15,44 +15,44 @@ * Public: No */ -params ["_staticWeapon"]; -private _typeOf = typeOf _staticWeapon; -private _configOf = configOf _staticWeapon; +params ["_vehicle"]; +private _typeOf = typeOf _vehicle; +private _configOf = configOf _vehicle; private _configEnabled = (getNumber (_configOf >> "ace_csw" >> "enabled")) == 1; private _assemblyConfig = _configEnabled && {(getText (_configOf >> "ace_csw" >> "disassembleWeapon")) != ""}; -TRACE_4("staticWeaponInit",_staticWeapon,_typeOf,_configEnabled,_assemblyConfig); +TRACE_4("staticWeaponInit",_vehicle,_typeOf,_configEnabled,_assemblyConfig); if (_configEnabled && {GVAR(ammoHandling) == 2}) then { - TRACE_1("adding AI fired handler",_staticWeapon); - _staticWeapon addEventHandler ["Fired", LINKFUNC(ai_handleFired)]; - _staticWeapon addEventHandler ["GetIn", LINKFUNC(ai_handleGetIn)]; // handle AI getting inside weapon with no ammo + TRACE_1("adding AI fired handler",_vehicle); + _vehicle addEventHandler ["Fired", LINKFUNC(ai_handleFired)]; + _vehicle addEventHandler ["GetIn", LINKFUNC(ai_handleGetIn)]; // handle AI getting inside weapon with no ammo }; -TRACE_2("",local _staticWeapon,_staticWeapon turretLocal [0]); -if (_configEnabled && {_staticWeapon turretLocal [0]}) then { // if turret is local to us, then handle mags/weapon +TRACE_2("",local _vehicle,_vehicle turretLocal [0]); +if (_configEnabled && {_vehicle turretLocal [0]}) then { // if turret is local to us, then handle mags/weapon [{ - params ["_staticWeapon"]; - if (!alive _staticWeapon) exitWith { TRACE_1("dead/deleted",_staticWeapon); }; + params ["_vehicle"]; + if (!alive _vehicle) exitWith { TRACE_1("dead/deleted",_vehicle); }; // Assembly mode: [0=disabled, 1=enabled, 2=enabled&unload, 3=default] - private _assemblyModeIndex = _staticWeapon getVariable [QGVAR(assemblyMode), 3]; + private _assemblyModeIndex = _vehicle getVariable [QGVAR(assemblyMode), 3]; private _emptyWeapon = _assemblyModeIndex isEqualTo 2; private _assemblyMode = [false, true, true, GVAR(defaultAssemblyMode)] select _assemblyModeIndex; - TRACE_2("turretLocal",_staticWeapon,_assemblyMode); - [_staticWeapon, [0], _assemblyMode, _emptyWeapon] call FUNC(proxyWeapon); - [_staticWeapon, _assemblyMode, _emptyWeapon] call FUNC(staticWeaponInit_unloadExtraMags); - }, [_staticWeapon]] call CBA_fnc_execNextFrame; // need to wait a frame to allow setting object vars during assembly + TRACE_2("turretLocal",_vehicle,_assemblyMode); + [_vehicle, [0], _assemblyMode, _emptyWeapon] call FUNC(proxyWeapon); + [_vehicle, _assemblyMode, _emptyWeapon] call FUNC(staticWeaponInit_unloadExtraMags); + }, [_vehicle]] call CBA_fnc_execNextFrame; // need to wait a frame to allow setting object vars during assembly }; if (_assemblyConfig) then { [{ - params ["_staticWeapon"]; - if (!alive _staticWeapon) exitWith { TRACE_1("dead/deleted",_staticWeapon); }; - private _assemblyMode = [false, true, true, GVAR(defaultAssemblyMode)] select (_staticWeapon getVariable [QGVAR(assemblyMode), 3]); - TRACE_2("assemblyConfig present",_staticWeapon,_assemblyMode); + params ["_vehicle"]; + if (!alive _vehicle) exitWith { TRACE_1("dead/deleted",_vehicle); }; + private _assemblyMode = [false, true, true, GVAR(defaultAssemblyMode)] select (_vehicle getVariable [QGVAR(assemblyMode), 3]); + TRACE_2("assemblyConfig present",_vehicle,_assemblyMode); if (_assemblyMode) then { // Disable vanilla assembly if assemblyMode eanbled - [QGVAR(disableVanillaAssembly), [_staticWeapon]] call CBA_fnc_localEvent; + [QGVAR(disableVanillaAssembly), [_vehicle]] call CBA_fnc_localEvent; }; - }, [_staticWeapon]] call CBA_fnc_execNextFrame; // need to wait a frame to allow setting object vars during assembly + }, [_vehicle]] call CBA_fnc_execNextFrame; // need to wait a frame to allow setting object vars during assembly }; // Add interactions for players diff --git a/addons/csw/functions/fnc_staticWeaponInit_unloadExtraMags.sqf b/addons/csw/functions/fnc_staticWeaponInit_unloadExtraMags.sqf index 41845c0eb3c..8709c1c1cd0 100644 --- a/addons/csw/functions/fnc_staticWeaponInit_unloadExtraMags.sqf +++ b/addons/csw/functions/fnc_staticWeaponInit_unloadExtraMags.sqf @@ -4,7 +4,7 @@ * Dumps ammo to container * * Arguments: - * 0: Weapon + * 0: CSW * 1: Using advanced assembly * * Return Value: @@ -16,11 +16,11 @@ * Public: No */ -params ["_staticWeapon", "_assemblyMode", "_emptyWeapon"]; -TRACE_3("staticWeaponInit_unloadExtraMags",_staticWeapon,_assemblyMode,_emptyWeapon); +params ["_vehicle", "_assemblyMode", "_emptyWeapon"]; +TRACE_3("staticWeaponInit_unloadExtraMags",_vehicle,_assemblyMode,_emptyWeapon); if (!_assemblyMode) exitWith {}; -private _desiredAmmo = getNumber (configOf _staticWeapon >> QUOTE(ADDON) >> "desiredAmmo"); +private _desiredAmmo = getNumber (configOf _vehicle >> QUOTE(ADDON) >> "desiredAmmo"); private _storeExtraMagazines = GVAR(handleExtraMagazines); if (_emptyWeapon) then { _desiredAmmo = 0; @@ -56,31 +56,32 @@ private _containerMagazineCount = []; } else { if ((_xMag select [0,4]) != "fake") then { WARNING_1("Unable to unload [%1] - No matching carry mag",_xMag); }; }; -} forEach (magazinesAllTurrets _staticWeapon); +} forEach (magazinesAllTurrets _vehicle); TRACE_1("Remove all loaded magazines",_magsToRemove); { - _staticWeapon removeMagazinesTurret _x; + _vehicle removeMagazinesTurret _x; if ((_loadedMagazineInfo select [0,2]) isEqualTo _x) then { TRACE_1("Re-add the starting mag",_loadedMagazineInfo); - _staticWeapon addMagazineTurret _loadedMagazineInfo; + _vehicle addMagazineTurret _loadedMagazineInfo; }; } forEach _magsToRemove; -if (_staticWeapon getVariable [QGVAR(secondaryWeaponMagazine), ""] isNotEqualTo "") then { - private _secondaryWeaponMagazine = _staticWeapon getVariable QGVAR(secondaryWeaponMagazine); - private _turret = allTurrets _staticWeapon param [0, []]; - private _vehicleMag = [_staticWeapon, _turret, _secondaryWeaponMagazine] call FUNC(reload_getVehicleMagazine); +if (_vehicle getVariable [QGVAR(secondaryWeaponMagazine), ""] isNotEqualTo "") then { + private _secondaryWeaponMagazine = _vehicle getVariable QGVAR(secondaryWeaponMagazine); + private _turret = allTurrets _vehicle param [0, []]; + private _vehicleMag = [_vehicle, _turret, _secondaryWeaponMagazine] call FUNC(reload_getVehicleMagazine); TRACE_3("Re-add previous mag",_secondaryWeaponMagazine,_turret,_vehicleMag); if (!isClass (configFile >> "CfgMagazines" >> _vehicleMag)) exitWith {}; - _staticWeapon addMagazineTurret [_vehicleMag, _turret, 1]; - _staticWeapon setVariable [QGVAR(secondaryWeaponMagazine), nil]; + _vehicle addMagazineTurret [_vehicleMag, _turret, 1]; + _vehicle setVariable [QGVAR(secondaryWeaponMagazine), nil]; }; if (_storeExtraMagazines) then { TRACE_1("saving extra mags to container",_containerMagazineCount); + { - [_staticWeapon, _x, _containerMagazineCount select _forEachIndex] call FUNC(reload_handleReturnAmmo); + [_vehicle, _x, _containerMagazineCount select _forEachIndex] call FUNC(reload_handleReturnAmmo); } forEach _containerMagazineClassnames; }; diff --git a/addons/csw/functions/fnc_unloadMagazines.sqf b/addons/csw/functions/fnc_unloadMagazines.sqf new file mode 100644 index 00000000000..02610023ec0 --- /dev/null +++ b/addons/csw/functions/fnc_unloadMagazines.sqf @@ -0,0 +1,50 @@ +#include "script_component.hpp" +/* + * Author: LinkIsGrim + * Unloads and returns magazines from a CSW + * + * Arguments: + * 0: CSW (default: objNull) + * 1: Turret Path or True to unload all turrets (default: [0]) + * 2: Return removed magazines (default: true) + * + * Return Value: + * None + * + * Example: + * [cursorTarget, [0]] call ace_csw_fnc_unloadMagazines + * + * Public: Yes + */ +params [["_vehicle", objNull, [objNull]], ["_turretPath", [0], [[0], true]], ["_returnMags", true, [true]]]; + +if (isNull _vehicle) exitWith {}; + +private _magsToRemove = []; +private _containerMagazineClassnames = []; +private _containerMagazineCount = []; + +{ + _x params ["_xMag", "_xTurret", "_xAmmo"]; + if (_xTurret isNotEqualTo _turretPath && {_turretPath isNotEqualTo true}) then {continue}; + private _carryMag = _xMag call FUNC(getCarryMagazine); + if (_carryMag != "") then { + _magsToRemove pushBackUnique [_xMag, _xTurret]; + private _index = _containerMagazineClassnames find _carryMag; + if (_index < 0) then { + _index = _containerMagazineClassnames pushBack _carryMag; + _containerMagazineCount pushBack 0; + }; + _containerMagazineCount set [_index, (_containerMagazineCount select _index) + _xAmmo]; + }; +} forEach (magazinesAllTurrets _vehicle); + +{ + _vehicle removeMagazinesTurret _x; +} forEach _magsToRemove; + +if (_returnMags) then { + { + [_vehicle, _x, _containerMagazineCount select _forEachIndex] call FUNC(reload_handleReturnAmmo); + } forEach _containerMagazineClassnames; +}; diff --git a/addons/csw/script_component.hpp b/addons/csw/script_component.hpp index 29521039f24..42b292c17ef 100644 --- a/addons/csw/script_component.hpp +++ b/addons/csw/script_component.hpp @@ -17,10 +17,13 @@ #include "\z\ace\addons\main\script_macros.hpp" +#define GET_NUMBER(config,default) (if (isNumber (config)) then {getNumber (config)} else {default}) #define DISTANCE_FROM_GUN 1.5 #define RELATIVE_DIRECTION(direction) [DISTANCE_FROM_GUN, direction] +#define NEARBY_SOURCES_CACHE_EXPIRY 5 + #ifdef FAST_PROGRESSBARS #define TIME_PROGRESSBAR(X) ((X) * 0.075) #else diff --git a/addons/csw/stringtable.xml b/addons/csw/stringtable.xml index 2782bad8500..dcb74d349ae 100644 --- a/addons/csw/stringtable.xml +++ b/addons/csw/stringtable.xml @@ -64,7 +64,7 @@ Bin 탑승하기 - + Load %1 Lade %1 Cargar %1 @@ -81,7 +81,7 @@ Yükle %1 %1 싣는중 - + Unload %1 Entlade %1 Descargar %1 @@ -113,6 +113,12 @@ Соединить %1 %1 연결 + + Loading %1... + + + Unloading %1... + Advanced Assembly Erweiterter Zusammenbau diff --git a/addons/mk6mortar/CfgVehicles.hpp b/addons/mk6mortar/CfgVehicles.hpp index 41e45abf351..8ffcde64f4b 100644 --- a/addons/mk6mortar/CfgVehicles.hpp +++ b/addons/mk6mortar/CfgVehicles.hpp @@ -29,6 +29,7 @@ class CfgVehicles { class ace_csw { proxyWeapon = QFUNC(csw_getProxyWeapon); magazineLocation = "_target selectionPosition 'usti hlavne'"; + container = "ACE_Box_82mm_Mo_Combo"; }; class Turrets: Turrets { class MainTurret: MainTurret { diff --git a/docs/wiki/framework/crew-served-weapons-framework.md b/docs/wiki/framework/crew-served-weapons-framework.md index 9b3ef28d4fb..2d2d19b4ae1 100644 --- a/docs/wiki/framework/crew-served-weapons-framework.md +++ b/docs/wiki/framework/crew-served-weapons-framework.md @@ -102,12 +102,12 @@ class ACE_CSW_Groups { class prefix_100rnd_hmg_csw_mag { // Same name as the carryable magazine prefix_100rnd_hmg_mag = 1; // Vehicle magazine that will be loaded when loading this magazine }; - + // Using an existing CSW magazine class ace_csw_100Rnd_127x99_mag { banana_dummy_ammo = 1; }; - + /* Carryable magazines already defined by ACE: - ace_csw_100Rnd_127x99_mag @@ -134,16 +134,18 @@ class CfgVehicles { class StaticMGWeapon; class prefix_hmg: StaticMGWeapon { class ACE_CSW { - enabled = 1; // Enables ACE CSW for this weapon + enabled = 1; // Enables ACE CSW for this weapon proxyWeapon = "prefix_hmg_weapon_proxy"; // The proxy weapon created above magazineLocation = "_target selectionPosition 'magazine'"; // Ammo handling interaction point location disassembleWeapon = "prefix_hmg_carry"; // Carryable weapon created above disassembleTurret = "ace_csw_m3Tripod"; // Which static tripod will appear when weapon is disassembled - ammoLoadTime = 7; // How long it takes in seconds to load ammo into the weapon + ammoLoadTime = 7; // How long it takes in seconds to load ammo into the weapon ammoUnloadTime = 5; // How long it takes in seconds to unload ammo from the weapon desiredAmmo = 100; // When the weapon is reloaded it will try and reload to this ammo capacity // Optional callback function for when the CSW gets disassembled, called with [tripod, staticWeapon] disassembleFunc = "prefix_fnc_handleDisassembly"; + // Optional object to store unloaded magazines in + container = "ReammoBox_F"; }; }; };