Jump to content
Luft08

How can I tell if AI are running low on ammo?

Recommended Posts

I have a mission where opfor has taken control of a town.  I have various weapon caches scattered throughout the town. When an AI unit gets low on ammo I want to set a waypoint to the nearest cache and when he arrives fill up his ammo.  The problem is that I don't know how to test to see if he is low on ammo. (Not completely out, just low). 

 

Is there a function or event handler that can help me do this?  Thanks.

Share this post


Link to post
Share on other sites

You could use the ReloadedEH to check magazines for an arbitrary amount - say, if they have one mag left in their inventory after reloading then move them to the cache.

 

There is a link in the ReloadedEH entry to a more verbose description with examples: https://community.bistudio.com/wiki/Arma_3:_Event_Handlers/Reloaded

  • Like 2
  • Thanks 1

Share this post


Link to post
Share on other sites

I believe Harzach has pointed to the right way (maybe there's more than just one right way though). You could possibly use "Reloaded" event handler to get the current magazine of the unit on reload and then use command "magazines" to get the total amount of such magazines left to the unit. This could possibly look like

/* Add the event handler (I assume the unit is in a variable called
 * "_unit" but you could very well use "this" if code is placed in
 * the unit's init field.
 */
_unit addEventHandler["Reloaded", {
  // Get the new mag class
  private _newMag = (_this select 3) select 0;
  
  // Get the count of this type of magazines the unit has
  // (excluding the currently loaded one)
  private _nMags = {_x isEqualTo _newMag} count (magazines _unit);
  
  // Now set the condition to send the unit to the ammo cache
  // (using Harzach's example of one magazine here)
  if (_nMags <= 1) then {
    // Using teleportation here for demonstration
    // I assume the cache is a named entity called "ammoCache_3"
    _unit setPos (getPos ammoCache_3);
  };
}];

You could very well one-line the calculation of the magazines left inside the condition of the if statement like

if (({_x isEqualTo _newMag} count (magazines _unit)) <= 1) then {
  // Blah blah blah
};

Or you could even one-line the whole thing which in my opinion makes things worse (unreadable or very-difficult-to-read code is not easily maintainable and the inclusion of a couple more temporary variables does not provide considerable overhead to avoid their use), but it could look like

if (({_x isEqualTo ((_this select 3) select 0)} count (magazines _unit)) <= 1) then {
  // Blah blah blah
};

Plus, this could potentially add some overhead due to the fact that, if the condition is left unoptimised (not sure if there's any optimisation being behind the scenes to the code being executed from an .sqf), there's a possibility that the selection of the first element of the third element of _this could be using some extra cpu cycles (if optimisation kicks in somehow it will most probably be placed in a temporary variable but we don't know that) every time you test against each magazine of the unit. Of course all this gibbering is only to try to move people to the direction of clean coding and it doesn't mean that one of the above snippets would destroy fps and ruin your gaming experience while the other is the way to go.

 

Anyway, I hope the snippet(s) above help somehow to point you towards a possible solution to your problem. Please do keep in mind that the code presented here is not tested and should be treated with caution. Don't use it without testing as it may need some corrections, refinements and/or may not achieve what you want to achieve.

 

Finally, please let us know if you require more help or if this is solves your problem. If not please do provide your solution for the benefit of people that either have the same issue or will do so in the future.

  • Like 1

Share this post


Link to post
Share on other sites

Thanks, I went with:

if(!isServer) exitWith {};

{
	private _index = soldiersResuppling find _x;
	if(_index == -1) then {
		if(alive _x) then {
			private _result = [_x] call isPrimaryAmmoLow;
			if(_result) then {
				// soldier has low ammo.
				soldiersResuppling pushBack _x;
				[_x] call goForAmmo;	
			};
		};
	};
} forEach troopArray;

isPrimaryAmmoLow:

if(!isServer) exitWith {};
params["_AIUnit"];

private _primaryAmmoLow = false;
private _allMags = magazines _AIUnit;
private _consolidatedWepArray = _allMags call BIS_fnc_consolidateArray;
private _wepMagTypeArray = primaryWeaponMagazine  _AIUnit;
private _wepMagType = _wepMagTypeArray # 0;
private _magCount = 0;
{
	private _magType = _x # 0;
	if(_magType == _wepMagType) exitWith { _magCount = _x # 1};;
} forEach _consolidatedWepArray; // Should always be only 1 entry for primary weapon? Maybe better not to use forEach?

if (_magCount == 0) then {_primaryAmmoLow = true;}; // Does not count the mag that is loaded.

_primaryAmmoLow

 

  • Like 1

Share this post


Link to post
Share on other sites
14 hours ago, Luft08 said:

New question related to my rearm goal:

How do you make AI go right up next to the weapon cache?  I need them to be right next to the cache so that I can start some kind of animation that gives the appearance of kneeling down and rearming. I'm using the following code to get AI to go to the cache but they end up several meters away.

goForAmmo.sqf:


if(!isServer) exitWith {};
params["_soldier"];
private _minDist = 5000;
private _nearestCache = [];
{
	private _dist = _soldier distance _x;
	if(_dist < _minDist) then {
		_nearestCache = [];
		_nearestCache pushBack _x;
		_minDist = _dist;
	};

	if(_dist == _minDist) then {
		_nearestCache pushBack _x;
	};
} forEach weaponCacheArray;

private _targetCache = selectRandom _nearestCache;
private _grp = group _soldier;
[_grp] call CBA_fnc_clearWaypoints;
_grp setBehaviour "SAFE";
_grp setCombatMode "BLUE";
_grp setSpeedMode "FULL";

private _wp = _grp addWaypoint [_targetCache, -1];
_wp setWaypointType "MOVE";
_wp setWaypointStatements ["true", "{[group this] call soldierReload;"];

 

 

Share this post


Link to post
Share on other sites

You might need to find a position just next to the cache, rather than the position of the cache itself. 

  • Like 1

Share this post


Link to post
Share on other sites
29 minutes ago, Harzach said:

You might need to find a position just next to the cache, rather than the position of the cache itself. 

I could do that with a vectorAdd.  Would that make the AI come closer?

  • Like 1

Share this post


Link to post
Share on other sites

Not sure, can't test right now. I'm assuming they are stopping short because they can't occupy the given position.

  • Like 2

Share this post


Link to post
Share on other sites

I'm sort of fiddling with it now, I suspect that the default waypoint completion radius is the issue. Try using setWaypointCompletionRadius to minimize the radius and hence the ultimate proximity of the AI to the cache object.

 

*edit* - with the limited testing I have done, I can't get an AI unit to move closer than 4m to a supplybox. If I ask it to get closer, it hangs out about 5m from it.

This is why I gave up trying to wrangle AI a few years ago 😄

  • Like 1
  • Haha 1

Share this post


Link to post
Share on other sites

Although I haven't tested it, a though would be to try to ask the AI to move further away from the supply box but on the opposite side of it. The thought is that in this way it would hopefully try to move on a straight line, thus ending up being closer to the supply box.

 

This should be the last step of the whole process as you first have to find what the position of the AI is when it "completes" the waypoint and then ask it to move towards the box. This last step could potentially look like the following

/*
 * I assume the following variables are valid
 * _unit: The AI
 * _box: The supply box
 */

// Calculate the unit vector pointing from the unit towards the box
private _uVec = (getPos _unit) vectorFromTo (getPos _box);

// Calculate coordinates of the new waypoint
private _dist = _unit distance _box; // The distance between the unit and the box
_dist = _dist - 1; // Subtract one from the distance to make the new waypoint (dist - 1) away from the box

private _newCoords = _uVec apply {_x * _dist}; // Scale the unit vector

// Add the new waypoint which is (dist - 1) meters away from the box on the opposite side (in respect
// to the unit's position) [using your own code for this
private _wp = _grp addWaypoint [_targetCache vectorAdd _newCoords, -1]; // ADD THE VECTOR TO THE COORDINATES OF THE CACHE
_wp setWaypointType "MOVE";
_wp setWaypointStatements ["true", "{[group this] call soldierReload;"];

Of course, this is just a thought. The AI may decide that the box is an obstacle and attempt to go around it. The worst case scenario is for the AI to decide differently every time :|...I believe that this is highly possible, otherwise Harzach wouldn't have given up on AI some years ago ;P.

 

Nevertheless, please note that this code is not tested and should be treated with caution and let us know if you managed to find a solution or workaround (for future reference).

Share this post


Link to post
Share on other sites
4 hours ago, ZaellixA said:

Although I haven't tested it

 

I did. 😕

  • Sad 1

Share this post


Link to post
Share on other sites
18 hours ago, Harzach said:

I'm sort of fiddling with it now, I suspect that the default waypoint completion radius is the issue. Try using setWaypointCompletionRadius to minimize the radius and hence the ultimate proximity of the AI to the cache object.

 

*edit* - with the limited testing I have done, I can't get an AI unit to move closer than 4m to a supplybox. If I ask it to get closer, it hangs out about 5m from it.

This is why I gave up trying to wrangle AI a few years ago 😄

Thanks, I'll do more testing.  Just thinking here... Maybe I need to check to see if the AI is within 5 m or so of the cache and then attach him to the supply crate somehow? That would probably stop any animation but maybe I could detach him without moving him. 

 

I'll play around with it. It may not even be possible.

Share this post


Link to post
Share on other sites

Did some more fiddling.

attachTo seems unnecessary (it's just a complicated way to setPos). 

 

setPos'ing the AI works just fine, but it won't be the most immersive thing to behold.

 

Making the cache a simpleObject fixes the initial issue of AI not approaching close enough, but then you have a cache that is, you know, a simpleObject.

 

@pierremgi created a script that does this and more:

I can see that he's checking bounding boxes and whatnot, so maybe he's got this issue sorted.

 

  • Like 1

Share this post


Link to post
Share on other sites

Hello all, back in the loop...  but still lame duck, moving from Tahiti to France with few stuff. Not very operational til 2022.

As @Harzach mentioned a module of mines, here is what i elaborated for making AIs rearm:

1 - first of all, I decided to count the remaining shot for the primary weapon only. So out of handgun or launcher (grenades,missiles) is not a decisive factor (but these weapons will be rearmed if any ammo found during the 1st wpn reloading)

2 - I coded for less than 10 shots remaining... perhaps, I'll add a param on module. Not sure.  of course, you need to know all the remaining shots inside all the magazines (loaded, unif, vest, bpk) 😊

3 - I coded also a max distance... 100 m for any crate/corpse/ weapon holder in fact.

4 - and a priority:  arsenal if available, compatible mags in crates, compatible mags on corpses, but also  another primary weapon available (If you find a loaded AK47, drop your "empty" gun).

5 - and yes, I coded a domove to the weapon holder, using the boundingBoxReal to have a decent stop and reload animation, on corpse or weapon on ground, as well as truck or tank (engine off)

6 - I decided how many mags (among all compatible), and why not launched grenades (if equipped) and why not hand grenades, and why not FAK a AI must pick. I didn't use any rearm action because there is no limitation about mags and if 2 AIs are out of ammo, the first served picks the bounty, the second one cries.

 

This is what a thought scripting and testing the module. Your approach will be different but I hope that helps.

  • Like 2
  • Thanks 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

×