Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add weapon on back functionality #7088

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions addons/weapononback/$PBOPREFIX$
@@ -0,0 +1 @@
z\ace\addons\weapononback
31 changes: 31 additions & 0 deletions addons/weapononback/CfgEventHandlers.hpp
@@ -0,0 +1,31 @@
class Extended_PreStart_EventHandlers {
class ADDON {
init = QUOTE(call COMPILE_FILE(XEH_preStart));
};
};

class Extended_PreInit_EventHandlers {
class ADDON {
init = QUOTE(call COMPILE_FILE(XEH_preInit));
};
};

class Extended_PostInit_EventHandlers {
class ADDON {
init = QUOTE(call COMPILE_FILE(XEH_postInit));
};
};

class Extended_DisplayLoad_EventHandlers {
class RscDisplayInventory {
ADDON = QUOTE(call FUNC(onInventoryOpened));
};
};

class Extended_Init_EventHandlers {
class WeaponHolderSimulated {
class ADDON {
init = QUOTE(_this call FUNC(onWHSInit));
};
};
};
14 changes: 14 additions & 0 deletions addons/weapononback/CfgVehicles.hpp
@@ -0,0 +1,14 @@
class CfgVehicles {
class ReammoBox;
class GVAR(weaponHolder): ReammoBox {
author = ECSTRING(common,ACETeam);
model = QPATHTOF(data\holder.p3d);
showWeaponCargo = 1;
scope = 1;
transportMaxWeapons = 1;
transportMaxMagazines = 0;
transportMaxItems = 0;
transportMaxBackpacks = 0;
destrType = "DestructNo";
};
};
16 changes: 16 additions & 0 deletions addons/weapononback/CfgWeapons.hpp
@@ -0,0 +1,16 @@
class CfgWeapons {
class Launcher_Base_F;
class GVAR(weapon): Launcher_Base_F {
scope = 1;
scopeCurator = 1;
scopeArsenal = 1;
model = "\A3\Weapons_f\empty";
picture = "\A3\Weapons_F\Data\clear_empty.paa";
magazines[] = {"ACE_FakeMagazine"};
displayName = CSTRING(FakeWeaponDisplayName);
type = TYPE_WEAPON_SECONDARY;
class WeaponSlotsInfo {
mass = 0;
};
};
};
11 changes: 11 additions & 0 deletions addons/weapononback/README.md
@@ -0,0 +1,11 @@
ace_weapononback
===================

Adds the possibility to have a second primary weapon.


## Maintainers

The people responsible for merging changes to this component or answering potential questions.

