Jump to content
thy_

[SOLVED] How do we know if a vehicle is shooting?

Recommended Posts

How do we know if a vehicle is shooting?

 

fnc_isSomeTeamMemberShooting = {
	
    params ["_teamVeh"];
    private [...];
  
    _isShooting = false;

    {
        if ( incapacitatedState (gunner _x) isEqualTo "SHOOTING" ) then { _isShooting = true };
        // output is an empty string "" when the artillery vehicle is sending 155mm bullets through the sky...
    } forEach _teamVeh;

    // return:
    _isShooting;
};

// IMPORTANT: this _teamVeh is NOT composed by member of the same Group (e.g. "Alpha-1-1").

https://community.bistudio.com/wiki/incapacitatedState

 

I know I could use findIf to avoid this forEach, but for another reason (not relevant now), I need to check _isShooting through each member.

 

 

 

Share this post


Link to post
Share on other sites

maybe try something like this

Use this to check for shots. It will be false after 5 to 15 seconds. OR Are you trying to find out if it can shoot at all? If so see Canfire

Spoiler

_vehicle addEventHandler ["Fired", {
    params ["_vehicle", "_weapon", "_muzzle", "_mode", "_ammo", "_magazine", "_projectile", "_gunner"];

    // Check if the vehicle already has the "hasshot" flag set if not it'll show as false
    if (_vehicle getVariable ["hasshot", false]) exitWith {};

    // Set the "hasshot" flag to true
    _vehicle setVariable ["hasshot", true]; 

    // Spawn a script to reset the "hasshot" flag after a delay
    [_vehicle] spawn {
        params ["_vehicle"]; // Extract the passed vehicle
        sleep 5 + random 15; // Wait for 5-15 seconds
        _vehicle setVariable ["hasshot", false]; // Reset the flag to false
    };
}];

 

Edited by mikey74
following Pierremgi's advice revising the script. For the love of God my grammar sux
  • Like 1

Share this post


Link to post
Share on other sites

 

You can apply:
thisCar addEventHandler ["Fired", { params ["_unit", "_weapon", "_muzzle", "_mode", "_ammo", "_magazine", "_projectile", "_gunner"]; }];

 

Here _unit is already the vehicle. No need for vehicle _unit (which also returns the same vehicle). You can use _gunner for the _unit who shot, but that doesn't work for passengers.

The reason why there is another EH:

 

{ _x  addEventHandler ["FiredMan", { params ["_unit", "_weapon", "_muzzle", "_mode", "_ammo", "_magazine", "_projectile", "_vehicle"]; }] } forEach crew thisCar;

 

 

  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites
15 hours ago, mikey74 said:

maybe try something like this

9...0 OR Are you trying to find out if it can shoot at all? If so see Canfire

 

I had a few issues with canFire. I'll read it again later.

 

12 hours ago, pierremgi said:

thisCar addEventHandler ["Fired", { params ["_unit", "_weapon", "_muzzle", "_mode", "_ammo", "_magazine", "_projectile", "_gunner"]; }];

 

Hmm, good. Even I got to know about the EH, now I think I finally got it. So, yes, it looks like work here:

 

fnc_isSomeTeamMemberShooting = {
	
    params ["_teamVeh"];
    private [...];
  
    _isShooting = false;

    {
        _x addEventHandler ["Fired", {
            //params ["_unit", "_weapon", "_muzzle", "_mode", "_ammo", "_magazine", "_projectile", "_gunner"];
            _isShooting = true;
        }];
    } forEach _teamVeh;

    // return:
    _isShooting;
};

About the code above: the output (_isShooting) is always "false", even between addEventHandler and forEach if I ask for _isShooting over there.

 

Context:

The _teamVeh is a bunch of artillery pieces from different types. That said, imagine 4 vehs where 2 are howitzers and 2 MRLs, firing times absolutely different. 12 rounds for an MRL is about 10 seconds against +60s for howitzers. I wanna make the group wait in a waitUntil loop until NO _teamVehs member is firing anymore. 

 

while { ... } do {

    ...
    ...The entire group firing a lot...

    waitUntil { sleep 20; [_teamVeh] call fnc_isSomeTeamMemberShooting };
    // restarting the shooting a few times more, but the entire group together/at the same time.
};

 

 

Thought about EH:

Spoiler

 

I didn't know that EH could be a replacement for conditionals. 

I've read a bit about EH but, in big terms, (assuming there's a way to check "fired" with conditionals as well) what's the coolest thing about EH? What is its feature that can be seen as a game-changer? Performance? Flexibility? Hope it wasn't a hard question.

 

 

Share this post


Link to post
Share on other sites

I'm trying but still not working and not understand the EH logic.

Share this post


Link to post
Share on other sites

Hi, if I understand correctly, you only need to check when all artillery units ceased to fire, right ?. You can do it by checking unitReady. Obviously, this should be put after artillery started firing.
 

_artilleries = [arty1,arty2,arty3];
{
_x doArtilleryFire [[3000, 120, 1000], "8Rnd_82mm_Mo_shells", 3];
} forEach _artilleries;
waitUntil {sleep 3;(_artilleries findIf {!unitReady _x}) == -1};
hint "artilleries ceased to fire";

