Jump to content
Fiddi

Only 1 of 7 groups get waypoints.

Recommended Posts

Hello,
 
I have need of a second, maybe third, set of eyes for finding out what the problem is with my patrol script for an 'ambient combat' system I'm working on. All groups are supposed to recieve semi-random waypoints around a player.
 
If there's a known enemy in the area recieve a 'Seek and destroy' waypoint around the area the enemy was spotted.
 
Problem is it's unreliable and doesn't produce the results I'm looking for. Some times it might work, other times it only generates waypoints for one group.

 

There's no script errors and I've tried to rewrite a couple of times to see if there's anything I missed but I'm thinking it's a logic issue rather than a script issue in itself.
 
AC_activeGroups contain 7 groups (at most) but is configurable.

_patrolType = ["SAFE", "SAD"];
_mp = true;

The script in question:

private [
	"_leader","_angle","_nearestUnit","_range","_dir","_newPos","_randomWay","_waypoint","_validSpot",
	"_marker","_distance","_spawnPos","_avoidArray"
];
params [
	["_syncedUnit", player, [objNull]],
	["_maxRange", 900, [0]],
	["_patrolType", 1, [0, []], 2],
	["_mp", false, [false]]
];

while {true} do {
	Sleep 15;
	{
		_leader = leader _x;
		_nearUnits = [];
		while {count _nearUnits < 1} do {
			_nearUnits = allPlayers select {alive _x AND _x distance _leader < _maxRange};
			Sleep 1;
		};
		_nearUnits = _nearUnits apply {[_leader distance _x, _x]};
		_nearUnits sort true;
		_nearestUnit = (_nearUnits select 0) select 1;
		if (!_mp) then {
			if (_syncedUnit distance _leader < _maxRange) then {
				_nearestUnit = _syncedUnit;
			};
		};
		
		_nearestEnemy = _leader findNearestEnemy _leader;
		if (!isNull _nearestEnemy AND _nearestEnemy distance _leader < 3000 AND alive _nearestEnemy) then {
			if (!isNil {_x getVariable "ACEnemyWaypoint"}) then {
				_x deleteWaypoint (_x getVariable "ACEnemyWaypoint");
			};
			_waypointEnemy = _x addWaypoint [_nearestEnemy, 50];
			_waypointEnemy setWaypointType "SAD";
			_waypointEnemy setWaypointBehaviour "AWARE";
			_waypointEnemy setWaypointCombatMode "RED";
			_waypointEnemy setWaypointFormation selectRandom ["STAG COLUMN", "WEDGE", "VEE", "DIAMOND", "FILE", "LINE"];
			_waypointEnemy setWaypointSpeed "NORMAL";
			
			_x setCurrentWaypoint _waypointEnemy;
			_x setVariable ["ACEnemyWaypoint", _waypointEnemy, true];
		} else {
			if (isNil {_x getVariable "ACWaypoint"}) then {
				_validSpot = false;
				_range = _leader distance _nearestUnit;
				while {!_validSpot} do {
					_dir = (_leader getDir _nearestUnit) + round random [-30, 0, 30] % 360;
					_distance = (_leader distance _nearestUnit) + round random [-100, 0, 100];
					_newPos = _leader getPos [_distance, _dir];
					
					if (!surfaceIsWater getPos _leader) then {
						if (surfaceIsWater _newPos) then {
							_randomWay = selectRandom [-20,20];
							while {surfaceIsWater _newPos} do {
								_dir = (_dir + _randomWay) % 360;
								_newPos = _leader getPos [_distance, _dir];
								Sleep 0.5;
							};
						};
						_validSpot = true;
					} else {
						_newPos = [_newPos,0,200,2,2,10,0] call BIS_fnc_findSafePos;
						_validSpot = true;
					};
				};
				
				_waypointOrig = _x addWaypoint [_newPos, 10];
				_waypointOrig setWaypointType "MOVE";
				_waypointOrig setWaypointBehaviour (_patrolType select 0);
				_waypointOrig setWaypointCombatMode "RED";
				_waypointOrig setWaypointFormation selectRandom ["STAG COLUMN", "WEDGE", "VEE", "DIAMOND", "FILE", "LINE"];
				_waypointOrig setWaypointSpeed "NORMAL";
				
				_waypointSAD = _x addWaypoint [_newPos, 100];
				_waypointSAD setWaypointType (_patrolType select 1);
				_waypointSAD setWaypointBehaviour (_patrolType select 0);
				_waypointSAD setWaypointCombatMode "RED";
				_waypointSAD setWaypointFormation selectRandom ["STAG COLUMN", "WEDGE", "VEE", "DIAMOND", "FILE", "LINE"];
				_waypointSAD setWaypointSpeed "NORMAL";
				
				_waypointCycle = _x addWaypoint [_newPos, 10];
				_waypointCycle setWaypointType "CYCLE";
				_waypointCycle setWaypointBehaviour (_patrolType select 0);
				_waypointCycle setWaypointCombatMode "RED";
				_waypointCycle setWaypointFormation selectRandom ["STAG COLUMN", "WEDGE", "VEE", "DIAMOND", "FILE", "LINE"];
				_waypointCycle setWaypointSpeed "NORMAL";
		
				_x setCurrentWaypoint _waypointSAD;
				_x setVariable ["ACWaypoint", _waypointSAD, true];
			};
			_x setCurrentWaypoint (_x getVariable "ACWaypoint");
		};

		Sleep 5;
	} forEach AC_activeGroups;
	Sleep 15;
}; 

 

Thanks!

Share this post


Link to post
Share on other sites

Gonna take a closer look at it later today,

for now it's always bad practice to use convoluted scripts with while true loops in foreach loops.

