Jump to content
ChaIie

How to use BIS_fnc_stalk?

Recommended Posts

Hello everyone,

 

Since days i try to build up a scenario where a set of enemys (for instance 1 heli, 2 tanks etc) starts on on side of the island while im on the other. for respawns, i already synced everything to a MGI system . But the issue is i have no idea how to make the AI chase me where ever i go. I already tried a script from here, but it only sets a waypoint to my spawn. 

I always came across the  BIS_fnc_stalk  https://community.bistudio.com/wiki/BIS_fnc_stalk . But i have no idea how to build it up. 

If i use the first example  [ _stalking = [BIS_grpStalkers, BIS_grpPlayer] spawn BIS_fnc_stalk; ]  what do i have to do with it? does it belong into the init from the enemy AI? do i have to change names? 

Also can i add behavior to SAD or destroy to this?

 

Thanks for any help 

Share this post


Link to post
Share on other sites

You could put example above in an init field, or activate it in a trigger, or a script. 

 

For this to work using the example above, you would have to name the group that will stalk the player, BIS_grpStalkers, and the player's group, BIS_grpPlayer. 

Share this post


Link to post
Share on other sites

A way I have used stalk is to place in the hunting unit's (BIS_grpStalkers) 2nd waypoint On Activation field:

_stalking = [BIS_grpStalkers, BIS_grpPlayer] spawn BIS_fnc_stalk;

or for MP:

_stalking = [BIS_grpStalkers, group (allPlayers select 0)] spawn BIS_fnc_stalk;

 

I can't remember why it doesn't work in first waypoint...I place first waypoint real close and 2nd waypoint also close.

I have never dealt with behavior other than setting speed, stance, and behavior in the edited unit and/or waypoint. They seem to close with me and engage just fine.

Share this post


Link to post
Share on other sites
9 hours ago, stburr91 said:

You could put example above in an init field, or activate it in a trigger, or a script. 

 

For this to work using the example above, you would have to name the group that will stalk the player, BIS_grpStalkers, and the player's group, BIS_grpPlayer. 

 

I don't know what im doing wrong but it doesn't want to work 

FuJA0S5.jpg Is this the way to change the group names? otherwise i dont know how 

if i put the example into a trigger , the enemy doesn't even start move . same when i make 2 waypoints into a trigger field for the enemy (they just fly to the 2 waypoint and stop there).  

Share this post


Link to post
Share on other sites

When using multiple groups, the groups get identified individually, and the script is run for each instance of a stalking: group A pursuing group B.  Don't limit yourself to BIS_grpStalkers and BIS_grpPlayer, those are example identifiers given for a single group stalking (BIS_grpStalkers) and a single group to be stalked (BIS_grpPlayer).

 

Identify a group to do stalking, and a group for them to stalk (it can be the same group another is already pursuing).  Run the script for the two groups.  You can do it in unit init fields, or in an init script, or a trigger.

A_1_handle = [grpA, grp1] Spawn BIS_fnc_stalk;  // grpA pursues grp1
B_1_handle = [grpB, grp1] Spawn BIS_fnc_stalk;  // grpB pursues grp1
C_1_handle = [grpC, grp1] Spawn BIS_fnc_stalk;  // grpC pursues grp1
D_2_handle = [grpD, grp2] Spawn BIS_fnc_stalk;  // grpD pursues grp2
E_2_handle = [grpE, grp2] Spawn BIS_fnc_stalk;  // grpE pursues grp2

The condition code is optional, a condition to end the stalking.  It gets checked each iteration (default 10 seconds) using isNil, as in: isNil {WhateverThisCodeReturns}, then whether the return is true or false.  Because isNil evaluates the expression, and it could be a complex expression, it can first be used to set the stalking group's current waypoint to SAD before returning the true/false condition.  But be very careful about that, 1) there can be no suspension, 2) don't make the code complex, keep it simple, and 3) the final code must be the return giving TRUE or FALSE, for ending the stalking.  Example:

// grpB pursues grp1 until all units in grp1 are dead, then returns to base (original start position).
B_1_handle = [grpB, grp1,10,0,{[grpB,currentWaypoint grpB] setWaypointType "SAD"; {Alive _x} Count (Units grp1) == 0},(Position Leader grpB)] Spawn BIS_fnc_stalk;

Zoom on a leader in editor, there is also a box for editing the group he is in.  You can name his group there.  Or old school, in a leader init field you can put "myGroupName = group this;"

 

Edited by opusfmspol
added condition example
  • Like 5
  • Thanks 1

Share this post


Link to post
Share on other sites

It looks like you are only changing the callsign in the editor.

