Jump to content
Sign in to follow this  
Binesi

Improved BIS_fnc_taskDefend

Recommended Posts

Updated to 1.1 - Added in a random repeating delayed waypoint swap between search & destroy and dismissed to confine micro patrol ranges to about 75m and increase overall activity. They will continuously switch between various activities such as sitting down, standing around, going on 1-4 man patrols, or doing an occasional coordinated sweep of their local area.

Updated to 1.2 - Typo fixed which could break the cycle and allow patrols to wander out of range.

Updated to 1.3 - Prevented units from running around while they are not in combat as it looked a bit off.

Updated to 1.3a - Fixed typo which shouldn't effect anything either way.

Alternative version added "BIN_taskDefendLoose.sqf". This one has simplified coding and will re-man defenses after completing each combat. However there is a downside with this script in that individual units may wander quite far from their defense point.

*****

I made some improvements to BIS_fnc_taskDefend. I know a lot of you are using this function as it's convenient so I thought I would share my optimized version as I've been very happy with it's behavior.

Basically more efficient and effective. This version will reliably man all nearby defenses (even buggy spawned BIS compositions) and will additionally send out micro patrols in it's vicinity and otherwise act fairly believably without using much CPU.

When enemies are detected the area is searched and cleared before resuming their normal activities.

This version will also man empty vehicle turrets so you can place vehicles as static defenses. Read the code notes to see how to prevent this behavior if not desired.

*****

Copy and paste this code into a new file called "BIN_taskDefend.sqf" and then put into your mission directory. After, in the mission editor copy the below line into the group leader's init field that you want to do the defending. Make sure he is in the right position.

null = [group this,(getPos this)] execVM "BIN_taskDefend.sqf"

Just use notepad to create this script and make sure you save the file as "BIN_taskDefend.sqf" and not "BIN_taskDefend.sqf.txt". To make sure go to Windows Explorer and then find folder options and see that "Hide extensions for known file types" is NOT checked.

BIN_taskDefend.sqf

/*
=======================================================================================================================
Script: BIN_taskDefend.sqf v1.3a
Author(s): Binesi
Partly based on original code by BIS

Description:
Group will man all nearby static defenses and vehicle turrets and guard/patrol the position and surrounding area.

Parameter(s):
_this select 0: group (Group)
_this select 1: defense position (Array)

Returns:
Boolean - success flag

Example(s):
null = [group this,(getPos this)] execVM "BIN_taskDefend.sqf"

-----------------------------------------------------------------------------------------------------------------------
Notes:

To prevent this script from manning vehicle turrets find and replace "LandVehicle" with "StaticWeapon".

The "DISMISS" waypoint is nice but bugged in a few ways. The odd hacks in this code are used to force the desired behavior.
The ideal method would be to write a new FSM and I may attempt that in a future project if no one else does. 

=======================================================================================================================
*/

private ["_grp", "_pos"];
_grp = _this select 0;
_pos = _this select 1;

_grp setBehaviour "SAFE";

private ["_list", "_units","_staticWeapons"];
_list = _pos nearObjects ["LandVehicle", 120];
_units = (units _grp) - [leader _grp]; // The leader should not man defenses
_staticWeapons = [];

// Find all nearby static defenses or vehicles without a gunner
{
   if ((_x emptyPositions "gunner") > 0) then 
   {
       _staticWeapons = _staticWeapons + [_x];    
   };
} forEach _list;

// Have the group man empty static defenses and vehicle turrets
{
   // Are there still units available?
   if ((count _units) > 0) then 
   {
       private ["_unit"];
       _unit = (_units select ((count _units) - 1));

       _unit assignAsGunner _x;
       [_unit] orderGetIn true;
       sleep 16; // Give gunner time to get in, otherwise force.
       _unit moveInGunner _x;

       _units resize ((count _units) - 1);
   };
} forEach _staticWeapons;

// Setup Waypoints
private ["_wp1","_wp2","_wp3","_wp4"];

_wp1 = _grp addWaypoint [_pos, 0];
_wp1 setWaypointType "MOVE";
[_grp, 1] setWaypointSpeed "LIMITED";
[_grp, 1] setWaypointBehaviour "SAFE";
[_grp, 1] setWaypointCombatMode "YELLOW";
[_grp, 1] setWaypointFormation "STAG COLUMN";
[_grp, 1] setWaypointCompletionRadius 50;
[_grp, 1] setWaypointStatements ["true", "null = [this] spawn {
       _grp = group (_this select 0);
       sleep (30+(random 60));
       {doStop _x} forEach units _grp;
       _grp setCurrentWaypoint [_grp,3];
       {_x doMove getPos _x} forEach units _grp;
       sleep 1;
       {_x forceSpeed 3} forEach units _grp;
       if ((random 3)> 2) then {sleep 3} else {sleep 30 + (random 30)};
       _grp setCurrentWaypoint [_grp, 1];
}; "];

