Aircraft - Drone "Follow Unit" Waypoint Action (#9889)

* Fix "Recharge" interaction showing on destroyed drone

* Add "Follow Unit" action

* Improve condition check

* UGV Following via PFH that updates WP Pos

* Use HOLD WP for all Follow Actions

Since FOLLOW WP would stop working on AI Soldiers after some time.

* Allow selecting a follow distance

* Follow Distance under separate interaction, just like Loiter Alt

Only visible when a HOLD waypoint is selected, which is pretty much always going to have been created by the "Follow" interaction.

* Localize "Follow" Interaction

* Show structuredText Hint when following/changing distance

* Variable for cursorTarget Reuse

* Better isKindOf condition use

* Make "Ship"-kind vehicles followable

* Clean up Comments and systemChat Debugs

* Comment explanation for custom PFH solution over vanilla "Follow"-WP

* Trim excess brackets from setWaypointPosition argument

Co-Authored-By: johnb432 <58661205+johnb432@users.noreply.github.com>

* Broader determination for UGV follow distances

Co-Authored-By: PabstMirror <pabstmirror@gmail.com>

* Prevent infinite PFH loop if follow target is deleted

Co-Authored-By: PabstMirror <pabstmirror@gmail.com>

* Delete Follow WP when PFH terminates

* The ternary rules

Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com>

* Various requested changes

Co-Authored-By: johnb432 <58661205+johnb432@users.noreply.github.com>

---------

Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com>
Co-authored-by: PabstMirror <pabstmirror@gmail.com>
This commit is contained in:
Fabio Schick 2024-07-02 11:16:48 +02:00 committed by GitHub
parent ba47c12a97
commit aecafe673b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 95 additions and 10 deletions

View File

@ -22,7 +22,7 @@ if (!alive _vehicle) exitWith {};
if (_vehicle getVariable [QGVAR(droneActionsAdded), false]) exitWith {}; if (_vehicle getVariable [QGVAR(droneActionsAdded), false]) exitWith {};
_vehicle setVariable [QGVAR(droneActionsAdded), true]; _vehicle setVariable [QGVAR(droneActionsAdded), true];
// move to location // Move to location
private _condition = { private _condition = {
params ["_vehicle"]; params ["_vehicle"];
(missionNamespace getVariable [QGVAR(droneWaypoints), true]) && {waypointsEnabledUAV _vehicle} && {(ACE_controlledUAV select 2) isEqualTo [0]} (missionNamespace getVariable [QGVAR(droneWaypoints), true]) && {waypointsEnabledUAV _vehicle} && {(ACE_controlledUAV select 2) isEqualTo [0]}
@ -37,14 +37,63 @@ private _action = [QGVAR(droneSetWaypointMove), localize "$STR_AC_MOVE",
"\a3\3DEN\Data\CfgWaypoints\Move_ca.paa", _statement, _condition] call EFUNC(interact_menu,createAction); "\a3\3DEN\Data\CfgWaypoints\Move_ca.paa", _statement, _condition] call EFUNC(interact_menu,createAction);
[_vehicle, 1, ["ACE_SelfActions"], _action] call EFUNC(interact_menu,addActionToObject); [_vehicle, 1, ["ACE_SelfActions"], _action] call EFUNC(interact_menu,addActionToObject);
// Follow unit/vehicle at turret location
_condition = {
params ["_vehicle"];
private _target = cursorTarget;
(missionNamespace getVariable [QGVAR(droneWaypoints), true]) && {waypointsEnabledUAV _vehicle} && {(ACE_controlledUAV select 2) isEqualTo [0]} && {!isNull _target} && {["CAManBase", "LandVehicle", "Ship"] findIf {_target isKindOf _x} != -1}
};
_statement = {
params ["_vehicle"];
private _group = group driver _vehicle;
private _pos = ([_vehicle, [0]] call FUNC(droneGetTurretTargetPos)) select 0;
[QGVAR(droneSetWaypoint), [_vehicle, _group, _pos, "FOLLOW", cursorTarget], _group] call CBA_fnc_targetEvent;
private _followDistance = _vehicle getVariable [QGVAR(wpFollowDistance), 0];
[[LLSTRING(DroneFollowHint), _followDistance], 3] call EFUNC(common,displayTextStructured);
};
_action = [QGVAR(droneSetWaypointFollow), localize "$STR_AC_FOLLOW", "\a3\3DEN\Data\CfgWaypoints\Follow_ca.paa", _statement, _condition] call EFUNC(interact_menu,createAction);
[_vehicle, 1, ["ACE_SelfActions"], _action] call EFUNC(interact_menu,addActionToObject);
// Set drone follow distance
_condition = {
params ["_vehicle"];
private _group = group driver _vehicle;
private _index = (currentWaypoint _group) min count waypoints _group;
private _waypoint = [_group, _index];
(missionNamespace getVariable [QGVAR(droneWaypoints), true]) && {waypointsEnabledUAV _vehicle} && {(ACE_controlledUAV select 2) isEqualTo [0]} && {(waypointType _waypoint) == "HOLD"}
};
_statement = {
params ["_vehicle", "", "_value"];
_vehicle setVariable [QGVAR(wpFollowDistance), _value];
[[LLSTRING(DroneFollowHint), _value], 3] call EFUNC(common,displayTextStructured);
};
_action = [QGVAR(droneSetFollowDistance), LLSTRING(DroneFollowDistance), "", {}, _condition] call EFUNC(interact_menu,createAction);
private _base = [_vehicle, 1, ["ACE_SelfActions"], _action] call EFUNC(interact_menu,addActionToObject);
private _followDistances = if (_vehicle isKindOf "Car_F") then {
[0, 25, 50, 100, 200]
} else {
[0, 100, 200, 300, 400, 500]
};
{
_action = [
QGVAR(droneSetFollowDistance_) + str _x,
str _x,
"",
_statement,
{true},
{},
_x
] call EFUNC(interact_menu,createAction);
[_vehicle, 1, _base, _action] call EFUNC(interact_menu,addActionToObject);
} forEach _followDistances;
if (_vehicle isKindOf "Air") then { if (_vehicle isKindOf "Air") then {
// loiter at location // Loiter at location
_condition = { _condition = {
params ["_vehicle"]; params ["_vehicle"];
(missionNamespace getVariable [QGVAR(droneWaypoints), true]) && {waypointsEnabledUAV _vehicle} && {(ACE_controlledUAV select 2) isEqualTo [0]} (missionNamespace getVariable [QGVAR(droneWaypoints), true]) && {waypointsEnabledUAV _vehicle} && {(ACE_controlledUAV select 2) isEqualTo [0]}
}; };
_statement = { _statement = {
params ["_vehicle"]; params ["_vehicle"];
private _group = group driver _vehicle; private _group = group driver _vehicle;
private _pos = ([_vehicle, [0]] call FUNC(droneGetTurretTargetPos)) select 0; private _pos = ([_vehicle, [0]] call FUNC(droneGetTurretTargetPos)) select 0;
@ -55,7 +104,7 @@ if (_vehicle isKindOf "Air") then {
[_vehicle, 1, ["ACE_SelfActions"], _action] call EFUNC(interact_menu,addActionToObject); [_vehicle, 1, ["ACE_SelfActions"], _action] call EFUNC(interact_menu,addActionToObject);
// set height // Set height
_condition = { _condition = {
params ["_vehicle"]; params ["_vehicle"];
(missionNamespace getVariable [QGVAR(droneWaypoints), true]) && {waypointsEnabledUAV _vehicle} && {(ACE_controlledUAV select 2) isEqualTo [0]} (missionNamespace getVariable [QGVAR(droneWaypoints), true]) && {waypointsEnabledUAV _vehicle} && {(ACE_controlledUAV select 2) isEqualTo [0]}
@ -74,7 +123,7 @@ if (_vehicle isKindOf "Air") then {
} forEach [20, 50, 200, 500, 2000]; } forEach [20, 50, 200, 500, 2000];
// set loiter radius // Set loiter radius
_condition = { _condition = {
params ["_vehicle"]; params ["_vehicle"];
private _group = group driver _vehicle; private _group = group driver _vehicle;
@ -97,7 +146,7 @@ if (_vehicle isKindOf "Air") then {
} forEach [500, 750, 1000, 1250, 1500]; } forEach [500, 750, 1000, 1250, 1500];
// set loiter direction // Set loiter direction
_condition = { _condition = {
params ["_vehicle", "", "_args"]; params ["_vehicle", "", "_args"];
private _group = group driver _vehicle; private _group = group driver _vehicle;

View File

@ -8,6 +8,7 @@
* 1: Group <GROUP> * 1: Group <GROUP>
* 2: Pos 2D <ARRAY> * 2: Pos 2D <ARRAY>
* 3: Type <STRING> * 3: Type <STRING>
* 4: Target to follow <OBJECT> (default: objNull)
* *
* Return Value: * Return Value:
* None * None
@ -18,7 +19,7 @@
* Public: No * Public: No
*/ */
params ["_vehicle", "_group", "_pos", "_type"]; params ["_vehicle", "_group", "_pos", "_type", ["_target", objNull]];
TRACE_4("droneSetWaypoint",_vehicle,_group,_pos,_type); TRACE_4("droneSetWaypoint",_vehicle,_group,_pos,_type);
private _index = (currentWaypoint _group) min count waypoints _group; private _index = (currentWaypoint _group) min count waypoints _group;
@ -34,9 +35,34 @@ _pos set [
[0, _currentHeight] select (_currentHeight >= 50) [0, _currentHeight] select (_currentHeight >= 50)
]; ];
// [_group] call CBA_fnc_clearWaypoints;
_waypoint = _group addWaypoint [_pos, 0]; _waypoint = _group addWaypoint [_pos, 0];
_waypoint setWaypointType _type; // The Vanilla "FOLLOW"-type waypoint is not used directly, due to 2 main issues (as of v2.16):
// - It does not work at all for UGVs, which is a known issue https://feedback.bistudio.com/T126283;
// - No clear scripting way was found to mimic the UAV Terminal's "Follow Distance" functionality;
// Instead, the solution for both UAV and UGV following consists of a CBA PFH that moves a "HOLD"-type Waypoint every 3 seconds.
// Either on the target itself, or on the Drone's current position if the target is within the desired follow distance.
if (_type == "FOLLOW" && {["CAManBase", "LandVehicle", "Ship"] findIf {_target isKindOf _x} != -1}) then {
_waypoint setWaypointType "HOLD";
[{
params ["_args", "_handle"];
_args params ["_vehicle", "_group", "_waypoint", "_target"];
if ( // Abort PFH if a new waypoint is created via UAV Terminal or ACE Interaction
_waypoint select 1 != currentWaypoint _group ||
{!alive _vehicle} || {isNull _target}
) exitWith {
deleteWaypoint _waypoint;
[_handle] call CBA_fnc_removePerFrameHandler;
};
private _followDistance = _vehicle getVariable [QGVAR(wpFollowDistance), 0];
if ((_vehicle distance2D _target) < _followDistance) then {
_waypoint setWaypointPosition [getPosASL _vehicle, -1];
} else {
_waypoint setWaypointPosition [getPosASL _target, -1];
};
}, 3, [_vehicle, _group, _waypoint, _target]] call CBA_fnc_addPerFrameHandler;
};
TRACE_3("",_currentHeight,_currentLoiterRadius,_currentLoiterType); TRACE_3("",_currentHeight,_currentLoiterRadius,_currentLoiterType);
if (_currentHeight > 1) then { _vehicle flyInHeight _currentHeight; }; if (_currentHeight > 1) then { _vehicle flyInHeight _currentHeight; };

View File

@ -177,5 +177,15 @@
<Russian>30мм СБ 5:1</Russian> <Russian>30мм СБ 5:1</Russian>
<Korean>30mm CM 5:1</Korean> <Korean>30mm CM 5:1</Korean>
</Key> </Key>
<Key ID="STR_ACE_Aircraft_DroneFollowDistance">
<English>Follow Distance</English>
<Italian>Distanza di seguimento</Italian>
<German>Folge-Entfernung</German>
</Key>
<Key ID="STR_ACE_Aircraft_DroneFollowHint">
<English>Following unit within %1m</English>
<Italian>Seguendo unità entro %1m</Italian>
<German>Folgt Einheit bis zu %1m</German>
</Key>
</Package> </Package>
</Project> </Project>

View File

@ -18,4 +18,4 @@
params ["_caller", "_target"]; params ["_caller", "_target"];
("ACE_UAVBattery" in (_caller call EFUNC(common,uniqueItems))) && {(fuel _target) < 1} && {(speed _target) < 1} && {!(isEngineOn _target)} && {(_target distance _caller) <= 4} (alive _target) && {"ACE_UAVBattery" in (_caller call EFUNC(common,uniqueItems))} && {(fuel _target) < 1} && {(speed _target) < 1} && {!(isEngineOn _target)} && {(_target distance _caller) <= 4}