You need to name each group...

@opusfmspol saves the day.

  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites

Ah i see what i did wrong. when i put the name into the variable name from the group it works. Gonna test around now also with mulitple groups

 

Also another question now, is there any simple way to reveal myself to the AI or change the behavior to SAD? 

i guess https://community.bistudio.com/wiki/reveal is correct but what should i do here? 

Share this post


Link to post
Share on other sites
6 minutes ago, ChaIie said:

is there any simple way to reveal myself to the AI or change the behavior to SAD? 

i guess https://community.bistudio.com/wiki/reveal is correct but what should i do here? 


Aye.
reveal is a good command, but it depends where and when you need the command.
You are still using BIS_fnc_stalk, right?

The SAD waypoint is is just setBehaviour "COMBAT" and setCombatMode "RED".
See Task Attack.

You need to be specific.
There are so many ways of doing something in Arma.

  • Like 1

Share this post


Link to post
Share on other sites
5 minutes ago, Maff said:

but it depends where and when you need the command.
You are still using BIS_fnc_stalk, right?

I use BIS_fnc_stalk right now. It works pretty good so far, but i feel like the enemy heli (for instance) hovers above me for a while. it only attacks when im like run around on a open field (even when i set it to combat and Fire at will in the editor). Is there a good way to make them more aggresiv? so i thought reveal could help here.

 

excuse me if i do some mistakes.. im relatively new to all this 

Share this post


Link to post
Share on other sites
36 minutes ago, ChaIie said:

I use BIS_fnc_stalk right now. It works pretty good so far, but i feel like the enemy heli (for instance) hovers above me for a while. it only attacks when im like run around on a open field (even when i set it to combat and Fire at will in the editor). Is there a good way to make them more aggresiv? so i thought reveal could help here.

I don't think BIS_fnc_stalk was intended for helicopters hunting a group or player.

You can learn a lot by looking at the function;
 

Spoiler

/*
	Author: Vaclav "WattyWatts" Oliva

	Description:
	Continuously set WP of one group to a different group to hunt it. It does not change the group's behaviour.
	Script terminates if one of the groups is eliminated or if the optional condition is activated.

	If the optional condition is activated, you can either:
	- return the group to its original waypoints
	- make the group search at current position (cycle in 50m radius)
	- send the group back to position from where it started to stalk (waypoint MOVE)
	- send to position of a marker (waypoint MOVE)
	- send to position of an object (waypoint MOVE)
	- send to [x,y,z] position (waypoint MOVE)

	Parameters:
	Select 0 = GROUP that will stalk
	Select 1 = GROUP that will be stalked
	Select 2 = (OPTIONAL) NUMBER: How often should the WP be refreshed, default 10 seconds, min 5 seconds
	Select 3 = (OPTIONAL) NUMBER: Radius of the WP, default 0 meters
	Select 4 = (OPTIONAL) CODE: Condition for ending the stalking process, default {false}
	Select 5 = (OPTIONAL) STRING or POSITION or OBJECT or NUMBER (0 for return to original waypoints (default), 1 to search at current position, 2 to return to position where they started to stalk)

	Returns:
	Boolean

	Examples:
	_stalking = [BIS_grpStalkers,BIS_grpPlayer] spawn BIS_fnc_stalk;
	_stalking = [BIS_grpStalkers,BIS_grpPlayer,nil,nil,{BIS_player distance BIS_Heli < 100},"BIS_mrkRetreatMarker"] spawn BIS_fnc_stalk;
	_stalking = [BIS_grpStalkers,BIS_grpPlayer,20,10,{BIS_Return},1] spawn BIS_fnc_stalk;
	_stalking = [BIS_grpStalkers,BIS_grpPlayer,5,0,{dayTime > 20},[3600,600,0]] spawn BIS_fnc_stalk;
*/

// Params
params
[
	["_stalkerGroup",grpNull,[grpNull]],
	["_stalkedGroup",grpNull,[grpNull]],
	["_refresh",10,[999]],
	["_radius",0,[999]],
	["_condition",{false},[{}]],
	["_returnWP",0,[999,"",objNull,[]]]
];

