Jump to content

Recommended Posts

Hi Folks,

 

SCO SP Hunter AI Script

This script is designed to simulate dynamic hunter AI groups engaging in Search and Destroy (SAD) operations, particularly suited for open jungle environments inspired by SOG-style gameplay. The focus is on creating plausible Escape and Evasion (E&E) scenarios where player tactics and fieldcraft can effectively help them evade pursuing enemies.

 

Key Features:

  • AI Hunter Groups: Multiple hunter groups can be assigned to patrol and search for players based on player proximity, without ever "knowing" the player's exact location. The AI relies on randomized waypoints near the player's last known position.
  • Dynamic Waypoints: Hunters cycle through various modes such as Search and Destroy (SAD), Expand (EXP), Found (FND), and Return to Home (HOM), each with different waypoint behaviors.
  • Stamina System: Hunter groups operate under a stamina system. As they search, their stamina depletes, and once it's exhausted, they return to their starting point (HOM). Hunters will search a bit longer if they detect the player, but if they don't, they'll tire and abandon the chase.
  • Realism Focus: Hunters don’t have omniscient knowledge of the player's location. Instead, they make plausible guesses based on the last known position and search randomly within a defined radius, giving players a genuine chance to escape using stealth and good tactics.

 

Configurable Parameters:

  • Search Distance: Varying search ranges are used for each mode (SAD, EXP, FND) to simulate expanding and contracting search areas.
  • Stamina: Configurable number of search cycles before the AI tires and returns home.
  • Chance to Track: You can adjust how likely a group is to continue tracking the player based on the last known position.
  • Debug Mode: In debug mode, waypoints, markers, and detailed AI behavior (such as stamina use, awareness levels, etc.) are logged to the screen and clipboard. This helps in refining or troubleshooting the AI behavior.

 

Workflow:

  • Initialization:
    • The script initializes by recording the starting positions of each hunter group and setting up a stamina counter for each - prior to starting the hunt.

 

  • Modes:
    • MOV (Move): Hunters patrol random positions near the last known player position - exempt from stamina.
    • SAD (Search & Destroy): Hunters actively search the designated area in the general vicinity of the player.
    • EXP (Expand): After searching SAD, the search radius expands to cover more ground.
    • FND (Found): When the player is detected, the AI attempts to engage near the player. If unsuccessful after several cycles, it switches to reposition mode.
    • REP (Reposition): Hunters attempt to break target lock and move away to reset the search.
    • HOM (Home): Hunters return to their starting position after exhausting their stamina and are deleted from the game.

 

  • Execution:
    • The script loops continuously, updating waypoints, managing AI behavior, and exiting when all groups have either been killed or returned home.

 

Example Usage:

Simply place the script in a trigger, define your hunter groups, and customize the parameters to your liking. For example, you can adjust the _stamTix variable to change how long hunter groups will search before tiring. In debug mode, you can monitor AI behaviors directly on the map and tweak settings accordingly.

 

  • private _hunters = [Hunt1, Hunt2];
  • [_hunters] execVM "SCOhunter.sqf";

 

Debug is on in the script posted below - just set it to "0" to turn it off:

 

  • private _debug = 1;

 

Hopefully this script provides a more immersive and plausible E&E experience, where good fieldcraft can help players evade their pursuers, making it ideal for jungle warfare scenarios.

 

 

SOG Test Mission 2.4 (CBA SOG/PF SOG_AI)

SCO_Demo_Hunter

 

 

 

FULL SCRIPT (Updated 2.4):

Spoiler

///////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////

// FILE NAME: SCOhunter.sqf
// ARGS: _huntArr - An array of hunter groups to manage.
// AUTHOR: Scottb613

// OVERVIEW: Manages the behavior of Hunter Groups in relation to player proximity, implementing SAD
//      FND and MOVE waypoints, stamina ticket consumption, and home return functionality. This is 
//      strictly designed for rural encounters - as buildings are not addressed.

// REQUIRES: Call [] SCOhunterGroups.sqf with an array of hunter groups. 

// SUGGESTION: Call from trigger.

// EXAMPLE CALL: private _hunters = [Hunt1, Hunt2];    
//               [_hunters] execVM "SCOhunter.sqf";

// NOTE: Tested SP only.

