From 92cdee443e96601fd3e992c463afb1212bcb5559 Mon Sep 17 00:00:00 2001 From: mharis001 Date: Fri, 23 Aug 2019 20:34:39 -0400 Subject: [PATCH 1/6] Add Throw Grenade context menu action --- addons/ai/XEH_PREP.hpp | 1 + addons/ai/XEH_postInit.sqf | 3 +- addons/ai/functions/fnc_throwGrenade.sqf | 88 ++++++++++++++++++ addons/context_actions/CfgContext.hpp | 14 ++- addons/context_actions/XEH_PREP.hpp | 3 + addons/context_actions/XEH_preInit.sqf | 2 + .../functions/fnc_compileGrenades.sqf | 35 +++++++ .../functions/fnc_getGrenadeActions.sqf | 49 ++++++++++ .../functions/fnc_selectThrowPos.sqf | 44 +++++++++ addons/context_actions/stringtable.xml | 6 ++ addons/context_actions/ui/grenade_ca.paa | Bin 0 -> 5625 bytes 11 files changed, 242 insertions(+), 3 deletions(-) create mode 100644 addons/ai/functions/fnc_throwGrenade.sqf create mode 100644 addons/context_actions/functions/fnc_compileGrenades.sqf create mode 100644 addons/context_actions/functions/fnc_getGrenadeActions.sqf create mode 100644 addons/context_actions/functions/fnc_selectThrowPos.sqf create mode 100644 addons/context_actions/ui/grenade_ca.paa diff --git a/addons/ai/XEH_PREP.hpp b/addons/ai/XEH_PREP.hpp index 909031ea9..b75b838c2 100644 --- a/addons/ai/XEH_PREP.hpp +++ b/addons/ai/XEH_PREP.hpp @@ -1,2 +1,3 @@ PREP(garrison); +PREP(throwGrenade); PREP(unGarrison); diff --git a/addons/ai/XEH_postInit.sqf b/addons/ai/XEH_postInit.sqf index e3c644f0a..575e8fc96 100644 --- a/addons/ai/XEH_postInit.sqf +++ b/addons/ai/XEH_postInit.sqf @@ -1,3 +1,4 @@ #include "script_component.hpp" -[QGVAR(unGarrison), FUNC(unGarrison)] call CBA_fnc_addEventHandler; +[QGVAR(throwGrenade), LINKFUNC(throwGrenade)] call CBA_fnc_addEventHandler; +[QGVAR(unGarrison), LINKFUNC(unGarrison)] call CBA_fnc_addEventHandler; diff --git a/addons/ai/functions/fnc_throwGrenade.sqf b/addons/ai/functions/fnc_throwGrenade.sqf new file mode 100644 index 000000000..1bd9433a0 --- /dev/null +++ b/addons/ai/functions/fnc_throwGrenade.sqf @@ -0,0 +1,88 @@ +#include "script_component.hpp" +/* + * Author: mharis001 + * Makes the unit throw a grenade at the given position. + * Must be called where the unit is local. + * + * Arguments: + * 0: Unit + * 1: Grenade Muzzle + * 2: Position ASL + * + * Return Value: + * None + * + * Example: + * [_unit, "HandGrenadeMuzzle", [0, 0, 0]] call zen_ai_fnc_throwGrenade + * + * Public: No + */ + +#define AIMING_TIMEOUT 10 +#define INITIAL_DELAY 0.5 +#define CLEANUP_DELAY 1.5 + +#define TOLERANCE_TIME 2 +#define MIN_TOLERANCE 10 +#define MAX_TOLERANCE 45 + +params ["_unit", "_muzzle", "_position"]; + +// Create a helper object for the unit to target +private _helper = "Land_HelipadEmpty_F" createVehicleLocal [0, 0, 0]; +_helper setPosASL _position; + +// Make the unit target the helper object +_unit reveal _helper; +_unit doWatch _helper; +_unit doTarget _helper; + +// Disable AI intelligence until unit throws the grenade +// Also interrupts a unit's movement to a waypoint, forcing them to stop +_unit disableAI "FSM"; +_unit disableAI "PATH"; + +// Wait until the unit is aiming at the helper object before throwing the grenade +// Initial delay helps prevent weird issue when the unit is moving to a waypoint and the helper is directly in front of it +[{ + _this set [2, CBA_missionTime]; + + [ + { + params ["_unit", "_helper", "_startTime"]; + + if (!alive _unit) exitWith {false}; + + // Check that the unit is aiming at the helper, increase tolerance as more time passes + private _direction = _unit getRelDir _helper; + private _tolerance = linearConversion [0, TOLERANCE_TIME, CBA_missionTime - _startTime, MIN_TOLERANCE, MAX_TOLERANCE, true]; + + _direction <= _tolerance || {_direction >= 360 - _tolerance} + }, + { + params ["_unit", "_helper", "", "_muzzle"]; + + if (alive _unit) then { + [_unit, _muzzle] call BIS_fnc_fire; + + // Reset AI intelligence and targeting + [{ + params ["_unit"]; + + _unit enableAI "FSM"; + _unit enableAI "PATH"; + _unit doWatch objNull; + }, _unit, CLEANUP_DELAY] call CBA_fnc_waitAndExecute; + }; + + deleteVehicle _helper; + }, + _this, + AIMING_TIMEOUT, + { + params ["", "_helper"]; + + deleteVehicle _helper; + } + ] call CBA_fnc_waitUntilAndExecute; +}, [_unit, _helper, 0, _muzzle], INITIAL_DELAY] call CBA_fnc_waitAndExecute; diff --git a/addons/context_actions/CfgContext.hpp b/addons/context_actions/CfgContext.hpp index 7bd4d5496..135cab936 100644 --- a/addons/context_actions/CfgContext.hpp +++ b/addons/context_actions/CfgContext.hpp @@ -1,8 +1,15 @@ class EGVAR(context_menu,actions) { + class ThrowGrenade { + displayName = CSTRING(ThrowGrenade); + icon = QPATHTOF(ui\grenade_ca.paa); + priority = -50; + insertChildren = QUOTE([_selectedObjects] call FUNC(getGrenadeActions)); + }; class Formation { displayName = "$STR_3DEN_Group_Attribute_Formation_displayName"; icon = "\a3\3den\data\displays\display3den\entitymenu\movetoformation_ca.paa"; condition = QUOTE(!(_selectedGroups isEqualTo [])); + priority = -60; class Wedge { displayName = "$STR_wedge"; icon = "\a3\Ui_F_Curator\Data\RscCommon\RscAttributeFormation\wedge_ca.paa"; @@ -61,6 +68,7 @@ class EGVAR(context_menu,actions) { class Behaviour { displayName = "$STR_3DEN_Group_Attribute_Behaviour_displayName"; condition = QUOTE(!(_selectedGroups isEqualTo [])); + priority = -61; class Careless { displayName = "$STR_3DEN_Attributes_Behaviour_Careless_text"; icon = QPATHTOF(ui\careless_ca.paa); @@ -94,6 +102,7 @@ class EGVAR(context_menu,actions) { class Speed { displayName = "$STR_HC_Menu_Speed"; condition = QUOTE(!(_selectedGroups isEqualTo [])); + priority = -62; class Limited { displayName = "$STR_speed_limited"; icon = "\a3\Ui_F_Curator\Data\RscCommon\RscAttributeSpeedMode\limited_ca.paa"; @@ -116,6 +125,7 @@ class EGVAR(context_menu,actions) { class Stance { displayName = "$STR_A3_RscAttributeUnitPos_Title"; condition = QUOTE(_selectedObjects findIf {_x isKindOf 'CAManBase' && {!isPlayer _x}} > -1); + priority = -63; class Auto { displayName = "$STR_A3_RscAttributeUnitPos_Auto_tooltip"; icon = QPATHTOF(ui\default_ca.paa); @@ -141,6 +151,7 @@ class EGVAR(context_menu,actions) { displayName = ECSTRING(modules,ModuleHeal); icon = QPATHTOF(ui\medical_cross_ca.paa); condition = QUOTE(_selectedObjects findIf {crew _x findIf {_x isKindOf 'CAManBase' && {alive _x}} != -1} != -1); + priority = -70; class All { displayName = ECSTRING(common,All); statement = QUOTE([ARR_2(_selectedObjects,HEAL_MODE_ALL)] call FUNC(healUnits)); @@ -158,7 +169,6 @@ class EGVAR(context_menu,actions) { statement = QUOTE([ARR_2(_selectedObjects,HEAL_MODE_PLAYERS)] call FUNC(healUnits)); priority = 1; }; - priority = -70; }; class VehicleLogistics { displayName = CSTRING(VehicleLogistics); @@ -179,6 +189,7 @@ class EGVAR(context_menu,actions) { } \ } != -1 \ ); + priority = -71; class Repair { displayName = CSTRING(Repair); icon = "\A3\ui_f\data\igui\cfg\simpleTasks\types\repair_ca.paa"; @@ -206,7 +217,6 @@ class EGVAR(context_menu,actions) { statement = QUOTE(_selectedObjects call FUNC(refuelVehicles)); priority = 1; }; - priority = -71; }; class Loadout { displayName = "$STR_3den_display3den_entitymenu_arsenal_text"; diff --git a/addons/context_actions/XEH_PREP.hpp b/addons/context_actions/XEH_PREP.hpp index aedfdd675..b601e2f00 100644 --- a/addons/context_actions/XEH_PREP.hpp +++ b/addons/context_actions/XEH_PREP.hpp @@ -1,7 +1,10 @@ +PREP(compileGrenades); +PREP(getGrenadeActions); PREP(healUnits); PREP(rearmVehicles); PREP(refuelVehicles); PREP(repairVehicles); +PREP(selectThrowPos); PREP(setBehaviour); PREP(setFormation); PREP(setSpeed); diff --git a/addons/context_actions/XEH_preInit.sqf b/addons/context_actions/XEH_preInit.sqf index b47cf6628..a360174e0 100644 --- a/addons/context_actions/XEH_preInit.sqf +++ b/addons/context_actions/XEH_preInit.sqf @@ -6,4 +6,6 @@ PREP_RECOMPILE_START; #include "XEH_PREP.hpp" PREP_RECOMPILE_END; +call FUNC(compileGrenades); + ADDON = true; diff --git a/addons/context_actions/functions/fnc_compileGrenades.sqf b/addons/context_actions/functions/fnc_compileGrenades.sqf new file mode 100644 index 000000000..f20f1df53 --- /dev/null +++ b/addons/context_actions/functions/fnc_compileGrenades.sqf @@ -0,0 +1,35 @@ +#include "script_component.hpp" +/* + * Author: mharis001 + * Compiles a list of all throwable grenades. + * + * Arguments: + * None + * + * Return Value: + * None + * + * Example: + * [] call zen_context_actions_fnc_compileGrenades + * + * Public: No + */ + +GVAR(grenades) = [] call CBA_fnc_createNamespace; +GVAR(grenadesList) = []; // For fast filtering of non-grenade magazines + +private _cfgWeapons = configFile >> "CfgWeapons"; +private _cfgMagazines = configFile >> "CfgMagazines"; + +{ + private _muzzle = _x; + + { + private _config = _cfgMagazines >> _x; + private _displayName = getText (_config >> "displayName"); + private _picture = getText (_config >> "picture"); + + GVAR(grenades) setVariable [_x, [_displayName, _picture, _x, _muzzle]]; + GVAR(grenadesList) pushBackUnique _x; + } forEach getArray (_cfgWeapons >> "Throw" >> _muzzle >> "magazines"); +} forEach getArray (_cfgWeapons >> "Throw" >> "muzzles"); diff --git a/addons/context_actions/functions/fnc_getGrenadeActions.sqf b/addons/context_actions/functions/fnc_getGrenadeActions.sqf new file mode 100644 index 000000000..f47559e7a --- /dev/null +++ b/addons/context_actions/functions/fnc_getGrenadeActions.sqf @@ -0,0 +1,49 @@ +#include "script_component.hpp" +/* + * Author: mharis001 + * Returns children actions based on grenades in selected AI's inventories. + * + * Arguments: + * 0: Selected Objects + * + * Return Value: + * Actions + * + * Example: + * [[_unit1, _unit2]] call zen_context_actions_fnc_getGrenadeActions + * + * Public: No + */ + +params ["_objects"]; + +// Get all magazines in the inventories of on foot AI +private _magazines = []; +{ + if (!isPlayer _x && {vehicle _x == _x}) then { + _magazines append magazines _x; + }; +} forEach _objects; + +// Filter out non-grenade magazines, sort alphabetically by display name +private _grenades = _magazines arrayIntersect GVAR(grenadesList) apply {GVAR(grenades) getVariable _x}; +_grenades sort true; + +private _actions = []; + +{ + _x params ["_displayName", "_picture", "_magazine", "_muzzle"]; + + private _action = [ + format [QGVAR(%1), _forEachIndex], + _displayName, + _picture, + {[_selectedObjects, _args] call FUNC(selectThrowPos)}, + {true}, + [_magazine, _muzzle] + ] call EFUNC(context_menu,createAction); + + _actions pushBack [_action, [], 0]; +} forEach _grenades; + +_actions diff --git a/addons/context_actions/functions/fnc_selectThrowPos.sqf b/addons/context_actions/functions/fnc_selectThrowPos.sqf new file mode 100644 index 000000000..5336c66b1 --- /dev/null +++ b/addons/context_actions/functions/fnc_selectThrowPos.sqf @@ -0,0 +1,44 @@ +#include "script_component.hpp" +/* + * Author: mharis001 + * Allows Zeus to select a position to make AI throw grenades at. + * + * Arguments: + * 0: Selected Objects + * 1: Arguments + * + * Return Value: + * None + * + * Example: + * [[_unit1, _unit2], ["HandGrenade", "HandGrenadeMuzzle"]] call zen_context_actions_fnc_selectThrowPos + * + * Public: No + */ + +#define MAX_DISTANCE 50 + +_args params ["_magazine", "_muzzle"]; + +// Get AI units that are alive, on foot, and have the selected grenade type +private _units = _selectedObjects select { + alive _x + && {!isPlayer _x} + && {_x isKindOf "CAManBase"} + && {vehicle _x == _x} + && {_magazine in magazines _x} +}; + +private _text = format [localize LSTRING(ThrowX), getText (configFile >> "CfgMagazines" >> _magazine >> "displayName")]; + +[_units, { + params ["_successful", "_units", "_position", "_muzzle"]; + + if (!_successful) exitWith {}; + + { + if (_x distance2D _position < MAX_DISTANCE) then { + [QEGVAR(ai,throwGrenade), [_x, _muzzle, _position], _x] call CBA_fnc_targetEvent; + }; + } forEach _units; +}, _muzzle, _text] call EFUNC(common,getTargetPos); diff --git a/addons/context_actions/stringtable.xml b/addons/context_actions/stringtable.xml index 3d848a405..d381175c7 100644 --- a/addons/context_actions/stringtable.xml +++ b/addons/context_actions/stringtable.xml @@ -1,6 +1,12 @@ + + Throw Grenade + + + Throw %1 + Edit Inventory Редактировать снаряжение diff --git a/addons/context_actions/ui/grenade_ca.paa b/addons/context_actions/ui/grenade_ca.paa new file mode 100644 index 0000000000000000000000000000000000000000..c215d51ef7b8fb4809955e77affd4c8bd5f04a1d GIT binary patch literal 5625 zcmeHLTWl0n7(UbPP|(yau@f)QP)+fY5Q9|rrRYv2X;~{Wi91SS6nn7>kzJyu`p|V- zUYhdITQE&Sv<)#5HYU(SCnkNUu}O<@6C{9fyP%{M3PnqyA(lGJ`2A;Qwsl$@N-4yI zKYRQ3%sK!0{>wT4IigWoS{&R^`f9O#ABDzerN z;Ek8z9>RFmz`LNM;CA5;Nq=BGtv}~`;6r&yQ-3hHQ2!C%B422N#*-vbTsN75u8Ays z5L4EA96#dWVQL2yVq}Ww_;2{+?JR~LfeZvNZ&$11!0|A*A3bk9#RHtibHg!c!uWmG zcybdT|1HiJ-Bs^T4SC5!J2+O9AbEs~?Z5frmJVNNq$V^%`b0?Uaer#SxP(bGmdP0G zkrTeq1?3vYqR3e0sBvX$bo`h-zghZ>ExT6ZMePE_jjywv#iHX`cyax*OjF=;v;189 z8!U4zUZjusoBq89`&%;`#gFI{;KBVX-#?VIGGWxH+8}BKFb~s{%-cqY(@TQ9_-jHuzsdgxVo`k{ zs`LDV{YfR4^ms9rlRA9RUf)w6Ni;PYul;IV8tBz| zyfZe({$x$q&R^&J7mB?@zKYlF{Q~h&kwQEi4*yR1fwAXZ@44BpYd?85u!+t*N@GNvd6=fA-S2O0Fmr*8X?d=R4gV8H}38bSg`qci~?f z*D8y&a=vY0S5==KY>y=BckpdiQM^*k@L02Pl~UhaAl#M-XS;W_J~HUnj}SjaabG4s zs3reRA8XhtghOD)wZ}Yh%PEYvO#hMetE#*Hf2^u%e|%$wy$oViRgtdgcEVNhW$(>wx9Ft#II)+m0tGgPF#Y!FJ-bPbDhfjN zDJ`3ozj={ktP|A+aG)J`I%vmsi^XFtx^Y@6@@kYlx#y|#ZAH{B6c-E2wD+5Ix@h7b(Qfsh zquR|)>dkt8HBT$>Qy)SC`;*hRM|lVSy(}zcOF@bi4lk)&m!E-$K?9~L?5ax*HmCR{ y4@FPmKHoN@Cd8+Snn%oU`BNY0UBinIG%FsgsIX_=$lzB?LT8TBFc^hKg8Tz`!ug>9 literal 0 HcmV?d00001 From 9a6ba3e8db39a48f6a7421ccbfbc7d714254a1c7 Mon Sep 17 00:00:00 2001 From: mharis001 Date: Fri, 23 Aug 2019 20:50:38 -0400 Subject: [PATCH 2/6] Fix selectThrowPos params --- addons/context_actions/functions/fnc_selectThrowPos.sqf | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/context_actions/functions/fnc_selectThrowPos.sqf b/addons/context_actions/functions/fnc_selectThrowPos.sqf index 5336c66b1..b5dab8f5e 100644 --- a/addons/context_actions/functions/fnc_selectThrowPos.sqf +++ b/addons/context_actions/functions/fnc_selectThrowPos.sqf @@ -18,6 +18,7 @@ #define MAX_DISTANCE 50 +params ["_selectedObjects", "_args"]; _args params ["_magazine", "_muzzle"]; // Get AI units that are alive, on foot, and have the selected grenade type From 34782fed91ba3ce5631a23784eb39de8a10a5f97 Mon Sep 17 00:00:00 2001 From: mharis001 Date: Sat, 24 Aug 2019 09:25:25 -0400 Subject: [PATCH 3/6] Change MAX_DISTANCE from 50 to 75 --- addons/context_actions/functions/fnc_selectThrowPos.sqf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/context_actions/functions/fnc_selectThrowPos.sqf b/addons/context_actions/functions/fnc_selectThrowPos.sqf index b5dab8f5e..ac8403d08 100644 --- a/addons/context_actions/functions/fnc_selectThrowPos.sqf +++ b/addons/context_actions/functions/fnc_selectThrowPos.sqf @@ -16,7 +16,7 @@ * Public: No */ -#define MAX_DISTANCE 50 +#define MAX_DISTANCE 75 params ["_selectedObjects", "_args"]; _args params ["_magazine", "_muzzle"]; From 0789d7aac73cf3f0151d25f96ea9572771e18d57 Mon Sep 17 00:00:00 2001 From: mharis001 Date: Sat, 24 Aug 2019 09:48:15 -0400 Subject: [PATCH 4/6] Add notification when units are too far from position --- addons/context_actions/functions/fnc_selectThrowPos.sqf | 8 ++++++++ addons/context_actions/stringtable.xml | 3 +++ 2 files changed, 11 insertions(+) diff --git a/addons/context_actions/functions/fnc_selectThrowPos.sqf b/addons/context_actions/functions/fnc_selectThrowPos.sqf index ac8403d08..1110b206e 100644 --- a/addons/context_actions/functions/fnc_selectThrowPos.sqf +++ b/addons/context_actions/functions/fnc_selectThrowPos.sqf @@ -37,9 +37,17 @@ private _text = format [localize LSTRING(ThrowX), getText (configFile >> "CfgMag if (!_successful) exitWith {}; + private _notInRange = 0; + { if (_x distance2D _position < MAX_DISTANCE) then { [QEGVAR(ai,throwGrenade), [_x, _muzzle, _position], _x] call CBA_fnc_targetEvent; + } else { + _notInRange = _notInRange + 1; }; } forEach _units; + + if (_notInRange > 0) then { + [LSTRING(PositionTooFar), _notInRange] call EFUNC(common,showMessage); + }; }, _muzzle, _text] call EFUNC(common,getTargetPos); diff --git a/addons/context_actions/stringtable.xml b/addons/context_actions/stringtable.xml index d381175c7..dabf01025 100644 --- a/addons/context_actions/stringtable.xml +++ b/addons/context_actions/stringtable.xml @@ -7,6 +7,9 @@ Throw %1 + + %1 units were too far away from the position + Edit Inventory Редактировать снаряжение From 62b228879dd8307af7ee8657e63764dc77a90de0 Mon Sep 17 00:00:00 2001 From: mharis001 Date: Fri, 6 Mar 2020 09:38:39 -0500 Subject: [PATCH 5/6] Fixes after merge --- addons/context_actions/CfgContext.hpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/addons/context_actions/CfgContext.hpp b/addons/context_actions/CfgContext.hpp index 9b5b353d1..f7f1cb502 100644 --- a/addons/context_actions/CfgContext.hpp +++ b/addons/context_actions/CfgContext.hpp @@ -221,14 +221,6 @@ class EGVAR(context_menu,actions) { statement = QUOTE(_objects call FUNC(toggleSurrender)); icon = "\z\ace\addons\captives\UI\Surrender_ca.paa"; }; - class Refuel { - displayName = CSTRING(Refuel); - icon = "\A3\ui_f\data\igui\cfg\simpleTasks\types\refuel_ca.paa"; - condition = QUOTE(_selectedObjects findIf {fuel _x < 1} != -1); - statement = QUOTE(_selectedObjects call FUNC(refuelVehicles)); - priority = 1; - }; - priority = -71; }; class Loadout { displayName = "$STR_A3_VR_Stamina_01_Loadout"; From 904d099472a273f7153b012eba0c28629c934c01 Mon Sep 17 00:00:00 2001 From: mharis001 Date: Mon, 23 Aug 2021 08:55:34 -0400 Subject: [PATCH 6/6] Various improvements - more consistent behaviour, use new commands --- AUTHORS.txt | 1 + addons/ai/XEH_PREP.hpp | 1 + addons/ai/XEH_postInit.sqf | 3 +- addons/ai/functions/fnc_canThrowGrenade.sqf | 28 ++++ addons/ai/functions/fnc_throwGrenade.sqf | 135 ++++++++++++------ addons/common/XEH_PREP.hpp | 2 + addons/common/functions/fnc_isSwimming.sqf | 20 +++ .../functions/fnc_parseMagazineDetail.sqf | 23 +++ addons/context_actions/CfgContext.hpp | 4 +- addons/context_actions/XEH_PREP.hpp | 1 - addons/context_actions/XEH_preInit.sqf | 2 - addons/context_actions/XEH_preStart.sqf | 2 + .../functions/fnc_compileGrenades.sqf | 17 +-- .../functions/fnc_getGrenadeActions.sqf | 43 +++--- .../functions/fnc_selectThrowPos.sqf | 34 ++--- addons/context_actions/stringtable.xml | 18 +-- addons/context_actions/ui/grenade_ca.paa | Bin 5625 -> 5625 bytes addons/main/script_mod.hpp | 2 +- 18 files changed, 225 insertions(+), 111 deletions(-) create mode 100644 addons/ai/functions/fnc_canThrowGrenade.sqf create mode 100644 addons/common/functions/fnc_isSwimming.sqf create mode 100644 addons/common/functions/fnc_parseMagazineDetail.sqf diff --git a/AUTHORS.txt b/AUTHORS.txt index 481f604b2..26fab3c6d 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -21,6 +21,7 @@ Beaumont Brett bux commy2 +das attorney Dedmen diwako Dystopian diff --git a/addons/ai/XEH_PREP.hpp b/addons/ai/XEH_PREP.hpp index d70fee63f..6efe5e16f 100644 --- a/addons/ai/XEH_PREP.hpp +++ b/addons/ai/XEH_PREP.hpp @@ -1,4 +1,5 @@ PREP(applySkills); +PREP(canThrowGrenade); PREP(garrison); PREP(handleObjectEdited); PREP(handleSkillsChange); diff --git a/addons/ai/XEH_postInit.sqf b/addons/ai/XEH_postInit.sqf index 2c7313ca1..7e0f6467b 100644 --- a/addons/ai/XEH_postInit.sqf +++ b/addons/ai/XEH_postInit.sqf @@ -1,8 +1,9 @@ #include "script_component.hpp" QGVAR(skills) addPublicVariableEventHandler LINKFUNC(handleSkillsChange); -[QGVAR(throwGrenade), LINKFUNC(throwGrenade)] call CBA_fnc_addEventHandler; ["CAManBase", "InitPost", LINKFUNC(initMan), true, [], false] call CBA_fnc_addClassEventHandler; +[QGVAR(throwGrenade), LINKFUNC(throwGrenade)] call CBA_fnc_addEventHandler; + [QGVAR(unGarrison), LINKFUNC(unGarrison)] call CBA_fnc_addEventHandler; diff --git a/addons/ai/functions/fnc_canThrowGrenade.sqf b/addons/ai/functions/fnc_canThrowGrenade.sqf new file mode 100644 index 000000000..6d7cfdae6 --- /dev/null +++ b/addons/ai/functions/fnc_canThrowGrenade.sqf @@ -0,0 +1,28 @@ +#include "script_component.hpp" +/* + * Author: mharis001 + * Checks if the given unit can throw a grenade. + * When specified, also checks if the unit has the given grenade magazine. + * + * Arguments: + * 0: Unit + * 1: Grenade Magazine (default: "") + * + * Return Value: + * Can Throw Grenade + * + * Example: + * [_unit, "HandGrenade"] call zen_ai_fnc_canThrowGrenade + * + * Public: No + */ + +params [["_unit", objNull, [objNull]], ["_magazine", "", [""]]]; + +alive _unit +&& {!isPlayer _unit} +&& {vehicle _unit == _unit} +&& {_unit isKindOf "CAManBase"} +&& {lifeState _unit in ["HEALTHY", "INJURED"]} +&& {!(_unit call EFUNC(common,isSwimming))} +&& {_magazine == "" || {_magazine in magazines _unit}} diff --git a/addons/ai/functions/fnc_throwGrenade.sqf b/addons/ai/functions/fnc_throwGrenade.sqf index 1bd9433a0..4a427fb70 100644 --- a/addons/ai/functions/fnc_throwGrenade.sqf +++ b/addons/ai/functions/fnc_throwGrenade.sqf @@ -2,18 +2,17 @@ /* * Author: mharis001 * Makes the unit throw a grenade at the given position. - * Must be called where the unit is local. * * Arguments: * 0: Unit - * 1: Grenade Muzzle + * 1: Grenade Magazine * 2: Position ASL * * Return Value: * None * * Example: - * [_unit, "HandGrenadeMuzzle", [0, 0, 0]] call zen_ai_fnc_throwGrenade + * [_unit, "HandGrenade", [0, 0, 0]] call zen_ai_fnc_throwGrenade * * Public: No */ @@ -26,63 +25,105 @@ #define MIN_TOLERANCE 10 #define MAX_TOLERANCE 45 -params ["_unit", "_muzzle", "_position"]; +#define DISABLED_ABILITIES ["AIMINGERROR", "AUTOTARGET", "FSM", "PATH", "SUPPRESSION", "TARGET"] + +params [ + ["_unit", objNull, [objNull]], + ["_magazine", "", [""]], + ["_position", [0, 0, 0], [[]], 3] +]; + +if (!local _unit) exitWith { + [QGVAR(throwGrenade), _this, _unit] call CBA_fnc_targetEvent; +}; + +// Exit if the unit cannot throw the given grenade type +if !([_unit, _magazine] call FUNC(canThrowGrenade)) exitWith {}; + +// Disable AI abilities to make units more responsive to commands +// Also interrupts a unit's movement to a waypoint, forcing them to stop +private _abilities = DISABLED_ABILITIES apply {_unit checkAIFeature _x}; +{_unit disableAI _x} forEach DISABLED_ABILITIES; + +// Set the unit's behaviour to COMBAT to make them raise their weapon and aim at the target +private _behaviour = combatBehaviour _unit; +_unit setCombatBehaviour "COMBAT"; + +// Set the unit's combat mode to BLUE to make them hold their fire +// The unit will still track the target but only fire when told to +private _combatMode = unitCombatMode _unit; +_unit setUnitCombatMode "BLUE"; + +// Prevent the unit from changing stance due to combat behaviour by +// forcing a unit position that matches their current stance +// Usually only a problem with the AUTO unit position +private _unitPos = unitPos _unit; +private _stanceIndex = ["STAND", "CROUCH", "PRONE"] find stance _unit; +private _unitPosForStance = ["UP", "MIDDLE", "DOWN"] param [_stanceIndex, "UP"]; +_unit setUnitPos _unitPosForStance; // Create a helper object for the unit to target -private _helper = "Land_HelipadEmpty_F" createVehicleLocal [0, 0, 0]; +private _helper = createVehicle ["CBA_B_InvisibleTargetVehicle", [0, 0, 0], [], 0, "CAN_COLLIDE"]; _helper setPosASL _position; // Make the unit target the helper object -_unit reveal _helper; +_unit reveal [_helper, 4]; +_unit lookAt _helper; _unit doWatch _helper; _unit doTarget _helper; -// Disable AI intelligence until unit throws the grenade -// Also interrupts a unit's movement to a waypoint, forcing them to stop -_unit disableAI "FSM"; -_unit disableAI "PATH"; - // Wait until the unit is aiming at the helper object before throwing the grenade // Initial delay helps prevent weird issue when the unit is moving to a waypoint and the helper is directly in front of it [{ - _this set [2, CBA_missionTime]; - - [ - { - params ["_unit", "_helper", "_startTime"]; - - if (!alive _unit) exitWith {false}; + _this set [7, CBA_missionTime]; - // Check that the unit is aiming at the helper, increase tolerance as more time passes - private _direction = _unit getRelDir _helper; - private _tolerance = linearConversion [0, TOLERANCE_TIME, CBA_missionTime - _startTime, MIN_TOLERANCE, MAX_TOLERANCE, true]; + [{ + params ["_unit", "_helper", "_magazine", "_abilities", "_behaviour", "_combatMode", "_unitPos", "_startTime"]; - _direction <= _tolerance || {_direction >= 360 - _tolerance} - }, - { - params ["_unit", "_helper", "", "_muzzle"]; + // Check that the unit is aiming at the helper, increase tolerance as more time passes + private _direction = _unit getRelDir _helper; + private _tolerance = linearConversion [0, TOLERANCE_TIME, CBA_missionTime - _startTime, MIN_TOLERANCE, MAX_TOLERANCE, true]; + private _throwGrenade = _direction <= _tolerance || {_direction >= 360 - _tolerance}; - if (alive _unit) then { - [_unit, _muzzle] call BIS_fnc_fire; + if (_throwGrenade) then { + private _index = magazines _unit find _magazine; - // Reset AI intelligence and targeting - [{ - params ["_unit"]; - - _unit enableAI "FSM"; - _unit enableAI "PATH"; - _unit doWatch objNull; - }, _unit, CLEANUP_DELAY] call CBA_fnc_waitAndExecute; + if (_index != -1) then { + private _magazine = magazinesDetail _unit select _index; + _magazine call EFUNC(common,parseMagazineDetail) params ["_id", "_owner"]; + CBA_logic action ["UseMagazine", _unit, _unit, _owner, _id]; }; - - deleteVehicle _helper; - }, - _this, - AIMING_TIMEOUT, - { - params ["", "_helper"]; - - deleteVehicle _helper; - } - ] call CBA_fnc_waitUntilAndExecute; -}, [_unit, _helper, 0, _muzzle], INITIAL_DELAY] call CBA_fnc_waitAndExecute; + }; + + if ( + _throwGrenade + || {!alive _unit} + || {isNull _helper} + || {CBA_missionTime >= _startTime + AIMING_TIMEOUT} + ) exitWith { + // Restore AI abilities, behaviour, combat mode, stance, and targeting + // Small delay before cleanup to give the unit time to finish throwing the grenade + [{ + params ["_unit", "_helper", "_abilities", "_behaviour", "_combatMode", "_unitPos"]; + + { + if (_x) then { + _unit enableAI (DISABLED_ABILITIES select _forEachIndex); + }; + } forEach _abilities; + + _unit setCombatBehaviour _behaviour; + _unit setUnitCombatMode _combatMode; + _unit setUnitPos _unitPos; + _unit doWatch objNull; + _unit lookAt objNull; + + deleteVehicle _helper; + }, [_unit, _helper, _abilities, _behaviour, _combatMode, _unitPos], CLEANUP_DELAY] call CBA_fnc_waitAndExecute; + + true // Exit + }; + + false // Continue + }, {}, _this] call CBA_fnc_waitUntilAndExecute; +}, [_unit, _helper, _magazine, _abilities, _behaviour, _combatMode, _unitPos], INITIAL_DELAY] call CBA_fnc_waitAndExecute; diff --git a/addons/common/XEH_PREP.hpp b/addons/common/XEH_PREP.hpp index 771245431..a0476f6c4 100644 --- a/addons/common/XEH_PREP.hpp +++ b/addons/common/XEH_PREP.hpp @@ -42,11 +42,13 @@ PREP(initSliderEdit); PREP(isInScreenshotMode); PREP(isPlacementActive); PREP(isRemoteControlled); +PREP(isSwimming); PREP(isVLS); PREP(isWeapon); PREP(loadMagazineInstantly); PREP(messageBox); PREP(openArsenal); +PREP(parseMagazineDetail); PREP(runAfterSettingsInit); PREP(selectPosition); PREP(serializeInventory); diff --git a/addons/common/functions/fnc_isSwimming.sqf b/addons/common/functions/fnc_isSwimming.sqf new file mode 100644 index 000000000..1c2422f5d --- /dev/null +++ b/addons/common/functions/fnc_isSwimming.sqf @@ -0,0 +1,20 @@ +#include "script_component.hpp" +/* + * Author: das attorney, Jonpas + * Checks if the given unit is swimming (surface swimming or diving). + * + * Arguments: + * 0: Unit + * + * Return Value: + * Is Swimming + * + * Example: + * [_unit] call zen_common_fnc_isSwimming + * + * Public: Yes + */ + +params [["_unit", objNull, [objNull]]]; + +animationState _unit select [1, 3] in ["bdv", "bsw", "dve", "sdv", "ssw", "swm"] diff --git a/addons/common/functions/fnc_parseMagazineDetail.sqf b/addons/common/functions/fnc_parseMagazineDetail.sqf new file mode 100644 index 000000000..c37dab197 --- /dev/null +++ b/addons/common/functions/fnc_parseMagazineDetail.sqf @@ -0,0 +1,23 @@ +#include "script_component.hpp" +/* + * Author: mharis001 + * Parses the given magazine detail string and returns the magazine's ID and creator. + * + * Arguments: + * 0: Magazine Detail + * + * Return Value: + * Parsed Data + * 0: ID + * 1: Creator + * + * Example: + * ["6.5 mm 30Rnd Sand Mag(30/30)[id/cr:10000001/0]"] call zen_common_fnc_parseMagazineDetail + * + * Public: No + */ + +params [["_magazine", "", [""]]]; + +private _split = _magazine splitString "[:/]"; +_split select [count _split - 2, 2] apply {parseNumber _x} diff --git a/addons/context_actions/CfgContext.hpp b/addons/context_actions/CfgContext.hpp index 840ca36fb..8f6f023d3 100644 --- a/addons/context_actions/CfgContext.hpp +++ b/addons/context_actions/CfgContext.hpp @@ -8,8 +8,8 @@ class EGVAR(context_menu,actions) { class ThrowGrenade { displayName = CSTRING(ThrowGrenade); icon = QPATHTOF(ui\grenade_ca.paa); - priority = -50; - insertChildren = QUOTE([_selectedObjects] call FUNC(getGrenadeActions)); + insertChildren = QUOTE(_objects call FUNC(getGrenadeActions)); + priority = 70; }; class Formation { displayName = "$STR_3DEN_Group_Attribute_Formation_displayName"; diff --git a/addons/context_actions/XEH_PREP.hpp b/addons/context_actions/XEH_PREP.hpp index 789551b85..a4208c039 100644 --- a/addons/context_actions/XEH_PREP.hpp +++ b/addons/context_actions/XEH_PREP.hpp @@ -10,7 +10,6 @@ PREP(canToggleSurrender); PREP(canUnloadViV); PREP(copyVehicleAppearance); PREP(compileGrenades); -PREP(editableObjects); PREP(getArtilleryActions); PREP(getGrenadeActions); PREP(healUnits); diff --git a/addons/context_actions/XEH_preInit.sqf b/addons/context_actions/XEH_preInit.sqf index 4f3e6d4d9..b1ccf1ae3 100644 --- a/addons/context_actions/XEH_preInit.sqf +++ b/addons/context_actions/XEH_preInit.sqf @@ -8,6 +8,4 @@ PREP_RECOMPILE_END; GVAR(appearances) = [] call CBA_fnc_createNamespace; -call FUNC(compileGrenades); - ADDON = true; diff --git a/addons/context_actions/XEH_preStart.sqf b/addons/context_actions/XEH_preStart.sqf index 022888575..30f189a74 100644 --- a/addons/context_actions/XEH_preStart.sqf +++ b/addons/context_actions/XEH_preStart.sqf @@ -1,3 +1,5 @@ #include "script_component.hpp" #include "XEH_PREP.hpp" + +call FUNC(compileGrenades); diff --git a/addons/context_actions/functions/fnc_compileGrenades.sqf b/addons/context_actions/functions/fnc_compileGrenades.sqf index f20f1df53..bb8e97de3 100644 --- a/addons/context_actions/functions/fnc_compileGrenades.sqf +++ b/addons/context_actions/functions/fnc_compileGrenades.sqf @@ -15,21 +15,18 @@ * Public: No */ -GVAR(grenades) = [] call CBA_fnc_createNamespace; -GVAR(grenadesList) = []; // For fast filtering of non-grenade magazines - +private _grenades = createHashMap; private _cfgWeapons = configFile >> "CfgWeapons"; private _cfgMagazines = configFile >> "CfgMagazines"; { - private _muzzle = _x; - { private _config = _cfgMagazines >> _x; - private _displayName = getText (_config >> "displayName"); - private _picture = getText (_config >> "picture"); + private _name = getText (_config >> "displayName"); + private _icon = getText (_config >> "picture"); - GVAR(grenades) setVariable [_x, [_displayName, _picture, _x, _muzzle]]; - GVAR(grenadesList) pushBackUnique _x; - } forEach getArray (_cfgWeapons >> "Throw" >> _muzzle >> "magazines"); + _grenades set [configName _config, [_name, _icon]]; + } forEach getArray (_cfgWeapons >> "Throw" >> _x >> "magazines"); } forEach getArray (_cfgWeapons >> "Throw" >> "muzzles"); + +uiNamespace setVariable [QGVAR(grenades), _grenades]; diff --git a/addons/context_actions/functions/fnc_getGrenadeActions.sqf b/addons/context_actions/functions/fnc_getGrenadeActions.sqf index f47559e7a..32f813d92 100644 --- a/addons/context_actions/functions/fnc_getGrenadeActions.sqf +++ b/addons/context_actions/functions/fnc_getGrenadeActions.sqf @@ -1,46 +1,51 @@ #include "script_component.hpp" /* * Author: mharis001 - * Returns children actions based on grenades in selected AI's inventories. + * Returns children actions for grenades in unit inventories. * * Arguments: - * 0: Selected Objects + * N: Objects * * Return Value: * Actions * * Example: - * [[_unit1, _unit2]] call zen_context_actions_fnc_getGrenadeActions + * [_object] call zen_context_actions_fnc_getGrenadeActions * * Public: No */ -params ["_objects"]; +// Get all magazines in the inventories of units that can throw grenades +private _magazines = flatten (_this select { + _x call EFUNC(ai,canThrowGrenade) +} apply { + magazines _x +}); -// Get all magazines in the inventories of on foot AI -private _magazines = []; -{ - if (!isPlayer _x && {vehicle _x == _x}) then { - _magazines append magazines _x; - }; -} forEach _objects; +// Filter out non-grenade magazines and sort them alphabetically by name +private _cache = uiNamespace getVariable QGVAR(grenades); +private _grenades = _magazines arrayIntersect keys _cache apply { + (_cache get _x) params ["_name", "_icon"]; + [_name, _icon, _x] +}; -// Filter out non-grenade magazines, sort alphabetically by display name -private _grenades = _magazines arrayIntersect GVAR(grenadesList) apply {GVAR(grenades) getVariable _x}; _grenades sort true; +// Create actions for every grenade type private _actions = []; { - _x params ["_displayName", "_picture", "_magazine", "_muzzle"]; + _x params ["_name", "_icon", "_magazine"]; private _action = [ - format [QGVAR(%1), _forEachIndex], - _displayName, - _picture, - {[_selectedObjects, _args] call FUNC(selectThrowPos)}, + _magazine, + _name, + _icon, + { + [_objects, _args] call FUNC(selectThrowPos); + }, {true}, - [_magazine, _muzzle] + _magazine ] call EFUNC(context_menu,createAction); _actions pushBack [_action, [], 0]; diff --git a/addons/context_actions/functions/fnc_selectThrowPos.sqf b/addons/context_actions/functions/fnc_selectThrowPos.sqf index 1110b206e..d2852232b 100644 --- a/addons/context_actions/functions/fnc_selectThrowPos.sqf +++ b/addons/context_actions/functions/fnc_selectThrowPos.sqf @@ -1,47 +1,43 @@ #include "script_component.hpp" /* * Author: mharis001 - * Allows Zeus to select a position to make AI throw grenades at. + * Allows Zeus to select a position to make units throw grenades at. * * Arguments: - * 0: Selected Objects - * 1: Arguments + * 0: Objects + * 1: Magazine * * Return Value: * None * * Example: - * [[_unit1, _unit2], ["HandGrenade", "HandGrenadeMuzzle"]] call zen_context_actions_fnc_selectThrowPos + * [_objects, "HandGrenade"] call zen_context_actions_fnc_selectThrowPos * * Public: No */ #define MAX_DISTANCE 75 -params ["_selectedObjects", "_args"]; -_args params ["_magazine", "_muzzle"]; +params ["_objects", "_magazine"]; -// Get AI units that are alive, on foot, and have the selected grenade type -private _units = _selectedObjects select { - alive _x - && {!isPlayer _x} - && {_x isKindOf "CAManBase"} - && {vehicle _x == _x} - && {_magazine in magazines _x} +// Get units that can throw the selected grenade type +private _units = _objects select { + [_x, _magazine] call EFUNC(ai,canThrowGrenade) }; -private _text = format [localize LSTRING(ThrowX), getText (configFile >> "CfgMagazines" >> _magazine >> "displayName")]; +private _name = getText (configFile >> "CfgMagazines" >> _magazine >> "displayName"); +private _text = format [LLSTRING(ThrowX), _name]; [_units, { - params ["_successful", "_units", "_position", "_muzzle"]; + params ["_confirmed", "_units", "_position", "_magazine"]; - if (!_successful) exitWith {}; + if (!_confirmed) exitWith {}; private _notInRange = 0; { - if (_x distance2D _position < MAX_DISTANCE) then { - [QEGVAR(ai,throwGrenade), [_x, _muzzle, _position], _x] call CBA_fnc_targetEvent; + if (_x distance2D _position <= MAX_DISTANCE) then { + [_x, _magazine, _position] call EFUNC(ai,throwGrenade); } else { _notInRange = _notInRange + 1; }; @@ -50,4 +46,4 @@ private _text = format [localize LSTRING(ThrowX), getText (configFile >> "CfgMag if (_notInRange > 0) then { [LSTRING(PositionTooFar), _notInRange] call EFUNC(common,showMessage); }; -}, _muzzle, _text] call EFUNC(common,getTargetPos); +}, _magazine, _text] call EFUNC(common,selectPosition); diff --git a/addons/context_actions/stringtable.xml b/addons/context_actions/stringtable.xml index 60ec3366a..04b11d0d6 100644 --- a/addons/context_actions/stringtable.xml +++ b/addons/context_actions/stringtable.xml @@ -1,15 +1,6 @@ - - Throw Grenade - - - Throw %1 - - - %1 units were too far away from the position - Edit Inventory Modifier l'inventaire @@ -139,6 +130,15 @@ Nie wszystkie pojazdy są w zasięgu do otwarcia ognia. 全車両が射程内に無い + + Throw Grenade + + + Throw %1 + + + %1 unit(s) were too far away from the position + Captives Gefangene diff --git a/addons/context_actions/ui/grenade_ca.paa b/addons/context_actions/ui/grenade_ca.paa index c215d51ef7b8fb4809955e77affd4c8bd5f04a1d..9c4034cc9fc0a7bf00423f935d405a206cb799bc 100644 GIT binary patch literal 5625 zcmcgw4Nz3q6~0S$VYP!Sx+@5hWyq30lc2#+Q-eH)&KepVH)gk`O;vuPHAWVbbWA%A zt|l3^ooOI6no-QGRcofsw1DVqMn*yKCuoPX!B%hym|&q(g@r7#AaA)n=ic{rmt{w> zX?hv8vcG%9k9lPc^#y1$^grh94a9G=*)+lc;GKI} z^ft8qI{g1((1HDJHi7(j4eA&6act1!j+x(+#&~q-OpYtSm*@Sz$9G5s2J7d4DZ)Zj z7Usta4Q1gP#-W0y$Pgp{J8V4m&sXA){CZ7mmSd=i>4VB6H1~V$KoK#q0ONl?yU8W4 z>tX$0G-zJgc)^LW$oeb}^ugc!@A;E2DYdFOUqYF*MNNXzjkE0YB*nu)oN3-{8Xw@4(1InT-{=y7KkWGA#?c3rTYM=D0 zHmi)ABk;Wi8uxzhPt*@L{y)0X`|6plVo8xFGrn)Ld;(wVDj4jg8Fnwq4H}IGpV$<> z3kKkuW4KX%FAyu>%E)9H8|VZmvpn%Pq5ba{M~znd8XKg~u%9K&`eng|`9S?}{O7sN zc27pp%S^7(7#{W2CAFs=XhUoT2XTWJ+`a*~k{`0V9hrNK_=#@j+m89&ZPLmkTFw7uA5R+tq_qORn*?PGHL;it;!H+ZrSuALQTAyuP3b zrULs*7g!ald)k4U1#6yoA|D-fv;l6;MBTSkcP)MYoNPz19_?~Zw3cpS`p7>- zKNQce7+!O8(Xx8f2m0zzc_>bxCsw<5WWp-N-62pP6@M5VHpJn^|47T-`A6me|KkDv zi64m3xnoYomTf+iBYnH-RqE-K`OkX=*3XP1wZ@)BYi{CuHvY^@Kpv`}_-489nzM|J zfAIc@defQzDP3Z5y;#WRH%xz9(q-yt_+7afsAp64C-sm0)$lU!8+NA8_}@dnuovcM4L`pGp9iPQKbYHezMERb zl6S=7m(jir_D`6fLS@kW-@8xz2#P$L9k?DA?GsDV7Ow1J`amdDpX?(Q@6xfgOb+_d zpl^bb!7yJhlkCTx62F-1kS=rmF!fv}f%55$|8zLtO=rQ7HPb}6PF!QTb9J;FO&;Q-1*jWI__lo!<}f!Abh1B|NX~w<>Mq} zye$?hD?w;6wEe&MXOr9td4~9baF7TESdJq)Ktx&Sh6*v zh%J-+c&&EHz|y$(<2)_IV%5(XZ65Gl>gLuVZrO`}ncNGny#2dqSKSJhW+CWWjQvuf zJ=-o8^~hyQtJTIog=g6GZMRTv(5p%0D5XE6!-pUM#xM39jgekT@%sl%X>JjeWxpJ7 zL;$;M%R2T%vtVJ?BYa!LduZ}S=g;$Nb6A;#dxV-Eh9nT} zb;Y0hd{4PFT8)s!7k{IB;;VAcVFfQc<$ygGkA<*ipl4#xH38h4Lj6BeJn5RFN~ljy zOJ7*Pe%8QkC!wBJy+S0XVn3n&PPHkr1|jpGP~WhB!*(A#2cT`xhieY2RZQMM@|sL5 z`L)snE!6)Ecb7Y}t2hs>VVO2I!m&4_^c}=->(mqnXUMX*$s1RyxhO7&io_2 zQ{C|S+lrj-Mh}5)_#}D$kSXtL&?h9Eeg2Fx_CwF0oq!uc!b&)!|ciW1=-l?R8JOn7&S@H+3Cd_nVBOaUO(Po&Hsf zqwxEG%2f0>T%s}L7oQjv{Dc0wXxE26wk-5I9Z5W#VZSNbAHx1P%^p6tVdERE#Yee4 zI880xGm)Xb)vxqV|6)d7Q$r{028rFUI|>*Zw)uT{+P9LVqvoPM@ij(UrO}XCpFRHP z^!|uurT=3?2a?+1bcFFk_(ThT0ukzJyu`p|V- zUYhdITQE&Sv<)#5HYU(SCnkNUu}O<@6C{9fyP%{M3PnqyA(lGJ`2A;Qwsl$@N-4yI zKYRQ3%sK!0{>wT4IigWoS{&R^`f9O#ABDzerN z;Ek8z9>RFmz`LNM;CA5;Nq=BGtv}~`;6r&yQ-3hHQ2!C%B422N#*-vbTsN75u8Ays z5L4EA96#dWVQL2yVq}Ww_;2{+?JR~LfeZvNZ&$11!0|A*A3bk9#RHtibHg!c!uWmG zcybdT|1HiJ-Bs^T4SC5!J2+O9AbEs~?Z5frmJVNNq$V^%`b0?Uaer#SxP(bGmdP0G zkrTeq1?3vYqR3e0sBvX$bo`h-zghZ>ExT6ZMePE_jjywv#iHX`cyax*OjF=;v;189 z8!U4zUZjusoBq89`&%;`#gFI{;KBVX-#?VIGGWxH+8}BKFb~s{%-cqY(@TQ9_-jHuzsdgxVo`k{ zs`LDV{YfR4^ms9rlRA9RUf)w6Ni;PYul;IV8tBz| zyfZe({$x$q&R^&J7mB?@zKYlF{Q~h&kwQEi4*yR1fwAXZ@44BpYd?85u!+t*N@GNvd6=fA-S2O0Fmr*8X?d=R4gV8H}38bSg`qci~?f z*D8y&a=vY0S5==KY>y=BckpdiQM^*k@L02Pl~UhaAl#M-XS;W_J~HUnj}SjaabG4s zs3reRA8XhtghOD)wZ}Yh%PEYvO#hMetE#*Hf2^u%e|%$wy$oViRgtdgcEVNhW$(>wx9Ft#II)+m0tGgPF#Y!FJ-bPbDhfjN zDJ`3ozj={ktP|A+aG)J`I%vmsi^XFtx^Y@6@@kYlx#y|#ZAH{B6c-E2wD+5Ix@h7b(Qfsh zquR|)>dkt8HBT$>Qy)SC`;*hRM|lVSy(}zcOF@bi4lk)&m!E-$K?9~L?5ax*HmCR{ y4@FPmKHoN@Cd8+Snn%oU`BNY0UBinIG%FsgsIX_=$lzB?LT8TBFc^hKg8Tz`!ug>9 diff --git a/addons/main/script_mod.hpp b/addons/main/script_mod.hpp index 965d7c1ed..0c262f793 100644 --- a/addons/main/script_mod.hpp +++ b/addons/main/script_mod.hpp @@ -11,7 +11,7 @@ // MINIMAL required version for the Mod. Components can specify others.. #define REQUIRED_VERSION 2.04 -#define REQUIRED_CBA_VERSION {3,14,0} +#define REQUIRED_CBA_VERSION {3,15,5} #ifdef COMPONENT_BEAUTIFIED #define COMPONENT_NAME QUOTE(ZEN - COMPONENT_BEAUTIFIED)