Try splitting it up in smaller functions and you'll see that it's way easier to find errors / logical mishaps.

 

Cheers

Share this post


Link to post
Share on other sites

while {count _nearUnits < 1} do {
	_nearUnits = allPlayers select {alive _x AND _x distance _leader < _maxRange};
	Sleep 1;
};
Whilst looping around your groups if one happens to be > 900 (default distance) then the whole loop will stop here waiting for this group to become close to a player.

None of the other groups will get processed.

Share this post


Link to post
Share on other sites
while {count _nearUnits < 1} do {
	_nearUnits = allPlayers select {alive _x AND _x distance _leader < _maxRange};
	Sleep 1;
};
Whilst looping around your groups if one happens to be > 900 (default distance) then the whole loop will stop here waiting for this group to become close to a player.

None of the other groups will get processed.

 

 

While that would have been a problem, that's not what was wrong. I have a suspicion that it was the cleanup that worked alongside this one that was the culprit.

 

I've taken the time to rewrite the entire 'group control' system I have in place for the ambient groups, it now is a single loop for each group that checks if they're alive or too far away, gives them new waypoints and alerts them of nearby enemies. Should help the performance too, hard to measure that exactly but it seems smoother atleast.

 

Looks like this:

private ["_newPos"];
params [
	["_group", grpNull, [grpNull]],
	["_maxRange", 900, [0]]
];

_maxDist = _group getVariable "AC_maxDist";

_Comms = _group spawn {
	_group = _this;
	while {true} do {
		Sleep random [5, 10, 15];
		{
			if ((side _group) knowsAbout _x > 1) then {
				_group reveal [_x, 2];
			};
			Sleep 2;
			true
		} count allUnits;
		Sleep random [10, 20, 30];
	};
};

_nearUnits = [];
_nearUnits = allPlayers select {alive _x AND (_x distance leader _group) < _maxRange};

if (count _nearUnits > 0) then {
	_nearUnits = _nearUnits apply {[leader _group distance _x, _x]};
	_nearUnits sort true;
	_nearestUnit = (_nearUnits select 0) select 1;
	
	_validSpot = false;
	_range = leader _group distance _nearestUnit;
	while {!_validSpot} do {
		_dir = (leader _group getDir _nearestUnit) + round random [-90, 0, 90] % 360;
		_distance = (leader _group distance _nearestUnit) + round random [-200, 0, 200];
		_newPos = leader _group getPos [_distance, _dir];
		
		if (!surfaceIsWater getPos leader _group) then {
			if (surfaceIsWater _newPos) then {
				_randomWay = selectRandom [-20, 20];
				while {surfaceIsWater _newPos} do {
					_dir = (_dir + _randomWay) % 360;
					_newPos = leader _group getPos [_distance, _dir];
					Sleep 0.5;
				};
			};
			_validSpot = true;
		} else {
			_newPos = [_newPos,0,200,2,2,10,0] call BIS_fnc_findSafePos;
			_validSpot = true;
		};
		Sleep 0.5;
	};
	
	_waypointOrig = _group addWaypoint [_newPos, 10];
	_waypointOrig setWaypointType "MOVE";
	_waypointOrig setWaypointBehaviour "SAFE";
	_waypointOrig setWaypointCombatMode "RED";
	_waypointOrig setWaypointFormation selectRandom ["STAG COLUMN", "WEDGE", "VEE", "DIAMOND", "FILE", "LINE"];
	_waypointOrig setWaypointSpeed "NORMAL";
	
	_waypointSAD = _group addWaypoint [_newPos, 100];
	_waypointSAD setWaypointType "SAD";
	
	_waypointCycle = _group addWaypoint [_newPos, 10];
	_waypointCycle setWaypointType "CYCLE";
	
	_group setCurrentWaypoint _waypointSAD;
	
	while {{alive _x} count units _group > 0 AND {_x distance (leader _group) < _maxDist} count allPlayers > 0} do {
		_nearestEnemy = leader _group findNearestEnemy leader _group;
		
		if (!isNull _nearestEnemy AND (_nearestEnemy distance leader _group) < 3000 AND alive _nearestEnemy) then {
			_waypointOrig setWaypointPosition [_nearestEnemy, 10];
			_waypointOrig setWaypointBehaviour "AWARE";
			
			_waypointSAD setWaypointPosition [_nearestEnemy, 50];
			_waypointSAD setWaypointBehaviour "AWARE";
			
			_waypointCycle setWaypointPosition [_nearestEnemy, 100];
			_waypointCycle setWaypointBehaviour "AWARE";
			
			_group setCurrentWaypoint _waypointSAD;
		};
		Sleep random [10, 15, 20];
	};
};

call {
	if (side _group isEqualTo west) exitWith {
		AC_BLUGroups = AC_BLUGroups select {_x != _group};
	};
	if (side _group isEqualTo east) exitWith {
		AC_OPFGroups = AC_OPFGroups select {_x != _group};
	};
	if (side _group isEqualTo resistance) exitWith {
		AC_INDGroups = AC_INDGroups select {_x != _group};
	};
};

terminate _Comms;
_group setVariable ["ACDelete", true, true];
if ({alive _x} count units _group > 0) then {
	{deleteVehicle _x} count units _group;
}; 

 

Anyway, thanks for the help and words of inspiration. I'm going to test some more to see if it is foolproof.

Share this post


Link to post
Share on other sites

Gonna take a closer look at it later today,

for now it's always bad practice to use convoluted scripts with while true loops in foreach loops.

Try splitting it up in smaller functions and you'll see that it's way easier to find errors / logical mishaps.

 

Cheers

 

Heh, yep, I'm afraid I did the opposite, put everything in one consistent function and switched most forEach with a descending for loop (as I've heard they're are better if you need to modify the array in action).

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

×