// GIVEN: Multiple Hunter Groups per instance of script supported.
// GIVEN: Records the starting positions of each Hunter Group for return home.
// GIVEN: Hunter Groups do not "know" player position - just a random area surrounding same for WP.
// GIVEN: Hunter Groups are given a random value to maintain track.
// GIVEN: Hunter Groups search area expands and contracts based on mode and discovery.
// GIVEN: In debug mode - waypoints create markers on the map at WP's location - (debug = 1).
// GIVEN: In debug mode - hint will display as hunter Stamina Tickets are consumed - (debug = 1).
// GIVEN: In debug mode - Marker label shows the value of knowsAbout.
// GIVEN: Marker labeled FND (found) are Yellow for SAD WP's after discovery.
// GIVEN: Marker labeled SAD (S&D) are Red for SAD WP's.
// GIVEN: Marker labeled MOV (move) are Blue for Move WP's.
// GIVEN: Marker labeled HOM (home) are Green for home position and are Move WP's.
// GIVEN: Marker labeled EXP (expand) are Orange for expanded search and are SAD WP's.
// GIVEN: Marker labeled REP (reposition) are Brown to get AI to move off and reposition on target.
// GIVEN: Hunter Groups enter SAD Mode when within a specified distance to the player - _sadDist.
// GIVEN: When in SAD Mode - player position is not updated for search until next MOV or FND WP.
// GIVEN: If _sadDist is exceeded, Hunter Groups transition to MOV Mode with new waypoints.
// GIVEN: Hunter Groups in SAD Mode are not provided further updates on player pos until return to MOV Mode.
// GIVEN: Random search methods for SAD and EXP modes are chosen within specified search distances.
// GIVEN: The search area expands after SAD Mode to allow for broader search by EXP Mode.
// GIVEN: When in FND on target - transitions to REP to give space and reset search.
// GIVEN: Stamina Tickets - counts maintained by group.
// GIVEN: Stamina Tickets - randomly assigned base variable - plus or minus variation variable - per group.
// GIVEN: Stamina Tickets - consumtion .75 when _knowsAbout is exceeded - FND - a little more searching.
// GIVEN: Stamina Tickets - are not consumed in MOV Mode.
// GIVEN: Stamina Tickets - are consumed - 1 per cycle - _loopTime.
// GIVEN: When all Stamina Tickets are consumed - Hunter Groups return to HOM.
// GIVEN: When Hunter Groups arrive HOM - groups are deleted.
// GIVEN: Script terminates if all hunter groups killed or ordered HOM.

///////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////

// User Configurable Variables
private _debug = 0;             // Debug flag "0" is off

private _sadDist = 150;         // Distance threshold for SAD mode
private _sadCycles = 2;         // Number of SAD cycles before switch to EXP
private _fndCycles = 2;         // Number of FND cycles before switch to REP
private _knowsAbout = 1.0;      // Threshold for knowsAbout to switch to FND
private _loopTime = 45;         // Loop time in seconds

private _chanceTrack = .50;     // Chance of maintaining track per cycle
private _trkErrMax = 100;       // If Tracked max position error
private _trkErrMin = 50;        // If Tracked min position error

private _movRandMax = 100;      // MOV Random WP search distance
private _movRandMin = 70;       // MOV Random WP search distance

private _expRandMax = 150;      // EXP Random WP search distance
private _expRandMin = 100;      // EXP Random WP search distance

private _sadRandMax = 100;      // SAD Random WP search distance
private _sadRandMin = 70;       // SAD Random WP search distance

private _fndRandMax = 70;       // FND Random WP search distance
private _fndRandMin = 50;       // FND Random WP search distance

private _stamTix = 0;           // Stamina ticket init
private _stamTixBas = 7;        // Stamina ticket base count
private _stamTixVar = 4;        // Stamina ticket random variation +/- base

///////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////

// System Variables
private _stamTixPerGroup = [];  // Stores individual stamina tickets for each group

//Accept the array of hunt groups passed from the call
params ["_huntArr"];

// Clear Windows Clipboard
copyToClipboard "";

// FUNCTION - Log to Windows Clipboard
_fcLogger = {
    params ["_logEnt"];
    private ["_logHld", "_logSpc", "_logPut"];
    _logHld = copyFromClipboard;
    _logSpc = " ## ";
    _logPut = _logHld + _logEnt + _logSpc;
    copyToClipboard _logPut;
};