- [BaerMitUmlaut](https://github.com/BaerMitUmlaut)
16 changes: 16 additions & 0 deletions addons/weapononback/RscDisplayInventory.hpp
@@ -0,0 +1,16 @@
class RscActiveText;

class RscDisplayInventory {
class controls {
class GVAR(weaponImage): RscActiveText {
idc = IDC_WEAPON_IMAGE;
style = "0x30 + 0x800";
color[] = {1, 1, 1, 1};
colorFocused[] = {1, 1, 1, 1};
colorText[] = {1, 1, 1, 1};
colorBackground[] = {1, 1, 1, 0.1};
colorBackgroundSelected[] = {1, 1, 1, 0.1};
onLoad = "_this#0 ctrlEnable false";
};
};
};
14 changes: 14 additions & 0 deletions addons/weapononback/XEH_PREP.hpp
@@ -0,0 +1,14 @@
PREP(add);
PREP(get);
PREP(getIDCContainer);
PREP(onDrag);
PREP(onDragWOB);
PREP(onDrop);
PREP(onDropWOB);
PREP(onInventoryOpened);
PREP(onWeaponChange);
PREP(onWHSInit);
PREP(remove);
PREP(renderPFH);
PREP(swap);
PREP(updateInventory);
43 changes: 43 additions & 0 deletions addons/weapononback/XEH_postInit.sqf
@@ -0,0 +1,43 @@
#include "script_component.hpp"

["weapon", FUNC(onWeaponChange)] call CBA_fnc_addPlayerEventHandler;

["unit", {
params ["_newUnit", "_oldUnit"];

private _inventoryEHs = _oldUnit getVariable [QGVAR(inventoryEHs), [-1, -1]];
_oldUnit removeEventHandler ["InventoryOpened", _inventoryEHs#0];
_oldUnit removeEventHandler ["InventoryClosed", _inventoryEHs#1];

_inventoryEHs = [
_newUnit addEventHandler ["InventoryOpened", {
params ["", "_firstContainer", "_secondContainer"];

// If only one container was opened, pretend it's both box and ground
// WOB holder sometimes gets opened for a frame, but is immediately
// closed and should never be accessed anyways
if (isNull _secondContainer || {typeOf _secondContainer == QGVAR(weaponHolder)}) then {
_secondContainer = _firstContainer;
};
GVAR(openedContainers) = [_firstContainer, _secondContainer];
}],
_newUnit addEventHandler ["InventoryClosed", {
GVAR(openedContainers) = [objNull, objNull];
}]
];

_newUnit setVariable [QGVAR(inventoryEHs), _inventoryEHs];
}, true] call CBA_fnc_addPlayerEventHandler;

["loadout", {
// One frame delay, because dropping from inventory isn't instant but still handled by us
// See also fnc_onDragWOB
[{
private _hasWeaponHolder = !isNull (ACE_player getVariable [QGVAR(weaponHolder), objNull]);
private _hasFakeWeapon = secondaryWeapon ACE_player == QGVAR(weapon);

if !(_hasWeaponHolder isEqualTo _hasFakeWeapon) then {
[ACE_player] call FUNC(remove);
};
}] call CBA_fnc_execNextFrame;
}] call CBA_fnc_addPlayerEventHandler;
28 changes: 28 additions & 0 deletions addons/weapononback/XEH_preInit.sqf
@@ -0,0 +1,28 @@
#include "script_component.hpp"

ADDON = false;

PREP_RECOMPILE_START;
#include "XEH_PREP.hpp"
PREP_RECOMPILE_END;

#include "initSettings.sqf"


GVAR(units) = [];
GVAR(openedContainers) = [objNull, objNull];

// Add "add" event handler in preInit to catch JIP events
[QGVAR(add), {
params ["_unit", "_weaponsItems"];

[_unit, _weaponsItems, true] call FUNC(add);
}] call CBA_fnc_addEventHandler;

[QGVAR(remove), {
params ["_unit"];

[_unit, true] call FUNC(remove);
}] call CBA_fnc_addEventHandler;

ADDON = true;
3 changes: 3 additions & 0 deletions addons/weapononback/XEH_preStart.sqf
@@ -0,0 +1,3 @@
#include "script_component.hpp"

#include "XEH_PREP.hpp"
20 changes: 20 additions & 0 deletions addons/weapononback/config.cpp
@@ -0,0 +1,20 @@
#include "script_component.hpp"

class CfgPatches {
class ADDON {
name = COMPONENT_NAME;
units[] = {};
weapons[] = {};
requiredVersion = REQUIRED_VERSION;
requiredAddons[] = {"ace_common"};
author = ECSTRING(common,ACETeam);
authors[] = {"BaerMitUmlaut"};
url = ECSTRING(main,URL);
VERSION_CONFIG;
};
};

#include "CfgEventHandlers.hpp"
#include "CfgVehicles.hpp"
#include "CfgWeapons.hpp"
#include "RscDisplayInventory.hpp"
Binary file added addons/weapononback/data/holder.p3d
Binary file not shown.
27 changes: 27 additions & 0 deletions addons/weapononback/data/model.cfg
@@ -0,0 +1,27 @@
class CfgSkeletons
{
class Skeleton
{
isDiscrete=0;
skeletonInherit="";
skeletonBones[]={};
};
};
class CfgModels
{
class holder
{
htMin=0;
htMax=0;
afMax=0;
mfMax=0;
mFact=0;
tBody=0;
skeletonName="Skeleton";
sectionsInherit="";
sections[]={};
class Animations
{
};
};
};
Binary file added addons/weapononback/data/weapononback_ca.paa
Binary file not shown.
79 changes: 79 additions & 0 deletions addons/weapononback/functions/fnc_add.sqf
@@ -0,0 +1,79 @@
#include "script_component.hpp"
/*
* Author: BaerMitUmlaut
* Adds a weapon to the units back (global effect).
*
* Arguments:
* 0: Unit <OBJECT>
* 1: Weapons items (weaponsItems format) <ARRAY>
*
* Return Value:
* None
*
* Example:
* [player, weaponsItems player select 1] call ace_weapononback_fnc_add
*
* Public: Yes
*/
params ["_unit", "_weaponsItems", ["_calledFromEvent", false]];

if (!_calledFromEvent) exitWith {
[QGVAR(add), [_unit, _weaponsItems], EVENT_ID(_unit)] call CBA_fnc_globalEventJIP;
};

// Replace old weapon holder
private _weaponHolder = _unit getVariable [QGVAR(weaponHolder), objNull];
private _oldWeapon = "";
if (!isNull _weaponHolder) then {
deleteVehicle _weaponHolder;
};

_weaponHolder = QGVAR(weaponHolder) createVehicleLocal [0, 0, 0];
_weaponHolder attachTo [_unit, [0, 0, 0], "proxy:\a3\characters_f\proxies\launcher.001"];

// Add weapon to weapon holder
_weaponHolder addWeaponWithAttachmentsCargo [_weaponsItems, 1];

// Disable simulation to lock
_weaponHolder enableSimulation false;

_unit setVariable [QGVAR(weaponHolder), _weaponHolder];
GVAR(units) pushBack _unit;

if (local _unit) then {
private _oldMass = _unit getVariable [QGVAR(weaponMass), 0];
private _newMass = 0;

// Calculate weapon weight with all items
_weaponsItems params ["_weapon", "_muzzle", "_side", "_optic", "_magPrimary", "_magSecondary", "_bipod"];

// Weapon itself
_newMass = _newMass + getNumber (configFile >> "CfgWeapons" >> _weapon >> "WeaponSlotsInfo" >> "mass");

// Attachments
{
if (_x != "") then {
_newMass = _newMass + getNumber (configFile >> "CfgWeapons" >> _x >> "ItemInfo" >> "mass");
};
} forEach [_muzzle, _side, _optic, _bipod];

// Magazines
{
if !(_x isEqualTo []) then {
_newMass = _newMass + getNumber (configFile >> "CfgMagazines" >> _x#0 >> "mass");
};
} forEach [_magPrimary, _magSecondary];

[_unit, _unit, _newMass - _oldMass] call EFUNC(movement,addLoadToUnitContainer);
_unit setVariable [QGVAR(weaponMass), _newMass, true];

// Reset saved zeroing, if this weapon was swapped it will be restored in FUNC(swap)
ACE_player setVariable [QGVAR(scopeAdjustment), [0, 0, 0]];

_unit addWeapon QGVAR(weapon);
[] call FUNC(updateInventory);
};

if (isNil QGVAR(renderPFH)) then {
GVAR(renderPFH) = [FUNC(renderPFH), 0, []] call CBA_fnc_addPerFrameHandler;
};
25 changes: 25 additions & 0 deletions addons/weapononback/functions/fnc_get.sqf
@@ -0,0 +1,25 @@
#include "script_component.hpp"
/*
* Author: BaerMitUmlaut
* Returns the weapon on a units back.
*
* Arguments:
* 0: Unit <OBJECT>
*
* Return Value:
* Weapon, attachments and magazines (weaponsItems format) or empty array <ARRAY>
*
* Example:
* [player] call ace_weapononback_fnc_get
*
* Public: Yes
*/
params ["_unit"];

private _weaponHolder = _unit getVariable [QGVAR(weaponHolder), objNull];

if (isNull _weaponHolder) then {
[]
} else {
(weaponsItemsCargo _weaponHolder)#0
};
35 changes: 35 additions & 0 deletions addons/weapononback/functions/fnc_getIDCContainer.sqf
@@ -0,0 +1,35 @@
#include "script_component.hpp"
/*
* Author: BaerMitUmlaut
* Gets the container associated with the given inventory display IDC.
*
* Arguments:
* 0: Control IDC <NUMBER>
*
* Return Value:
* Container <OBJECT>
*
* Public: No
*/
params ["_ctrlIDC"];

switch (_ctrlIDC) do {
case IDC_GROUND_CONTAINER: {
GVAR(openedContainers)#1
};
case IDC_SOLDIER_CONTAINER: {
GVAR(openedContainers)#0
};
case IDC_UNIFORM_CONTAINER: {
uniformContainer ACE_player
};
case IDC_VEST_CONTAINER: {
vestContainer ACE_player
};
case IDC_BACKPACK_CONTAINER: {
backpackContainer ACE_player
};
default {
objNull
};
};