Jump to content
Binesi

Improved BIS_fnc_taskPatrol

Recommended Posts

Updated to 1.1 - The debug parameter is now optional. Slack space has also been increased to create a more rough circular patrol path and also give a greater chance for the script to find safe positions to place waypoints.

Updated to 1.2 - Performance optimizations (no spawn calls, less code). Formation type and combat mode semi randomized. Accepts 2D map coordinates (thanks Wolffy.au).

****

Following up with my tweaks to BIS_fnc_taskDefend I also had a go at BIS_fnc_taskPatrol.

My version creates a continually randomized roughly circular patrol path around a given point (as opposed to the BIS function which is purely random and chaotic). Generally it will move clockwise with a random chance to skip ahead and intersect across to another waypoint. It will also occasionally search out the area inside of this circle. It is very low CPU usage and doesn't use any continually running scripts after it starts but instead relies on code attached to waypoints.

It won't compete with UPS or a more advanced patrol script, but it can accomplish similar goals while using a small fraction of the resources. It will probably work best with infantry in relatively open areas or aircraft as it doesn't use a lot of intelligence for creating the patrol points other than making sure they are clear of obstacles and level enough for movement.

I may improve this in the future as I think of any new ideas which keep within the framework of using low resources and no continually running scripts. Suggestions welcome.

*****

Copy and paste the code into a new file called "BIN_taskPatrol.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 patrolling. Make sure he is in the right position as this method creates a circular path of waypoints around him. In this case the patrol will have a radius of 250m which you can change to whatever you like and the script will compensate by using more waypoints. Also make sure you have a "Functions" module placed on the map.

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

Just use notepad to create this script and make sure you save the file as "BIN_taskPatrol.sqf" and not "BIN_taskPatrol.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.

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

Description:
Creates a continually randomized patrol path which circles and intersects a given position.

Parameter(s):
_this select 0: the group to which to assign the waypoints (Group)
_this select 1: the position on which to base the patrol (Array)
_this select 2: the maximum distance between waypoints (Number)
_this select 3: (optional) debug markers on or off (Number)
_this select 4: (optional) blacklist of areas (Array)

Returns:
Boolean - success flag

Example(s):
null = [group this,(getPos this),250] execVM "BIN_taskPatrol.sqf"
null = [group this,(getPos this),250,1] execVM "BIN_taskPatrol.sqf" // Same with debug markers

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

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

_grp = _this select 0;
_pos = _this select 1;
_max_dist = _this select 2;
_debug = if ((count _this) > 3) then {_this select 3} else {0};
_blacklist = if ((count _this) > 4) then {_blacklist = _this select 4} else {[]};

_mode = ["YELLOW", "RED"] call BIS_fnc_selectRandom;
_formation = ["STAG COLUMN", "WEDGE", "ECH LEFT", "ECH RIGHT", "VEE", "DIAMOND"] call BIS_fnc_selectRandom;

_grp setBehaviour "AWARE";
_grp setSpeedMode "LIMITED";
_grp setCombatMode _mode;
_grp setFormation _formation;

_center_x = (_pos) select 0;
_center_y = (_pos) select 1;
_center_z = (_pos) select 2;
if(isNil "_center_z")then{_center_z = 0;};

_wp_count = 4 + (floor random 3) + (floor (_max_dist / 100 ));
_angle = (360 / (_wp_count -1));

_new_angle = 0;
_wp_array = [];
_slack = _max_dist / 5.5;
if ( _slack < 20 ) then { _slack = 20 };

while {count _wp_array < _wp_count} do 
{
   private ["_x1","_y1","_wp_pos"];

   _newangle = count _wp_array * _angle;

   _x1 = _center_x - (sin _newangle * _max_dist);
   _y1 = _center_y - (cos _newangle * _max_dist);

   _wp_pos = [[_x1, _y1, _center_z], 0, _slack, 6, 0, 50 * (pi / 180), 0, _blacklist] call BIS_fnc_findSafePos;

   _wp_array = _wp_array + [_wp_pos];

   sleep 0.5;
};

sleep 1;

for "_i" from 1 to (_wp_count - 1) do
{
   private ["_wp","_cur_pos","_marker","_marker_name"];

   _cur_pos = (_wp_array select _i);

   // Create waypoints based on array of positions
   _wp = _grp addWaypoint [_cur_pos, 0];
   _wp setWaypointType "MOVE";
   _wp setWaypointCompletionRadius (5 + _slack);
   [_grp,_i] setWaypointTimeout [0, 2, 16];
   // When completing waypoint have 33% chance to choose a random next wp
   [_grp,_i] setWaypointStatements ["true", "if ((random 3) > 2) then { group this setCurrentWaypoint [(group this), (floor (random (count (waypoints (group this)))))];};"];

   if (_debug > 0) then {
       _marker_name = str(_wp_array select _i);
       _marker = createMarker[_marker_name,[_cur_pos select 0,_cur_pos select 1]];
       _marker setMarkerShape "ICON";
       _marker_name setMarkerType "DOT";
   };

   sleep 0.5;
};