With eventhandlers...that's not how they work. They cannot be used as replacement for conditionals. Events are fired when specific engine coded script is done. It happens in the background even without you knowing it. Event is called when unit changes animation (animDone), gets hurt (HandleDamage, Hit, Hitpart), reloads weapon (Reloaded) and so on . So to have something practical to explain on, when unit dies, it calls killed event. Then the game checks if any code is added to unit via addEventhandler with "Killed" type and runs all assigned codes. If you add eventhandler it stores the code in some query, or array and when event happens, game runs every code stored in that query. Code is running in unscheduled environment (cannot be paused with sleep/waitUntil). More importantly it's completely new scope, the code is separated and cannot see code above or bellow.
Code you wrote will always return false, because it's in the scope that is not direct parent of eventhander scope that means _isShooting in function is not the same variable as _isShooting in event code even when they have the same name. Take a look at this.
If you need deeper understanding of that, you can experiment and simulate similar behavior in some of your own function with BIS_fnc_callScriptedEventHandler which will behave like engine scripted code and somewhere else BIS_fnc_addScriptedEventHandler which then simulates addEventHandler behavior. So my quick fun to make idea is try make door opening script and add functionality to be able to call external code with scripted event whenever doors open/closes.
I'll understand if it's too complicated. It takes time to fully get what eventhandlers do.

Also I made function that checks if some bullet is still flying. Returns TRUE if any bullet is still in air, FALSE if no bullet is flying. Might be useful for someone.
 

Spoiler

Function that checks if any bullet unit/vehicle fired is still flying and dangerous
addBulletCheck must be run first, then it's possible to run hasBulletInAir


soldierXXXX_fnc_addBulletCheck = {
scriptName "soldierXXXX_fnc_addBulletCheck";
params ["_unit"];
if (!isNil {_unit getVariable "bulletCheck"}) exitWith {["BulletCheck is already added to %1",_unit] call BIS_fnc_error;};
private _eventToAdd = ["FiredMan","Fired"] select (_unit isKindOf "AllVehicles");
private _Eh = _unit addEventHandler [_eventToAdd, {
 params ["_unit", "_weapon", "_muzzle", "_mode", "_ammo", "_magazine", "_projectile"];
_projectile addEventHandler ["Deleted", {  
 params ["_projectile"]; 
 private _unit = ((getShotParents _projectile) select 0); 
private _bullets = _unit getVariable ["liveBullets",0]; 
if (_bullets > 0) then { 
_unit setVariable ["liveBullets",_bullets - 1]; 
}; 
}]; 
 private _bullets = _unit getVariable ["liveBullets",0]; 
_unit setVariable ["liveBullets",_bullets + 1]; 
}];
_unit setVariable ["bulletCheck",_Eh];
};
 
soldierXXXX_fnc_hasBulletInAir = {params ["_unit"];
scriptName "soldierXXXX_fnc_hasBulletInAir";
private _firing = FALSE; 
private _bullets = _unit getVariable ["liveBullets",0]; 
if (_bullets > 0) then {_firing = TRUE;}; 
hintSilent str _firing; 
_firing 
}; 

//for testing purpose only 
private _Eh = player call soldierXXXX_fnc_addBulletCheck; 
onEachFrame {player call soldierXXXX_fnc_hasBulletInAir}; 

 

 

  • Like 1

Share this post


Link to post
Share on other sites
5 hours ago, thy_ said:

I'm trying but still not working and not understand the EH logic.

_isShooting is a local variable. This is why I went with the SetVariable. So when your EH fires that variable stays with the event. So anywhere else you're looking for that variable it just sees that its false because you set it this way. Think of EH as a separate script. You want to go global, or imo use setVariable.

  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites

You can use simple global variable:

isShooting = false;
{
  _x addEventHandler ["Fired", {  isShooting = TRUE }];
} forEach _teamVeh;

 

Perhaps I missed something.
 

 

 

 

 

  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites

Well, looking at how BIS built its BIS_fnc_wpArtillery function internally (via Eden Editor > Function viewer), I figured out there's a currentCommand returns that's not registered on the Wiki (?) and that makes totally difference to check if the vehicle team is shooting or not. That missing return is literally "FIRE AT POSITION". Not sure if another return (like "FIRE") has the same effect, I didn't test it.

 

4IUM9Vp.png

 

 

// If no more _fmTeam members are shooting, flag it:
if ( currentCommand _veh isEqualTo "FIRE AT POSITION" ) then { _isNotShooting = false };

So, my solution was to include this snippet above each looping check and everything run as I needed without any publicVariable/global variable.

Here is a simpler version of the real function built for the Dynamic Artillery Pieces (DAP) script, but the essential is here below:

THY_fnc_DAP_firing = {
	// This function makes the specific fire-mission-team shelling down a specific target position once before return.
	// Returns true after all alive team vehicles shoot: bool.

	params ["_fmTeam", "_pos", "_rounds", "_mag"];
	private ["_isNotShooting", "_veh", "_alreadyShoot"];

	// Initial values:
	_isNotShooting = nil;
	_veh           = objNull;
	_alreadyShoot  = [];

	// Wait until no more _veh are shooting:
	waituntil {
		// Each new loop, assuming no one is shooting:
		_isNotShooting = true;
		// Check each unit in charge of _veh:
		{
			_veh = vehicle _x;
			// Escape > Skip those units that is not in charge in _veh:
			if ( _x isNotEqualTo (effectiveCommander _veh) ) then { continue };
			// If _veh doesn't fire yet:
			if !(_veh in _alreadyShoot) then {
				// Fire:
				_veh doArtilleryFire [_pos, _mag, _rounds];
				// Flag it already shoot:
				_alreadyShoot pushBack _veh;
			};
			// If no more _fmTeam members are shooting, flag it:
			if ( currentCommand _veh isEqualTo "FIRE AT POSITION" ) then { _isNotShooting = false };
		} foreach units _fmTeam;
		// Next check:
		sleep 10;
		// Stop waiting if: cycle completed.
		_isNotShooting;
	};  // waitUntil ends.

	// Return:
	true;
};

 

Topic solved. Thanks, folks.

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

×