_wp2 = _grp addWaypoint [_pos, 0];
_wp2 setWaypointType "DISMISS";
[_grp, 2] setWaypointStatements ["true", "null = [this] spawn {
       _grp = group (_this select 0);
       {_x forceSpeed -1 } forEach units _grp;
}; "];

_wp3 = _grp addWaypoint [_pos, 0];
_wp3 setWaypointType "SAD";
[_grp, 3] setWaypointSpeed "FULL";
[_grp, 3] setWaypointBehaviour "ALERT";
[_grp, 3] setWaypointCombatMode "RED";
[_grp, 3] setWaypointFormation "VEE";
[_grp, 3] setWaypointCompletionRadius 50;
[_grp, 3] setWaypointStatements ["true", "null = [this] spawn {
       _grp = group (_this select 0);
       _grp setCurrentWaypoint [_grp, 1];
}; "];

_wp4 = _grp addWaypoint [_pos, 0];
_wp4 setWaypointType "CYCLE"; // Redundant failsafe

true

BIN_taskDefendLoose.sqf

/*
============================================================================================================
Script: BIN_taskDefendLoose.sqf v1.0
Author(s): Binesi
Partly based on original code by BIS

Description:
Group will man all nearby static defenses and vehicle turrets and guard/patrol the position and surrounding area.

Parameter(s):
_this select 0: group (Group)
_this select 1: defense position (Array)
_this select 2: radius (Number)

Returns:
Boolean - success flag

Example(s):
null = [group this,(getPos this)] execVM "BIN\BIN_taskDefend.sqf"

------------------------------------------------------------------------------------------------------------
Notes:

To prevent this script from manning vehicle turrets find and replace "LandVehicle" with "StaticWeapon".

Beware that this script uses the "DISMISS" waypoint waypoint which allows some units to wander quite far from their defense position.

============================================================================================================
*/
private ["_grp", "_pos", "_radius", "_list", "_static_weapons", "_units", "_wp1","_wp2","_wp3"];

_grp = _this select 0;
_pos = _this select 1;
_radius = if ((count _this) > 2) then {_this select 2} else {100};
_grp setBehaviour "SAFE";
_list = _pos nearObjects ["LandVehicle", _radius];
_units = (units _grp) - [leader _grp]; // The leader should not man defenses
_static_weapons = [];

// Find all nearby static defenses or vehicles without a gunner
{
   if ((_x emptyPositions "gunner") > 0) then 
   {
       _static_weapons = _static_weapons + [_x];    
   };
} forEach _list;

// Have the group man empty static defenses and vehicle turrets
{
   // Are there still units available?
   if ((count _units) > 0) then 
   {
       private ["_unit"];
       _unit = (_units select ((count _units) - 1));

       _unit assignAsGunner _x;
       [_unit] orderGetIn true;
       // Give gunner time to get in, otherwise force.
       _unit spawn { sleep 16; _this moveInGunner _x; };        
       _units resize ((count _units) - 1);
   };
} forEach _static_weapons;