// End back near start point and then pick a new random point
_wp1 = _grp addWaypoint [_pos, 0];
_wp1 setWaypointType "SAD";
_wp1 setWaypointCompletionRadius (random (_max_dist));
[_grp,(count waypoints _grp)] setWaypointStatements ["true", "group this setCurrentWaypoint [(group this), (round (random 2) + 1)];"];

// Cycle in case we reach the end
_wp2 = _grp addWaypoint [_pos, 0];
_wp2 setWaypointType "CYCLE";
_wp2 setWaypointCompletionRadius 100;

true

Edited by Binesi
Added more instructions. Updated script to 1.1

Share this post


Link to post
Share on other sites

Excellent idea! :D

Hey, real quick - I like how you modify the new angle. Here's a little function I made that can "normalize" a dynamically created and adjusted angle. Ok, that sounded confusing. Say you have a guy facing 15 degrees, and you want a waypoint that will be a random angle +/- 30. If it is too far "left" then it will be less than 0. Call this function and it'll return the normalized angle.

Example:

	_dirTemp = (_dirTemp + (random 120)) - 60;
	_dir = [_dirTemp] call JTD_fnc_dirNorm;

Function

/* JTD direction normalization function - JTD_fnc_dirNormal.sqf
By Trexian
ooooooooooooooooooooooooooooooooooooooooooooooooooo
Credits:
OFPEC
DMarkwick, for math

ooooooooooooooooooooooooooooooooooooooooooooooooooo
The purpose of the JTD direction normalization function is to take a number and adapt it so that it is between 0 and 360.  This allows for the initiating script to take a direction, add or subtract from it, call the function, and end up with a valid number returned.
ooooooooooooooooooooooooooooooooooooooooooooooooooo
*/


//hint "function init";
//sleep 1;
_tempDir = _this select 0;

 if ((_tempDir > 360) || (_tempDir < 0)) then
 {
	_dir = abs (abs (_tempDir) - 360);
 }
 else
 {
	_dir = _tempDir;
 };
// return the normalized function
_dir

Just something to keep handy, if you want. :)

Share this post


Link to post
Share on other sites
Here's a little function I made that can "normalize" a dynamically created and adjusted angle

Thanks for that. That definitely can be useful.

I should experiment with pre-randomizing those angles a bit instead of just using the random on BIS_fnc_findSafePos. I was already happy enough to remember my math schooling to plot a circle... haha.

BTW if anyone wants to make the created waypoints even more rough and less circular find this line and lower the 7 to 6 or maybe 5.

_slack = _max_dist / 7;

Share this post


Link to post
Share on other sites

Binesi, I keep getting findSafePos errors

File ca\modules\functions\misc\fn_findSafePos.sqf, line 98

