CSW - Add reloading from nearSupplies (#8776)

* allow players to reload from nearSupplies

* limit reloading to friendly sides

* add handling for ai getting inside empty weapon

* configOf for lookup

* add getin handler, hammer out remaining bugs

* configOf lookup

* improve friendly/object filter

* more configOf lookups

* Capitalize settings, add ammo storage setting

* remove systemChat

Co-authored-by: PabstMirror <pabstmirror@gmail.com>

* fix TRACE

Co-authored-by: PabstMirror <pabstmirror@gmail.com>

Co-authored-by: PabstMirror <pabstmirror@gmail.com>
This commit is contained in:
GhostIsSpooky 2022-03-07 15:29:19 -03:00 committed by GitHub
parent 5a72b61a50
commit a4ae61f1fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 286 additions and 164 deletions

View File

@ -31,9 +31,8 @@ private _fnc_removeMagazine = {
if (_specificMagazineIndex > -1) exitWith {
clearMagazineCargoGlobal _container;
private _containerType = typeOf _container;
if (_containerType in ["GroundWeaponHolder", "WeaponHolderSimulated"]) then {
_container = createVehicle [_containerType, getPosATL _container, [], 0, "CAN_COLLIDE"];
if (_container isKindOf "WeaponHolder" && {_allMagazines isNotEqualTo []}) then {
_container = createVehicle [typeOf _container, getPosATL _container, [], 0, "CAN_COLLIDE"];
};
{
_container addMagazineAmmoCargo [_x select 0, 1, _x select 1];

View File

@ -272,5 +272,15 @@ class CfgVehicles {
ammoUnloadTime = 3;
};
};
// Ammo holder for returning ammo
class ReammoBox_F;
class GVAR(ammo_holder): ReammoBox_F {
EGVAR(cargo,canLoad) = 0;
EGVAR(cargo,noRename) = 1;
EGVAR(dragging,canCarry) = 1; // Allow this to be moved alongside the weapon
EGVAR(dragging,canDrag) = 1;
scope = 1;
maximumLoad = 0; // don't allow anything to be placed inside, only removed
model = "\A3\Structures_F_EPB\Items\Military\Ammobox_rounds_F.p3d";
};
};

View File

@ -3,6 +3,8 @@ TRACE_1("",QUOTE(ADDON));
PREP(aceRearmGetCarryMagazines);
PREP(ai_handleFired);
PREP(ai_handleGetIn);
PREP(ai_reload);
PREP(assemble_canDeployTripod);
PREP(assemble_canDeployWeapon);

View File

@ -1,6 +1,6 @@
#include "script_component.hpp"
GVAR(vehicleMagCache) = call CBA_fnc_createNamespace;
GVAR(vehicleMagCache) = createHashMap;
["CBA_settingsInitialized", {
TRACE_3("settingsInit",GVAR(defaultAssemblyMode),GVAR(handleExtraMagazines),GVAR(ammoHandling));

View File

@ -31,11 +31,11 @@ private _allCarryMags = [];
private _weapon = _x;
{
private _xMag = _x;
private _carryMag = GVAR(vehicleMagCache) getVariable _xMag;
private _carryMag = GVAR(vehicleMagCache) get _xMag;
if (isNil "_carryMag") then {
private _groups = "getNumber (_x >> _xMag) == 1 && {isClass (configFile >> 'CfgMagazines' >> configName _x)}" configClasses (configFile >> QGVAR(groups));
_carryMag = configName (_groups param [0, configNull]);
GVAR(vehicleMagCache) setVariable [_x, _carryMag];
GVAR(vehicleMagCache) set [_x, _carryMag];
TRACE_2("setting cache",_xMag,_carryMag);
};
if (_carryMag != "") then {

View File

@ -1,92 +1,23 @@
#include "script_component.hpp"
/*
* Author: PabstMirror
* Initializes weapon to disable weapon disassembling
* Handles AI Fired EH
*
* Arguments:
* 0: Weapon <OBJECT>
* Fired EH
*
* Return Value:
* None
*
* Example:
* [weapon] call ace_csw_fnc_ai_handleFired
*
* Public: No
*/
params ["_staticWeapon", "_weapon", "_muzzle", "_mode", "_ammo", "_magazine", "_projectile", "_gunner"];
TRACE_8("firedEH:",_staticWeapon, _weapon, _muzzle, _mode, _ammo, _magazine, _projectile, _gunner);
TRACE_8("firedEH:",_staticWeapon,_weapon,_muzzle,_mode,_ammo,_magazine,_projectile,_gunner);
if ((!local _gunner) || {[_gunner] call EFUNC(common,isPlayer)}) exitWith {};
if (someAmmo _staticWeapon) exitWith {};
TRACE_2("need ammo",someAmmo _staticWeapon,magazinesAllTurrets _staticWeapon);
private _turretPath = [_gunner] call EFUNC(common,getTurretIndex);
private _reloadSource = objNull;
private _reloadMag = "";
private _reloadNeededAmmo = -1;
// Find if there is anything we can reload with
{
scopeName "findSource";
private _xSource = _x;
private _cswMagazines = [];
{
if (isClass (configFile >> QGVAR(groups) >> _x)) then { _cswMagazines pushBackUnique _x; };
} forEach (if (_xSource isKindOf "CaManBase") then {magazines _x} else {magazineCargo _x});
TRACE_2("",_xSource,_cswMagazines);
private _compatibleMags = [_magazine] + ([_weapon] call CBA_fnc_compatibleMagazines); // Check current mag first
{
private _xWeaponMag = _x;
{
if ((getNumber (configFile >> QGVAR(groups) >> _x >> _xWeaponMag)) == 1) then {
private _loadInfo = [_staticWeapon, _turretPath, _reloadMag, objNull] 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 ([_gunner] + (_staticWeapon nearSupplies 10));
if (_reloadMag == "") exitWith {TRACE_1("could not find mag",_reloadMag);};
// 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");};
// Remove the mag from the source
[_reloadSource, _reloadMag, _bestAmmoToSend] call EFUNC(common,removeSpecificMagazine);
private _timeToLoad = 1;
if (!isNull(configOf _staticWeapon >> QUOTE(ADDON) >> "ammoLoadTime")) then {
_timeToLoad = getNumber(configOf _staticWeapon >> QUOTE(ADDON) >> "ammoLoadTime");
};
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);};
// Reload the static weapon
TRACE_5("calling addTurretMag event",_staticWeapon, _turretPath, _gunner, _reloadMag, _bestAmmoToSend);
[QGVAR(addTurretMag), _this] call CBA_fnc_globalEvent;
}, [_staticWeapon, _turretPath, _gunner, _reloadMag, _bestAmmoToSend], _timeToLoad] call CBA_fnc_waitAndExecute;
[_staticWeapon, _gunner, _weapon, _magazine] call FUNC(ai_reload);

View File

@ -0,0 +1,22 @@
#include "script_component.hpp"
/*
* Author: GhostIsSpooky
* Handles AI GetIn on an empty weapon
*
* Arguments:
* GetIn EH
*
* Return Value:
* None
*
* Public: No
*/
params ["_staticWeapon", "_role", "_gunner"];
TRACE_3("getInEH:",_staticWeapon,_role,_gunner);
if ((!local _gunner) || {[_gunner] call EFUNC(common,isPlayer)}) exitWith {};
if (someAmmo _staticWeapon) exitWith {};
TRACE_2("need ammo",someAmmo _staticWeapon,magazinesAllTurrets _staticWeapon);
[_staticWeapon, _gunner, currentWeapon _staticWeapon] call FUNC(ai_reload);

View File

@ -0,0 +1,95 @@
#include "script_component.hpp"
/*
* Author: PabstMirror, modified by GhostIsSpooky
* Handles AI reloading
*
* Arguments:
* 0: Static Weapon <OBJECT>
* 1: Gunner <OBJECT>
* 2: Weapon <STRING>
* 3: Magazine <STRING> (default: "")
*
* Return Value:
* None
*
* Public: No
*/
params ["_staticWeapon", "_gunner", "_weapon", ["_magazine", ""]];
private _turretPath = [_gunner] call EFUNC(common,getTurretIndex);
private _reloadSource = objNull;
private _reloadMag = "";
private _reloadNeededAmmo = -1;
private _cfgMagGroups = configFile >> QGVAR(groups);
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}}
});
// Find if there is anything we can reload with
{
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];
};
{
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);};
// 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");};
// Remove the mag from the source
[_reloadSource, _reloadMag, _bestAmmoToSend] call EFUNC(common,removeSpecificMagazine);
private _timeToLoad = 1;
if (!isNull(configOf _staticWeapon >> QUOTE(ADDON) >> "ammoLoadTime")) then {
_timeToLoad = getNumber(configOf _staticWeapon >> QUOTE(ADDON) >> "ammoLoadTime");
};
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);};
// Reload the static weapon
TRACE_5("calling addTurretMag event",_staticWeapon,_turretPath,_gunner,_reloadMag,_bestAmmoToSend);
[QGVAR(addTurretMag), _this] call CBA_fnc_globalEvent;
}, [_staticWeapon, _turretPath, _gunner, _reloadMag, _bestAmmoToSend], _timeToLoad] call CBA_fnc_waitAndExecute;

