Skip to content

Commit

Permalink
Add Switch Weapon context menu actions for vehicles (#537)
Browse files Browse the repository at this point in the history
* Add Vehicle Logistics > Switch Weapons context actions
* Actions labelled Turret - Muzzle - Magazine
* Switch is instant and does not require gunner unit to be present

Co-authored-by: Neil Evers <neil.evers.1995@gmail.com>
Co-authored-by: Ralfs Garkaklis <ralfs@garkaklis.com>
Co-authored-by: mharis001 <mhariszakar@gmail.com>
Co-authored-by: mharis001 <34453221+mharis001@users.noreply.github.com>
  • Loading branch information
5 people authored Mar 8, 2023
1 parent 1679273 commit bd5c438
Show file tree
Hide file tree
Showing 9 changed files with 224 additions and 31 deletions.
1 change: 1 addition & 0 deletions addons/common/XEH_PREP.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ PREP(getCargoPositionsCount);
PREP(getDefaultInventory);
PREP(getDLC);
PREP(getEffectiveGunner);
PREP(getGunnerName);
PREP(getLightingSelections);
PREP(getPhoneticName);
PREP(getPlayers);
Expand Down
6 changes: 6 additions & 0 deletions addons/common/XEH_postInit.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,11 @@
_unit selectWeapon _muzzle;
}] call CBA_fnc_addEventHandler;

[QGVAR(selectWeaponTurret), {
params ["_vehicle", "_weapon", "_turretPath", ["_muzzle", ""], ["_fireMode", ""]];
_vehicle selectWeaponTurret [_weapon, _turretPath, _muzzle, _fireMode];
}] call CBA_fnc_addEventHandler;