Error in expression <fnc_isPosBlacklisted)) then{if ((_pos distance _testPos) >= minDist) then{i>

Error position: <distance _testPos) >= _minDist) then{i>

Error Type Any, expected Number

The line I'm calling it from is:

call{[group _sl, _pos, _dist, 1] execVM "scripts\BIN_taskPatrol.sqf";};

Which, if I remove the debug parameter (can you make that optional?), and use the original BIS function, it works fine. Any ideas?

Edited by Wolffy.au

Share this post


Link to post
Share on other sites

Using this in a couple new mission of mine, saves me a LOT of time, thank you!

Share this post


Link to post
Share on other sites
Binesi, I keep getting findSafePos errors

I haven't seen this error but I updated the script with a greater amount of slack space to search for a waypoint position and it is less picky about being near something. This will also cause the circular path to be a bit more random and reduce chances of a findSafePos error.

The debug parameter is also now optional. You can use the same parameters as the BIS function if you like.

Edited by Binesi

Share this post


Link to post
Share on other sites

Here's something that's odd, and just started happening on my new mission. Every one of the units I put this in, no matter where, a waypoint is created to a building in Novy Sobor. Even when I'm on the other side of the map, any idea why?

EDIT - The reason was because I had the module "Functions" placed. Strange.

Share this post


Link to post
Share on other sites

This script uses the BIS_fnc_findSafePos from the functions module to find a safe place to put a waypoint. I forgot to add that into the notes and instructions. Updated.

Edited by Binesi

Share this post


Link to post
Share on other sites
Binesi, I keep getting findSafePos errors

Problem fixed. It only occur when you pass 2D positions to the function.

Here's the patch to resolve it.

_center_y = (_pos) select 1;
_center_z = (_pos) select 2;
[b]if(isNil "_center_z")then{_center_z = 0;};[/b]

_wp_count = 4 + (floor random 3) + (floor (_max_dist / 100 ));
_angle = (360 / (_wp_count -1));

Share this post


Link to post
Share on other sites

Thanks for the patch. I've integrated this and some other improvements to create version 1.2. There is some randomization of formations type and combat mode now. I also tightened up the code attached to waypoints a lot so it should use the lowest possible resources.

Share this post


Link to post
Share on other sites

I've changed it slightly, as I didn't want to set the height to 0 unnecessarily.

This appears to work correctly.

while {count _wp_array < _wp_count} do 
{
   private ["_x1","_y1","_wp_pos", "_prepos"];

   _newangle = count _wp_array * _angle;

   _x1 = _center_x - (sin _newangle * _max_dist);
   _y1 = _center_y - (cos _newangle * _max_dist);

   _prepos = [_x1, _y1, _center_z];
   if ( isNil "_center_z" ) then {
    _prepos = [_x1, _y1];
   };

   _wp_pos = [_prepos, 0, _slack, 6, 0, 50 * (pi / 180), 0, _blacklist] call BIS_fnc_findSafePos;

   _wp_array = _wp_array + [_wp_pos];

   sleep 0.5;
};

Share this post


Link to post
Share on other sites

If anyone is interested, I've made some additions to Binesi's BIN_taskPatrol script.

  • Random initial patrol direction - I noticed every patrol started off in the same direction, so I've randomised it.
  • Fixed the 2D position / findSafePos errors
  • Added building positions as possible patrol locations using Random Building Position Script v1.0 by Tophe of Östgöta Ops

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

Description:
Creates a continually randomized patrol path which circles and intersects a given position.

Parameter(s):
_this select 0: the group to which to assign the waypoints (Group)
_this select 1: the position on which to base the patrol (Array)
_this select 2: the maximum distance between waypoints (Number)
_this select 3: (optional) debug markers on or off (Number)
_this select 4: (optional) blacklist of areas (Array)

Returns:
Boolean - success flag

Example(s):
null = [group this,(getPos this),250] execVM "BIN_taskPatrol.sqf"
null = [group this,(getPos this),250,1] execVM "BIN_taskPatrol.sqf" // Same with debug markers

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

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

_grp = _this select 0;
_pos = _this select 1;
_max_dist = _this select 2;
_debug = if ((count _this) > 3) then {_this select 3} else {0};
_blacklist = if ((count _this) > 4) then {_blacklist = _this select 4} else {[]};

_mode = ["YELLOW", "RED"] call BIS_fnc_selectRandom;
_formation = ["STAG COLUMN", "WEDGE", "ECH LEFT", "ECH RIGHT", "VEE", "DIAMOND"] call BIS_fnc_selectRandom;

_grp setBehaviour "AWARE";
_grp setSpeedMode "LIMITED";
_grp setCombatMode _mode;
_grp setFormation _formation;

_center_x = (_pos) select 0;
_center_y = (_pos) select 1;
_center_z = (_pos) select 2;
if(isNil "_center_z")then{_center_z = 0;};

_wp_count = 4 + (floor random 3) + (floor (_max_dist / 100 ));
_angle = (360 / (_wp_count -1));

_new_angle = 0;
_wp_array = [];
_slack = _max_dist / 5.5;
if ( _slack < 20 ) then { _slack = 20 };

_angle_offset = random 360;
while {count _wp_array < _wp_count} do 
{
   private ["_x1","_y1","_wp_pos", "_prepos","_bldgpos","_bldgs"];

   _newangle = (count _wp_array * _angle) + _angle_offset;

   _x1 = _center_x - (sin _newangle * _max_dist);
   _y1 = _center_y - (cos _newangle * _max_dist);

   _prepos = [_x1, _y1, _center_z];
   if ( isNil "_center_z" ) then {
       _prepos = [_x1, _y1];
   };

   _wp_pos = [_prepos, 0, _slack, 6, 0, 50 * (pi / 180), 0, _blacklist] call BIS_fnc_findSafePos;

   //////////////////////////////////////////////////////////////////
   // The following code is an extract from Random Building Position Script v1.0 by Tophe of Östgöta Ops
   //////////////////////////////////////////////////////////////////
   _bldgpos = [];
   _bldgs = nearestObjects [_wp_pos, ["Building"], 50];
   {
  private["_i","_y"];
       _i = 0;
       _y = _x buildingPos _i;
       while {format["%1", _y] != "[0,0,0]"} do {
		_bldgpos = _bldgpos + [_y];
		_i = _i + 1;
		_y = _x buildingPos _i;
       };
   } forEach _bldgs;
   if(count _bldgpos != 0) then {_wp_pos = _bldgpos call BIS_fnc_selectRandom;};
   _wp_array = _wp_array + [_wp_pos];

   sleep 0.5;
};

sleep 1;

for "_i" from 1 to (_wp_count - 1) do
{
   private ["_wp","_cur_pos","_marker","_marker_name"];

   _cur_pos = (_wp_array select _i);

   // Create waypoints based on array of positions
   _wp = _grp addWaypoint [_cur_pos, 0];
   _wp setWaypointType "MOVE";
   _wp setWaypointCompletionRadius (5 + _slack);
   [_grp,_i] setWaypointTimeout [0, 2, 16];
   // When completing waypoint have 33% chance to choose a random next wp
   [_grp,_i] setWaypointStatements ["true", "if ((random 3) > 2) then { group this setCurrentWaypoint [(group this), (floor (random (count (waypoints (group this)))))];};"];

   if (_debug > 0) then {
       _marker_name = str(_wp_array select _i);
       _marker = createMarker[_marker_name,[_cur_pos select 0,_cur_pos select 1]];
       _marker setMarkerShape "ICON";
       _marker_name setMarkerType "DOT";
   };

   sleep 0.5;
};

// End back near start point and then pick a new random point
_wp1 = _grp addWaypoint [_pos, 0];
_wp1 setWaypointType "SAD";
_wp1 setWaypointCompletionRadius (random (_max_dist));
[_grp,(count waypoints _grp)] setWaypointStatements ["true", "group this setCurrentWaypoint [(group this), (round (random 2) + 1)];"];

// Cycle in case we reach the end
_wp2 = _grp addWaypoint [_pos, 0];
_wp2 setWaypointType "CYCLE";
_wp2 setWaypointCompletionRadius 100;

true

Share this post


Link to post
Share on other sites
If anyone is interested, I've made some additions to Binesi's BIN_taskPatrol script.

Cheers Wolffy, I'll be using it!

Share this post


Link to post
Share on other sites

Hey Wolfy-

I like the changes/additions! :)