View File

@ -41,11 +41,11 @@
{
_x params ["_xMag", "", "_xAmmo"];
private _carryMag = GVAR(vehicleMagCache) getVariable _xMag;
private _carryMag = GVAR(vehicleMagCache) get _xMag;
if (isNil "_carryMag") then {
private _groups = "getNumber (_x >> _xMag) == 1 && {isClass (configFile >> 'CfgMagazines' >> configName _x)}" configClasses (configFile >> QGVAR(groups));
_carryMag = configName (_groups param [0, configNull]);
GVAR(vehicleMagCache) setVariable [_xMag, _carryMag];
GVAR(vehicleMagCache) set [_xMag, _carryMag];
TRACE_2("setting cache",_xMag,_carryMag);
};
if ((_xAmmo > 0) && {_carryMag != ""}) then {
@ -93,4 +93,3 @@
[TIME_PROGRESSBAR(_pickupTime), [_staticWeapon, _player, _carryWeaponClassname, _turretClassname, _onDisassembleFunc], _onFinish, {}, localize LSTRING(DisassembleCSW_progressBar), _condition] call EFUNC(common,progressBar);
}, _this] call CBA_fnc_execNextFrame;

View File

@ -23,8 +23,7 @@ TRACE_4("proxyWeapon",_staticWeapon,_turret,_needed,_emptyWeapon);
if (_staticWeapon getVariable [format [QGVAR(proxyHandled_%1), _turret], false]) exitWith { TRACE_1("already handled",typeOf _staticWeapon); };
private _typeOf = typeOf _staticWeapon;
private _proxyWeapon = getText(configFile >> "CfgVehicles" >> _typeOf >> "ace_csw" >> "proxyWeapon");
private _proxyWeapon = getText (configOf _staticWeapon >> "ace_csw" >> "proxyWeapon");
TRACE_2("",_typeOf,_proxyWeapon);
if (_proxyWeapon == "") exitWith {};