// Check for validity
if (isNull _stalkerGroup) exitWith {["STALKING: Non-existing group %1 to stalk used!",_stalkerGroup] call BIS_fnc_logFormat; false};
if (_stalkerGroup getVariable "BIS_Stalk" == 1) exitWith {["STALKING: %1 is already stalking!",_stalkerGroup] call BIS_fnc_logFormat; false};
if (isNull _stalkedGroup) exitWith {["STALKING: Non-existing group %2 to be stalked used!",_stalkedGroup] call BIS_fnc_logFormat; false};
if (_stalkerGroup == _stalkedGroup) exitWith {["STALKING: Group %1 cannot stalk itself!",_stalkerGroup] call BIS_fnc_logFormat; false};
if ((_refresh isEqualType 999) and {_refresh < 5}) exitWith {["STALKING: %1 Delay cannot be lower than 5 seconds!",_stalkerGroup] call BIS_fnc_logFormat; false};
if ((_radius isEqualType 999) and {_radius < 0}) exitWith {["STALKING: %1 Radius cannot be lower than 0 meters!",_stalkerGroup] call BIS_fnc_logFormat; false};
if ((_returnWP isEqualType 999) and {!(_returnWP in [0,1,2])}) exitWith {["STALKING: %1 Incorrect return WP type, only 0, 1 or 2 can be used!",_stalkerGroup] call BIS_fnc_logFormat; false};
if ((_returnWP isEqualType "") and {getMarkerType _returnWP == ""}) exitWith {["STALKING: %1 Non-existent marker for return waypoint used!",_stalkerGroup] call BIS_fnc_logFormat; false};
if ((_returnWP isEqualType objNull) and {isNull _returnWP}) exitWith {["STALKING: %1 Non-existent object for return waypoint used!",_stalkerGroup] call BIS_fnc_logFormat; false};
if ((_returnWP isEqualType []) and {count _returnWP != 3}) exitWith {["STALKING: %1 Wrong [X,Y,Z] format for return waypoint used!",_stalkerGroup] call BIS_fnc_logFormat; false};

// Set variable to be able to check if the unit is stalking or not and to prevent running the script multiple times on the same group
_stalkerGroup setVariable ["BIS_Stalk",1];

// Initial position of the stalking group to enable return
private ["_originalPos"];
_originalPos = (getPos leader _stalkerGroup);

// Create dummy group to enable returning to original waypoints
_grpOriginalWP = createGroup Civilian;
"C_man_1" createUnit [(position leader _stalkerGroup),_grpOriginalWP];
_grpOriginalWP copyWaypoints _stalkerGroup;
{deleteVehicle _x} forEach (units _grpOriginalWP);

// Set Waypoint, loop and check for casualties
_wp = _stalkerGroup addWaypoint [(leader _stalkerGroup),0];
// ["%1 starting to stalk %2",_stalkerGroup,_stalkedGroup] call BIS_fnc_logFormat;

While
{
	({alive _x} count (units _stalkerGroup) > 0) and
	({alive _x} count (units _stalkedGroup) > 0)
}
Do
{
	if (simulationEnabled (leader _stalkerGroup)) then {
		while {(count (waypoints _stalkerGroup)) > 0} do {deleteWaypoint ((waypoints _stalkerGroup) select 0)};
		_wp = _stalkerGroup addWaypoint [(leader _stalkedGroup),_radius];
	};
	sleep _refresh;

	if (!(isNil _condition) and (_condition)) exitWith {/*["STALKING: Condition to end stalking for group %1 activated.",_stalkerGroup] call BIS_fnc_logFormat*/};
};

// Stalking ended, if by the optional condition, then decide where to put the next WP
if (!(isNil _condition) and (_condition)) then
{
	// Group is available for another stalking
	_stalkerGroup setVariable ["BIS_Stalk",0];

	if ({alive _x} count (units _stalkerGroup) > 0) then
	{
		{_x commandTarget objNull} forEach (units _stalkerGroup);
                while {(count (waypoints _stalkerGroup)) > 0} do {deleteWaypoint ((waypoints _stalkerGroup) select 0)};

		if (_returnWP isEqualType 999) then
		{
			if (_returnWP == 0) then
			{
				_stalkerGroup copyWaypoints _grpOriginalWP;
				// ["STALKING: Stalker group %1 returning to original waypoints.",_stalkerGroup] call BIS_fnc_logFormat;
			};
			if (_returnWP == 1) then
			{
				_pos01 = [(position leader _stalkerGroup), 50, 0] call BIS_fnc_relPos;
				_pos02 = [(position leader _stalkerGroup), 50, 90] call BIS_fnc_relPos;
				_pos03 = [(position leader _stalkerGroup), 50, 180] call BIS_fnc_relPos;
				_pos04 = [(position leader _stalkerGroup), 50, 270] call BIS_fnc_relPos;
				_wp01 = _stalkerGroup addWaypoint [_pos01,0];
				_wp02 = _stalkerGroup addWaypoint [_pos02,0];
				_wp03 = _stalkerGroup addWaypoint [_pos03,0];
				_wp04 = _stalkerGroup addWaypoint [_pos04,0];
				_wp05 = _stalkerGroup addWaypoint [_pos04,0];
				_wp05 setWaypointType "Cycle";
				// ["STALKING: Stalker group %1 searching at current position.",_stalkerGroup] call BIS_fnc_logFormat;
			};
			if (_returnWP == 2) then
			{
				_wp = _stalkerGroup addWaypoint [_originalPos,0];
				// ["STALKING: Stalker group %1 returning to original position.",_stalkerGroup] call BIS_fnc_logFormat;
			};
		};
		if (_returnWP isEqualType "") then
		{
			_wp = _stalkerGroup addWaypoint [(getMarkerPos _returnWP),0];
                                    // ["STALKING: Stalker group %1 moving to marker %2.",_stalkerGroup,_returnWP] call BIS_fnc_logFormat;
		};
		if (_returnWP isEqualType objNull) then
		{
			_wp = _stalkerGroup addWaypoint [(getPos _returnWP),0];
                                    // ["STALKING: Stalker group %1 moving to object %2.",_stalkerGroup,_returnWP] call BIS_fnc_logFormat;
		};
		if (_returnWP isEqualType []) then
		{
			_wp = _stalkerGroup addWaypoint [_returnWP,0];
                                    // ["STALKING: Stalker group %1 moving to coordinates %2.",_stalkerGroup,_returnWP] call BIS_fnc_logFormat;
		};
	};
};