// FUNCTION - Reset Amok AI Squad 
_fcUnitsAmok = {
    params ["_huntGroup"];
    for "_i" from 1 to 4 do {
        {
            private _unitHunt = _x;
            {
                private _unitPlay = _x;
                _unitHunt forgetTarget _unitPlay;
                _unitHunt reveal [_unitPlay, -1];
            } forEach units group player;

            _unitHunt disableAI "TARGET";
            _unitHunt disableAI "AUTOTARGET";
            _unitHunt disableAI "SUPPRESSION";
            _unitHunt disableAI "FSM";     
            _unitHunt disableAI "COVER";  
            _unitHunt disableAI "AUTOCOMBAT"; 

            sleep 0.15;

            _unitHunt enableAI "TARGET";
            _unitHunt enableAI "AUTOTARGET";
            _unitHunt enableAI "SUPPRESSION";
            _unitHunt enableAI "FSM";
            _unitHunt enableAI "COVER";
            _unitHunt enableAI "AUTOCOMBAT"; 

            _unitHunt setCombatMode "BLUE";  
            _unitHunt setBehaviour "AWARE";
            _unitHunt setUnitPos "UP";
    
        } forEach (units _huntGroup);
    }; 
};

// FUNCTION - Resume Normal AI Squad 
_fcUnitsNorm = {
    params ["_huntGroup"];
        {
            private _unitHunt = _x;
            _unitHunt setCombatMode "YELLOW";  
            _unitHunt setBehaviour "AWARE";
            _unitHunt setUnitPos "AUTO"; 
            
        } forEach (units _huntGroup);
};

// Record player position
SCOlastKnown = getPos player;

// Record the starting positions of each hunter group
private _startPos = [];

// Initialize flag for tracking SAD-to-MOV transitions
private _expFlag = false;

// Initialize SAD cycle count for each group
private _sadCycleCounts = []; 

// Additional variable to track consecutive FND cycles for each group
private _fndCycleCounts = [];  // Track FND cycles for each group

// Test if the _huntArr array is empty
if (count _huntArr == 0) exitWith {
    if (_debug == 1) then {
        hint "No hunter groups passed to script.\n-EXITING SCRIPT-";
    };
    true;
};

// Test to see which Hunter Groups are valid
_existGrp = _huntArr select {!isNil "_x"};
_huntArr = _existGrp;

// Test if the _huntArr array is empty
if (count _huntArr == 0) exitWith {
    if (_debug == 1) then {
        hint "No valid hunter groups added to mission.\n-EXITING SCRIPT-";
    };
    true;
};

// Last Known POS Marker - initialization
private _markLastKnownName = "LastKnownMarker"; // Marker name
private _markLastKnown = createMarker [_markLastKnownName, SCOlastKnown];

// Initialize each group with the starting stamina tickets
{
    _startPos pushBack (getPos leader _x);
    _sadCycleCounts pushBack 0;  // Initialize SAD cycle count for each group
    _fndCycleCounts pushBack 0;  // Initialize FND cycle count for each group

    // Calculate the random stamina ticket count and round to the nearest whole number
    private _stamTix = round (_stamTixBas + (random (_stamTixVar * 2)) - _stamTixVar);
    _stamTixPerGroup pushBack _stamTix;
    
} forEach _huntArr;

// Additional variable to track groups that have been ordered "HOM"
private _homGroups = [];  // Store the group indices that have been ordered "HOM"

