Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Patcom patrol attack flanks #2901

Open
wants to merge 6 commits into
base: unstable
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions A3A/addons/patcom/CfgFunctions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class CfgFunctions {
class patrolCreateWaypoint {};
class patrolDefend {};
class patrolEnterableBuildings {};
class patrolFlankPos {};
class patrolGetEnemies {};
class patrolGroupGarrison {};
class patrolGroupVariables {};
Expand Down
2 changes: 1 addition & 1 deletion A3A/addons/patcom/functions/Patcom/fn_patrolArea.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ if (_group getVariable "PATCOM_WaypointTime" < serverTime) exitWith {
};

// Check for current waypoints and make sure they are type MOVE for patrol
if (currentWaypoint _group == count waypoints _group || waypointType [_group, currentWaypoint _group] != "MOVE") then {
if ((waypointType [_group, currentWaypoint _group] != "MOVE") || ((waypointName [_group, currentWaypoint _group]) != "PATCOM_PATROL_AREA")) then {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the first check required?

if (_searchBuildings) then {
// Percentage chance on searching a nearby building.
if (15 > random 100) exitWith {
Expand Down
117 changes: 104 additions & 13 deletions A3A/addons/patcom/functions/Patcom/fn_patrolAttack.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -47,25 +47,116 @@ if (count _knownEnemies < 1) exitWith {

[_group, "COMBAT", "FULL", "COLUMN", "RED", "AUTO"] call A3A_fnc_patrolSetCombatModes;

if (PATCOM_DEBUG) then {
[leader _group, "ATTACK", 10, "White"] call A3A_fnc_debugText3D;
};
// Get random attack type.
private _attackType = selectRandomWeighted ["Direct", 0.6, "FlankQuick", 0.4, "FlankLong", 0.2];
private _attackWaypointNames = ["PATROL_ATTACK_DIRECT", "PATROL_ATTACK_FLANKQUICK", "PATROL_ATTACK_FLANKLONG"];

// If Enabled unit in combat, activly check for statics near their positions to man.
if (PATCOM_AI_STATICS) then {
[_group] call A3A_fnc_patrolArmStatics;
};

// Set Waypoint Name
private _waypointName = "PATCOM_PATROL_ATTACK";
// Direct attack - Group makes a direct attack on enemies group.
if (_attackType == "Direct") then {
// Set Waypoint Name
private _waypointName = "PATROL_ATTACK_DIRECT";

if !((waypointName [_group, currentWaypoint _group]) in _attackWaypointNames) then {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be a do-nothing case for all three attack types. Any reason not to move these checks after the static-arming and exitWith there?

if (PATCOM_DEBUG) then {
[leader _group, format["ATTACK-%1", _attackType], 30, "White"] call A3A_fnc_debugText3D;
};

// Select random group in the array to attack.
private _targetGroup = selectRandom _knownEnemies;

// Instead of taking the Perceived Position and creating a waypoint from there. We opt to get our own waypoint so we can add some variation.
// Center Position | Min Radius | Max Radius | Min Object Distance | Water Mode | Max Gradient | ShoreMode
private _nextWaypointPos = [getPosATL (leader _targetGroup), 0, 25, _objectDistance, _waterMode, _maxGradient, _shoreMode] call A3A_fnc_getSafePos;

[_group, _nextWaypointPos, "SAD", _waypointName, -1, 50] call A3A_fnc_patrolCreateWaypoint;
};
};

/* Quick flank - Add's a single flanking waypoint between groups location and enemies location.
* Flank is calculated based on terrain.
*/
if (_attackType == "FlankQuick") then {
// Set Waypoint Name
private _waypointName = "PATROL_ATTACK_FLANKQUICK";

if !((waypointName [_group, currentWaypoint _group]) in _attackWaypointNames) then {
if (PATCOM_DEBUG) then {
[leader _group, format["ATTACK-%1", _attackType], 30, "White"] call A3A_fnc_debugText3D;
};

// Select random group in the array to attack.
private _targetGroup = selectRandom _knownEnemies;

// Define final enemy position to attack.
private _enemyPosition = getPosATL (leader _targetGroup);

// Get flanking position.
private _flankPosition = [_enemyPosition, 250] call A3A_fnc_patrolFlankPos;

// Add first waypoint to group.
private _flankWaypoint = _group addwaypoint [_flankPosition, 0, 1, _waypointName];
_flankWaypoint setWaypointType "MOVE";
[_group, (_flankWaypoint select 1)] setWaypointCompletionRadius 50;
_group setCurrentWaypoint [_group, (_flankWaypoint select 1)];

// Add final waypoint to group.
private _finalWaypoint = _group addwaypoint [_enemyPosition, 0, 2, _waypointName];
_finalWaypoint setWaypointType "MOVE";
[_group, (_finalWaypoint select 1)] setWaypointCompletionRadius 50;
deleteWaypoint [_group, 3];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the logic with the waypoint deletion here? Feels like you're creating a lot more waypoints than you're deleting, overall.


// Set Waypoint time 5 minutes into the future.
private _waypointTime = serverTime + 300;
_group setVariable ["PATCOM_WaypointTime", _waypointTime];
};
};

/* Long flank - Add's two waypoints between current group location and enemies location.
* Both flanks are calculated based on terrain.
*/
if (_attackType == "FlankLong") then {
// Set Waypoint Name
private _waypointName = "PATROL_ATTACK_FLANKLONG";

if !((waypointName [_group, currentWaypoint _group]) in _attackWaypointNames) then {
if (PATCOM_DEBUG) then {
[leader _group, format["ATTACK-%1", _attackType], 30, "White"] call A3A_fnc_debugText3D;
};

// Select random group in the array to attack.
private _targetGroup = selectRandom _knownEnemies;

// Define final enemy position to attack.
private _enemyPosition = getPosATL (leader _targetGroup);

// Get first and second flanking positions.
private _flankPositionNear = [getPosATL (leader _group), 150] call A3A_fnc_patrolFlankPos;
private _flankPositionFar = [_enemyPosition, 150] call A3A_fnc_patrolFlankPos;

// Add first waypoint to group.
private _flankWaypointNear = _group addwaypoint [_flankPositionNear, 0, 1, _waypointName];
_flankWaypointNear setWaypointType "MOVE";
[_group, (_flankWaypointNear select 1)] setWaypointCompletionRadius 50;
_group setCurrentWaypoint [_group, (_flankWaypointNear select 1)];

// Add second waypoint to group.
private _flankWaypointFar = _group addwaypoint [_flankPositionFar, 0, 2, _waypointName];
_flankWaypointFar setWaypointType "MOVE";
[_group, (_flankWaypointFar select 1)] setWaypointCompletionRadius 50;

if ((waypointType [_group, currentWaypoint _group] != "SAD") || ((waypointName [_group, currentWaypoint _group]) != _waypointName)) then {
// Select random group in the array to attack.
private _targetGroup = selectRandom _knownEnemies;
// Add Final waypoint to group.
private _finalWaypoint = _group addwaypoint [_enemyPosition, 0, 3, _waypointName];
_finalWaypoint setWaypointType "MOVE";
[_group, (_finalWaypoint select 1)] setWaypointCompletionRadius 50;
deleteWaypoint [_group, 4];

// Instead of taking the Perceived Position and creating a waypoint from there. We opt to get our own waypoint so we can add some variation.
// Center Position | Min Radius | Max Radius | Min Object Distance | Water Mode | Max Gradient | ShoreMode
private _nextWaypointPos = [getPosATL (leader _targetGroup), _minimumRadius, _maximumRadius, _objectDistance, _waterMode, _maxGradient, _shoreMode] call A3A_fnc_getSafePos;

[_group, _nextWaypointPos, "SAD", _waypointName, -1, 50] call A3A_fnc_patrolCreateWaypoint;
// Set Waypoint time 5 minutes into the future.
private _waypointTime = serverTime + 300;
_group setVariable ["PATCOM_WaypointTime", _waypointTime];
};
};
10 changes: 10 additions & 0 deletions A3A/addons/patcom/functions/Patcom/fn_patrolDefend.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,16 @@ params [

private _leader = leader _group;

// Get home position of the unit.
private _groupHomePosition = _group getVariable "PATCOM_Patrol_Home";
private _patrolParams = _group getVariable "PATCOM_Patrol_Params";

// We check to see if the waypoint is still active after 3 minutes. If waypoint isn't complete the unit is likely stuck.
if (_group getVariable "PATCOM_WaypointTime" < serverTime) exitWith {
// Return home
[_group, _groupHomePosition, "MOVE", "PATCOM_PATROL_DEFEND", -1, _patrolParams # 1] call A3A_fnc_patrolCreateWaypoint;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aren't you better off giving a random waypoint to a stuck group? Otherwise they might stay stuck forever because they can't find a path to home. Maybe questionable if the home waypoint is guaranteed safe.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Home waypoint is their initial spawn point so should always be considered "safe".

};

[_group, "SAFE", "LIMITED", "COLUMN", "WHITE", "AUTO"] call A3A_fnc_patrolSetCombatModes;
_group setVariable ["PATCOM_Group_State", "CALM"];

Expand Down
49 changes: 49 additions & 0 deletions A3A/addons/patcom/functions/Patcom/fn_patrolFlankPos.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
Author: [Hazey]
Description:
Get a flank position based on best position forumla.

Arguments:
<Array> Position to find the flank position around.
<Number> Radius to search for the flank position.
<Number> Precision of the search. Higher = Better performance.
<Number> Max results to return. The maximum possible is the number of random samples, which is n = 2 * radius / precision

Return Value:
<Array> Found flank position.

Scope: Any
Environment: Any
Public: No

Example:
private _flankPosition = [_enemyPosition, 250] call A3A_fnc_patrolFlankPos;

License: MIT License
*/
#include "..\..\script_component.hpp"
FIX_LINE_NUMBERS()

params [
"_position",
"_radius",
["_precision", 100],
["_sources", 5]
];

private _flankPosition = [];

// Get best attack vector for flank. I have dead bodies set maybe a little high, but we really don't want them flanking into the firefight.
private _bestPositions = selectBestPlaces [_position, _radius, "((6*hills + 2*forest + 4*houses + 2*meadow) - sea + (2*trees)) - (100*deadbody)", _precision, _sources];

// If no position is found, we create a random one.
if (_bestPositions isEqualTo []) then {
_flankPosition = [(_position select 0) + (sin (random 360)) * (random 100 + 100), (_position select 1) + (cos (random 360)) * (random 100 + 100), 0];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getPos [random 360, 100 + random 100] ?

} else {
// Selects random from _bestPositions, array contains x number of defined sources in selectBestPlaces
private _randomPosition = selectRandom _bestPositions;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be selectRandomWeighted? Otherwise you're throwing away a lot of info from selectBestPlaces.

Maybe that's intentional and you're doing something more like "select random place without bodies in it".

_flankPosition = _randomPosition select 0;
_flankPosition set [2, 0];
};

_flankPosition;