// Setup Waypoints
_wp1 = _grp addWaypoint [_pos, 0];
_wp1 setWaypointType "DISMISS";
[_grp, 1] setWaypointSpeed "LIMITED";
[_grp, 1] setWaypointBehaviour "SAFE";
[_grp, 1] setWaypointCombatMode "YELLOW";
[_grp, 1] setWaypointFormation "STAG COLUMN";
[_grp, 1] setWaypointCompletionRadius 50;
[_grp, 1] setWaypointStatements ["true", "null = [this] spawn
{
   _grp = group (_this select 0);
   _grp setBehaviour 'STEALTH';
   { _x setUnitPos 'DOWN'; } forEach units _grp;
   sleep (2+(random 3));
   { _x setUnitPos 'MIDDLE'; } forEach units _grp;
   sleep (20+(random 40));
   { _x setUnitPos 'AUTO'; } forEach units _grp;
}; "];

_wp2 = _grp addWaypoint [_pos, 0];
_wp2 setWaypointType "SAD";
[_grp, 2] setWaypointSpeed "FULL";
[_grp, 2] setWaypointBehaviour "ALERT";
[_grp, 2] setWaypointCombatMode "RED";
[_grp, 2] setWaypointFormation "VEE";
[_grp, 2] setWaypointCompletionRadius 50;
[_grp, 2] setWaypointStatements ["true", "null = [this] spawn
{
   _grp = group (_this select 0);
   _list = position (_this select 0) nearObjects ['LandVehicle', 120];
   _static_weapons = [];
   {
       if ((_x emptyPositions 'gunner') > 0) then 
       {
           _static_weapons = _static_weapons + [_x];    
       };
   } forEach _list;
   {
       _units = units _grp;
       if ((count _units) > 0) then 
       {
           _unit = (_units select ((count _units) - 1));
           _unit assignAsGunner _x;
           [_unit] orderGetIn true;
           _unit spawn { sleep 16; _this moveInGunner _x; };        
           _units resize ((count _units) - 1);
       };
   } forEach _static_weapons;
}; "];

_wp3 = _grp addWaypoint [_pos, 0];
_wp3 setWaypointType "CYCLE";

true

Edited by Binesi
More instructions. Updated to 1.3

Share this post


Link to post
Share on other sites

Excellent! Had planned on bastardizing my own version, but you look like you've done much the same thing. Look forward to trying it out!

Hey - do you have an OFPEC tag? Want to name it as "yours." :D

Share this post


Link to post
Share on other sites
Hey - do you have an OFPEC tag? Want to name it as "yours."

No, but good idea. I registered one:

BIN_

Share this post


Link to post
Share on other sites

Hey - you taken a look at the taskPatrol script? I've used it a bit, and while it serves its purpose it also has some room for improvement. The waypoints can end up in a tangled mess, since each one can be at any angle from the prior one. You can have a "patrol" that criss-crosses a relatively small area.

At one time, I had a wp-generation system that basically created a pentagon around a spot, so that it ended up being more of a sequence. Was also planning on doing something like that with the taskPatrol.... unless someone beats me to it.... ;)

Share this post


Link to post
Share on other sites

Your pentagon system is interesting TRexian.

I need to give that some thought - how would a human setup patrols? A circular perimeter patrol is what I usually use with centrally located static defense.

I'll take a look at that function as well. It did look a bit rough. It isn't something I've used yet as patrols is an area I usually like to setup on a case by case basis or use Kronzky's UPS (although the later is a bit CPU heavy).

I can see some potential for using extra intelligence like checking height and going to high ground and trying to stay near cover. Also something that would work better for air units would be nice.

Share this post


Link to post
Share on other sites

Never ever use Dismiss. It has no restriction on how far units travel.

You will find 1, 2 man groups up to 4km away from that position if you leave it long enough (ie more than 10minutes).

Share this post


Link to post
Share on other sites
You will find 1, 2 man groups up to 4km away from that position if you leave it long enough (ie more than 10minutes).

Are you sure that this still happens in ArmaA 2? As much as I've watched this script they usually turn back toward center after getting about 100m out. Not saying it *never* happens, but I have yet to see such an extreme example.

For my purposes I like the effect of the small area patrols. It's a cheap way to get a bit more realism and non-predictability which would otherwise require more scripting overhead.

Edited by Binesi

Share this post


Link to post
Share on other sites

Just in case this problem with a dismissed waypoint still happens and to improve the script I've written in a waypoint reset (check first post for update). This keeps patrols within about 75m of center and increases the overall activity of the group for some added realism.

Edited by Binesi

Share this post


Link to post
Share on other sites
Any chance of an example mission

I could but there really isn't much to it. The script does everything by itself. Just copy it to the mission folder and put this in the init line of a group leader. Make sure that group leader is in the position you want to defend.

null = [group this,(getPos this)] execVM "BIN_taskDefend.sqf"

Or maybe you have an object you want to defend. In that case name the object something like DEFENDME. Again put this into the group leader init.

null = [group this,(getPos DEFENDME)] execVM "BIN_taskDefend.sqf"

Edited by Binesi
Oops, missed a bracket.

Share this post


Link to post
Share on other sites

Great work Binesi - the code sample in the first post still says 1.2 - is it updated?

Share this post


Link to post
Share on other sites

Yes, the code in the first post is current. I think I'll need to spend some time learning how to create a FSM to go any further with it.

Share this post


Link to post
Share on other sites

Typo in v1.3:

Line 68: private ["_wp1","_wp2","_wp3","wp4"];

wp4 should be _wp4

Share this post


Link to post
Share on other sites

Thanks for catching the typo shk. It could potentially cause an issue if anyone uses the call command to start this script and already has a _wp4 defined in that calling script.

I added in a second version, BIN_taskDefendLoose.sqf. This is the one I am using for missions. It is a bit more simple in that it doesn't try to work around the wandering units issue in the "Dismiss" type waypoint but instead relies on the normal cycling of that waypoint to add in some additional actions. The first is that it will re-man defenses after each engagement, and the second is that it will change through different combat stances at the start of battle to allow it to dive for cover immediately and then to move quickly into firing positions and fire over mid height fortifications like sandbags for a short time before going into automatic mode.

I am currently working on the latest version which does not use waypoints at all but runs in a loop to control each unit. This version tries to simulate normal ambient behavior. Units will cycle between different actions like talking to each other, sitting on benches and chairs, watching a campfire or burning barrel or television, lying down, etc. They will continue to do small patrols and man defenses. Still working out bugs in this version though...

Share this post


Link to post
Share on other sites

If it does everything and more that the default BIS taskDefend does, then just publish it as a replacement.

What I would really like to see is random building position patrols. Any chance you can put that in there?

Feel free to rip out any code from my RelaxedAI.sqf file.

Edited by Wolffy.au

Share this post


Link to post
Share on other sites

Hahaha, Wolffy - as you mentioned before our coding style is really similar. The logic you are using is not much different at all from what I have been working on. Thanks for that, I'll see if I can push forward with this script again. It was starting to get a bit too hamfisted with workarounds and I need to clean it up.

Share this post


Link to post
Share on other sites

Hi Binesi - I haven't attempted to merge building patrols yet, but I did merge another of your scripts into this one, so that units would man static defenses if they are killed - very handy for keeping MG nests manned in long fire fights. (I have another script that keeps the MG Nests rearmed).

Anyway, here's your code merged back into your script.

...
[_grp, 3] setWaypointStatements ["true", "null = [this] spawn {
       _grp = group (_this select 0);
       _list = position (_this select 0) nearObjects ['LandVehicle', 30];
       _static_weapons = [];
       {
               if ((_x emptyPositions 'gunner') > 0) then 
               {
                       _static_weapons = _static_weapons + [_x];    
               };
       } forEach _list;
  {
     _units = units _grp;
     if ((count _units) > 0) then 
     {
         _unit = (_units select ((count _units) - 1));
         _unit assignAsGunner _x;
         [_unit] orderGetIn true;
         _unit spawn { _this moveInGunner _x; };        
         _units resize ((count _units) - 1);
     };
   } forEach _static_weapons;
        _grp setCurrentWaypoint [_grp, 1];
}; "];
...

Share this post


Link to post
Share on other sites

Noob question.

"This version will reliably man all nearby defenses (even buggy spawned BIS compositions)"

Can someone give me an example of what the init line needs to look like, if i have KORD called "Static1"?

null = [group this,(getPos this),[static1]] execVM "scripts\BIN_taskDefend.sqf"

or

null = [group this,(getPos this),["static1"]] execVM "scripts\BIN_taskDefend.sqf"

or something else?

Also, my KORD is already premanned, does it need to be empty at start for this to work? Ie if Kord gunner gets killed, this script will reman it from Defencs patrol?

Haven't dealt with arrrays before, and am a bit confused as to where this array goes in the init line, as you can tell!

Share this post


Link to post
Share on other sites

Heya Gnarly,

There is no third parameter, as the script will look for empty man-able objects (such as an empty Kord emplacement) within 50m of the stated position (first parameter) and put a member of your group in there.

If its already manned, and you merge my code from post #19, every so often it will check to re-man killed positions for you.

Share this post


Link to post
Share on other sites

If its already manned, and you merge my code from post #19, every so often it will check to re-man killed positions for you.

Cheers Wolfy, I dodn't actually read the whole thread.

Now, I am a scripting noob, so when you say 'Merge' is it repalcing anything? Comparing your code and the original, there are elements that seem similar, so I'm not sure if I should be commenting out some of the original and adding yours in, or if yours is purley supplemental (and therefore where I place it makes a difference?

Have tested both options (but obviously particularly the former option, I'm not really sure if I'm commenting out too little or much) and neither remans a static Kord after I shoot the gunner, even after 5 minutes, so would it be easiest if you posted the full modified code? Sorry to be a pain! Chances are my attempts to Merge is simply breaking the code!

Share this post


Link to post
Share on other sites

I've given it v1.4 - maybe when Binesi has time, he can update it accordingly.

/*
=======================================================================================================================
Script: BIN_taskDefend.sqf v1.4
Author(s): Binesi
Partly based on original code by BIS

Description:
Group will man all nearby static defenses and vehicle turrets and guard/patrol the position and surrounding area.

Parameter(s):
_this select 0: group (Group)
_this select 1: defense position (Array)

Returns:
Boolean - success flag

Example(s):
null = [group this,(getPos this)] execVM "BIN_taskDefend.sqf"

-----------------------------------------------------------------------------------------------------------------------
Notes:

To prevent this script from manning vehicle turrets find and replace "LandVehicle" with "StaticWeapon".

The "DISMISS" waypoint is nice but bugged in a few ways. The odd hacks in this code are used to force the desired behavior.
The ideal method would be to write a new FSM and I may attempt that in a future project if no one else does. 

=======================================================================================================================
*/

private ["_grp", "_pos"];
_grp = _this select 0;
_pos = _this select 1;

_grp setBehaviour "SAFE";

private ["_list", "_units","_staticWeapons"];
_list = _pos nearObjects ["LandVehicle", 120];
_units = (units _grp) - [leader _grp]; // The leader should not man defenses
_staticWeapons = [];

// Find all nearby static defenses or vehicles without a gunner
{
   if ((_x emptyPositions "gunner") > 0) then 
   {
       _staticWeapons = _staticWeapons + [_x];    
   };
} forEach _list;

// Have the group man empty static defenses and vehicle turrets
{
   // Are there still units available?
   if ((count _units) > 0) then 
   {
       private ["_unit"];
       _unit = (_units select ((count _units) - 1));

       _unit assignAsGunner _x;
       [_unit] orderGetIn true;
       sleep 16; // Give gunner time to get in, otherwise force.
       _unit moveInGunner _x;

       _units resize ((count _units) - 1);
   };
} forEach _staticWeapons;

// Setup Waypoints
private ["_wp1","_wp2","_wp3","_wp4"];

_wp1 = _grp addWaypoint [_pos, 0];
_wp1 setWaypointType "MOVE";
[_grp, 1] setWaypointSpeed "LIMITED";
[_grp, 1] setWaypointBehaviour "SAFE";
[_grp, 1] setWaypointCombatMode "YELLOW";
[_grp, 1] setWaypointFormation "STAG COLUMN";
[_grp, 1] setWaypointCompletionRadius 50;
[_grp, 1] setWaypointStatements ["true", "null = [this] spawn {
       _grp = group (_this select 0);
       sleep (30+(random 60));
       {doStop _x} forEach units _grp;
       _grp setCurrentWaypoint [_grp,3];
       {_x doMove getPos _x} forEach units _grp;
       sleep 1;
       {_x forceSpeed 3} forEach units _grp;
       if ((random 3)> 2) then {sleep 3} else {sleep 30 + (random 30)};
       _grp setCurrentWaypoint [_grp, 1];
}; "];

_wp2 = _grp addWaypoint [_pos, 0];
_wp2 setWaypointType "DISMISS";
[_grp, 2] setWaypointStatements ["true", "null = [this] spawn {
       _grp = group (_this select 0);
       {_x forceSpeed -1 } forEach units _grp;
}; "];

_wp3 = _grp addWaypoint [_pos, 0];
_wp3 setWaypointType "SAD";
[_grp, 3] setWaypointSpeed "FULL";
[_grp, 3] setWaypointBehaviour "ALERT";
[_grp, 3] setWaypointCombatMode "RED";
[_grp, 3] setWaypointFormation "VEE";
[_grp, 3] setWaypointCompletionRadius 50;
[_grp, 3] setWaypointStatements ["true", "null = [this] spawn {
       _grp = group (_this select 0);
       _list = position (_this select 0) nearObjects ['LandVehicle', 30];
       _static_weapons = [];
       {
               if ((_x emptyPositions 'gunner') > 0) then 
               {
                       _static_weapons = _static_weapons + [_x];    
               };
       } forEach _list;
  {
     _units = units _grp;
     if ((count _units) > 0) then 
     {
         _unit = (_units select ((count _units) - 1));
         _unit assignAsGunner _x;
         [_unit] orderGetIn true;
         _unit spawn { _this moveInGunner _x; };        
         _units resize ((count _units) - 1);
     };
   } forEach _static_weapons;
        _grp setCurrentWaypoint [_grp, 1];
}; "];

_wp4 = _grp addWaypoint [_pos, 0];
_wp4 setWaypointType "CYCLE"; // Redundant failsafe

true

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
Sign in to follow this  

×