// Main Cycle Loop
private _loopRun = true;  // Control variable for the loop
while {_loopRun} do {

    // Flag to check if any group entered SAD mode
    private _anySadMode = false;
    
    // Flag to check if any group entered FND mode
    private _anyFndMode = false;
    
    // Flag to check if any group entered EXP mode
    private _anyExpMode = false;

    // Flag to check if any group entered REP mode
    private _anyRepMode = false;

    // Keep track of the number of alive groups
    private _aliveGroups = 0;

    // Collect stamina ticket information for all groups
    private _staminaHintText = "Stamina Tickets\n";

    // Hunter Groups Cycle Loop
    {
        private _huntGroup = _x;  // Current hunter group
        private _groupIndex = _forEachIndex;  // Get the index of the group
        private _groupStamTix = _stamTixPerGroup select _groupIndex;  // Get the group's individual stamina tickets

        // Check if the hunter group is still alive
        if ({alive _x} count units _huntGroup == 0) then {
            if (_debug == 1) then {
                hint format ["Hunter group %1 is dead, removing markers and from hunt group array.", _huntGroup];
                sleep 3;
            };

            // Remove markers associated with the dead group
            private _markSadName = format ["HuntSadMarker_%1", _huntGroup];
            private _markMovName = format ["HuntMovMarker_%1", _huntGroup];
            private _markHomName = format ["HuntHomMarker_%1", _huntGroup];

            deleteMarker _markSadName;
            deleteMarker _markMovName;
            deleteMarker _markHomName;

            continue;
        };


        // Increment the count of alive groups
        _aliveGroups = _aliveGroups + 1;

        // If the group has already been ordered "HOM," skip it
        if (_groupIndex in _homGroups) then {
            continue;
        };

        // Create unique marker names based on the group index
        private _markSadName = format ["HuntSadMarker_%1", _huntGroup];
        private _markMovName = format ["HuntMovMarker_%1", _huntGroup];
        private _markHomName = format ["HuntHomMarker_%1", _huntGroup];
        
        // Clear any existing markers for the current group
        if (_debug == 1) then {
            deleteMarker _markSadName;
            deleteMarker _markMovName;
            deleteMarker _markHomName;
            deleteMarker _markLastKnown;
        };

        // Convert group name to string for marker label
        private _grpName = str _huntGroup;
        private _splitName = _grpName splitString " ";
        private _markLabel = _splitName select 1;

        // Get the player position
        private _playerPos = getPos player;

        // Check if the hunter group knows about the player
        private _knowsAboutValue = (_huntGroup knowsAbout player);

        // Log awareness status
        if (_debug == 1) then {
            private _logEntAware = format ["KnowsAbout Value for %1: %2", _huntGroup, _knowsAboutValue];
            [_logEntAware] call _fcLogger;
        };

        // Get the hunter group position
        private _huntPos = getPos leader _huntGroup;

        // Calculate the distance from the hunter group to the last known position
        private _distToPlayer = _huntPos distance SCOlastKnown;

        // Log the distance for debugging
        if (_debug == 1) then {
            private _logEntDistance = format ["Distance to Player for %1: %2", _huntGroup, _distToPlayer];
            [_logEntDistance] call _fcLogger;
        };

        // Delete existing waypoints if they exist
        {
            deleteWaypoint _x;
        } forEach waypoints _huntGroup;

        // Mode Pick Logic
        private _mode = "";
        if (_groupStamTix <= 0) then {
            _mode = "HOM";  // If stamina tickets are exhausted, set to HOM mode
        } else {
            if (_knowsAboutValue >= _knowsAbout && _distToPlayer < _sadDist) then {
                // Check if REP mode should be triggered instead of FND
                if (_fndCycleCounts select _groupIndex >= _fndCycles) then {
                    _mode = "REP";  // Trigger REP mode after enough FND cycles
                } else {
                    _mode = "FND";  // Found mode if knowsAbout value exceeds the threshold and within range
                }
            } else {
                if (_distToPlayer < _sadDist) then {
                    // If the SAD cycles are fewer than the threshold, stay in SAD
                    if (_sadCycleCounts select _groupIndex < _sadCycles) then {
                        _mode = "SAD";
                    } else {
                        _mode = "EXP";  // Transition to EXP only after enough SAD cycles
                    };
                } else {
                    _mode = "MOV";
                };
            };
        };
        
        // Chance of maintaining track
        private _groupNum = count _huntArr;
        private _additionalChance = 0;

        if (_groupNum > 1) then {
            _additionalChance = _groupNum * 0.025;
        };

        if (random 1 < ((_chanceTrack / _groupNum) + _additionalChance)) then {
            SCOlastKnown = getPos player;

            // Tracking Error
            private _newTrkPos = [SCOlastKnown, _trkErrMin, _trkErrMax, 3, 0, 20, 0] call BIS_fnc_findSafePos;
            SCOlastKnown = _newTrkPos;

            // Reset the SAD cycle count for the group when the player is discovered
            _sadCycleCounts set [_groupIndex, 0];
        };


        // Action based on mode
        switch (_mode) do {
            case "SAD": {
                _anySadMode = true;  // Mark that at least one group is in SAD mode
                
                // Call Resume Normal AI 
                [_huntGroup] call _fcUnitsNorm;                   
                
                private _newRandomPos = [SCOlastKnown, _sadRandMin, _sadRandMax, 3, 0, 20, 0] call BIS_fnc_findSafePos;
                
                // SAD Waypoint
                private _wpSad = _huntGroup addWaypoint [_newRandomPos, 0];
                _wpSad setWaypointType "MOVE";
    
                // 50% chance to set Limited/Stealth
                if (random 1 < 0.5) then {
                    _wpSad setWaypointSpeed "LIMITED";
                    _wpSad setWaypointBehaviour "STEALTH";
                    _wpSad setWaypointFormation "LINE";
                } else {
                    _wpSad setWaypointSpeed "LIMITED";
                    _wpSad setWaypointBehaviour "AWARE";
                    _wpSad setWaypointFormation "LINE";
                };

                // Increment the SAD cycle count for the group
                _sadCycleCounts set [_groupIndex, (_sadCycleCounts select _groupIndex) + 1];

                // Decrement the stamina tickets for SAD mode
                _groupStamTix = _groupStamTix - 1;

                if (_debug == 1) then {
                    private _logEntSAD = format ["SAD WP %1: %2", _huntGroup, _newRandomPos];
                    [_logEntSAD] call _fcLogger;

                    private _markSad = createMarker [_markSadName, _newRandomPos];
                    _markSad setMarkerType "mil_dot";
                    _markSad setMarkerColor "ColorRed";
                    _markSad setMarkerText format ["SAD %1: %2", _markLabel, _knowsAboutValue];
                    _markSad setMarkerSize [0.5, 0.5];
                };
            };

            case "MOV": {
            
                // Call Resume Normal AI 
                [_huntGroup] call _fcUnitsNorm;

                private _randomPos = [SCOlastKnown, _movRandMin, _movRandMax, 3, 0, 20, 0] call BIS_fnc_findSafePos;
                
                // MOV Waypoint
                private _wpMov = _huntGroup addWaypoint [_randomPos, 0];
                _wpMov setWaypointType "MOVE";
                _wpMov setWaypointBehaviour "AWARE";
                _wpMov setWaypointSpeed "FULL";
                _wpMov setWaypointFormation "COLUMN";

                // Reset SAD cycle count when moving to MOV
                _sadCycleCounts set [_groupIndex, 0];

                if (_debug == 1) then {
                    private _logEntWP = format ["MOV WP %1: %2", _huntGroup, _randomPos];
                    [_logEntWP] call _fcLogger;

                    private _markMov = createMarker [_markMovName, _randomPos];
                    _markMov setMarkerType "mil_dot";
                    _markMov setMarkerColor "ColorBlue";
                    _markMov setMarkerText format ["MOV %1: %2", _markLabel, _knowsAboutValue];
                    _markMov setMarkerSize [0.5, 0.5];
                };
            };

            case "EXP": {
                _anyExpMode = true;  // Mark that at least one group is in EXP mode

                // Call Resume Normal AI 
                [_huntGroup] call _fcUnitsNorm;                   

                private _expPos = [SCOlastKnown, _expRandMin, _expRandMax, 3, 0, 20, 0] call BIS_fnc_findSafePos;
                
                // EXP Waypoint
                private _wpExp = _huntGroup addWaypoint [_expPos, 0];
                _wpExp setWaypointType "MOVE";

                // 50% chance to set Limited/Stealth
                if (random 1 < 0.5) then {
                    _wpExp setWaypointSpeed "LIMITED";
                    _wpExp setWaypointBehaviour "STEALTH";
                    _wpExp setWaypointFormation "LINE";
                } else {
                    _wpExp setWaypointSpeed "NORMAL";
                    _wpExp setWaypointBehaviour "AWARE";
                    _wpExp setWaypointFormation "LINE";
                };

                // Decrement stamina tickets for EXP mode
                _groupStamTix = _groupStamTix - 1;

                if (_debug == 1) then {
                    private _logEntEXP = format ["EXP WP %1: %2", _huntGroup, _expPos];
                    [_logEntEXP] call _fcLogger;

                    private _markExp = createMarker [_markMovName, _expPos];
                    _markExp setMarkerType "mil_dot";
                    _markExp setMarkerColor "ColorOrange";
                    _markExp setMarkerText format ["EXP %1: %2", _markLabel, _knowsAboutValue];
                    _markExp setMarkerSize [0.5, 0.5];
                };
            };
            
            case "REP": {
                _anyRepMode = true;  // Mark that at least one group is in REP mode

                // Call Reset Amok AI 
                [_huntGroup] call _fcUnitsAmok;    
                
                private _expPos = [SCOlastKnown, _expRandMin, _expRandMax, 3, 0, 20, 0] call BIS_fnc_findSafePos;
                
                // REP Waypoint
                private _wpRep = _huntGroup addWaypoint [_expPos, 0];
                _wpRep setWaypointType "Move";
                _wpRep setWaypointSpeed "FULL";
                _wpRep setWaypointBehaviour "AWARE";
                _wpRep setWaypointFormation "COLUMN";

                // Decrement stamina tickets for REP mode
                _groupStamTix = _groupStamTix - 1;

                if (_debug == 1) then {
                    private _logEntREP = format ["REP WP %1: %2", _huntGroup, _expPos];
                    [_logEntREP] call _fcLogger;

                    private _markRep = createMarker [_markMovName, _expPos];
                    _markRep setMarkerType "mil_dot";
                    _markRep setMarkerColor "ColorBrown";
                    _markRep setMarkerText format ["REP %1: %2", _markLabel, _knowsAboutValue];
                    _markRep setMarkerSize [0.5, 0.5];
                };

                // Reset FND cycles count after REP action
                _fndCycleCounts set [_groupIndex, 0];
            };

            case "FND": {
                _anyFndMode = true;  // Mark that at least one group is in FND mode
                
                // Call Resume Normal AI 
                [_huntGroup] call _fcUnitsNorm;                   
                
                SCOlastKnown = getPos player;
                private _foundPos = [_playerPos, _fndRandMax, _fndRandMax, 3, 0, 20, 0] call BIS_fnc_findSafePos;
                
                // FND Waypoint
                private _wpFnd = _huntGroup addWaypoint [_foundPos, 0];
                _wpFnd setWaypointType "SAD";
                _wpFnd setWaypointSpeed "LIMITED";
                _wpFnd setWaypointFormation "LINE";

                // Decrement 0.75 stamina tickets for FND mode
                _groupStamTix = _groupStamTix - 0.75;

                // Increment the FND cycle count for the group
                _fndCycleCounts set [_groupIndex, (_fndCycleCounts select _groupIndex) + 1];

                if (_debug == 1) then {
                    private _logEntFND = format ["FND WP %1: %2", _huntGroup, _foundPos];
                    [_logEntFND] call _fcLogger;

                    private _markFnd = createMarker [_markMovName, _foundPos];
                    _markFnd setMarkerType "mil_dot";
                    _markFnd setMarkerColor "ColorYellow";
                    _markFnd setMarkerText format ["FND %1: %2", _markLabel, _knowsAboutValue];
                    _markFnd setMarkerSize [0.5, 0.5];
                };
            };

            case "HOM": {
                private _startPos = _startPos select _groupIndex;
                
                // Call Reset Amok AI 
                [_huntGroup] call _fcUnitsAmok;    

                // HOM Waypoint
                private _wpHom = _huntGroup addWaypoint [_startPos, 0];
                _wpHom setWaypointType "MOVE";
                _wpHom setWaypointSpeed "NORMAL";
                _wpHom setWaypointFormation "COLUMN";
                _wpHom setWaypointBehaviour "AWARE";
                _wpHom setWaypointStatements ["true", "{deleteVehicle _x} forEach units group this;"];
                    
                if (_debug == 1) then {
                    private _logEntHOM = format ["%1 return HOM: %2", _huntGroup, _startPos];
                    [_logEntHOM] call _fcLogger;

                    private _markHom = createMarker [_markHomName, _startPos];
                    _markHom setMarkerType "mil_dot";
                    _markHom setMarkerColor "ColorGreen";
                    _markHom setMarkerText format ["HOM %1", _markLabel];
                    _markHom setMarkerSize [0.5, 0.5];
                };

                // Add the group to the list of groups that have been ordered "HOM"
                _homGroups pushBack _groupIndex;
            };
        };

        // Update the group's stamina tickets in the array
        _stamTixPerGroup set [_groupIndex, _groupStamTix];

        // Add the group's stamina tickets to the accumulated hint text
        _staminaHintText = _staminaHintText + format ["%1: %2\n", _markLabel, _groupStamTix];

    } forEach _huntArr;

    // Remove dead groups
    _huntArr = _huntArr select { {alive _x} count units _x > 0 };

    // Display a combined hint with the stamina tickets for all groups
    if (_debug == 1) then {
        hint _staminaHintText;
    };

    // Check if the marker exists by verifying its position
    if (_debug == 1) then {
        _markLastKnown = createMarker [_markLastKnownName, SCOlastKnown]; // Recreate to update position
        _markLastKnown setMarkerType "mil_dot";
        _markLastKnown setMarkerColor "ColorPink"; // Change color as needed
        _markLastKnown setMarkerText "Last Known";
        _markLastKnown setMarkerSize [0.5, 0.5];
    };

    // Exit the loop if no more alive groups or all groups have been ordered "HOM"
    if (_aliveGroups == 0 || {count _homGroups == count _huntArr}) then {
        _loopRun = false;
    };

    sleep _loopTime;
}; // End While Loop