if ({alive _x} count (units _stalkerGroup) == 0) then {/*["Stalker group %1 was eliminated",_stalkerGroup] call BIS_fnc_logFormat;*/ _stalkerGroup setVariable ["BIS_Stalk",nil]};
if ({alive _x} count (units _stalkedGroup) == 0) then {/*["Stalked group %1 was eliminated",_stalkedGroup] call BIS_fnc_logFormat*/};

// Delete the dummy group
deleteGroup _grpOriginalWP;

// Returns
true

 


If you need further help, then feel free to ask.

 

37 minutes ago, ChaIie said:

excuse me if i do some mistakes.. im relatively new to all this 

No worries. One day you may help me. Or someone more important.

  • Like 2

Share this post


Link to post
Share on other sites
16 minutes ago, Maff said:

I don't think BIS_fnc_stalk was intended for helicopters hunting a group or player.

What do i need to use instead? i still think that reveal may come handy here but i have no idea how to set it up 

_soldierOne reveal [_soldierTwo, 1.5];

If this is correct, where do the soldierOne/Two parameters belong? i tried it with the variable name of the player and enemy but it makes no difference, do i need to put the group names in here? also is the 1.5   the range where they spot me? 

 

33 minutes ago, Maff said:

No worries. One day you may help me. Or someone more important

really want to learn it but its kinda difficult with a whole new program language

Share this post


Link to post
Share on other sites
6 minutes ago, ChaIie said:

What do i need to use instead? i still think that reveal may come handy here but i have no idea how to set it up 


_soldierOne reveal [_soldierTwo, 1.5];

If this is correct, where do the soldierOne/Two parameters belong? i tried it with the variable name of the player and enemy but it makes no difference, do i need to put the group names in here? also is the 1.5   the range where they spot me? 

 

really want to learn it but its kinda difficult with a whole new program language


There are a fair few methods of AI hunting players.
G00gle.

They may not suit your needs, but they will get you on the track. Believe me.

Don't worry. 


 

  • Like 1

Share this post


Link to post
Share on other sites

For helos, here's copy of a script I've used in my missions for years to have a helo circle a team, usually a support helo though.  Should the helo be enemy, when it becomes aware of the circled unit or team, it will engage.  The radius, angle and height can be adjusted to suit.

 

The script's credit belongs to @demonized, @neokika and @jkhaaja, one of their postings in the forums years ago was where I picked it up, and it was so long I don't recall the forum post.

 

The leader being circled:  ldr

The helo doing the circling:  transport

 

Spoiler

nul = transport spawn 
{
	radius = 400;
	angle = 1;
	while {alive transport && canMove transport} do 
	{
		private ["_center", "_pos"];
		_center = [((position ldr) select 0), ((position ldr) select 1),80];
		_pos = [_center, radius, angle] call BIS_fnc_relPos;
		transport doMove _pos;
		transport flyInHeight 80;
		angle = angle + 60;
		waitUntil {!alive transport || !canMove Transport || transport distance _pos < (radius * .75)};
	};
};

 

 

  • Like 2

Share this post


Link to post
Share on other sites

So pleased to see this is a recent thread as I'm just now coming back to AMRA3 (after a LONG time away!) and want to use this function too.

