From ca7fbe742c024c8adbfe6a3420defc9e43c95af0 Mon Sep 17 00:00:00 2001 From: Brandon Danyluk Date: Tue, 12 Oct 2021 03:33:05 -0600 Subject: [PATCH] Add Vehicle Towing (#8380) Co-authored-by: PabstMirror --- addons/fastroping/CfgVehicles.hpp | 10 ++ addons/fastroping/CfgWeapons.hpp | 60 -------- addons/fastroping/config.cpp | 4 +- .../fastroping/functions/fnc_deployRopes.sqf | 2 +- addons/fastroping/stringtable.xml | 108 +++---------- addons/logistics_rope/$PBOPREFIX$ | 1 + addons/logistics_rope/CfgWeapons.hpp | 67 ++++++++ addons/logistics_rope/README.md | 11 ++ addons/logistics_rope/config.cpp | 18 +++ .../data/m_rope_ca.paa | Bin addons/logistics_rope/script_component.hpp | 17 +++ addons/logistics_rope/stringtable.xml | 102 +++++++++++++ addons/towing/$PBOPREFIX$ | 1 + addons/towing/CfgEventHandlers.hpp | 17 +++ addons/towing/CfgVehicles.hpp | 85 +++++++++++ addons/towing/README.md | 11 ++ addons/towing/XEH_PREP.hpp | 8 + addons/towing/XEH_postInit.sqf | 14 ++ addons/towing/XEH_preInit.sqf | 9 ++ addons/towing/XEH_preStart.sqf | 3 + addons/towing/config.cpp | 19 +++ addons/towing/functions/fnc_attachRopePFH.sqf | 79 ++++++++++ addons/towing/functions/fnc_canStartTow.sqf | 21 +++ addons/towing/functions/fnc_detach.sqf | 48 ++++++ .../functions/fnc_isSuitableSimulation.sqf | 26 ++++ .../functions/fnc_onMouseButtonDown.sqf | 26 ++++ .../towing/functions/fnc_onMouseButtonUp.sqf | 26 ++++ addons/towing/functions/fnc_startTow.sqf | 33 ++++ .../functions/fnc_towStateMachinePFH.sqf | 144 ++++++++++++++++++ addons/towing/functions/script_component.hpp | 1 + addons/towing/script_component.hpp | 27 ++++ addons/towing/stringtable.xml | 38 +++++ 32 files changed, 889 insertions(+), 147 deletions(-) delete mode 100644 addons/fastroping/CfgWeapons.hpp create mode 100644 addons/logistics_rope/$PBOPREFIX$ create mode 100644 addons/logistics_rope/CfgWeapons.hpp create mode 100644 addons/logistics_rope/README.md create mode 100644 addons/logistics_rope/config.cpp rename addons/{fastroping => logistics_rope}/data/m_rope_ca.paa (100%) create mode 100644 addons/logistics_rope/script_component.hpp create mode 100644 addons/logistics_rope/stringtable.xml create mode 100644 addons/towing/$PBOPREFIX$ create mode 100644 addons/towing/CfgEventHandlers.hpp create mode 100644 addons/towing/CfgVehicles.hpp create mode 100644 addons/towing/README.md create mode 100644 addons/towing/XEH_PREP.hpp create mode 100644 addons/towing/XEH_postInit.sqf create mode 100644 addons/towing/XEH_preInit.sqf create mode 100644 addons/towing/XEH_preStart.sqf create mode 100644 addons/towing/config.cpp create mode 100644 addons/towing/functions/fnc_attachRopePFH.sqf create mode 100644 addons/towing/functions/fnc_canStartTow.sqf create mode 100644 addons/towing/functions/fnc_detach.sqf create mode 100644 addons/towing/functions/fnc_isSuitableSimulation.sqf create mode 100644 addons/towing/functions/fnc_onMouseButtonDown.sqf create mode 100644 addons/towing/functions/fnc_onMouseButtonUp.sqf create mode 100644 addons/towing/functions/fnc_startTow.sqf create mode 100644 addons/towing/functions/fnc_towStateMachinePFH.sqf create mode 100644 addons/towing/functions/script_component.hpp create mode 100644 addons/towing/script_component.hpp create mode 100644 addons/towing/stringtable.xml diff --git a/addons/fastroping/CfgVehicles.hpp b/addons/fastroping/CfgVehicles.hpp index 24f996d825..fc4aed6ae4 100644 --- a/addons/fastroping/CfgVehicles.hpp +++ b/addons/fastroping/CfgVehicles.hpp @@ -48,6 +48,16 @@ class CfgVehicles { condition = QUOTE([_target] call FUNC(canStowFRIES)); statement = QUOTE([_target] call FUNC(stowFRIES)); }; + class ACE_deployRopes3 { + displayName = CSTRING(Interaction_deployRopes3); + condition = QUOTE([ARR_3(_target,_player,'ACE_rope3')] call FUNC(canDeployRopes)); + statement = QUOTE([ARR_2(QQGVAR(deployRopes),[ARR_3(_target,_player,'ACE_rope3')])] call CBA_fnc_serverEvent); + }; + class ACE_deployRopes6 { + displayName = CSTRING(Interaction_deployRopes6); + condition = QUOTE([ARR_3(_target,_player,'ACE_rope6')] call FUNC(canDeployRopes)); + statement = QUOTE([ARR_2(QQGVAR(deployRopes),[ARR_3(_target,_player,'ACE_rope6')])] call CBA_fnc_serverEvent); + }; class ACE_deployRopes12 { displayName = CSTRING(Interaction_deployRopes12); condition = QUOTE([ARR_3(_target,_player,'ACE_rope12')] call FUNC(canDeployRopes)); diff --git a/addons/fastroping/CfgWeapons.hpp b/addons/fastroping/CfgWeapons.hpp deleted file mode 100644 index 116497c6fa..0000000000 --- a/addons/fastroping/CfgWeapons.hpp +++ /dev/null @@ -1,60 +0,0 @@ -class CfgWeapons { - class ACE_ItemCore; - class CBA_MiscItem_ItemInfo; - - class ACE_rope12: ACE_ItemCore { - scope = 2; - GVAR(ropeLength) = 12.2; - picture = QPATHTOF(data\m_rope_ca); - model = "\A3\Structures_F_Heli\Items\Tools\Rope_01_F.p3d"; - displayName = CSTRING(Rope_12_Display); - descriptionShort = CSTRING(descriptionShort); - class ItemInfo: CBA_MiscItem_ItemInfo { - mass = 36; - }; - }; - class ACE_rope15: ACE_ItemCore { - scope = 2; - GVAR(ropeLength) = 15.2; - picture = QPATHTOF(data\m_rope_ca); - model = "\A3\Structures_F_Heli\Items\Tools\Rope_01_F.p3d"; - displayName = CSTRING(Rope_15_Display); - descriptionShort = CSTRING(descriptionShort); - class ItemInfo: CBA_MiscItem_ItemInfo { - mass = 45; - }; - }; - class ACE_rope18: ACE_ItemCore { - scope = 2; - GVAR(ropeLength) = 18.3; - picture = QPATHTOF(data\m_rope_ca); - model = "\A3\Structures_F_Heli\Items\Tools\Rope_01_F.p3d"; - displayName = CSTRING(Rope_18_Display); - descriptionShort = CSTRING(descriptionShort); - class ItemInfo: CBA_MiscItem_ItemInfo { - mass = 54; - }; - }; - class ACE_rope27: ACE_ItemCore { - scope = 2; - GVAR(ropeLength) = 27.4; - picture = QPATHTOF(data\m_rope_ca); - model = "\A3\Structures_F_Heli\Items\Tools\Rope_01_F.p3d"; - displayName = CSTRING(Rope_27_Display); - descriptionShort = CSTRING(descriptionShort); - class ItemInfo: CBA_MiscItem_ItemInfo { - mass = 81; - }; - }; - class ACE_rope36: ACE_ItemCore { - scope = 2; - GVAR(ropeLength) = 36.6; - picture = QPATHTOF(data\m_rope_ca); - model = "\A3\Structures_F_Heli\Items\Tools\Rope_01_F.p3d"; - displayName = CSTRING(Rope_36_Display); - descriptionShort = CSTRING(descriptionShort); - class ItemInfo: CBA_MiscItem_ItemInfo { - mass = 108; - }; - }; -}; diff --git a/addons/fastroping/config.cpp b/addons/fastroping/config.cpp index bdbd92c3b0..749586708c 100644 --- a/addons/fastroping/config.cpp +++ b/addons/fastroping/config.cpp @@ -6,7 +6,7 @@ class CfgPatches { units[] = {"ACE_fastropingSupplyCrate"}; weapons[] = {"ACE_rope12","ACE_rope15","ACE_rope18","ACE_rope27","ACE_rope36"}; requiredVersion = REQUIRED_VERSION; - requiredAddons[] = {"ace_interaction"}; + requiredAddons[] = {"ace_interaction","ace_logistics_rope"}; author = ECSTRING(common,ACETeam); authors[] = {"KoffeinFlummi", "BaerMitUmlaut", "Pokertour"}; url = ECSTRING(main,URL); @@ -19,4 +19,4 @@ class CfgPatches { #include "CfgSounds.hpp" #include "CfgVehicles.hpp" #include "CfgWaypoints.hpp" -#include "CfgWeapons.hpp" + diff --git a/addons/fastroping/functions/fnc_deployRopes.sqf b/addons/fastroping/functions/fnc_deployRopes.sqf index 17627b63f2..d6f3afbf98 100644 --- a/addons/fastroping/functions/fnc_deployRopes.sqf +++ b/addons/fastroping/functions/fnc_deployRopes.sqf @@ -26,7 +26,7 @@ private _ropeOrigins = getArray (_config >> QGVAR(ropeOrigins)); private _deployedRopes = _vehicle getVariable [QGVAR(deployedRopes), []]; private _hookAttachment = _vehicle getVariable [QGVAR(FRIES), _vehicle]; -private _ropeLength = getNumber (configfile >> "CfgWeapons" >> _ropeClass >> QGVAR(ropeLength)); +private _ropeLength = getNumber (configfile >> "CfgWeapons" >> _ropeClass >> QEGVAR(logistics_rope,length)); if (_ropeLength <= 0) then { _ropeLength = DEFAULT_ROPE_LENGTH; diff --git a/addons/fastroping/stringtable.xml b/addons/fastroping/stringtable.xml index 6450670d36..0afc9a7799 100644 --- a/addons/fastroping/stringtable.xml +++ b/addons/fastroping/stringtable.xml @@ -156,6 +156,30 @@ UMOŽNIT JEDNOTKÁM SLAŇOVAT INDICAR A LAS UNIDADES DESCENDER POR LA CUERDA + + Deploy 3m ropes + 3m Seile einsetzen + Déployer les cordes de 3 m + Wysuń linę o długości 3 m. + Выпустить 3 м канат + Jogar cordar (3m) + Dispiegamento corde 3m + Připravit 3m lana + 3m halat sal + Desplegar cuerdas de 3m + + + Deploy 6m ropes + 6m Seile einsetzen + Déployer les cordes de 6 m + Wysuń linę o długości 6 m. + Выпустить 6 м канат + Jogar cordar (6m) + Dispiegamento corde 6m + Připravit 6m lana + 6m halat sal + Desplegar cuerdas de 6m + Deploy 12m ropes 12m Seile einsetzen @@ -240,90 +264,6 @@ [ACE] Halat Sandığı [ACE] Caja de suministros - cuerdas - - Used to do deploy ropes from a compatibile helicopter - Wird zum Bereitstellen von Seilen aus einem kompatiblen Hubschrauber verwendet - Utilisé pour déployer des cordes depuis un hélicoptère compatible. - 対応するヘリコプターからロープを展開する為に使用されます - Używane do opuszczania lin z kompatybilnych smigłowców - Используется для выпуска канатов с совместимого вертолета - Usado para fazer descida rápida de corda em helicópteros compatíveis com FRIES - 在可相容的直升機上部屬繩索 - Utilizzato per distribuire corde da un elicottero compatibile - Používané na přípravu lan na slaňování z kompatibilních helikoptér - Usar para desplegar cuerdas desde helicopteros compatibles - Halatları uyumlu helikopterlerden salmak için kullanır - - - Rope 12.2 meters - 12.2 Meter Seil - Corde de 12,2 mètres - ロープ (12.2 メートル) - Lina, długość 12,2 m. - Канат 12.2 метров - Corda (12.2m) - 繩索(12.2公尺長) - Corda da 12.2 metri - Lano 12.2 metrů - 12.2 metre halat - Cuerda de 12.2 metros - - - Rope 15.2 meters - 15.2 Meter Seil - Corde de 15,2 mètres - ロープ (15.2 メートル) - Lina, długość 15,2 m. - Канат 15.2 метров - Corda (15.2m) - 繩索(15.2公尺長) - Corda da 15.2 metri - Lano 15.2 metrů - 15.2 metre halat - Cuerda de 15.2 metros - - - Rope 18.3 meters - 18.3 Meter Seil - Corde de 18,3 mètres - ロープ (18.3 メートル) - Lina, długość 18,3 m. - Канат 18.3 метров - Corda (18.3m) - 繩索(18.3公尺長) - Corda da 18.3 metri - Lano 18.3 metrů - 18.3 metre halat - Cuerda de 18.3 metros - - - Rope 27.4 meters - 27.4 Meter Seil - Corde de 27,4 mètres - ロープ (27.4 メートル) - Lina, długość 27,4 m. - Канат 27.4 метров - Corda (27.4m) - 繩索(27.4公尺長) - Corda da 27.4 metri - Lano 27.4 metrů - 27.4 metre halat - Cuerda de 27.4 metros - - - Rope 36.6 meters - 36.6 Meter Seil - Corde de 36,6 mètres - ロープ (36.6 メートル) - Lina, długość 36,6 m. - Канат 36.6 метров - Corda (36.6m) - 繩索(36.6公尺長) - Corda da 36.6 metri - Lano 36.6 metrů - 36.6 metre halat - Cuerda 36.6 metros - Fast-roping Hélicordage diff --git a/addons/logistics_rope/$PBOPREFIX$ b/addons/logistics_rope/$PBOPREFIX$ new file mode 100644 index 0000000000..12790e5206 --- /dev/null +++ b/addons/logistics_rope/$PBOPREFIX$ @@ -0,0 +1 @@ +z\ace\addons\logistics_rope \ No newline at end of file diff --git a/addons/logistics_rope/CfgWeapons.hpp b/addons/logistics_rope/CfgWeapons.hpp new file mode 100644 index 0000000000..1b492be2a2 --- /dev/null +++ b/addons/logistics_rope/CfgWeapons.hpp @@ -0,0 +1,67 @@ +class CfgWeapons { + class CBA_MiscItem_ItemInfo; + class ACE_ItemCore; + class ACE_ropeBase: ACE_ItemCore { + scope = 1; + picture = QPATHTOF(data\m_rope_ca); + model = "\A3\Structures_F_Heli\Items\Tools\Rope_01_F.p3d"; + descriptionShort = CSTRING(descriptionShort); + }; + + class ACE_rope3: ACE_ropeBase { + scope = 2; + GVAR(length) = 3.2; + displayName = CSTRING(Rope_3_Display); + class ItemInfo: CBA_MiscItem_ItemInfo { + mass = 6; + }; + }; + class ACE_rope6: ACE_ropeBase { + scope = 2; + GVAR(length) = 6.2; + displayName = CSTRING(Rope_6_Display); + class ItemInfo: CBA_MiscItem_ItemInfo { + mass = 18; + }; + }; + class ACE_rope12: ACE_ropeBase { + scope = 2; + GVAR(length) = 12.2; + displayName = CSTRING(Rope_12_Display); + class ItemInfo: CBA_MiscItem_ItemInfo { + mass = 36; + }; + }; + class ACE_rope15: ACE_ropeBase { + scope = 2; + GVAR(length) = 15.2; + displayName = CSTRING(Rope_15_Display); + class ItemInfo: CBA_MiscItem_ItemInfo { + mass = 45; + }; + }; + class ACE_rope18: ACE_ropeBase { + scope = 2; + GVAR(length) = 18.3; + displayName = CSTRING(Rope_18_Display); + class ItemInfo: CBA_MiscItem_ItemInfo { + mass = 54; + }; + }; + class ACE_rope27: ACE_ropeBase { + scope = 2; + GVAR(length) = 27.4; + displayName = CSTRING(Rope_27_Display); + class ItemInfo: CBA_MiscItem_ItemInfo { + mass = 81; + }; + }; + class ACE_rope36: ACE_ropeBase { + scope = 2; + GVAR(length) = 36.6; + displayName = CSTRING(Rope_36_Display); + class ItemInfo: CBA_MiscItem_ItemInfo { + mass = 108; + }; + }; +}; \ No newline at end of file diff --git a/addons/logistics_rope/README.md b/addons/logistics_rope/README.md new file mode 100644 index 0000000000..b2f7cb6bce --- /dev/null +++ b/addons/logistics_rope/README.md @@ -0,0 +1,11 @@ +ace_logistics_rope +=================== + +Adds ropes. + + +## Maintainers + +The people responsible for merging changes to this component or answering potential questions. + +- [Brandon (TCVM)](https://github.com/TheCandianVendingMachine) diff --git a/addons/logistics_rope/config.cpp b/addons/logistics_rope/config.cpp new file mode 100644 index 0000000000..9e950de635 --- /dev/null +++ b/addons/logistics_rope/config.cpp @@ -0,0 +1,18 @@ +#include "script_component.hpp" + +class CfgPatches { + class ADDON { + name = COMPONENT_NAME; + units[] = {}; + weapons[] = {}; + requiredVersion = REQUIRED_VERSION; + requiredAddons[] = {"ace_common"}; + author = ECSTRING(common,ACETeam); + authors[] = {""}; + url = ECSTRING(main,URL); + VERSION_CONFIG; + }; +}; + +#include "CfgWeapons.hpp" + diff --git a/addons/fastroping/data/m_rope_ca.paa b/addons/logistics_rope/data/m_rope_ca.paa similarity index 100% rename from addons/fastroping/data/m_rope_ca.paa rename to addons/logistics_rope/data/m_rope_ca.paa diff --git a/addons/logistics_rope/script_component.hpp b/addons/logistics_rope/script_component.hpp new file mode 100644 index 0000000000..b5c11e5b20 --- /dev/null +++ b/addons/logistics_rope/script_component.hpp @@ -0,0 +1,17 @@ +#define COMPONENT logistics_rope +#define COMPONENT_BEAUTIFIED Rope +#include "\z\ace\addons\main\script_mod.hpp" + +// #define DEBUG_MODE_FULL +// #define DISABLE_COMPILE_CACHE +// #define ENABLE_PERFORMANCE_COUNTERS + +#ifdef DEBUG_ENABLED_LOGISTICS_ROPE + #define DEBUG_MODE_FULL +#endif + +#ifdef DEBUG_SETTINGS_LOGISTICS_ROPE + #define DEBUG_SETTINGS DEBUG_SETTINGS_LOGISTICS_ROPE +#endif + +#include "\z\ace\addons\main\script_macros.hpp" diff --git a/addons/logistics_rope/stringtable.xml b/addons/logistics_rope/stringtable.xml new file mode 100644 index 0000000000..3fa99dd722 --- /dev/null +++ b/addons/logistics_rope/stringtable.xml @@ -0,0 +1,102 @@ + + + + + A twisted braid of fibers. Usually used for rappelling or towing. + + + Rope 3.2 meters + 3.2 Meter Seil + Corde de 3,2 mètres + Lina, długość 3,2 m. + Канат 3.2 метров + Corda (3.2m) + Corda da 3.2 metri + Lano 3.2 metrů + 3.2 metre halat + Cuerda de 3.2 metros + + + Rope 6.2 meters + 6.2 Meter Seil + Corde de 6,2 mètres + Lina, długość 6,2 m. + Канат 6.2 метров + Corda (6.2m) + Corda da 6.2 metri + Lano 6.2 metrů + 6.2 metre halat + Cuerda de 6.2 metros + + + Rope 12.2 meters + 12.2 Meter Seil + Corde de 12,2 mètres + ロープ (12.2 メートル) + Lina, długość 12,2 m. + Канат 12.2 метров + Corda (12.2m) + 繩索(12.2公尺長) + Corda da 12.2 metri + Lano 12.2 metrů + 12.2 metre halat + Cuerda de 12.2 metros + + + Rope 15.2 meters + 15.2 Meter Seil + Corde de 15,2 mètres + ロープ (15.2 メートル) + Lina, długość 15,2 m. + Канат 15.2 метров + Corda (15.2m) + 繩索(15.2公尺長) + Corda da 15.2 metri + Lano 15.2 metrů + 15.2 metre halat + Cuerda de 15.2 metros + + + Rope 18.3 meters + 18.3 Meter Seil + Corde de 18,3 mètres + ロープ (18.3 メートル) + Lina, długość 18,3 m. + Канат 18.3 метров + Corda (18.3m) + 繩索(18.3公尺長) + Corda da 18.3 metri + Lano 18.3 metrů + 18.3 metre halat + Cuerda de 18.3 metros + + + Rope 27.4 meters + 27.4 Meter Seil + Corde de 27,4 mètres + ロープ (27.4 メートル) + Lina, długość 27,4 m. + Канат 27.4 метров + Corda (27.4m) + 繩索(27.4公尺長) + Corda da 27.4 metri + Lano 27.4 metrů + 27.4 metre halat + Cuerda de 27.4 metros + + + Rope 36.6 meters + 36.6 Meter Seil + Corde de 36,6 mètres + ロープ (36.6 メートル) + Lina, długość 36,6 m. + Канат 36.6 метров + Corda (36.6m) + 繩索(36.6公尺長) + Corda da 36.6 metri + Lano 36.6 metrů + 36.6 metre halat + Cuerda 36.6 metros + + + diff --git a/addons/towing/$PBOPREFIX$ b/addons/towing/$PBOPREFIX$ new file mode 100644 index 0000000000..6755fcc3bf --- /dev/null +++ b/addons/towing/$PBOPREFIX$ @@ -0,0 +1 @@ +z\ace\addons\towing \ No newline at end of file diff --git a/addons/towing/CfgEventHandlers.hpp b/addons/towing/CfgEventHandlers.hpp new file mode 100644 index 0000000000..0d3301d6e0 --- /dev/null +++ b/addons/towing/CfgEventHandlers.hpp @@ -0,0 +1,17 @@ +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)); + }; +}; diff --git a/addons/towing/CfgVehicles.hpp b/addons/towing/CfgVehicles.hpp new file mode 100644 index 0000000000..f74cf5d300 --- /dev/null +++ b/addons/towing/CfgVehicles.hpp @@ -0,0 +1,85 @@ +#define TOW_ACTION \ +class ACE_Actions {\ + class ACE_MainActions {\ + class ADDON {\ + displayName = CSTRING(displayName);\ + distance = TOW_ACTION_DISTANCE;\ + condition = QUOTE([ARR_1(_target)] call FUNC(isSuitableSimulation));\ + statement = "";\ + exceptions[] = { INTERACTION_EXCEPTIONS };\ + showDisabled = 0;\ + icon = "";\ + class GVAR(startTow3) {\ + displayName = CSTRING(start3);\ + condition = QUOTE(([ARR_2(_player,_target)] call FUNC(canStartTow)) && [ARR_2(_player, 'ACE_rope3')] call EFUNC(common,hasItem));\ + statement = QUOTE([ARR_3(_player,_target,'ACE_rope3')] call FUNC(startTow));\ + exceptions[] = { INTERACTION_EXCEPTIONS };\ + };\ + class GVAR(startTow6) {\ + displayName = CSTRING(start6);\ + condition = QUOTE(([ARR_2(_player,_target)] call FUNC(canStartTow)) && [ARR_2(_player, 'ACE_rope6')] call EFUNC(common,hasItem));\ + statement = QUOTE([ARR_3(_player,_target,'ACE_rope6')] call FUNC(startTow));\ + exceptions[] = { INTERACTION_EXCEPTIONS };\ + };\ + class GVAR(startTow12) {\ + displayName = CSTRING(start12);\ + condition = QUOTE(([ARR_2(_player,_target)] call FUNC(canStartTow)) && [ARR_2(_player, 'ACE_rope12')] call EFUNC(common,hasItem));\ + statement = QUOTE([ARR_3(_player,_target,'ACE_rope12')] call FUNC(startTow));\ + exceptions[] = { INTERACTION_EXCEPTIONS };\ + };\ + class GVAR(startTow15) {\ + displayName = CSTRING(start15);\ + condition = QUOTE(([ARR_2(_player,_target)] call FUNC(canStartTow)) && [ARR_2(_player, 'ACE_rope15')] call EFUNC(common,hasItem));\ + statement = QUOTE([ARR_3(_player,_target,'ACE_rope15')] call FUNC(startTow));\ + exceptions[] = { INTERACTION_EXCEPTIONS };\ + };\ + class GVAR(startTow18) {\ + displayName = CSTRING(start18);\ + condition = QUOTE(([ARR_2(_player,_target)] call FUNC(canStartTow)) && [ARR_2(_player, 'ACE_rope18')] call EFUNC(common,hasItem));\ + statement = QUOTE([ARR_3(_player,_target,'ACE_rope18')] call FUNC(startTow));\ + exceptions[] = { INTERACTION_EXCEPTIONS };\ + };\ + class GVAR(startTow27) {\ + displayName = CSTRING(start27);\ + condition = QUOTE(([ARR_2(_player,_target)] call FUNC(canStartTow)) && [ARR_2(_player, 'ACE_rope27')] call EFUNC(common,hasItem));\ + statement = QUOTE([ARR_3(_player,_target,'ACE_rope27')] call FUNC(startTow));\ + exceptions[] = { INTERACTION_EXCEPTIONS };\ + };\ + class GVAR(startTow36) {\ + displayName = CSTRING(start36);\ + condition = QUOTE(([ARR_2(_player,_target)] call FUNC(canStartTow)) && [ARR_2(_player, 'ACE_rope36')] call EFUNC(common,hasItem));\ + statement = QUOTE([ARR_3(_player,_target,'ACE_rope36')] call FUNC(startTow));\ + exceptions[] = { INTERACTION_EXCEPTIONS };\ + };\ + };\ + };\ +} + +class CfgVehicles { + class LandVehicle; + class Car: LandVehicle { + TOW_ACTION; + }; + + class Tank: LandVehicle { + TOW_ACTION; + }; + + class ThingX; + class GVAR(hook): ThingX { + displayName = "hook"; // not publicly visible, no stringtable needed + scope = 1; + scopeCurator = 1; + model = "\a3\Structures_F_Orange\VR\Helpers\Sign_sphere10cm_Geometry_F.p3d"; + destrType = "DestructNo"; + + class ACE_Actions { + class ACE_MainActions { + displayName = CSTRING(detach); + condition = "true"; + statement = QUOTE(private _parent = _target getVariable [ARR_2(QQGVAR(parent), objNull)]; private _child = _target getVariable [ARR_2(QQGVAR(child), objNull)]; [ARR_3(_player,_parent,_child)] call FUNC(detach)); + distance = 2; + }; + }; + }; +}; diff --git a/addons/towing/README.md b/addons/towing/README.md new file mode 100644 index 0000000000..cbd2f0103c --- /dev/null +++ b/addons/towing/README.md @@ -0,0 +1,11 @@ +ace_towing +=================== + +Adds the ability to tow vehicles. + + +## Maintainers + +The people responsible for merging changes to this component or answering potential questions. + +- [Brandon (TCVM)](https://github.com/TheCandianVendingMachine) diff --git a/addons/towing/XEH_PREP.hpp b/addons/towing/XEH_PREP.hpp new file mode 100644 index 0000000000..f3937e01c3 --- /dev/null +++ b/addons/towing/XEH_PREP.hpp @@ -0,0 +1,8 @@ +PREP(attachRopePFH); +PREP(canStartTow); +PREP(detach); +PREP(isSuitableSimulation); +PREP(onMouseButtonDown); +PREP(onMouseButtonUp); +PREP(startTow); +PREP(towStateMachinePFH); diff --git a/addons/towing/XEH_postInit.sqf b/addons/towing/XEH_postInit.sqf new file mode 100644 index 0000000000..455532f889 --- /dev/null +++ b/addons/towing/XEH_postInit.sqf @@ -0,0 +1,14 @@ +#include "script_component.hpp" +["MouseButtonDown", LINKFUNC(onMouseButtonDown)] call CBA_fnc_addDisplayHandler; +["MouseButtonUp", LINKFUNC(onMouseButtonUp)] call CBA_fnc_addDisplayHandler; +GVAR(mouseLeft) = false; +GVAR(mouseRight) = false; + +GVAR(cancel) = false; +GVAR(canAttach) = false; + +[QGVAR(setTowParent), { + params ["_parent", "_child"]; + _child setTowParent _parent; +}] call CBA_fnc_addEventHandler; + diff --git a/addons/towing/XEH_preInit.sqf b/addons/towing/XEH_preInit.sqf new file mode 100644 index 0000000000..b47cf6628d --- /dev/null +++ b/addons/towing/XEH_preInit.sqf @@ -0,0 +1,9 @@ +#include "script_component.hpp" + +ADDON = false; + +PREP_RECOMPILE_START; +#include "XEH_PREP.hpp" +PREP_RECOMPILE_END; + +ADDON = true; diff --git a/addons/towing/XEH_preStart.sqf b/addons/towing/XEH_preStart.sqf new file mode 100644 index 0000000000..022888575e --- /dev/null +++ b/addons/towing/XEH_preStart.sqf @@ -0,0 +1,3 @@ +#include "script_component.hpp" + +#include "XEH_PREP.hpp" diff --git a/addons/towing/config.cpp b/addons/towing/config.cpp new file mode 100644 index 0000000000..32b80109ea --- /dev/null +++ b/addons/towing/config.cpp @@ -0,0 +1,19 @@ +#include "script_component.hpp" + +class CfgPatches { + class ADDON { + name = COMPONENT_NAME; + units[] = {}; + weapons[] = {}; + requiredVersion = REQUIRED_VERSION; + requiredAddons[] = {"ace_common", "ace_logistics_rope"}; + author = ECSTRING(common,ACETeam); + authors[] = {"Brandon (TCVM)"}; + url = ECSTRING(main,URL); + VERSION_CONFIG; + }; +}; + +#include "CfgEventHandlers.hpp" +#include "CfgVehicles.hpp" + diff --git a/addons/towing/functions/fnc_attachRopePFH.sqf b/addons/towing/functions/fnc_attachRopePFH.sqf new file mode 100644 index 0000000000..5fd9fd6f32 --- /dev/null +++ b/addons/towing/functions/fnc_attachRopePFH.sqf @@ -0,0 +1,79 @@ +#include "script_component.hpp" +/* + * Author: Brandon (TCVM) + * PFH which allows the user to attach a rope to the given target vehicle + * + * Arguments: + * 0: Unit wanting to attach rope + * 1: Vehicle to attach rope + * + * Return Value: + * None + * + * Example: + * [player, cursorObject] call ace_towing_fnc_attachRopePFH + * + * Public: No + */ +params ["_unit", "_target", "_ignoreParent", "_ignoreRope", "_source", "_maxRange"]; + +private _viewDirection = getCameraViewDirection _unit; +GVAR(attachHelper) setPosASL (_unit modelToWorldVisualWorld [0, 1, 1.5]); + +private _hintLMB = ""; +private _hintRMB = localize ELSTRING(dragging,Drop); + +private _startPos = eyePos _unit; +private _endPos = _startPos vectorAdd (_viewDirection vectorMultiply TOW_ACTION_DISTANCE); +private _intersections = lineIntersectsSurfaces [_startPos, _endPos, _unit, GVAR(attachHelper), true, 2]; +GVAR(canAttach) = false; +if (_intersections isNotEqualTo []) then { + private _intersectionToUse = []; + { + _x params ["", "", "_object"]; + if (_object isKindOf "AllVehicles" && { _object isNotEqualTo _ignoreRope && { _object isNotEqualTo _ignoreParent } }) exitWith { + _intersectionToUse = _x; + }; + } forEach _intersections; + + if (_intersectionToUse isEqualTo []) exitWith {}; + + _intersectionToUse params ["_intersectPosition", "", "_intersectObject"]; + + // if we have a target object, we assume we are attaching to the parent. If no target object, we are attaching to child + GVAR(canAttach) = (_intersectObject isNotEqualTo _ignoreParent) && { (!isNull _target && { _intersectObject isEqualTo _target }) || { isNull _target && { [_intersectObject] call FUNC(isSuitableSimulation) }}} && { !(_intersectObject getVariable [QGVAR(towing), false]) }; + + if (GVAR(canAttach)) then { + TRACE_4("can attach",_target,_intersectObject,_ignoreParent,_ignoreRope); + GVAR(attachHelper) setPosASL _intersectPosition; + _hintLMB = localize LSTRING(attach); + + GVAR(attachHelper) setVariable [QGVAR(object), _intersectObject]; + }; + +}; + +if (_source isNotEqualTo [0, 0, 0]) then { + private _distanceFromSource = _source vectorDistance getPosASLVisual GVAR(attachHelper); + if (_distanceFromSource > _maxRange) then { + GVAR(canAttach) = false; + + private _direction = _source vectorFromTo getPosASLVisual GVAR(attachHelper); + GVAR(attachHelper) setPosASL (_source vectorAdd (_direction vectorMultiply _maxRange)); + + _hintLMB = ""; + + if (_distanceFromSource > _maxRange + 2) then { + GVAR(cancel) = true; + } else { + GVAR(cancel) = false; + }; + }; +}; + +private _hint = [_hintLMB, _hintRMB]; +if (_hint isNotEqualTo (_unit getVariable [QGVAR(hint), []])) then { + _unit setVariable [QGVAR(hint), _hint]; + _hint call EFUNC(interaction,showMouseHint); +}; + diff --git a/addons/towing/functions/fnc_canStartTow.sqf b/addons/towing/functions/fnc_canStartTow.sqf new file mode 100644 index 0000000000..593762c68c --- /dev/null +++ b/addons/towing/functions/fnc_canStartTow.sqf @@ -0,0 +1,21 @@ +#include "script_component.hpp" +/* + * Author: Brandon (TCVM) + * Condition for whether or not we can tow from this object + * + * Arguments: + * 0: Unit wanting to start towing + * 1: Vehicle to tow from + * + * Return Value: + * Whether or not we can start towing + * + * Example: + * [player, cursorObject] call ace_towing_fnc_canStartTow + * + * Public: No + */ +params ["_unit", "_target"]; +private _isTowing = _target getVariable [QGVAR(towing), false]; +TRACE_1("is towing",_isTowing); +!_isTowing diff --git a/addons/towing/functions/fnc_detach.sqf b/addons/towing/functions/fnc_detach.sqf new file mode 100644 index 0000000000..e7cd95e079 --- /dev/null +++ b/addons/towing/functions/fnc_detach.sqf @@ -0,0 +1,48 @@ +#include "script_component.hpp" +/* + * Author: Brandon (TCVM) + * Detaches child from parent, and gives rope item back + * + * Arguments: + * 0: Parent + * 1: Child + * + * Return Value: + * None + * + * Example: + * [player, cursorObject] call ace_towing_fnc_detach + * + * Public: No + */ +params ["_unit", "_parent", "_child"]; +TRACE_3("detach",_unit,_parent,_child); + +private _hook = _child getVariable [QGVAR(hook), objNull]; + +_parent removeEventHandler ["Deleted", _hook getVariable QGVAR(parentDeleteEventHandler)]; +_hook setVariable [QGVAR(parentDeleteEventHandler), -1]; + +_child removeEventHandler ["Deleted", _hook getVariable QGVAR(childDeleteEventHandler)]; +_hook setVariable [QGVAR(childDeleteEventHandler), -1]; + +_parent removeEventHandler ["RopeBreak", _parent getVariable QGVAR(ropeBreakEventHandler)]; +_parent setVariable [QGVAR(ropeBreakEventHandler), -1]; + +private _rope = _child getVariable [QGVAR(rope), objNull]; +ropeDestroy _rope; + +private _ropeClass = _hook getVariable [QGVAR(ropeClass), ""]; +deleteVehicle _hook; + +TRACE_1("rope",_ropeClass); + +if (_ropeClass isNotEqualTo "") then { + [_unit, _ropeClass, true] call CBA_fnc_addItem; +}; + +[QGVAR(setTowParent), [objNull, _child], _child] call CBA_fnc_targetEvent; + +_child setVariable [QGVAR(towing), false, true]; +_parent setVariable [QGVAR(towing), false, true]; + diff --git a/addons/towing/functions/fnc_isSuitableSimulation.sqf b/addons/towing/functions/fnc_isSuitableSimulation.sqf new file mode 100644 index 0000000000..076b7933c3 --- /dev/null +++ b/addons/towing/functions/fnc_isSuitableSimulation.sqf @@ -0,0 +1,26 @@ +#include "script_component.hpp" +/* + * Author: Brandon (TCVM) + * Condition for whether or not this object is a simulation type which can be a tow parent (TankX or CarX) + * + * Arguments: + * 0: Vehicle to tow from + * 1: Check type - Parent or Child + * + * Return Value: + * Whether or not this vehicle can tow + * + * Example: + * [cursorObject] call ace_towing_fnc_isSuitableSimulation + * + * Public: No + */ +params ["_target"]; + +// need toLower since apparently this isn't case sensitive +private _simulationType = getText ((configOf _target) >> "simulation"); +TRACE_1("sim type",_simulationType); + +// Biki lies, you can both tow and tow as either TankX or CarX +(toLower _simulationType) in ["tankx", "carx"] + diff --git a/addons/towing/functions/fnc_onMouseButtonDown.sqf b/addons/towing/functions/fnc_onMouseButtonDown.sqf new file mode 100644 index 0000000000..a20c2cf38c --- /dev/null +++ b/addons/towing/functions/fnc_onMouseButtonDown.sqf @@ -0,0 +1,26 @@ +#include "script_component.hpp" +/* + * Author: Brandon (TCVM) + * Handles mouse interaction for attaching rope + * + * Arguments: + * None + * + * Return Value: + * None + * + * Example: + * [] call ace_towing_fnc_onMouseButtonDown + * + * Public: No + */ +params ["", "_button"]; + +if (_button > 1) exitWith {}; + +if (_button == 1) then { + GVAR(mouseRight) = true; +} else { + GVAR(mouseLeft) = true; +} + diff --git a/addons/towing/functions/fnc_onMouseButtonUp.sqf b/addons/towing/functions/fnc_onMouseButtonUp.sqf new file mode 100644 index 0000000000..ff0bac85d3 --- /dev/null +++ b/addons/towing/functions/fnc_onMouseButtonUp.sqf @@ -0,0 +1,26 @@ +#include "script_component.hpp" +/* + * Author: Brandon (TCVM) + * Handles mouse interaction for attaching rope + * + * Arguments: + * None + * + * Return Value: + * None + * + * Example: + * [] call ace_towing_fnc_onMouseButtonUp + * + * Public: No + */ +params ["", "_button"]; + +if (_button > 1) exitWith {}; + +if (_button == 1) then { + GVAR(mouseRight) = false; +} else { + GVAR(mouseLeft) = false; +} + diff --git a/addons/towing/functions/fnc_startTow.sqf b/addons/towing/functions/fnc_startTow.sqf new file mode 100644 index 0000000000..d216576499 --- /dev/null +++ b/addons/towing/functions/fnc_startTow.sqf @@ -0,0 +1,33 @@ +#include "script_component.hpp" +/* + * Author: Brandon (TCVM) + * Start rope attach PFH + * + * Arguments: + * 0: Unit wanting to start towing + * 1: Vehicle to tow from + * 2: Rope Classname + * + * Return Value: + * None + * + * Example: + * [player, cursorObject, "ACE_rope3"] call ace_towing_fnc_startTow + * + * Public: No + */ +params ["_unit", "_target", "_ropeClass"]; + +GVAR(attachHelper) = "Sign_Sphere10cm_F" createVehicleLocal [0, 0, 0]; +[_unit] call EFUNC(weaponselect,putWeaponAway); + +private _ropeLength = getNumber (configFile >> "CfgWeapons" >> _ropeClass >> QEGVAR(logistics_rope,length)); +if (_ropeLength == 0) then { + _ropeLength = 3; +}; + +_unit removeItem _ropeClass; + +GVAR(canAttach) = false; +[LINKFUNC(towStateMachinePFH), 0, [TOW_STATE_ATTACH_PARENT, _unit, _target, objNull, _ropeLength, _ropeClass]] call CBA_fnc_addPerFrameHandler; + diff --git a/addons/towing/functions/fnc_towStateMachinePFH.sqf b/addons/towing/functions/fnc_towStateMachinePFH.sqf new file mode 100644 index 0000000000..ef642e5cc8 --- /dev/null +++ b/addons/towing/functions/fnc_towStateMachinePFH.sqf @@ -0,0 +1,144 @@ +#include "script_component.hpp" +/* + * Author: Brandon (TCVM) + * Called per frame. Handles current unit state for attaching a rope to two vehicles + * + * Arguments: + * 0: PFEH Args + * 1: PFID + * + * Return Value: + * None + * + * Example: + * [[],0]] call ace_towing_fnc_towStateMachinePFH + * + * Public: No + */ +params ["_args", "_handle"]; +_args params ["_state", "_unit", "_parent", "_rope", "_length", "_ropeClass"]; + +private _exitCondition = !( + (alive GVAR(attachHelper)) && + { alive _target } && + { alive _unit } && + { "" isEqualTo currentWeapon _unit || { _unit call EFUNC(common,isSwimming) }} && + { [_unit, objNull, [INTERACTION_EXCEPTIONS]] call EFUNC(common,canInteractWith) } && + { "unconscious" isNotEqualTo toLower animationState _unit } && + { !(_unit getVariable ["ACE_isUnconscious", false]) } +); + +if (_exitCondition) then { + _state = TOW_STATE_CANCEL; +}; + +switch (_state) do { + case TOW_STATE_ATTACH_PARENT: { + TRACE_2("state attach parent",_unit,_parent); + [_unit, _parent, objNull, objNull, [0, 0, 0], _length] call FUNC(attachRopePFH); + + if (GVAR(canAttach) && { GVAR(mouseLeft) }) then { + _args set [0, TOW_STATE_ATTACH_CHILD]; + _rope = ropeCreate [_parent, _parent worldToModelVisual ASLtoAGL getPosASLVisual GVAR(attachHelper), _length]; + [GVAR(attachHelper), [0, 0, 0]] ropeAttachTo _rope; + + _args set [3, _rope]; + }; + + if (GVAR(mouseRight)) then { + _args set [0, TOW_STATE_CANCEL]; + }; + }; + case TOW_STATE_ATTACH_CHILD: { + TRACE_3("state attach child",_unit,_parent,_rope); + [_unit, objNull, _parent, _rope, getPosASLVisual _rope, _length] call FUNC(attachRopePFH); + + if (GVAR(canAttach) && { GVAR(mouseLeft) }) then { + _args set [0, TOW_STATE_ATTACH]; + }; + + if (GVAR(mouseRight) || GVAR(cancel)) then { + _args set [0, TOW_STATE_CANCEL]; + GVAR(cancel) = false; + }; + }; + case TOW_STATE_ATTACH: { + TRACE_3("state attach",GVAR(attachHelper),_parent,_rope); + private _child = GVAR(attachHelper) getVariable [QGVAR(object), objNull]; + private _relativeAttachPos = _child worldToModelVisual ASLtoAGL getPosASLVisual GVAR(attachHelper); + + TRACE_3("child&pos",_parent,_child,_relativeAttachPos); + + if (_child isEqualTo _parent) exitWith { + _args set [0, TOW_STATE_CANCEL]; + ERROR_MSG("_child isEqualTo _parent"); + }; + + [QGVAR(setTowParent), [_parent, _child], _parent] call CBA_fnc_targetEvent; + + GVAR(attachHelper) ropeDetach _rope; + [_child, _relativeAttachPos] ropeAttachTo _rope; + + private _hook = createVehicle [QGVAR(hook), [0, 0, 0], [], 0, "NONE"]; + _hook attachTo [_child, _relativeAttachPos]; + + _hook setVariable [QGVAR(parent), _parent, true]; + _hook setVariable [QGVAR(child), _child, true]; + _child setVariable [QGVAR(rope), _rope, true]; + _child setVariable [QGVAR(hook), _hook, true]; + + _parent setVariable [QGVAR(hook), _hook, true]; + + _hook setVariable [QGVAR(ropeClass), _ropeClass, true]; + + _child setVariable [QGVAR(towing), true, true]; + _parent setVariable [QGVAR(towing), true, true]; + + _hook setVariable [QGVAR(parentDeleteEventHandler), _parent addEventHandler ["Deleted", { + params ["_entity"]; + + private _hook = _entity getVariable [QGVAR(hook), objNull]; + private _child = _hook getVariable [QGVAR(child), objNull]; + private _parent = _hook getVariable [QGVAR(parent), objNull]; + + [objNull, _parent, _child] call FUNC(detach); + }], true]; + + _hook setVariable [QGVAR(childDeleteEventHandler), _child addEventHandler ["Deleted", { + params ["_entity"]; + + private _hook = _entity getVariable [QGVAR(hook), objNull]; + private _child = _hook getVariable [QGVAR(child), objNull]; + private _parent = _hook getVariable [QGVAR(parent), objNull]; + + [objNull, _parent, _child] call FUNC(detach); + }], true]; + + _parent setVariable [QGVAR(ropeBreakEventHandler), _parent addEventHandler ["RopeBreak", { + params ["_parent", "_rope", "_child"]; + + [objNull, _parent, _child] call FUNC(detach); + + _parent removeEventHandler ["RopeBreak", _parent getVariable QGVAR(ropeBreakEventHandler)]; + _parent setVariable [QGVAR(ropeBreakEventHandler), -1]; + }], true]; + + _args set [0, TOW_STATE_CLEANUP]; + }; + case TOW_STATE_CANCEL: { + TRACE_1("state cancel",_rope); + ropeDestroy _rope; + [_unit, _ropeClass, true] call CBA_fnc_addItem; + _args set [0, TOW_STATE_CLEANUP]; + + (localize LSTRING(canceled)) call CBA_fnc_notify; + }; + case TOW_STATE_CLEANUP: { + TRACE_2("state cleanup",GVAR(attachHelper),_handle); + deleteVehicle GVAR(attachHelper); + [_handle] call CBA_fnc_removePerFrameHandler; + _unit setVariable [QGVAR(hint), []]; + call EFUNC(interaction,hideMouseHint); + }; +}; + diff --git a/addons/towing/functions/script_component.hpp b/addons/towing/functions/script_component.hpp new file mode 100644 index 0000000000..cb87a08576 --- /dev/null +++ b/addons/towing/functions/script_component.hpp @@ -0,0 +1 @@ +#include "\z\ace\addons\towing\script_component.hpp" \ No newline at end of file diff --git a/addons/towing/script_component.hpp b/addons/towing/script_component.hpp new file mode 100644 index 0000000000..d3c12463c9 --- /dev/null +++ b/addons/towing/script_component.hpp @@ -0,0 +1,27 @@ +#define COMPONENT towing +#define COMPONENT_BEAUTIFIED Towing +#include "\z\ace\addons\main\script_mod.hpp" + +// #define DEBUG_MODE_FULL +// #define DISABLE_COMPILE_CACHE +// #define ENABLE_PERFORMANCE_COUNTERS + +#ifdef DEBUG_ENABLED_TOWING + #define DEBUG_MODE_FULL +#endif + +#ifdef DEBUG_SETTINGS_TOWING + #define DEBUG_SETTINGS DEBUG_SETTINGS_TOWING +#endif + +#include "\z\ace\addons\main\script_macros.hpp" + +#define TOW_ACTION_DISTANCE 3 +#define INTERACTION_EXCEPTIONS "isNotInside", "isNotOnLadder", "isNotSwimming" + +#define TOW_STATE_ATTACH_PARENT 0 +#define TOW_STATE_ATTACH_CHILD 1 +#define TOW_STATE_ATTACH 2 +#define TOW_STATE_CANCEL 3 +#define TOW_STATE_CLEANUP 4 + diff --git a/addons/towing/stringtable.xml b/addons/towing/stringtable.xml new file mode 100644 index 0000000000..aaf5e6a234 --- /dev/null +++ b/addons/towing/stringtable.xml @@ -0,0 +1,38 @@ + + + + + Towing + + + Attach Tow Rope + + + Attaching Cancelled + + + Attach Tow Rope (3.2m) + + + Attach Tow Rope (6.2m) + + + Attach Tow Rope (12.2m) + + + Attach Tow Rope (15.2m) + + + Attach Tow Rope (18.2m) + + + Attach Tow Rope (27.2m) + + + Attach Tow Rope (36.2m) + + + Detach Tow Rope + + + \ No newline at end of file