View File

@ -23,24 +23,26 @@ private _loadableMagazines = [_vehicle, _player] call FUNC(reload_getLoadableMag
private _statement = {
params ["_target", "_player", "_params"];
_params params ["_carryMag", "_turretPath"];
_params params ["_carryMag", "_turretPath", "", "_magSource"];
[_target, _turretPath, _carryMag, _player] call FUNC(reload_loadMagazine);
[_target, _turretPath, _carryMag, _magSource, _player] call FUNC(reload_loadMagazine);
};
private _condition = {
params ["_target", "_player", "_params"];
_params params ["_carryMag", "_turretPath"];
_params params ["_carryMag", "_turretPath", "", "_magSource"];
([_target, _turretPath, _carryMag, _player] call FUNC(reload_canLoadMagazine)) select 0
([_target, _turretPath, _carryMag, _magSource] call FUNC(reload_canLoadMagazine)) select 0
};
private _cfgMagazines = configFile >> "CfgMagazines"; // micro-optimization
{
_x params ["_carryMag", "_turretPath", "_loadInfo"];
_x params ["_carryMag", "", "_loadInfo"];
_loadInfo params ["", "", "", "_isBeltLinking"];
private _displayName = getText (configFile >> "CfgMagazines" >> _carryMag >> "displayName");
private _picture = getText (configFile >> "CfgMagazines" >> _carryMag >> "picture");
private _displayName = getText (_cfgMagazines >> _carryMag >> "displayName");
private _picture = getText (_cfgMagazines >> _carryMag >> "picture");
private _text = if (_isBeltLinking) then {
format [localize LSTRING(actionLink), _displayName];
} else {
@ -53,4 +55,3 @@ private _condition = {
TRACE_1("loadActions",count _actions);
_actions

View File

@ -1,7 +1,7 @@
#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 unload from the static weapon
*
* Arguments:
* 0: Target <OBJECT>
@ -52,25 +52,27 @@ private _condition = {
private _actions = [];
private _handeledMagTypes = [];
private _cfgMagazines = configFile >> "CfgMagazines";
// Go through magazines on static weapon and check if any are unloadable
{
_x params ["_xMag", "_xTurret", "_xAmmo"];
if ((_xAmmo > 0) && {!(_xMag in _handeledMagTypes)}) then {
_handeledMagTypes pushBack _xMag;
private _carryMag = GVAR(vehicleMagCache) getVariable _xMag;
private _carryMag = GVAR(vehicleMagCache) get _xMag;
if (isNil "_carryMag") then {
private _groups = "getNumber (_x >> _xMag) == 1 && {isClass (configFile >> 'CfgMagazines' >> configName _x)}" configClasses (configFile >> QGVAR(groups));
_carryMag = configName (_groups param [0, configNull]);
GVAR(vehicleMagCache) setVariable [_xMag, _carryMag];
GVAR(vehicleMagCache) set [_xMag, _carryMag];
TRACE_2("setting cache",_xMag,_carryMag);
};
if (_carryMag == "") exitWith {};
private _displayName = getText (configFile >> "CfgMagazines" >> _carryMag >> "displayName");
private _displayName = getText (_cfgMagazines >> _carryMag >> "displayName");
private _text = format [LLSTRING(unloadX), _displayName];
private _picture = getText (configFile >> "CfgMagazines" >> _carryMag >> "picture");
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];
};
@ -78,4 +80,3 @@ private _handeledMagTypes = [];
TRACE_1("unloadActions",count _actions);
_actions

View File

@ -7,7 +7,7 @@
* 0: Static Weapon <OBJECT>
* 1: Turret Path <ARRAY>
* 2: Carryable Magazine <STRING>
* 3: Player <OBJECT>
* 3: Supplier <OBJECT>
*
* Return Value:
* [CanLoad<BOOL>, LoadedMag<STRING>, AmmoNeeded<NUMBER>, IsBeltLinking<BOOL>]<ARRAY>
@ -18,17 +18,30 @@
* Public: No
*/
params ["_vehicle", "_turret", "_carryMag", ["_unit", objNull]];
// TRACE_4("reload_canLoadMagazine",_vehicle,_turret,_carryMag,_unit);
params ["_vehicle", "_turret", "_carryMag", ["_magSource", objNull]];
// TRACE_4("reload_canLoadMagazine",_vehicle,_turret,_carryMag,_magSource);
private _return = [false, "", -2, false];
// Handle disassembled or deleted
if (!alive _vehicle) exitWith { [false, "", -1, false] };
// Verify unit has carry magazine
if ((!isNull _unit) && {((_vehicle distance _unit) > 5) || {((magazines _unit) findIf {_x == _carryMag}) == -1}}) exitWith { [false, "", -2, false] };
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 };
// solve config lookups
private _cfgMagazines = configFile >> "CfgMagazines";
private _cfgMagazinesCarryMag = _cfgMagazines >> _carryMag;
private _desiredAmmo = getNumber (configOf _vehicle >> QUOTE(ADDON) >> "desiredAmmo");
if (_desiredAmmo == 0) then { _desiredAmmo = 100; };
private _ammoNeeded = _desiredAmmo min getNumber (configFile >> "CfgMagazines" >> _carryMag >> "count"); // assume it needs full carry mag
private _ammoNeeded = _desiredAmmo min getNumber (_cfgMagazinesCarryMag >> "count"); // assume it needs full carry mag
private _loadedMag = "";
private _isBeltLinking = false;
@ -40,13 +53,13 @@ scopeName "main";
_loadedMag = _xMag;
if (_xAmmo > 0) then {
// There is a magazine with ammo loaded in the turret (are there any multi-muzzle static weapons??), see if we can add to this mag
if (getNumber (configFile >> QGVAR(groups) >> _carryMag >> _xMag) != 1) exitWith {
if (getNumber (_cfgMagazinesCarryMag >> _xMag) != 1) exitWith {
[false, _loadedMag, -4, false] breakOut "main"; // Carry mag cannot be added to existing vehicle mag (e.g. red to green tracers)
};
if (getNumber (configFile >> "CfgMagazines" >> _carryMag >> "ACE_isBelt") == 0) exitWith {
if (getNumber (_cfgMagazinesCarryMag >> "ACE_isBelt") == 0) exitWith {
[false, _loadedMag, -5, false] breakOut "main"; // Non-linkable mag loaded, can't add any more
};
private _maxMagazineAmmo = _desiredAmmo min getNumber (configFile >> "CfgMagazines" >> _xMag >> "count");
private _maxMagazineAmmo = _desiredAmmo min getNumber (_cfgMagazines >> _xMag >> "count");
if (_xAmmo >= _maxMagazineAmmo) exitWith {
[false, _loadedMag, -6, false] breakOut "main"; // Already at capicity
};

View File

@ -9,7 +9,7 @@
*
* Return Value:
* Mags <ARRAY>
* [Carry Magazine <STRING>, Turret Path <ARRAY>, Ammo Needed <NUMBER>]
* [Carry Magazine <STRING>, Turret Path <ARRAY>, Load Info <NUMBER>, Magazine Source <OBJECT>]
*
* Example:
* [cursorObject, player] call ace_csw_fnc_reload_getLoadableMagazines
@ -19,15 +19,37 @@
params ["_vehicle", "_player"];
private _carriedMagazines = [];
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;
{
if (isClass (configFile >> QGVAR(groups) >> _x)) then {
_carriedMagazines pushBackUnique _x;
};
} forEach (magazines _player);
private _xSource = _x;
private _mags = magazineCargo _xSource;
if (_carriedMagazines isEqualTo []) exitWith { [] }; // fast exit if no carry mags
{
_availableMagazines set [_x, _xSource];
} forEach (_mags select {isClass (_magGroupsConfig >> _x)});
} forEach _nearSupplies;
if (_availableMagazines isEqualTo createHashMap) exitWith { [] }; // fast exit if no available mags
private _loadInfo = [];
private _return = [];
@ -37,14 +59,19 @@ private _return = [];
{
private _weapon = _x;
{
//IGNORE_PRIVATE_WARNING ["_x", "_y"];
private _carryMag = _x;
private _carryGroup = configFile >> QGVAR(groups) >> _carryMag;
private _magSource = _y;
private _carryGroup = _magGroupsConfig >> _carryMag;
{
if (((getNumber (_carryGroup >> _x)) == 1) && {_loadInfo = [_vehicle, _turretPath, _carryMag, _player] call FUNC(reload_canLoadMagazine); _loadInfo select 0}) exitWith {
_return pushBack [_carryMag, _turretPath, _loadInfo];
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 _carriedMagazines;
} forEach _availableMagazines;
} forEach (_vehicle weaponsTurret _turretPath);
} forEach (allTurrets _vehicle);
// Note: these nested forEach's looks terrible, but most only have one element

View File

@ -7,9 +7,10 @@
* Arguments:
* 0: Static Weapon <OBJECT>
* 1: Turret Path <ARRAY>
* 2: Unit doing action <OBJECT>
* 2: Source of magazine <OBJECT>
* 3: Vehicle Magazine <STRING>
* 4: Ammo in magazine <NUMBER>
* 5: Unit or object to return ammo to <OBJECT>
*
* Return Value:
* None
@ -20,8 +21,8 @@
* Public: No
*/
params ["_vehicle", "_turret", "_unit", "_carryMag" ,"_ammoRecieved"];
TRACE_5("reload_handleAddTurretMag",_vehicle,_turret,_unit,_carryMag,_ammoRecieved);
params ["_vehicle", "_turret", "_magSource", "_carryMag", "_ammoReceived", ["_returnTo", _magSource]];
TRACE_6("reload_handleAddTurretMag",_vehicle,_turret,_magSource,_carryMag,_ammoReceived,_returnTo);
TRACE_2("",local _vehicle, _vehicle turretLocal _turret);
if (!(_vehicle turretLocal _turret)) exitWith {};
@ -29,9 +30,9 @@ if (!(_vehicle turretLocal _turret)) exitWith {};
([_vehicle, _turret, _carryMag] call FUNC(reload_canLoadMagazine)) params ["_canAdd", "_loadedMag", "_neededAmmo", "_isBeltLinking"];
TRACE_4("canLoad",_canAdd,_loadedMag,_neededAmmo,_isBeltLinking);
private _ammoRemaining = _ammoRecieved;
private _ammoRemaining = _ammoReceived;
if (_canAdd) then {
private _ammoUsed = _neededAmmo min _ammoRecieved;
private _ammoUsed = _neededAmmo min _ammoReceived;
_ammoRemaining = _ammoRemaining - _ammoUsed;
if (_isBeltLinking) then {
@ -46,7 +47,6 @@ if (_canAdd) then {
_vehicle setAmmo [_weapon, _currentAmmo];
private _currentAmmo = _vehicle magazineTurretAmmo [_loadedMag, _turret];
if ((_weapon == "") || {_currentAmmo != _currentAmmo}) then { ERROR_1("failed to setAmmo - %1", _this); };
} else {
if (_loadedMag != "") then {
TRACE_1("Removing emtpy mag",_loadedMag);
@ -60,7 +60,6 @@ if (_canAdd) then {
};
if (_ammoRemaining > 0) then {
TRACE_3("Returning ammo",_unit,_carryMag,_ammoRemaining);
[QGVAR(returnAmmo), [_unit, _carryMag, _ammoRemaining], _unit] call CBA_fnc_targetEvent;
TRACE_3("Returning ammo",_returnTo,_carryMag,_ammoRemaining);
[QGVAR(returnAmmo), [_returnTo, _carryMag, _ammoRemaining], _returnTo] call CBA_fnc_targetEvent;
};

View File

@ -9,7 +9,7 @@
* 1: Turret Path <ARRAY>
* 2: Magainze Unit Can Carry <STRING>
* 3: Magazine To Remove From Static <STRING>
* 4: Unit to unload to <OBJECT>
* 4: Unit or container to unload to <OBJECT>
*
* Return Value:
* None
@ -20,10 +20,10 @@
* Public: No
*/
params ["_vehicle", "_turretPath", "_carryMag", "_vehMag", "_unit"];
TRACE_5("removeTurretMag EH",_vehicle,_turretPath,_carryMag,_vehMag,_unit);
params ["_vehicle", "_turretPath", "_carryMag", "_vehMag", "_unloadTo"];
TRACE_5("removeTurretMag EH",_vehicle,_turretPath,_carryMag,_vehMag,_unloadTo);
TRACE_3("",local _vehicle, _vehicle turretLocal _turretPath,local _unit);
TRACE_3("",local _vehicle, _vehicle turretLocal _turretPath,local _unloadTo);
if (!(_vehicle turretLocal _turretPath)) exitWith {};
private _magsInWeapon = []; // Check how much ammo it has now:
@ -75,5 +75,5 @@ if ((_magsInWeapon isEqualTo []) && {_ammoInFirstMag > _ammoRemoved}) then {
} forEach _magsInWeapon;
};
TRACE_3("Returning ammo",_unit,_carryMag,_ammoRemoved);
[QGVAR(returnAmmo), [_unit, _carryMag, _ammoRemoved], _unit] call CBA_fnc_targetEvent;
TRACE_3("Returning ammo",_unloadTo,_carryMag,_ammoRemoved);
[QGVAR(returnAmmo), [_unloadTo, _carryMag, _ammoRemoved], _unloadTo] call CBA_fnc_targetEvent;

View File

@ -39,18 +39,17 @@ if ((_fullMagazines == 0) && {_bulletsRemaining == 0}) exitWith {};
// Try to use existing container
private _container = _unloadTo getVariable [QGVAR(container), objNull];
if ((_container distance _unloadTo) > 4) then { _container = objNull; };
if ((_container distance _unloadTo) > 10) then { _container = objNull; };
if (isNull _container) then {
_container = (nearestObjects [_unloadTo, ["groundWeaponHolder"], 4]) param [0, objNull];
_container = (nearestObjects [_unloadTo, [QGVAR(ammo_holder), "GroundWeaponHolder"], 10]) param [0, objNull];
};
if (isNull _container) then {
// Create ground weapon holder container
// Create ammo storage container
private _weaponRelPos = _unloadTo getRelPos RELATIVE_DIRECTION(270);
_weaponRelPos set [2, ((getPosATL _unloadTo) select 2) + 0.05];
_container = createVehicle ["groundWeaponHolder", [0, 0, 0], [], 0, "NONE"];
// ToDo: Unload to ammo box??
_container = createVehicle [["GroundWeaponHolder", QGVAR(ammo_holder)] select GVAR(handleExtraMagazinesType), [0, 0, 0], [], 0, "NONE"];
_unloadTo setVariable [QGVAR(container), _container, true];
_container setDir random [0, 180, 360];
_container setPosATL _weaponRelPos;

View File

@ -1,25 +1,26 @@
#include "script_component.hpp"
/*
* Author: PabstMirror
* Loads a magazine into a static weapon from a magazine carried by the player.
* Loads a magazine into a static weapon from a magazine carried by or next to the player.
*
* Arguments:
* 0: Vehicle <OBJECT>
* 1: Turret <ARRAY>
* 2: Unit Carried Magazine <STRING>
* 3: Player <OBJECT>
* 3: Magazine source <OBJECT>
* 4: Unit doing the action <OBJECT>
*
* Return Value:
* None
*
* Example:
* [cursorTarget, [0], "ACE_csw_100Rnd_127x99_mag_red", player] call ace_csw_fnc_reload_loadMagazine
* [cursorTarget, [0], "ACE_csw_100Rnd_127x99_mag_red", player, player] call ace_csw_fnc_reload_loadMagazine
*
* Public: No
*/
params ["_vehicle", "_turret", "_carryMag", "_unit"];
TRACE_4("loadMagazine",_vehicle,_turret,_carryMag,_unit);
params ["_vehicle", "_turret", "_carryMag", "_magSource", "_unit"];
TRACE_5("loadMagazine",_vehicle,_turret,_carryMag,_magSource,_unit);
private _timeToLoad = 1;
if (!isNull(configOf _vehicle >> QUOTE(ADDON) >> "ammoLoadTime")) then {
@ -29,10 +30,10 @@ if (!isNull(configOf _vehicle >> QUOTE(ADDON) >> "ammoLoadTime")) then {
private _displayName = format [localize LSTRING(loadX), getText (configFile >> "CfgMagazines" >> _carryMag >> "displayName")];
private _onFinish = {
(_this select 0) params ["_vehicle", "_turret", "_carryMag", "_unit"];
TRACE_4("load progressBar finish",_vehicle,_turret,_carryMag,_unit);
(_this select 0) params ["_vehicle", "_turret", "_carryMag", "_magSource", "_unit"];
TRACE_5("load progressBar finish",_vehicle,_turret,_carryMag,_magSource,_unit);
([_vehicle, _turret, _carryMag, _unit] call FUNC(reload_canLoadMagazine)) params ["", "", "_neededAmmo", ""];
([_vehicle, _turret, _carryMag, _magSource] 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
@ -44,20 +45,20 @@ private _onFinish = {
_bestAmmoToSend = _xAmmo;
};
};
} forEach (magazinesAmmo _unit);
} forEach (magazinesAmmo _magSource);
if (_bestAmmoToSend == -1) exitWith {ERROR_2("No ammo [%1 - %2]?",_xMag,_bestAmmoToSend);};
[_unit, _carryMag, _bestAmmoToSend] call EFUNC(common,removeSpecificMagazine);
[_magSource, _carryMag, _bestAmmoToSend] call EFUNC(common,removeSpecificMagazine);
if (_bestAmmoToSend == 0) exitWith {};
TRACE_5("calling addTurretMag event",_vehicle,_turret,_unit,_carryMag,_bestAmmoToSend);
[QGVAR(addTurretMag), [_vehicle, _turret, _unit, _carryMag, _bestAmmoToSend]] call CBA_fnc_globalEvent;
TRACE_6("calling addTurretMag event",_vehicle,_turret,_magSource,_carryMag,_bestAmmoToSend, _unit);
[QGVAR(addTurretMag), [_vehicle, _turret, _magSource, _carryMag, _bestAmmoToSend, _unit]] call CBA_fnc_globalEvent;
};
[
TIME_PROGRESSBAR(_timeToLoad),
[_vehicle, _turret, _carryMag, _unit],
[_vehicle, _turret, _carryMag, _magSource],
_onFinish,
{TRACE_1("load progressBar fail",_this);},
_displayName,

View File

@ -17,13 +17,15 @@
params ["_staticWeapon"];
private _typeOf = typeOf _staticWeapon;
private _configEnabled = (getNumber (configFile >> "CfgVehicles" >> _typeOf >> "ace_csw" >> "enabled")) == 1;
private _assemblyConfig = _configEnabled && {(getText (configFile >> "CfgVehicles" >> _typeOf >> "ace_csw" >> "disassembleWeapon")) != ""};
private _configOf = configOf _staticWeapon;
private _configEnabled = (getNumber (_configOf >> "ace_csw" >> "enabled")) == 1;
private _assemblyConfig = _configEnabled && {(getText (_configOf >> "ace_csw" >> "disassembleWeapon")) != ""};
TRACE_4("staticWeaponInit",_staticWeapon,_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_2("",local _staticWeapon,_staticWeapon turretLocal [0]);
@ -65,7 +67,7 @@ if (hasInterface && {!(_typeOf in GVAR(initializedStaticTypes))}) then {
private _ammoActionPath = [];
private _magazineLocation = getText (configFile >> "CfgVehicles" >> _typeOf >> QUOTE(ADDON) >> "magazineLocation");
private _magazineLocation = getText (_configOf >> QUOTE(ADDON) >> "magazineLocation");
private _condition = { //IGNORE_PRIVATE_WARNING ["_target", "_player"];
// If magazine handling is enabled or weapon assembly/disassembly is enabled we enable ammo handling
if ((GVAR(ammoHandling) == 0) && {!([false, true, true, GVAR(defaultAssemblyMode)] select (_target getVariable [QGVAR(assemblyMode), 3]))}) exitWith { false };

View File

@ -36,11 +36,11 @@ private _containerMagazineCount = [];
{
_x params ["_xMag", "_xTurret", "_xAmmo"];
private _carryMag = GVAR(vehicleMagCache) getVariable _xMag;
private _carryMag = GVAR(vehicleMagCache) get _xMag;
if (isNil "_carryMag") then {
private _groups = "getNumber (_x >> _xMag) == 1 && {isClass (configFile >> 'CfgMagazines' >> configName _x)}" configClasses (configFile >> QGVAR(groups));
_carryMag = configName (_groups param [0, configNull]);
GVAR(vehicleMagCache) setVariable [_xMag, _carryMag];
GVAR(vehicleMagCache) set [_xMag, _carryMag];
TRACE_2("setting cache",_xMag,_carryMag);
};
if (_carryMag != "") then {

View File

@ -20,6 +20,16 @@ private _categoryArray = [format ["ACE %1", localize LSTRING(DisplayName)]];
true // Needs mission restart
] call CBA_fnc_addSetting;
[
QGVAR(handleExtraMagazinesType), "LIST",
[LSTRING(handleExtraMagazinesType_displayName), LSTRING(handleExtraMagazinesType_description)],
_categoryArray,
[[0, 1], [LSTRING(handleExtraMagazinesType_weaponHolder), LSTRING(handleExtraMagazinesType_ammoBox)], 0],
true, // isGlobal
{[QGVAR(handleExtraMagazinesType), _this] call EFUNC(common,cbaSettings_settingChanged)},
true // Needs mission restart
] call CBA_fnc_addSetting;
[
QGVAR(ammoHandling), "LIST",
[LSTRING(ammoHandling_displayName), LSTRING(ammoHandling_description)],

View File

@ -114,7 +114,7 @@
<Korean>%1 연결</Korean>
</Key>
<Key ID="STR_ACE_CSW_defaultAssemblyMode_displayName">
<English>Advanced assembly</English>
<English>Advanced Assembly</English>
<German>Erweiterter Zusammenbau</German>
<Portuguese>Montagem Avançada</Portuguese>
<French>Assemblage avancé</French>
@ -129,7 +129,7 @@
<Korean>고급 조립</Korean>
</Key>
<Key ID="STR_ACE_CSW_defaultAssemblyMode_description">
<English>Use ace for Assemble/Disassemble of supported static weapons. Loaded ammo is reduced to a single magazine.</English>
<English>Use ACE for Assemble/Disassemble of supported static weapons. Loaded ammo is reduced to a single magazine.</English>
<German>Benutze ACE um unterstützte statische Waffen zu montieren/demontieren. Geladene Munition ist auf ein einzelnes Magazin reduziert.</German>
<Portuguese>Usar o ACE para Montar/Desmontar armas estáticas suportadas. Munição carregada é reduzida para um único carregador.</Portuguese>
<French>Utilise ACE pour l'assemblage/le désassemblage des armes statiques supportées.\nLes munitions chargées sont réduites à un seul chargeur.</French>
@ -144,7 +144,7 @@
<Korean>ACE의 조립/분해 기능을 사용하여 공용화기를 다룹니다. 장전된 탄은 한 탄창으로 제한됩니다.</Korean>
</Key>
<Key ID="STR_ACE_CSW_handleExtraMagazines_displayName">
<English>Save extra ammo</English>
<English>Save Extra Ammo</English>
<German>Spare extra Munition</German>
<Portuguese>Economizar munição extra</Portuguese>
<French>Conserver le surplus de munitions</French>
@ -173,6 +173,18 @@
<Russian>Хранить дополнительные магазины рядом со статическим оружием</Russian>
<Korean>공용화기 옆에 남은 탄들을 저장합니다.</Korean>
</Key>
<Key ID="STR_ACE_CSW_handleExtraMagazinesType_displayName">
<English>Ammo Storage</English>
</Key>
<Key ID="STR_ACE_CSW_handleExtraMagazinesType_description">
<English>Determines whether extra magazines are stored on the ground or inside an ammo box</English>
</Key>
<Key ID="STR_ACE_CSW_handleExtraMagazinesType_weaponHolder">
<English>Ground</English>
</Key>
<Key ID="STR_ACE_CSW_handleExtraMagazinesType_ammoBox">
<English>Ammo Box</English>
</Key>
<Key ID="STR_ACE_CSW_ammoHandling_displayName">
<English>Ammo handling</English>
<German>Munitionsmanagement</German>
@ -234,7 +246,7 @@
<Korean>공용화기의 조립 및 재장전 속도를에 관여하는 계수입니다.</Korean>
</Key>
<Key ID="STR_ACE_CSW_dragAfterDeploy_displayName">
<English>Drag tripods after deploying</English>
<English>Drag Tripods after Deploying</English>
<German>Ziehe Dreibeine nach Aufbau</German>
<Portuguese>Arrastar tripés após montar</Portuguese>
<French>Glisser le trépied après déploiement</French>
@ -622,7 +634,7 @@
<English>M3 Tripod</English>
<Spanish>Trípode M3</Spanish>
<German>M3 Dreibein</German>
<Portuguese>M3 Tripé</Portuguese>
<Portuguese>Tripé M3</Portuguese>
<French>Trépied M3</French>
<Japanese>M3 三脚</Japanese>
<Chinese>M3 三腳架</Chinese>
@ -750,7 +762,7 @@
<English>[CSW] M3 Deployable Tripod</English>
<Spanish>[CSW] Trípode desplegable M3</Spanish>
<German>[CSW] M3 aufstellbares Dreibein</German>
<Portuguese>[CSW] M3 Tripe Ajustável</Portuguese>
<Portuguese>[CSW] Tripe Ajustável M3</Portuguese>
<French>[CSW] M3 Trépied déployable</French>
<Japanese>[CSW] M3 設置型三脚</Japanese>
<Chinese>[CSW] M3 部屬型三腳架</Chinese>