mirror of
https://github.com/acemod/ACE3.git
synced 2024-08-30 18:23:18 +00:00
Add weapon on back functionality
This commit is contained in:
parent
cd65c2f196
commit
877183d690
1
addons/weapononback/$PBOPREFIX$
Normal file
1
addons/weapononback/$PBOPREFIX$
Normal file
@ -0,0 +1 @@
|
|||||||
|
z\ace\addons\weapononback
|
31
addons/weapononback/CfgEventHandlers.hpp
Normal file
31
addons/weapononback/CfgEventHandlers.hpp
Normal file
@ -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
addons/weapononback/CfgVehicles.hpp
Normal file
14
addons/weapononback/CfgVehicles.hpp
Normal file
@ -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
addons/weapononback/CfgWeapons.hpp
Normal file
16
addons/weapononback/CfgWeapons.hpp
Normal file
@ -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
addons/weapononback/README.md
Normal file
11
addons/weapononback/README.md
Normal file
@ -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
addons/weapononback/RscDisplayInventory.hpp
Normal file
16
addons/weapononback/RscDisplayInventory.hpp
Normal file
@ -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
addons/weapononback/XEH_PREP.hpp
Normal file
14
addons/weapononback/XEH_PREP.hpp
Normal file
@ -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
addons/weapononback/XEH_postInit.sqf
Normal file
43
addons/weapononback/XEH_postInit.sqf
Normal file
@ -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
addons/weapononback/XEH_preInit.sqf
Normal file
28
addons/weapononback/XEH_preInit.sqf
Normal file
@ -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
addons/weapononback/XEH_preStart.sqf
Normal file
3
addons/weapononback/XEH_preStart.sqf
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
|
||||||
|
#include "XEH_PREP.hpp"
|
20
addons/weapononback/config.cpp
Normal file
20
addons/weapononback/config.cpp
Normal file
@ -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"
|
BIN
addons/weapononback/data/holder.p3d
Normal file
BIN
addons/weapononback/data/holder.p3d
Normal file
Binary file not shown.
27
addons/weapononback/data/model.cfg
Normal file
27
addons/weapononback/data/model.cfg
Normal file
@ -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
|
||||||
|
{
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
BIN
addons/weapononback/data/weapononback_ca.paa
Normal file
BIN
addons/weapononback/data/weapononback_ca.paa
Normal file
Binary file not shown.
79
addons/weapononback/functions/fnc_add.sqf
Normal file
79
addons/weapononback/functions/fnc_add.sqf
Normal file
@ -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
addons/weapononback/functions/fnc_get.sqf
Normal file
25
addons/weapononback/functions/fnc_get.sqf
Normal file
@ -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
addons/weapononback/functions/fnc_getIDCContainer.sqf
Normal file
35
addons/weapononback/functions/fnc_getIDCContainer.sqf
Normal file
@ -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
|
||||||
|
};
|
||||||
|
};
|
94
addons/weapononback/functions/fnc_onDrag.sqf
Normal file
94
addons/weapononback/functions/fnc_onDrag.sqf
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
/*
|
||||||
|
* Author: BaerMitUmlaut
|
||||||
|
* Handles dragging weapons onto the secondary slot.
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* 0: Drag origin <CONTROL>
|
||||||
|
* 1: Information about the dragged item <ARRAY>
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Public: No
|
||||||
|
*/
|
||||||
|
params ["_ctrl", "_info"];
|
||||||
|
|
||||||
|
if !(secondaryWeapon ACE_player in ["", QGVAR(weapon)]) exitWith {};
|
||||||
|
|
||||||
|
// Check if dragged item is a primary weapon
|
||||||
|
private _ctrlIDC = ctrlIDC _ctrl;
|
||||||
|
private _isPrimary = if (_ctrlIDC == IDC_PRIMARY_SLOT) then {
|
||||||
|
(primaryWeapon ACE_player != "") && {_info == 0}
|
||||||
|
} else {
|
||||||
|
// Dragged from container
|
||||||
|
_info#0 params ["_displayName"];
|
||||||
|
|
||||||
|
private _container = [_ctrlIDC] call FUNC(getIDCContainer);
|
||||||
|
if (_container isKindOf "CAManBase") then {
|
||||||
|
_container = _container getVariable [QGVAR(droppedWeaponHolder), _container];
|
||||||
|
};
|
||||||
|
|
||||||
|
private _index = (weaponCargo _container) findIf {
|
||||||
|
private _cfg = configFile >> "CfgWeapons" >> _x;
|
||||||
|
(getText (_cfg >> "displayName") == _displayName)
|
||||||
|
&& {getNumber (_cfg >> "type") == TYPE_WEAPON_PRIMARY}
|
||||||
|
};
|
||||||
|
|
||||||
|
_index != -1
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!_isPrimary) exitWith {
|
||||||
|
TRACE_1("Dragged item is not a primary",_info);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set up drag and drop catcher
|
||||||
|
private _display = ctrlParent _ctrl;
|
||||||
|
private _slotSecondary = _display displayCtrl IDC_SECONDARY_SLOT;
|
||||||
|
|
||||||
|
// RscPicture does not trigger LBDrop
|
||||||
|
private _dropCatcher = _display ctrlCreate ["ctrlActivePictureKeepAspect", IDC_DROP_CATCHER];
|
||||||
|
if (secondaryWeapon ACE_player != QGVAR(weapon)) then {
|
||||||
|
_dropCatcher ctrlSetText QPATHTOF(data\weapononback_ca.paa);
|
||||||
|
} else {
|
||||||
|
_dropCatcher ctrlSetText "#(rgb,8,8,3)color(1,1,1,0)";
|
||||||
|
};
|
||||||
|
_dropCatcher ctrlSetPosition ctrlPosition _slotSecondary;
|
||||||
|
_dropCatcher ctrlSetTextColor [1, 1, 1, 1];
|
||||||
|
_dropCatcher ctrlSetBackgroundColor [1, 1, 1, 0];
|
||||||
|
_dropCatcher ctrlCommit 0;
|
||||||
|
_dropCatcher ctrlAddEventHandler ["LBDrop", FUNC(onDrop)];
|
||||||
|
|
||||||
|
// Hide red "you can't drop this here"
|
||||||
|
_slotSecondary ctrlSetFade 1;
|
||||||
|
_slotSecondary ctrlCommit 0;
|
||||||
|
|
||||||
|
// Create white "you can drop this here"
|
||||||
|
private _secondaryBG = _display displayCtrl IDC_SECONDARY_BG;
|
||||||
|
_secondaryBG ctrlSetText "#(rgb,8,8,3)color(1,1,1,0.25)";
|
||||||
|
|
||||||
|
// Remove drop catcher when drag and drop action was completed
|
||||||
|
private _eventHandler = _display displayAddEventHandler ["MouseButtonUp", {
|
||||||
|
params ["_display"];
|
||||||
|
|
||||||
|
// Reset everything to its original state
|
||||||
|
private _eventHandler = _display getVariable QGVAR(mouseUpEH);
|
||||||
|
_display displayRemoveEventHandler ["MouseButtonUp", _eventHandler];
|
||||||
|
|
||||||
|
private _slotSecondary = _display displayCtrl IDC_SECONDARY_SLOT;
|
||||||
|
_slotSecondary ctrlSetFade 0;
|
||||||
|
_slotSecondary ctrlCommit 0;
|
||||||
|
|
||||||
|
private _secondaryBG = _display displayCtrl IDC_SECONDARY_BG;
|
||||||
|
_secondaryBG ctrlSetText "";
|
||||||
|
|
||||||
|
// Delay drop catcher destruction by one frame or drop event doesn't trigger
|
||||||
|
private _dropCatcher = _display displayCtrl IDC_DROP_CATCHER;
|
||||||
|
_dropCatcher ctrlSetText "#(rgb,8,8,3)color(1,1,1,0)";
|
||||||
|
|
||||||
|
[{
|
||||||
|
params ["_display"];
|
||||||
|
ctrlDelete (_display displayCtrl IDC_DROP_CATCHER);
|
||||||
|
}, _this] call CBA_fnc_execNextFrame;
|
||||||
|
}];
|
||||||
|
_display setVariable [QGVAR(mouseUpEH), _eventHandler];
|
100
addons/weapononback/functions/fnc_onDragWOB.sqf
Normal file
100
addons/weapononback/functions/fnc_onDragWOB.sqf
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
/*
|
||||||
|
* Author: BaerMitUmlaut
|
||||||
|
* Handles dragging the weapon on the back onto a container.
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* 0: Secondary slot control <CONTROL>
|
||||||
|
* 1: Mouse button ID <NUMBER>
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Public: No
|
||||||
|
*/
|
||||||
|
params ["_ctrl", "_mouseButton"];
|
||||||
|
|
||||||
|
if (_mouseButton != 0 || {secondaryWeapon ACE_player != QGVAR(weapon)}) exitWith {};
|
||||||
|
|
||||||
|
// Replace primary slot with drop catcher, make background white
|
||||||
|
private _display = ctrlParent _ctrl;
|
||||||
|
private _primarySlot = _display displayCtrl IDC_PRIMARY_SLOT;
|
||||||
|
_primarySlot ctrlSetFade 1;
|
||||||
|
_primarySlot ctrlCommit 0;
|
||||||
|
private _primaryBG = _display displayCtrl IDC_PRIMARY_BG;
|
||||||
|
_primaryBG ctrlSetText "#(rgb,8,8,3)color(1,1,1,0.25)";
|
||||||
|
|
||||||
|
// RscPicture does not trigger LBDrop
|
||||||
|
private _dropCatcher = _display ctrlCreate ["ctrlActivePictureKeepAspect", IDC_DROP_CATCHER];
|
||||||
|
if (primaryWeapon ACE_player == "") then {
|
||||||
|
_dropCatcher ctrlSetText "a3\ui_f\data\GUI\Rsc\RscDisplayGear\ui_gear_primary_gs.paa";
|
||||||
|
} else {
|
||||||
|
_dropCatcher ctrlSetText getText (configFile >> "CfgWeapons" >> primaryWeapon ACE_player >> "picture");
|
||||||
|
};
|
||||||
|
_dropCatcher ctrlSetPosition ctrlPosition _primarySlot;
|
||||||
|
_dropCatcher ctrlSetTextColor [1, 1, 1, 1];
|
||||||
|
_dropCatcher ctrlSetBackgroundColor [1, 1, 1, 1];
|
||||||
|
_dropCatcher ctrlCommit 0;
|
||||||
|
_dropCatcher ctrlAddEventHandler ["LBDrop", {[true] call FUNC(onDropWOB)}];
|
||||||
|
|
||||||
|
// Create image for the currently dragged weapon under the cursor
|
||||||
|
private _imgContainer = _display displayCtrl IDC_WEAPON_IMAGE;
|
||||||
|
private _dragImage = _display ctrlCreate ["RscPictureKeepAspect", -1];
|
||||||
|
|
||||||
|
_dragImage ctrlSetPosition ctrlPosition _imgContainer;
|
||||||
|
_dragImage ctrlSetText ctrlText _imgContainer;
|
||||||
|
_dragImage ctrlEnable false;
|
||||||
|
_dragImage ctrlCommit 0;
|
||||||
|
|
||||||
|
(ctrlPosition _dragImage) params ["", "", "_w", "_h"];
|
||||||
|
private _widthOffset = _w / 2;
|
||||||
|
private _heightOffset = _h / 2;
|
||||||
|
_dragImage ctrlSetPosition [getMousePosition#0 - _widthOffset, getMousePosition#1 - _heightOffset];
|
||||||
|
_dragImage ctrlCommit 0;
|
||||||
|
|
||||||
|
private _eventHandlers = [
|
||||||
|
_display displayAddEventHandler ["MouseMoving", {
|
||||||
|
params ["_display"];
|
||||||
|
|
||||||
|
private _dragImage = _display getVariable [QGVAR(dragImage), ctrlNull];
|
||||||
|
(ctrlPosition _dragImage) params ["", "", "_w", "_h"];
|
||||||
|
private _widthOffset = _w / 2;
|
||||||
|
private _heightOffset = _h / 2;
|
||||||
|
_dragImage ctrlSetPosition [getMousePosition#0 - _widthOffset, getMousePosition#1 - _heightOffset];
|
||||||
|
_dragImage ctrlCommit 0;
|
||||||
|
}],
|
||||||
|
_display displayAddEventHandler ["MouseButtonUp", {
|
||||||
|
params ["_display"];
|
||||||
|
|
||||||
|
private _dragImage = _display getVariable [QGVAR(dragImage), ctrlNull];
|
||||||
|
ctrlDelete _dragImage;
|
||||||
|
|
||||||
|
// Clean up event handlers
|
||||||
|
private _eventHandlers = _display getVariable [QGVAR(dragWOBEHs), []];
|
||||||
|
_eventHandlers params ["_mouseMoving", "_mouseButtonUp"];
|
||||||
|
_display displayRemoveEventHandler ["MouseMoving", _mouseMoving];
|
||||||
|
_display displayRemoveEventHandler ["MouseButtonUp", _mouseButtonUp];
|
||||||
|
|
||||||
|
// LBDrop triggers after MouseButtonUp, so delay by one frame
|
||||||
|
[{
|
||||||
|
params ["_display"];
|
||||||
|
ctrlDelete (_display displayCtrl IDC_DROP_CATCHER);
|
||||||
|
}, _this] call CBA_fnc_execNextFrame;
|
||||||
|
|
||||||
|
private _primarySlot = _display displayCtrl IDC_PRIMARY_SLOT;
|
||||||
|
_primarySlot ctrlSetFade 0;
|
||||||
|
_primarySlot ctrlCommit 0;
|
||||||
|
private _primaryBG = _display displayCtrl IDC_PRIMARY_BG;
|
||||||
|
_primaryBG ctrlSetText "";
|
||||||
|
|
||||||
|
// Inventory has some delay, timeout in case player didn't actually drop weapon somewhere
|
||||||
|
[{
|
||||||
|
secondaryWeapon ACE_player != QGVAR(weapon)
|
||||||
|
}, {
|
||||||
|
[false] call FUNC(onDropWOB);
|
||||||
|
}, [], 5] call CBA_fnc_waitUntilAndExecute;
|
||||||
|
}]
|
||||||
|
];
|
||||||
|
|
||||||
|
_display setVariable [QGVAR(dragImage), _dragImage];
|
||||||
|
_display setVariable [QGVAR(dragWOBEHs), _eventHandlers];
|
84
addons/weapononback/functions/fnc_onDrop.sqf
Normal file
84
addons/weapononback/functions/fnc_onDrop.sqf
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
/*
|
||||||
|
* Author: BaerMitUmlaut
|
||||||
|
* Handles dropping a weapon onto the secondary slot.
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* 0: Drop catcher control <CONTROL>
|
||||||
|
* 1: Ignored
|
||||||
|
* 2: Ignored
|
||||||
|
* 3: Control that the dragging operation started from <CONTROL>
|
||||||
|
* 4: Information about the dragged item <ARRAY>
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Public: No
|
||||||
|
*/
|
||||||
|
params ["_dropCatcher", "", "", "_originIDC", "_info"];
|
||||||
|
|
||||||
|
private _weaponsItems = [];
|
||||||
|
|
||||||
|
if (_originIDC == IDC_PRIMARY_SLOT) then {
|
||||||
|
[] call FUNC(swap);
|
||||||
|
} else {
|
||||||
|
_info#0 params ["_displayName", "_index"];
|
||||||
|
|
||||||
|
private _display = ctrlParent _dropCatcher;
|
||||||
|
private _listBox = _display displayCtrl _originIDC;
|
||||||
|
|
||||||
|
// First index is 127, followed by 1.
|
||||||
|
// Of course, the 128th item is then index -1, followed by 128.
|
||||||
|
// Thanks BI!
|
||||||
|
if (_index == 127) then {
|
||||||
|
_index = 0;
|
||||||
|
};
|
||||||
|
if (_index == -1) then {
|
||||||
|
_index = 127;
|
||||||
|
};
|
||||||
|
|
||||||
|
private _weaponIndex = -1;
|
||||||
|
for "_i" from 0 to _index do {
|
||||||
|
if (_listBox lbText _i == _displayName) then {
|
||||||
|
_weaponIndex = _weaponIndex + 1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
private _container = [_originIDC] call FUNC(getIDCContainer);
|
||||||
|
if (_container isKindOf "CAManBase") then {
|
||||||
|
_container = _container getVariable [QGVAR(droppedWeaponHolder), _container];
|
||||||
|
};
|
||||||
|
|
||||||
|
private _allWeaponsItems = weaponsItemsCargo _container;
|
||||||
|
|
||||||
|
// Get all weapons in container that have the name of the weapon that was taken
|
||||||
|
private _weaponsItemsWithName = _allWeaponsItems select {
|
||||||
|
getText (configFile >> "CfgWeapons" >> _x#0 >> "displayName") == _displayName
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get unique weapon attachment setups because identical ones stack
|
||||||
|
private _allWeaponsItemsNoMags = _weaponsItemsWithName apply {_x select {!(_x isEqualType [])}};
|
||||||
|
private _allWeaponsItemsUnique = _allWeaponsItemsNoMags arrayIntersect _allWeaponsItemsNoMags;
|
||||||
|
private _weaponAttachmentSetup = _allWeaponsItemsUnique#_weaponIndex;
|
||||||
|
private _weaponsItemsIndex = _allWeaponsItems findIf {
|
||||||
|
(_x select {!(_x isEqualType [])}) isEqualTo _weaponAttachmentSetup
|
||||||
|
};
|
||||||
|
|
||||||
|
// Choose first occurance of this weapon setup from container
|
||||||
|
private _weaponsItems = _allWeaponsItems#_weaponsItemsIndex;
|
||||||
|
_allWeaponsItems deleteAt _weaponsItemsIndex;
|
||||||
|
|
||||||
|
// Add weapon on back to container if there is one
|
||||||
|
if (secondaryWeapon ACE_player == QGVAR(weapon)) then {
|
||||||
|
private _weaponsItems = [ACE_player] call FUNC(get);
|
||||||
|
_allWeaponsItems pushBack _weaponsItems;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Remove setup from container
|
||||||
|
clearWeaponCargoGlobal _container;
|
||||||
|
{
|
||||||
|
_container addWeaponWithAttachmentsCargoGlobal [_x, 1];
|
||||||
|
} forEach _allWeaponsItems;
|
||||||
|
|
||||||
|
[ACE_player, _weaponsItems] call FUNC(add);
|
||||||
|
};
|
86
addons/weapononback/functions/fnc_onDropWOB.sqf
Normal file
86
addons/weapononback/functions/fnc_onDropWOB.sqf
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
/*
|
||||||
|
* Author: BaerMitUmlaut
|
||||||
|
* Handles dropping the weapon on the back onto a container.
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* 0: Dropped onto primary weapon slot <BOOL>
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Public: No
|
||||||
|
*/
|
||||||
|
params [["_droppedOntoPrimary", false]];
|
||||||
|
|
||||||
|
if (_droppedOntoPrimary) then {
|
||||||
|
[] call FUNC(swap);
|
||||||
|
} else {
|
||||||
|
// Find container the weapon was dropped into
|
||||||
|
private _possibleContainers = if (QGVAR(weapon) in weapons ACE_player) then {
|
||||||
|
[
|
||||||
|
// Ordered by likelyhood
|
||||||
|
backpackContainer ACE_player,
|
||||||
|
vestContainer ACE_player,
|
||||||
|
uniformContainer ACE_player
|
||||||
|
]
|
||||||
|
} else {
|
||||||
|
if (GVAR(openedContainers)#0 isKindOf "CAManBase") then {
|
||||||
|
// Weapons cannot be dropped onto dead bodies
|
||||||
|
[
|
||||||
|
// If the dropped primary of the unit wasn't taken yet, that holder is used
|
||||||
|
GVAR(openedContainers)#0 getVariable [QGVAR(droppedWeaponHolder), objNull],
|
||||||
|
// Otherwise a new one is created dynamically
|
||||||
|
nearestObject [ACE_player, "GroundWeaponHolder"]
|
||||||
|
]
|
||||||
|
} else {
|
||||||
|
GVAR(openedContainers)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private _container = {
|
||||||
|
if (QGVAR(weapon) in weaponCargo _x) exitWith { _x };
|
||||||
|
} forEach _possibleContainers;
|
||||||
|
|
||||||
|
// Remove and replace fake weapon with actual weapon
|
||||||
|
private _weaponsItems = [ACE_player] call FUNC(get);
|
||||||
|
private _allWeaponsItems = weaponsItemsCargo _container;
|
||||||
|
_allWeaponsItems deleteAt (_allWeaponsItems findIf { _x#0 == QGVAR(weapon) });
|
||||||
|
|
||||||
|
if (_container canAdd _weaponsItems#0) then {
|
||||||
|
_allWeaponsItems pushBack _weaponsItems;
|
||||||
|
[ACE_player] call FUNC(remove);
|
||||||
|
} else {
|
||||||
|
// If container cannot fit weapon on back, readd fake weapon to player, show hint
|
||||||
|
ACE_player addWeapon QGVAR(weapon);
|
||||||
|
|
||||||
|
private _containerCfg = switch (_container) do {
|
||||||
|
case (backpackContainer ACE_player): {
|
||||||
|
configFile >> "CfgWeapons" >> backpack ACE_player
|
||||||
|
};
|
||||||
|
case (vestContainer ACE_player): {
|
||||||
|
configFile >> "CfgWeapons" >> vest ACE_player
|
||||||
|
};
|
||||||
|
case (uniformContainer ACE_player): {
|
||||||
|
configFile >> "CfgWeapons" >> uniform ACE_player
|
||||||
|
};
|
||||||
|
default {
|
||||||
|
configFile >> "CfgVehicles" >> typeOf _container
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
[
|
||||||
|
format [
|
||||||
|
LLSTRING(CouldNotFit),
|
||||||
|
getText (configFile >> "CfgWeapons" >> _weaponsItems#0 >> "displayName"),
|
||||||
|
getText (_containerCfg >> "displayName")
|
||||||
|
],
|
||||||
|
true, 5
|
||||||
|
] call EFUNC(common,displayText);
|
||||||
|
};
|
||||||
|
|
||||||
|
clearWeaponCargoGlobal _container;
|
||||||
|
{
|
||||||
|
_container addWeaponWithAttachmentsCargoGlobal [_x, 1];
|
||||||
|
} forEach _allWeaponsItems;
|
||||||
|
};
|
48
addons/weapononback/functions/fnc_onInventoryOpened.sqf
Normal file
48
addons/weapononback/functions/fnc_onInventoryOpened.sqf
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
/*
|
||||||
|
* Author: BaerMitUmlaut
|
||||||
|
* Adds event handlers when opening the inventory display.
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* 0: Inventory display <DISPLAY>
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Public: No
|
||||||
|
*/
|
||||||
|
params ["_display"];
|
||||||
|
|
||||||
|
[_display] call FUNC(updateInventory);
|
||||||
|
|
||||||
|
// Add event handlers for dragging something onto the secondary slot
|
||||||
|
private _primarySlot = _display displayCtrl IDC_PRIMARY_SLOT;
|
||||||
|
_primarySlot ctrlAddEventHandler ["MouseButtonDown", FUNC(onDrag)];
|
||||||
|
|
||||||
|
{
|
||||||
|
private _ctrl = _display displayCtrl _x;
|
||||||
|
_ctrl ctrlAddEventHandler ["LBDrag", FUNC(onDrag)];
|
||||||
|
} forEach [
|
||||||
|
IDC_GROUND_CONTAINER,
|
||||||
|
IDC_SOLDIER_CONTAINER,
|
||||||
|
IDC_UNIFORM_CONTAINER,
|
||||||
|
IDC_VEST_CONTAINER,
|
||||||
|
IDC_BACKPACK_CONTAINER
|
||||||
|
];
|
||||||
|
|
||||||
|
// Add event handler for dragging the weapon on back to a container
|
||||||
|
private _secondarySlot = _display displayCtrl IDC_SECONDARY_SLOT;
|
||||||
|
_secondarySlot ctrlAddEventHandler ["MouseButtonDown", FUNC(onDragWOB)];
|
||||||
|
|
||||||
|
// Add event handler for right click dropping a weapon into a container
|
||||||
|
_secondarySlot ctrlAddEventHandler ["MouseButtonClick", {
|
||||||
|
params ["", "_mouseButton"];
|
||||||
|
|
||||||
|
if (_mouseButton == 1 && {ACE_player in GVAR(units)}) then {
|
||||||
|
[{
|
||||||
|
secondaryWeapon ACE_player != QGVAR(weapon)
|
||||||
|
}, {
|
||||||
|
[] call FUNC(onDropWOB);
|
||||||
|
}, [], 5] call CBA_fnc_waitUntilAndExecute;
|
||||||
|
};
|
||||||
|
}];
|
27
addons/weapononback/functions/fnc_onWHSInit.sqf
Normal file
27
addons/weapononback/functions/fnc_onWHSInit.sqf
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
/*
|
||||||
|
* Author: BaerMitUmlaut
|
||||||
|
* Associates unit and weapon holder on death and moves weapon on back into
|
||||||
|
* the dropped weapon holder.
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* 0: Weapon holder <OBJECT>
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Public: No
|
||||||
|
*/
|
||||||
|
params ["_weaponHolder"];
|
||||||
|
|
||||||
|
private _unit = nearestObject [_weaponHolder, "CAManBase"];
|
||||||
|
if (isNull _unit || {alive _unit}) exitWith {};
|
||||||
|
|
||||||
|
_unit setVariable [QGVAR(droppedWeaponHolder), _weaponHolder];
|
||||||
|
|
||||||
|
if (local _unit && {_unit in GVAR(units)}) then {
|
||||||
|
private _weaponsItems = [_unit] call FUNC(get);
|
||||||
|
_weaponHolder addWeaponWithAttachmentsCargoGlobal [_weaponsItems, 1];
|
||||||
|
|
||||||
|
[_unit] call FUNC(remove);
|
||||||
|
};
|
19
addons/weapononback/functions/fnc_onWeaponChange.sqf
Normal file
19
addons/weapononback/functions/fnc_onWeaponChange.sqf
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
/*
|
||||||
|
* Author: BaerMitUmlaut
|
||||||
|
* Handles switching to the weapon on the back.
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* 0: Player <OBJECT>
|
||||||
|
* 1: Weapon that was swapped to <STRING>
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Public: No
|
||||||
|
*/
|
||||||
|
params ["", "_weapon"];
|
||||||
|
|
||||||
|
if (_weapon != QGVAR(weapon)) exitWith {};
|
||||||
|
|
||||||
|
[FUNC(swap), [], 2] call CBA_fnc_waitAndExecute;
|
40
addons/weapononback/functions/fnc_remove.sqf
Normal file
40
addons/weapononback/functions/fnc_remove.sqf
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
/*
|
||||||
|
* Author: BaerMitUmlaut
|
||||||
|
* Removes the weapon on the back of a unit (global effect).
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* 0: Unit <OBJECT>
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* [player] call ace_weapononback_fnc_remove
|
||||||
|
*
|
||||||
|
* Public: Yes
|
||||||
|
*/
|
||||||
|
params ["_unit", ["_calledFromEvent", false]];
|
||||||
|
|
||||||
|
if !(_unit in GVAR(units)) exitWith {};
|
||||||
|
|
||||||
|
if (!_calledFromEvent) exitWith {
|
||||||
|
[EVENT_ID(_unit)] call CBA_fnc_removeGlobalEventJIP;
|
||||||
|
[QGVAR(remove), [_unit]] call CBA_fnc_globalEvent;
|
||||||
|
};
|
||||||
|
|
||||||
|
private _weaponHolder = _unit getVariable [QGVAR(weaponHolder), objNull];
|
||||||
|
deleteVehicle _weaponHolder;
|
||||||
|
|
||||||
|
// There is a delay when deleting the weapon holder, so ensure the variable is null
|
||||||
|
_unit setVariable [QGVAR(weaponHolder), objNull];
|
||||||
|
GVAR(units) deleteAt (GVAR(units) find _unit);
|
||||||
|
|
||||||
|
if (local _unit) then {
|
||||||
|
private _oldMass = _unit getVariable [QGVAR(weaponMass), 0];
|
||||||
|
[_unit, _unit, -_oldMass] call EFUNC(movement,addLoadToUnitContainer);
|
||||||
|
_unit setVariable [QGVAR(weaponMass), 0, true];
|
||||||
|
|
||||||
|
_unit removeWeapon QGVAR(weapon);
|
||||||
|
[] call FUNC(updateInventory);
|
||||||
|
};
|
51
addons/weapononback/functions/fnc_renderPFH.sqf
Normal file
51
addons/weapononback/functions/fnc_renderPFH.sqf
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
/*
|
||||||
|
* Author: BaerMitUmlaut
|
||||||
|
* Renders weapons on the backs of players.
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Public: No
|
||||||
|
*/
|
||||||
|
|
||||||
|
private _units = GVAR(units);
|
||||||
|
|
||||||
|
if (_units isEqualTo []) exitWith {};
|
||||||
|
|
||||||
|
// Sort units by distance if there is a render limit greater than 0
|
||||||
|
if (GVAR(renderLimit) > 0) then {
|
||||||
|
private _unitsWithDistance = GVAR(units) apply {[ACE_player distance _x, _x]};
|
||||||
|
_unitsWithDistance sort true;
|
||||||
|
_units = _unitsWithDistance apply {_x#1};
|
||||||
|
};
|
||||||
|
|
||||||
|
private _renderedUnits = 0;
|
||||||
|
{
|
||||||
|
private _weaponHolder = _x getVariable [QGVAR(weaponHolder), objNull];
|
||||||
|
|
||||||
|
if (_renderedUnits != GVAR(renderLimit) && {isNull objectParent _x}) then {
|
||||||
|
_weaponHolder hideObject false;
|
||||||
|
|
||||||
|
// Don't update orientation if not on screen, always update for player
|
||||||
|
if (_x == player || {!(worldToScreen ASLToAGL getPosWorld _weaponHolder isEqualTo [])}) then {
|
||||||
|
private _lShoulder = _x selectionPosition "leftshoulder";
|
||||||
|
private _rShoulder = _x selectionPosition "rightshoulder";
|
||||||
|
private _lUpLeg = _x selectionPosition "leftupleg";
|
||||||
|
|
||||||
|
private _ab = _lShoulder vectorFromTo _rShoulder;
|
||||||
|
private _bc = _lShoulder vectorFromTo _lUpLeg;
|
||||||
|
private _vectorDir = _ab vectorCrossProduct _bc;
|
||||||
|
private _vectorUp = _ab;
|
||||||
|
|
||||||
|
_weaponHolder setVectorDirAndUp [_vectorUp, _vectorDir];
|
||||||
|
|
||||||
|
_renderedUnits = _renderedUnits + 1;
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
_weaponHolder hideObject true;
|
||||||
|
};
|
||||||
|
} forEach _units;
|
85
addons/weapononback/functions/fnc_swap.sqf
Normal file
85
addons/weapononback/functions/fnc_swap.sqf
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
/*
|
||||||
|
* Author: BaerMitUmlaut
|
||||||
|
* Swaps primary and weapon on back. Can handle no primary or no weapon on back.
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Public: No
|
||||||
|
*/
|
||||||
|
|
||||||
|
private _oldPrimary = (getUnitLoadout ACE_player)#0;
|
||||||
|
private _newPrimary = [ACE_player] call FUNC(get);
|
||||||
|
|
||||||
|
// Save scope adjustment
|
||||||
|
private _adjustments = ACE_player getVariable [QEGVAR(scopes,adjustment), [[0, 0, 0], [0, 0, 0], [0, 0, 0]]];
|
||||||
|
private _oldAdjustment = _adjustments#0;
|
||||||
|
private _newAdjustement = ACE_player getVariable [QGVAR(scopeAdjustment), [0, 0, 0]];
|
||||||
|
EGVAR(scopes,guns) set [0, ""];
|
||||||
|
|
||||||
|
ACE_player removeWeapon (_oldPrimary param [0, ""]);
|
||||||
|
|
||||||
|
if !(_newPrimary isEqualTo []) then {
|
||||||
|
_newPrimary params ["_weapon"];
|
||||||
|
|
||||||
|
// addWeapon is going to eat a mag for each muzzle before we can fill the weapon with addWeaponItem
|
||||||
|
// Because of that, we need to save where that mag was taken from and readd it
|
||||||
|
private _containerMags = [
|
||||||
|
uniformContainer ACE_player,
|
||||||
|
vestContainer ACE_player,
|
||||||
|
backpackContainer ACE_player
|
||||||
|
] apply {magazinesAmmo _x};
|
||||||
|
|
||||||
|
ACE_player addWeapon _weapon;
|
||||||
|
|
||||||
|
// Readd lost magazines
|
||||||
|
{
|
||||||
|
private _container = _x;
|
||||||
|
private _before = _containerMags#_forEachIndex;
|
||||||
|
private _after = magazinesAmmo _container;
|
||||||
|
|
||||||
|
{
|
||||||
|
_before deleteAt (_before find _x);
|
||||||
|
} forEach _after;
|
||||||
|
|
||||||
|
{
|
||||||
|
_container addMagazineAmmoCargo [_x#0, 1, _x#1];
|
||||||
|
} forEach _before;
|
||||||
|
} forEach [
|
||||||
|
uniformContainer ACE_player,
|
||||||
|
vestContainer ACE_player,
|
||||||
|
backpackContainer ACE_player
|
||||||
|
];
|
||||||
|
|
||||||
|
removeAllPrimaryWeaponItems ACE_player;
|
||||||
|
{
|
||||||
|
ACE_player addWeaponItem [_weapon, _x, true];
|
||||||
|
} forEach (_newPrimary select [1, 6]);
|
||||||
|
|
||||||
|
ACE_player selectWeapon _weapon;
|
||||||
|
|
||||||
|
// Restore scope adjustment
|
||||||
|
[{
|
||||||
|
EGVAR(scopes,guns)#0 != ""
|
||||||
|
}, {
|
||||||
|
params ["_oldAdjustment", "_newAdjustement"];
|
||||||
|
|
||||||
|
if !(_newAdjustement isEqualTo [0, 0, 0]) then {
|
||||||
|
private _scopeAdjustmentParams = [ACE_player];
|
||||||
|
_scopeAdjustmentParams append _newAdjustement;
|
||||||
|
_scopeAdjustmentParams call EFUNC(scopes,applyScopeAdjustment);
|
||||||
|
};
|
||||||
|
|
||||||
|
ACE_player setVariable [QGVAR(scopeAdjustment), _oldAdjustment];
|
||||||
|
}, [_oldAdjustment, _newAdjustement]] call CBA_fnc_waitUntilAndExecute;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (_oldPrimary isEqualTo []) then {
|
||||||
|
[ACE_player] call FUNC(remove);
|
||||||
|
} else {
|
||||||
|
[ACE_player, _oldPrimary] call FUNC(add);
|
||||||
|
};
|
39
addons/weapononback/functions/fnc_updateInventory.sqf
Normal file
39
addons/weapononback/functions/fnc_updateInventory.sqf
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#include "script_component.hpp"
|
||||||
|
/*
|
||||||
|
* Author: BaerMitUmlaut
|
||||||
|
* Updates the inventory display by hiding / showing the weapon on the back.
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* 0: Inventory display (optional, for UI EH) <DISPLAY>
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Public: No
|
||||||
|
*/
|
||||||
|
params [["_display", findDisplay IDD_INVENTORY]];
|
||||||
|
if (isNull _display) exitWith {};
|
||||||
|
|
||||||
|
private _weaponHolder = ACE_player getVariable [QGVAR(weaponHolder), objNull];
|
||||||
|
private _hasWeaponOnBack = !isNull _weaponHolder;
|
||||||
|
|
||||||
|
// Hide attachment slots if player has weapon on their back
|
||||||
|
{
|
||||||
|
private _ctrl = _display displayCtrl _x;
|
||||||
|
_ctrl ctrlSetFade ([0, 1] select _hasWeaponOnBack);
|
||||||
|
_ctrl ctrlCommit 0;
|
||||||
|
} forEach IDCS_SECONDARY_ATTACHMENTS;
|
||||||
|
|
||||||
|
// Show/hide image of weapon on back
|
||||||
|
private _imgContainer = _display displayCtrl IDC_WEAPON_IMAGE;
|
||||||
|
private _secondarySlot = _display displayCtrl IDC_SECONDARY_SLOT;
|
||||||
|
|
||||||
|
_imgContainer ctrlSetPosition ctrlPosition _secondarySlot;
|
||||||
|
_imgContainer ctrlSetBackgroundColor [1, 1, 1, 0];
|
||||||
|
if (_hasWeaponOnBack) then {
|
||||||
|
private _weapon = (weaponCargo _weaponHolder)#0;
|
||||||
|
_imgContainer ctrlSetText getText (configFile >> "CfgWeapons" >> _weapon >> "picture");
|
||||||
|
} else {
|
||||||
|
_imgContainer ctrlSetText "";
|
||||||
|
};
|
||||||
|
_imgContainer ctrlCommit 0;
|
1
addons/weapononback/functions/script_component.hpp
Normal file
1
addons/weapononback/functions/script_component.hpp
Normal file
@ -0,0 +1 @@
|
|||||||
|
#include "\z\ace\addons\weapononback\script_component.hpp"
|
13
addons/weapononback/initSettings.sqf
Normal file
13
addons/weapononback/initSettings.sqf
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[
|
||||||
|
QGVAR(enabled), "CHECKBOX",
|
||||||
|
LELSTRING(common,Enabled),
|
||||||
|
LELSTRING(common,ACEKeybindCategoryWeapons),
|
||||||
|
true, false
|
||||||
|
] call CBA_settings_fnc_init;
|
||||||
|
|
||||||
|
[
|
||||||
|
QGVAR(renderLimit), "SLIDER",
|
||||||
|
[LSTRING(RenderLimit), LSTRING(RenderLimitDescription)],
|
||||||
|
LELSTRING(common,ACEKeybindCategoryWeapons),
|
||||||
|
[-1, 100, -1, -1], false
|
||||||
|
] call CBA_settings_fnc_init;
|
46
addons/weapononback/script_component.hpp
Normal file
46
addons/weapononback/script_component.hpp
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#define COMPONENT weapononback
|
||||||
|
#define COMPONENT_BEAUTIFIED Weapon on Back
|
||||||
|
#include "\z\ace\addons\main\script_mod.hpp"
|
||||||
|
|
||||||
|
// #define DEBUG_MODE_FULL
|
||||||
|
// #define DISABLE_COMPILE_CACHE
|
||||||
|
// #define ENABLE_PERFORMANCE_COUNTERS
|
||||||
|
|
||||||
|
#ifdef DEBUG_ENABLED_WEAPONONBACK
|
||||||
|
#define DEBUG_MODE_FULL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DEBUG_SETTINGS_WEAPONONBACK
|
||||||
|
#define DEBUG_SETTINGS DEBUG_SETTINGS_WEAPONONBACK
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "\z\ace\addons\main\script_macros.hpp"
|
||||||
|
|
||||||
|
// Inventory IDD
|
||||||
|
#define IDD_INVENTORY 602
|
||||||
|
|
||||||
|
// Relevant slot IDCs
|
||||||
|
#define IDC_PRIMARY_SLOT 610
|
||||||
|
#define IDC_SECONDARY_SLOT 611
|
||||||
|
|
||||||
|
// Custom controls
|
||||||
|
#define IDC_WEAPON_IMAGE 135001
|
||||||
|
#define IDC_DROP_CATCHER 135002
|
||||||
|
#define IDC_DROP_CATCHER_BG 135003
|
||||||
|
|
||||||
|
// Container IDCs
|
||||||
|
#define IDC_GROUND_CONTAINER 632
|
||||||
|
#define IDC_SOLDIER_CONTAINER 640
|
||||||
|
#define IDC_UNIFORM_CONTAINER 633
|
||||||
|
#define IDC_VEST_CONTAINER 638
|
||||||
|
#define IDC_BACKPACK_CONTAINER 619
|
||||||
|
|
||||||
|
// Attachement IDCs
|
||||||
|
#define IDCS_SECONDARY_ATTACHMENTS [1248, 1266, 1249, 1250, 1251, 624, 642, 626, 625, 627]
|
||||||
|
|
||||||
|
// Background IDCs
|
||||||
|
#define IDC_PRIMARY_BG 1242
|
||||||
|
#define IDC_SECONDARY_BG 1247
|
||||||
|
|
||||||
|
// ID generator for JIP events
|
||||||
|
#define EVENT_ID(obj) (QGVAR(eventID_) + netId obj)
|
21
addons/weapononback/stringtable.xml
Normal file
21
addons/weapononback/stringtable.xml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project name="ACE">
|
||||||
|
<Package name="WeaponOnBack">
|
||||||
|
<Key ID="STR_ACE_WeaponOnBack_FakeWeaponDisplayName">
|
||||||
|
<English>Weapon on back</English>
|
||||||
|
<German>Waffe auf dem Rücken</German>
|
||||||
|
</Key>
|
||||||
|
<Key ID="STR_ACE_WeaponOnBack_RenderLimit">
|
||||||
|
<English>Render limit</English>
|
||||||
|
<German>Renderlimit</German>
|
||||||
|
</Key>
|
||||||
|
<Key ID="STR_ACE_WeaponOnBack_RenderLimitDescription">
|
||||||
|
<English>Limit the amount of weapons on backs to be rendered (-1 for no limit).</English>
|
||||||
|
<German>Limitiert die Anzahl der Waffen auf dem Rücken die gerendert werden (-1 bedeutet kein Limit).</German>
|
||||||
|
</Key>
|
||||||
|
<Key ID="STR_ACE_WeaponOnBack_CouldNotFit">
|
||||||
|
<English>Could not fit %1 into %2.</English>
|
||||||
|
<German>%1 passt nicht in %2.</German>
|
||||||
|
</Key>
|
||||||
|
</Package>
|
||||||
|
</Project>
|
Loading…
Reference in New Issue
Block a user