Skip to content

Commit b9264f6

Browse files
authored
Add Throw Grenade context menu action (#132)
1 parent a22ac29 commit b9264f6

16 files changed

+338
-2
lines changed

AUTHORS.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ bux
2525
CesarStef
2626
classicarma
2727
commy2
28+
das attorney
2829
dedmen
2930
DeliciousJaffa
3031
diaverso

addons/ai/XEH_PREP.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
PREP(applySkills);
2+
PREP(canThrowGrenade);
23
PREP(garrison);
34
PREP(handleObjectEdited);
45
PREP(handleSkillsChange);
56
PREP(initMan);
67
PREP(searchBuilding);
78
PREP(suppressiveFire);
9+
PREP(throwGrenade);
810
PREP(unGarrison);

addons/ai/XEH_postInit.sqf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ QGVAR(skills) addPublicVariableEventHandler LINKFUNC(handleSkillsChange);
55
["CAManBase", "InitPost", LINKFUNC(initMan), true, [], false] call CBA_fnc_addClassEventHandler;
66

77
[QGVAR(suppressiveFire), LINKFUNC(suppressiveFire)] call CBA_fnc_addEventHandler;
8-
8+
[QGVAR(throwGrenade), LINKFUNC(throwGrenade)] call CBA_fnc_addEventHandler;
99
[QGVAR(unGarrison), LINKFUNC(unGarrison)] call CBA_fnc_addEventHandler;
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#include "script_component.hpp"
2+
/*
3+
* Author: mharis001
4+
* Checks if the given unit can throw a grenade.
5+
* When specified, also checks if the unit has the given grenade magazine.
6+
*
7+
* Arguments:
8+
* 0: Unit <OBJECT>
9+
* 1: Grenade Magazine <STRING> (default: "")
10+
*
11+
* Return Value:
12+
* Can Throw Grenade <BOOL>
13+
*
14+
* Example:
15+
* [_unit, "HandGrenade"] call zen_ai_fnc_canThrowGrenade
16+
*
17+
* Public: No
18+
*/
19+
20+
params [["_unit", objNull, [objNull]], ["_magazine", "", [""]]];
21+
22+
alive _unit
23+
&& {!isPlayer _unit}
24+
&& {vehicle _unit == _unit}
25+
&& {_unit isKindOf "CAManBase"}
26+
&& {lifeState _unit in ["HEALTHY", "INJURED"]}
27+
&& {!(_unit call EFUNC(common,isSwimming))}
28+
&& {_magazine == "" || {_magazine in magazines _unit}}
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
#include "script_component.hpp"
2+
/*
3+
* Author: mharis001
4+
* Makes the unit throw a grenade at the given position.
5+
*
6+
* Arguments:
7+
* 0: Unit <OBJECT>
8+
* 1: Grenade Magazine <STRING>
9+
* 2: Position ASL <ARRAY>
10+
*
11+
* Return Value:
12+
* None
13+
*
14+
* Example:
15+
* [_unit, "HandGrenade", [0, 0, 0]] call zen_ai_fnc_throwGrenade
16+
*
17+
* Public: No
18+
*/
19+
20+
#define AIMING_TIMEOUT 10
21+
#define INITIAL_DELAY 0.5
22+
#define CLEANUP_DELAY 1.5
23+
24+
#define TOLERANCE_TIME 2
25+
#define MIN_TOLERANCE 10
26+
#define MAX_TOLERANCE 45
27+
28+
#define DISABLED_ABILITIES ["AIMINGERROR", "AUTOTARGET", "FSM", "PATH", "SUPPRESSION", "TARGET"]
29+
30+
params [
31+
["_unit", objNull, [objNull]],
32+
["_magazine", "", [""]],
33+
["_position", [0, 0, 0], [[]], 3]
34+
];
35+
36+
if (!local _unit) exitWith {
37+
[QGVAR(throwGrenade), _this, _unit] call CBA_fnc_targetEvent;
38+
};
39+
40+
// Exit if the unit cannot throw the given grenade type
41+
if !([_unit, _magazine] call FUNC(canThrowGrenade)) exitWith {};
42+
43+
// Disable AI abilities to make units more responsive to commands
44+
// Also interrupts a unit's movement to a waypoint, forcing them to stop
45+
private _abilities = DISABLED_ABILITIES apply {_unit checkAIFeature _x};
46+
{_unit disableAI _x} forEach DISABLED_ABILITIES;
47+
48+
// Set the unit's behaviour to COMBAT to make them raise their weapon and aim at the target
49+
private _behaviour = combatBehaviour _unit;
50+
_unit setCombatBehaviour "COMBAT";
51+
52+
// Set the unit's combat mode to BLUE to make them hold their fire
53+
// The unit will still track the target but only fire when told to
54+
private _combatMode = unitCombatMode _unit;
55+
_unit setUnitCombatMode "BLUE";
56+
57+
// Prevent the unit from changing stance due to combat behaviour by
58+
// forcing a unit position that matches their current stance
59+
// Usually only a problem with the AUTO unit position
60+
private _unitPos = unitPos _unit;
61+
private _stanceIndex = ["STAND", "CROUCH", "PRONE"] find stance _unit;
62+
private _unitPosForStance = ["UP", "MIDDLE", "DOWN"] param [_stanceIndex, "UP"];
63+
_unit setUnitPos _unitPosForStance;
64+
65+
// Create a helper object for the unit to target
66+
private _helper = createVehicle ["CBA_B_InvisibleTargetVehicle", [0, 0, 0], [], 0, "CAN_COLLIDE"];
67+
_helper setPosASL _position;
68+
69+
// Make the unit target the helper object
70+
_unit reveal [_helper, 4];
71+
_unit lookAt _helper;
72+
_unit doWatch _helper;
73+
_unit doTarget _helper;
74+
75+
// Wait until the unit is aiming at the helper object before throwing the grenade
76+
// Initial delay helps prevent weird issue when the unit is moving to a waypoint and the helper is directly in front of it
77+
[{
78+
_this set [7, CBA_missionTime];
79+
80+
[{
81+
params ["_unit", "_helper", "_magazine", "_abilities", "_behaviour", "_combatMode", "_unitPos", "_startTime"];
82+
83+
// Check that the unit is aiming at the helper, increase tolerance as more time passes
84+
private _direction = _unit getRelDir _helper;
85+
private _tolerance = linearConversion [0, TOLERANCE_TIME, CBA_missionTime - _startTime, MIN_TOLERANCE, MAX_TOLERANCE, true];
86+
private _throwGrenade = _direction <= _tolerance || {_direction >= 360 - _tolerance};
87+
88+
if (_throwGrenade) then {
89+
private _index = magazines _unit find _magazine;
90+
91+
if (_index != -1) then {
92+
private _magazine = magazinesDetail _unit select _index;
93+
_magazine call EFUNC(common,parseMagazineDetail) params ["_id", "_owner"];
94+
CBA_logic action ["UseMagazine", _unit, _unit, _owner, _id];
95+
};
96+
};
97+
98+
if (
99+
_throwGrenade
100+
|| {!alive _unit}
101+
|| {isNull _helper}
102+
|| {CBA_missionTime >= _startTime + AIMING_TIMEOUT}
103+
) exitWith {
104+
// Restore AI abilities, behaviour, combat mode, stance, and targeting
105+
// Small delay before cleanup to give the unit time to finish throwing the grenade
106+
[{
107+
params ["_unit", "_helper", "_abilities", "_behaviour", "_combatMode", "_unitPos"];
108+
109+
{
110+
if (_x) then {
111+
_unit enableAI (DISABLED_ABILITIES select _forEachIndex);
112+
};
113+
} forEach _abilities;
114+
115+
_unit setCombatBehaviour _behaviour;
116+
_unit setUnitCombatMode _combatMode;
117+
_unit setUnitPos _unitPos;
118+
_unit doWatch objNull;
119+
_unit lookAt objNull;
120+
121+
deleteVehicle _helper;
122+
}, [_unit, _helper, _abilities, _behaviour, _combatMode, _unitPos], CLEANUP_DELAY] call CBA_fnc_waitAndExecute;
123+
124+
true // Exit
125+
};
126+
127+
false // Continue
128+
}, {}, _this] call CBA_fnc_waitUntilAndExecute;
129+
}, [_unit, _helper, _magazine, _abilities, _behaviour, _combatMode, _unitPos], INITIAL_DELAY] call CBA_fnc_waitAndExecute;

addons/common/XEH_PREP.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ PREP(initSliderEdit);
4242
PREP(isInScreenshotMode);
4343
PREP(isPlacementActive);
4444
PREP(isRemoteControlled);
45+
PREP(isSwimming);
4546
PREP(isUnitFFV);
4647
PREP(isVLS);
4748
PREP(isWeapon);
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#include "script_component.hpp"
2+
/*
3+
* Author: das attorney, Jonpas
4+
* Checks if the given unit is swimming (surface swimming or diving).
5+
*
6+
* Arguments:
7+
* 0: Unit <OBJECT>
8+
*
9+
* Return Value:
10+
* Is Swimming <BOOL>
11+
*
12+
* Example:
13+
* [_unit] call zen_common_fnc_isSwimming
14+
*
15+
* Public: Yes
16+
*/
17+
18+
params [["_unit", objNull, [objNull]]];
19+
20+
animationState _unit select [1, 3] in ["bdv", "bsw", "dve", "sdv", "ssw", "swm"]

addons/context_actions/CfgContext.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ class EGVAR(context_menu,actions) {
55
insertChildren = QUOTE(_objects call FUNC(getArtilleryActions));
66
priority = 70;
77
};
8+
class ThrowGrenade {
9+
displayName = CSTRING(ThrowGrenade);
10+
icon = QPATHTOF(ui\grenade_ca.paa);
11+
insertChildren = QUOTE(_objects call FUNC(getGrenadeActions));
12+
priority = 70;
13+
};
814
class Formation {
915
displayName = "$STR_3DEN_Group_Attribute_Formation_displayName";
1016
condition = QUOTE(_groups findIf {units _x findIf {!isPlayer _x} != -1} != -1);

addons/context_actions/XEH_PREP.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,17 @@ PREP(canRepairVehicles);
99
PREP(canToggleSurrender);
1010
PREP(canUnloadViV);
1111
PREP(copyVehicleAppearance);
12+
PREP(compileGrenades);
1213
PREP(getArtilleryActions);
14+
PREP(getGrenadeActions);
1315
PREP(healUnits);
1416
PREP(openEditableObjectsDialog);
1517
PREP(pasteVehicleAppearance);
1618
PREP(rearmVehicles);
1719
PREP(refuelVehicles);
1820
PREP(repairVehicles);
1921
PREP(selectArtilleryPos);
22+
PREP(selectThrowPos);
2023
PREP(setBehaviour);
2124
PREP(setCombatMode);
2225
PREP(setFormation);
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
#include "script_component.hpp"
22

33
#include "XEH_PREP.hpp"
4+
5+
call FUNC(compileGrenades);

0 commit comments

Comments
 (0)