diff --git a/A3A/addons/patcom/CfgFunctions.hpp b/A3A/addons/patcom/CfgFunctions.hpp index 9453820b1f..17fa7364c2 100644 --- a/A3A/addons/patcom/CfgFunctions.hpp +++ b/A3A/addons/patcom/CfgFunctions.hpp @@ -36,6 +36,7 @@ class CfgFunctions { class patrolCreateWaypoint {}; class patrolDefend {}; class patrolEnterableBuildings {}; + class patrolFlankPos {}; class patrolGetEnemies {}; class patrolGroupGarrison {}; class patrolGroupVariables {}; diff --git a/A3A/addons/patcom/functions/Patcom/fn_patrolArea.sqf b/A3A/addons/patcom/functions/Patcom/fn_patrolArea.sqf index ccbdc174c5..21f13ca299 100644 --- a/A3A/addons/patcom/functions/Patcom/fn_patrolArea.sqf +++ b/A3A/addons/patcom/functions/Patcom/fn_patrolArea.sqf @@ -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 { if (_searchBuildings) then { // Percentage chance on searching a nearby building. if (15 > random 100) exitWith { diff --git a/A3A/addons/patcom/functions/Patcom/fn_patrolAttack.sqf b/A3A/addons/patcom/functions/Patcom/fn_patrolAttack.sqf index f4fecee21c..64ce0d0799 100644 --- a/A3A/addons/patcom/functions/Patcom/fn_patrolAttack.sqf +++ b/A3A/addons/patcom/functions/Patcom/fn_patrolAttack.sqf @@ -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 { + 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]; + + // 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]; + }; }; \ No newline at end of file diff --git a/A3A/addons/patcom/functions/Patcom/fn_patrolDefend.sqf b/A3A/addons/patcom/functions/Patcom/fn_patrolDefend.sqf index 1d25452d62..ae63928320 100644 --- a/A3A/addons/patcom/functions/Patcom/fn_patrolDefend.sqf +++ b/A3A/addons/patcom/functions/Patcom/fn_patrolDefend.sqf @@ -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; +}; + [_group, "SAFE", "LIMITED", "COLUMN", "WHITE", "AUTO"] call A3A_fnc_patrolSetCombatModes; _group setVariable ["PATCOM_Group_State", "CALM"]; diff --git a/A3A/addons/patcom/functions/Patcom/fn_patrolFlankPos.sqf b/A3A/addons/patcom/functions/Patcom/fn_patrolFlankPos.sqf new file mode 100644 index 0000000000..79805b18a0 --- /dev/null +++ b/A3A/addons/patcom/functions/Patcom/fn_patrolFlankPos.sqf @@ -0,0 +1,49 @@ +/* + Author: [Hazey] + Description: + Get a flank position based on best position forumla. + + Arguments: + Position to find the flank position around. + Radius to search for the flank position. + Precision of the search. Higher = Better performance. + Max results to return. The maximum possible is the number of random samples, which is n = 2 * radius / precision + + Return Value: + 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]; +} else { + // Selects random from _bestPositions, array contains x number of defined sources in selectBestPlaces + private _randomPosition = selectRandom _bestPositions; + _flankPosition = _randomPosition select 0; + _flankPosition set [2, 0]; +}; + +_flankPosition; \ No newline at end of file