One minor thing - I've had success using the older Binesi patrol function with vehicles, also. Before making the building position wps, it might be worth checking if there is a vehicle in the group?

Functionally, I'm not sure how to achieve this, though. Might require a loop at the beginning to check each unit in the group if vehicle _x = _x (that's how I've checked if a unit is in a vehicle) and if any unit in the group is in a vehicle, then bypass the building position part?

Just an idea. Regardless, it is a very useful script!

Share this post


Link to post
Share on other sites

I could check if the SL is a "Man" - if yes, then use the Building positions, otherwise don't. The advantage of this would be if you have a dismounted Motorised or Mechanised patrol, the SL will still go into buildings (which I think is cool) - how does that sound? If you think it would suffice, I can make the changes fairly quickly.

Share this post


Link to post
Share on other sites

I cant seem to get this working...

Im testing the map in the editor not sure if that makes any difference... start out by doing this:

_option = round(random 1);

switch _option do {

case 0: {

call {[getMarkerPos "enemy","Infantry",200] execVM "cB_randomGroup.sqf"};

call {[getMarkerPos "enemy","Infantry",300] execVM "cB_randomGroup.sqf"};

};

case 1: {

call {[getMarkerPos "enemy","Infantry",500] execVM "cB_randomGroup.sqf"};

call {[getMarkerPos "enemy","Infantry",400] execVM "cB_randomGroup.sqf"};

};

};

I can see the units beeing created and the BIN_taskPatrol script is beeing called (tried placing hint's in the code)... Ive forced the _debug to 1; but no markers on the map is created and no units start patrolling...

I seem to have some trouples after the line

sleep 1;

If I do the hint "yay"; before it I get the yay... after no matter where i place it I get nothing.... any ideas?

Share this post


Link to post
Share on other sites
The advantage of this would be if you have a dismounted Motorised or Mechanised patrol, the SL will still go into buildings (which I think is cool) - how does that sound? If you think it would suffice, I can make the changes fairly quickly.

I think that f'n rocks! :D

Vehicles maintain overwatch outside, while infantry clears the building....

b00yah

Share this post


Link to post
Share on other sites

hey thats an awesome little script you have there. was wondering if its posable to change the shape of the patrolls so maybe make it ovel or even square

Share this post


Link to post
Share on other sites

@ Binesi,

Excellent script! Thank you so much!

Question: Is there a way to have the algorithm point away from the sea?

I placed a unit along the shore to patrol a pier and they jumped off into the water.

It was cool to see that (don't get me wrong), but in real life that wouldn't happen (unless you're in a training camp). :D

Still, awesome script! :notworthy:

Best, Splicer.

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

×