I've personally got it working in the most basic fashion;

  • Triger activates.
  • Hunters go looking for Hunted.
  • Hunters kill hunted.
  • Hunters stay put(!)

I cant make them 'return' home though.  Not even when they kill Hunted!

My main question is; can I send them home if the trigger turns false?  
So, if Hunted leaves the trigger area, Hunter goes back to base. 
If Hunted goes back in to the trigger, Hunter comes out again.
and so on.

Any help anyone could offer would be much appreciated.
 

  • Like 1

Share this post


Link to post
Share on other sites

Having the trigger repeatable, and set to spawn the function when activated, should take care of the Hunter pursuing the Hunted each time the Hunted enters the zone.

 

The function's condition (select 4) and return (select 5) params are what would make the Hunter RTB whenever the Hunted leaves the zone.  The function's params are:

[
	select 0: GROUP - The group that is the Hunter.  Default: grpNull.
	select 1: GROUP - The group that will be Hunted.  Default: grpNull.
	select 2: (OPTIONAL) - NUMBER: How often (in seconds) the Hunter updates their waypoint at the Hunted leader's pos.  Default: 10 (minimum 5).
	select 3: (OPTIONAL) - NUMBER: Radius (in meters) of the Hunter's new waypoint from the Hunted leader's pos.  Default: 0 meters.
	select 4: (OPTIONAL) - CODE: Condition that gets evaluated to end the hunt.  Default {false}.
	select 5: (OPTIONAL) - STRING or ARRAY (POSITION) or OBJECT or NUMBER: Where the Hunter goes when the hunting ends.  Default: 0.
		Can be one of:
			STRING: Name of a marker.
			ARRAY:  Position (Hunter gets a waypoint with position inserted: [_position,0]).
			OBJECT: Existing object (Hunter gets a waypoint with object position inserted: [(GetPos _object),0]).
			NUMBER:	0 - Hunter returns to original given waypoints.
				1 - Hunter stays at current position, searching around.
				2 - Hunter returns to the position they began hunting from (when the script began).
]

As I mentioned previously, the condition code (select 4) gets evaluated using isNil, which can be used to run a complex expression if necessary, but at the end must be an expression returning true or false.

 

And in this discussion I had mentioned before that there can be a problem with using 0 (which is default) for the return parameter (select 5), when empty groups are getting deleted.

 

Hope this helps.

  • Like 1

Share this post


Link to post
Share on other sites
On 12/23/2021 at 9:40 PM, Maff said:

No worries. One day you may help me. Or someone more important.

This is why I love this forum.  @Maff is a stand up guy!

  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites
On 1/11/2022 at 10:53 PM, opusfmspol said:

Having the trigger repeatable, and set to spawn the function when activated, should take care of the Hunter pursuing the Hunted each time the Hunted enters the zone.

 

The function's condition (select 4) and return (select 5) params are what would make the Hunter RTB whenever the Hunted leaves the zone.  The function's params are:


[
	select 0: GROUP - The group that is the Hunter.  Default: grpNull.
	select 1: GROUP - The group that will be Hunted.  Default: grpNull.
	select 2: (OPTIONAL) - NUMBER: How often (in seconds) the Hunter updates their waypoint at the Hunted leader's pos.  Default: 10 (minimum 5).
	select 3: (OPTIONAL) - NUMBER: Radius (in meters) of the Hunter's new waypoint from the Hunted leader's pos.  Default: 0 meters.
	select 4: (OPTIONAL) - CODE: Condition that gets evaluated to end the hunt.  Default {false}.
	select 5: (OPTIONAL) - STRING or ARRAY (POSITION) or OBJECT or NUMBER: Where the Hunter goes when the hunting ends.  Default: 0.
		Can be one of:
			STRING: Name of a marker.
			ARRAY:  Position (Hunter gets a waypoint with position inserted: [_position,0]).
			OBJECT: Existing object (Hunter gets a waypoint with object position inserted: [(GetPos _object),0]).
			NUMBER:	0 - Hunter returns to original given waypoints.
				1 - Hunter stays at current position, searching around.
				2 - Hunter returns to the position they began hunting from (when the script began).
]

As I mentioned previously, the condition code (select 4) gets evaluated using isNil, which can be used to run a complex expression if necessary, but at the end must be an expression returning true or false.

 

And in this discussion I had mentioned before that there can be a problem with using 0 (which is default) for the return parameter (select 5), when empty groups are getting deleted.

 

Hope this helps.


So sorry!  I only just saw this response!
I'll give it a whirl.
cheers dude.

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

×