// Log Exit
if (_debug == 1) then {
    private _logExit = "Program Exit";
    [_logExit] call _fcLogger;
    
    // Display a hint on exit
    hint "Program Exit";
};

 

 

 

 

Regards,
Scott

  • Like 1

Share this post


Link to post
Share on other sites

Hi Folks,

 

Updated the script - not the mission - if you try the mission you'll need to copy and paste the script.

  • Added known location marker in debug so you know the point where waypoint generation is based.
  • When in SAD or EXP - known location is not updated so you can work on making a successful egress.
  • Changed some parameters of BIS_fnc_findSafePos - to better replicate searching.
  • Changed the logic - after x number of SAD cycles - respective group will switch to EXP - to expand the search area.
  • Added some randomness to how the hunter groups search.

 

Cycle Modes:

  • MOV - Move
  • SAD - Search and Destroy
  • EXP - Expanded Search and Destroy
  • FND - AI Found Player (knowsAbout)
  • HOM - Home After Search is Done

 

 

Regards,
Scott 

Share this post


Link to post
Share on other sites

Hi Folks,

 

Question - when knowsAbout is high - I can't get a group to depart and follow waypoints - is there any trick to this?

 

Here is what I've tried:

				// Reset knowsAbout to depart and disable AI targeting behavior
				{
				    _x reveal [player, 0];  
				    _x disableAI "TARGET";  
				    _x disableAI "AUTOTARGET";  
				    _x disableAI "SUPPRESSION";  
				    _x disableAI "FSM";  
				} forEach units _huntGroup;

 