[QGVAR(setPilotLight), {
params ["_vehicle", "_lights"];
_vehicle setPilotLight _lights;
Expand Down Expand Up @@ -321,6 +326,7 @@
[QGVAR(fireArtillery), LINKFUNC(fireArtillery)] call CBA_fnc_addEventHandler;
[QGVAR(fireWeapon), LINKFUNC(fireWeapon)] call CBA_fnc_addEventHandler;
[QGVAR(forceFire), LINKFUNC(forceFire)] call CBA_fnc_addEventHandler;
[QGVAR(loadMagazineInstantly), LINKFUNC(loadMagazineInstantly)] call CBA_fnc_addEventHandler;
[QGVAR(setLampState), LINKFUNC(setLampState)] call CBA_fnc_addEventHandler;
[QGVAR(setMagazineAmmo), LINKFUNC(setMagazineAmmo)] call CBA_fnc_addEventHandler;
[QGVAR(setTurretAmmo), LINKFUNC(setTurretAmmo)] call CBA_fnc_addEventHandler;
Expand Down
27 changes: 27 additions & 0 deletions addons/common/functions/fnc_getGunnerName.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include "script_component.hpp"
/*
* Author: NeilZar
* Returns the (gunner) name of the given vehicle's specified turret.
*
* Arguments:
* 0: Vehicle <STRING|OBJECT|CONFIG>
* 1: Turret Path <ARRAY>
*
* Return Value:
* Gunner Name <STRING>
*
* Example:
* ["B_MRAP_01_hmg_F", [0]] call zen_common_fnc_getGunnerName
*
* Public: No
*/

params [["_vehicle", "", ["", objNull, configNull]], ["_turretPath", [], [[]]]];

private _name = getText ([_vehicle, _turretPath] call CBA_fnc_getTurret >> "gunnerName");

if (_name == "") then {
_name = localize (["str_driver", "str_pilot"] select (_vehicle isKindOf "Air"));
};

_name
68 changes: 43 additions & 25 deletions addons/common/functions/fnc_loadMagazineInstantly.sqf
Original file line number Diff line number Diff line change
@@ -1,51 +1,69 @@
#include "script_component.hpp"
/*
* Author: Kex
* Instantly loads the given magazine into the specified weapon.
* Instantly loads the given magazine into the specified vehicle's turret weapon.
*
* Arguments:
* 0: Vehicle <OBJECT>
* 1: Turret path <ARRAY>
* 2: Muzzle class <STRING>
* 3: Magazine class <STRING>
* 1: Turret Path <ARRAY>
* 2: Weapon <STRING>
* 3: Magazine <STRING>
*
* Return Value:
* None
*
* Example:
* [_vehicle, [0], "HE", "60Rnd_40mm_GPR_Tracer_Red_shells"] call zen_common_fnc_loadMagazineInstantly
* [_vehicle, [0, 0], "HMG_127_MBT", "200Rnd_127x99_mag_Tracer_Red"] call zen_common_fnc_loadMagazineInstantly
*
* Public: No
*/

params [["_vehicle", objNull, [objNull]], ["_turretPath", [], [[]]], ["_muzzle", "", [""]], ["_magazine", "", [""]]];
params [["_vehicle", objNull, [objNull]], ["_turretPath", [], [[]]], ["_weapon", "", [""]], ["_magazine", "", [""]]];

if !(_vehicle turretLocal _turretPath) exitWith {
[QGVAR(loadMagazineInstantly), _this, _vehicle, _turretPath] call CBA_fnc_turretEvent;
};

// Get all magazines compatible with the given weapon on the given turret
private _magazines = createHashMap;
private _compatibleMagazines = [_weapon, true] call CBA_fnc_compatibleMagazines;

private _magazines = [];
private _ammoCounts = [];
{
_x params ["_currentMagazine", "_currentTurretPath", "_currentAmmoCount"];
if (_turretPath isEqualTo _currentTurretPath) then {
_magazines pushBack _currentMagazine;
_ammoCounts pushBack _currentAmmoCount;
_x params ["_xMagazine", "_xTurretPath", "_xAmmoCount"];

if (_turretPath isEqualTo _xTurretPath && {_xMagazine in _compatibleMagazines}) then {
_magazines getOrDefault [_xMagazine, [], true] pushBack _xAmmoCount;
};
} forEach (magazinesAllTurrets _vehicle);
} forEach magazinesAllTurrets _vehicle;

// Ensure that the vehicle has the desired magazine to load
if (_magazine in _magazines) then {
// Remove given weapon and all compatible magazines
_vehicle removeWeaponTurret [_weapon, _turretPath];

private _magIdx = _magazines findIf {_x == _magazine};
if (_magIdx != -1) then {
// Remove weapon and magazines
{
_vehicle removeMagazineTurret [_x, _turretPath];
_vehicle removeMagazinesTurret [_x, _turretPath];
} forEach _magazines;
_vehicle removeWeaponTurret [_muzzle, _turretPath];

// Add desired magazine first
_vehicle addMagazineTurret [_magazine, _turretPath, _ammoCounts select _magIdx];
_magazines deleteAt _magIdx;
_ammoCounts deleteAt _magIdx;
// Add magazines of selected type back first (load magazine with most ammo)
private _selectedMagazine = _magazines deleteAt _magazine;
_selectedMagazine sort false;

// Restore weapon and magazines
_vehicle addWeaponTurret [_muzzle, _turretPath];
{
_vehicle addMagazineTurret [_x, _turretPath, _ammoCounts select _forEachIndex];
_vehicle addMagazineTurret [_magazine, _turretPath, _x];
} forEach _selectedMagazine;

// Restore weapon and other magazines (will load desired magazine since it was added first)
_vehicle addWeaponTurret [_weapon, _turretPath];

{
private _magazine = _x;

{
_vehicle addMagazineTurret [_magazine, _turretPath, _x];
} forEach _y;
} forEach _magazines;

// Select the weapon that the magazine was loaded into
_vehicle selectWeaponTurret [_weapon, _turretPath];
};
5 changes: 5 additions & 0 deletions addons/context_actions/CfgContext.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,11 @@ class EGVAR(context_menu,actions) {
statement = QUOTE(_objects call FUNC(refuelVehicles));
icon = "\a3\ui_f\data\igui\cfg\simpleTasks\types\refuel_ca.paa";
};
class SwitchWeapon {
displayName = "$STR_A3_Switch1";
icon = "\a3\ui_f\data\GUI\Cfg\Hints\VehicleAmmo_CA.paa";
insertChildren = QUOTE(_hoveredEntity call FUNC(getVehicleWeaponActions));
};
class UnloadViV {
displayName = "$STR_A3_ModuleDepot_Unload";
condition = QUOTE(_objects call FUNC(canUnloadViV));
Expand Down
2 changes: 2 additions & 0 deletions addons/context_actions/XEH_PREP.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ PREP(canUnloadViV);
PREP(copyVehicleAppearance);
PREP(compileGrenades);
PREP(getArtilleryActions);
PREP(getVehicleWeaponActions);
PREP(getGrenadeActions);
PREP(healUnits);
PREP(openEditableObjectsDialog);
Expand All @@ -26,6 +27,7 @@ PREP(setCombatMode);
PREP(setFormation);
PREP(setSpeedMode);
PREP(setStance);
PREP(switchVehicleWeapon);
PREP(switchWeaponModifier);
PREP(switchWeapon);
PREP(teleportPlayers);
Expand Down
108 changes: 108 additions & 0 deletions addons/context_actions/functions/fnc_getVehicleWeaponActions.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#include "script_component.hpp"
/*
* Author: Ampersand
* Returns children actions for switching between the given vehicle's weapons, muzzles, and magazines.
*
* Arguments:
* 0: Vehicle <OBJECT>
*
* Return Value:
* Actions <ARRAY>
*
* Example:
* [_vehicle] call zen_context_actions_fnc_getVehicleWeaponActions
*
* Public: No
*/

#define AMMO_SIMULATION_BLACKLIST ["shotcm", "laserdesignate"]

params ["_vehicle"];

if !(_vehicle isEqualType objNull && {alive _vehicle}) exitWith {[]};

private _actions = [];
private _cfgAmmo = configFile >> "CfgAmmo";
private _cfgMagazines = configFile >> "CfgMagazines";
private _cfgWeapons = configFile >> "CfgWeapons";

{
private _turretPath = _x;
private _turretMagazines = _vehicle magazinesTurret _turretPath;

weaponState [_vehicle, _turretPath] params ["_currentWeapon", "_currentMuzzle", "", "_currentMagazine"];

{
private _weapon = _x;
private _weaponConfig = _cfgWeapons >> _weapon;

{
private _muzzle = _x;
private _muzzleConfig = _weaponConfig;

if (_muzzle == "this") then {
_muzzle = _weapon;
} else {
_muzzleConfig = _muzzleConfig >> _muzzle;
};

private _compatibleMagazines = [_muzzleConfig] call CBA_fnc_compatibleMagazines;
private _magazines = _turretMagazines arrayIntersect _compatibleMagazines;

{
private _magazine = _x;
private _magazineConfig = _cfgMagazines >> _magazine;

// Skip current weapon, muzzle, and magazine combination
if (
_weapon == _currentWeapon
&& {_muzzle == _currentMuzzle}
&& {_magazine == _currentMagazine}
) then {continue};

// Skip blacklisted ammo simulation types
private _ammoConfig = _cfgAmmo >> getText (_magazineConfig >> "ammo");
private _ammoSimulation = toLower getText (_ammoConfig >> "simulation");
if (_ammoSimulation in AMMO_SIMULATION_BLACKLIST) then {continue};

private _name = format [
"%1 - %2 %3- %4",
[_vehicle, _turretPath] call EFUNC(common,getGunnerName),
getText (_weaponConfig >> "displayName"),
[format ["%1 ", _muzzle], ""] select (_muzzle == _weapon),
getText (_magazineConfig >> "displayName")
];

private _icon = switch (_ammoSimulation) do {
case "shotbullet": {
"\a3\ui_f_jets\data\gui\cfg\hints\weaponsguns_ca.paa"
};
case "shotmissile": {
"\a3\ui_f_jets\data\gui\cfg\hints\weaponsmissiles_ca.paa"
};
case "shotilluminating": {
"\a3\ui_f\data\gui\cfg\hints\flares_ca.paa"
};
default {
QPATHTOF(ui\ammo_ca.paa)
};
};

private _action = [
[_weapon, _muzzle, _magazine] joinString "",
_name,
_icon,
{
_args call FUNC(switchVehicleWeapon)
},
{true},
[_vehicle, _turretPath, _weapon, _muzzle, _magazine]
] call EFUNC(context_menu,createAction);

_actions pushBack [_action, [], 0];
} forEach _magazines;
} forEach getArray (_weaponConfig >> "muzzles");
} forEach (_vehicle weaponsTurret _turretPath);
} forEach (_vehicle call EFUNC(common,getAllTurrets));

_actions
31 changes: 31 additions & 0 deletions addons/context_actions/functions/fnc_switchVehicleWeapon.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include "script_component.hpp"
/*
* Author: Ampersand
* Switches the given vehicle turret's weapon, muzzle, and magazine.
*
* Arguments:
* 0: Vehicle <OBJECT>
* 1: Turret Path <ARRAY>
* 2: Weapon <STRING>
* 3: Muzzle <STRING>
* 4: Magazine <STRING>
*
* Return Value:
* None
*
* Example:
* [_vehicle, _turretPath, _weapon, _muzzle, _magazine] call zen_context_actions_fnc_switchVehicleWeapon
*
* Public: No
*/

params ["_vehicle", "_turretPath", "_weapon", "_muzzle", "_magazine"];

// For regular (non-pylon) magazines, load the magazine instantly into the selected weapon
// Pylon magazines work differently and only need to have the corresponding pylon weapon selected
if !(_magazine in getPylonMagazines _vehicle) then {
[_vehicle, _turretPath, _weapon, _magazine] call EFUNC(common,loadMagazineInstantly);
};

// Select the given weapon and muzzle on the vehicle's turret
[QEGVAR(common,selectWeaponTurret), [_vehicle, _weapon, _turretPath, _muzzle], _vehicle, _turretPath] call CBA_fnc_turretEvent;
7 changes: 1 addition & 6 deletions addons/loadout/functions/fnc_getWeaponName.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,5 @@
params ["_vehicle", "_weapon", "_turretPath"];

private _weaponName = getText (configFile >> "CfgWeapons" >> _weapon >> "displayName");
private _gunnerName = getText ([_vehicle, _turretPath] call CBA_fnc_getTurret >> "gunnerName");

if (_gunnerName == "") then {
_gunnerName = localize (["str_driver", "str_pilot"] select (_vehicle isKindOf "Air"));
};

private _gunnerName = [_vehicle, _turretPath] call EFUNC(common,getGunnerName);
format ["%1 (%2)", _weaponName, _gunnerName]

0 comments on commit bd5c438

Please sign in to comment.