Share this post


Link to post
Share on other sites

Hi Folks,

 

UPDATED the Script in first post - I think I have a routine added to pull the hunters off the players squad - when knowsAbout is high - to both reposition hunters instead from just standing over a hidden player group - and - to go home at mission end.

 

I added some randomness to maintain a good trail - tested per group - per cycle. 

 

Depending on the configurable variables set - it should prove challenging but possible to escape - with some real variation in the searching. 

 

Debug is ON - turn it off of you want to try it for real (no hints - no markers).

 

I use it with SOG's Random Site Module - with several hunt groups in different locations - and a few extra random sites hanging in dead air - so when the module is run - it could pick a hunter group from one of several sites at different distances/directions - or none at all. The thrill is not knowing.

 

Enjoy.

 

Regards,
Scott

Share this post


Link to post
Share on other sites

Hi Folks,

 

Updated both the script and the demo mission - need CBA and SOG for demo. I also added in my status screen via the actionMenu. The mission is in debug mode - simply set "_debug = 0;" to turn off the markers and hints. Just kill or avoid the random hunter teams - as you see fit and conditions dictate.

 

Regards,

Scott 

Share this post


Link to post
Share on other sites

Hi Folks,

 

User configurable.

 

Added some more randomness - to keep the player guessing - Stamina Tickets are assigned to each group - individually - base value - plus or minus random variation - so you don't know when the hunters will break off the attack. Multiple groups will break off at different times.

 

private _stamTix = 0;           // Stamina ticket init
private _stamTixBas = 7;        // Stamina ticket base count
private _stamTixVar = 4;        // Stamina ticket random variation +/- base

 

This was already in there but tries to replicate tracker skill.

 

private _chanceTrack = .50;     // Chance of maintaining track per cycle
private _trkErrMax = 80;        // If Tracked max position error
private _trkErrMin = 40;        // If Tracked min position error

 

Script updated in first post.

 

Demo mission updated in first post.

 

Regards,

Scott

  • Like 1

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now

×