Jump to content
Lorenz94

Audio played with MPKilled EH loops

Recommended Posts

Hi all, I kindly need you help for an EH headache!

 

What I'm trying to accomplish is to play a sound from the nearest unit/player (within 15m) warning who shot a civilian to hold fire. The problem I'm currently facing is that the sound is sometimes repeated two or three times and I'm not sure if it is played from the real closest unit or not.

 

From the biki, I understand that the EH MPkilled passes the killed unit (select 0), who killed the unit (select 1) and what's _this select 2?

 

Here's my code: (please feel free to suggest other ways to find the nearest player to the killer)

Spoiler

if !(isServer) exitWith {};

[] spawn {
	while {true} do {
		uiSleep 2; //Does a check each 2s	
		{
			if (_x getVariable ["BRZ_isCiv", false]) exitwith {};
			
			if (side _x == Civilian) then {
				_x addMPEventHandler ["MPKilled", 
					{
						[(_this select 1)] spawn {
							_killer = _this select 0;
							
							_allPlayers = [];
							{
								if (alive _x && (_x distance _killer < 25)) then {
									_allPlayers pushBack _x;
								};
							} foreach (if (isMultiplayer) then {playableUnits} else {switchableUnits});
								
							_randomPlayer = _allPlayers call BIS_fnc_selectRandom;
									
							hint "ciao";
							_randomPlayer say3D ['hold_fire_1', 85, 1];
						};
					}
				];
			};
		} foreach allUnits;
	}
};

 


Thank you!

PS: how can I pick up a random sound two play between two variants?

Share this post


Link to post
Share on other sites

I also thought about deleting the event handler, but I don't know what is the correct index to use, because I have another script running on AI deaths that hides bodies after a bunch of minutes.

Share this post


Link to post
Share on other sites

Your problem is that you are adding the eventHandler over and over again because of the while loop. You need to flag each civilian once they have had the event added.

You already have some form of check with...

if (_x getVariable ["BRZ_isCiv", false]) exitwith {};

..yet you never set this flag once the event has been added. As the check uses exitWith so the loop would exit once a checked civliian has been found, so I have left this check as is as I'm not sure what you are using it for. Instead I have added a separate one for this event "BRZ_hasKilledEvent"...

if !(isServer) exitWith {};

[] spawn {
	while {true} do {
		//Does a check each 2s	
		uiSleep 2;
		{
			if (_x getVariable ["BRZ_isCiv", false]) exitWith {};
				
			//If the unit is a civilian AND has not had the EH added
			if ( side _x == civilian && { !( _x getVariable ["BRZ_hasKilledEH", false] ) } ) then {
				
				//Add eventHandler
				_x addMPEventHandler ["MPKilled", {
					_nul = _this spawn {
						params[
							"_unit",
							"_killer",
							"_instigator",
							"_useEffects"
						];
						
						//Get all units
						_unitsToCheck = [ switchableUnits, playableUnits ] select isMultiplayer;
						
						//Select those in range of _killed
						_unitsInRange = _unitsToCheck select { alive _x && (_x distanceSqr _killer < ( 25^2 )) };
						
						//Arrange the units ready for sorting by distance
						_unitsToSort = _unitsInRange apply { [ _x distanceSqr _killer, _x ] };
						
						//The above could be done in one line, I have separated for easy reading
						//_unitsToSort = ( [ switchableUnits, playableUnits ] select isMultiplayer ) select { alive _x && (_x distanceSqr _killer < ( 25^2 )) } apply { [ _x distanceSqr _killer, _x ] };
						
						//Sort the units
						_unitsToSort sort true;
						
						//Select the nearest
						_nearestPlayer = _unitsToSort select 0 select 1;
						
						//If we have a nearest unit
						if !( isNil "_nearestPlayer" ) then {
							
							//Debug message
							hint format[ "Nearest player\n%1", _nearestPlayer ];
							
							//Select a random sound to play
							_randomSound = selectRandom [ "hold_fire_1", "hold_fire_2" ];
							
							//Make nearest say _randomSound
							_nearestPlayer say3D [_randomSound, 85, 1];
						};
					};
				}];
				
				//Flag civilian as having event added
				_x setVariable [ "BRZ_hasKilledEH", true ];
			};

		} forEach allUnits;
	}
};

Untested.

The event would be better added where you spawn the civilians rather than checking every 2 seconds for new spawns.

  • Like 3

Share this post


Link to post
Share on other sites
2 hours ago, Larrow said:

Untested.

Hi Larrow, thank you for your help. The variable "BRZ_isCiv" will be used in case of kamikaze or bad guys in general, we can leave this out for more clarity if needed.

 

I tested your code and it works, but the unit playing the sound is not the closest to who (me) shot a civilian. I can't figure this out and this fact happened even with my version of the script, so there would be be something wrong with the parameters of the EH!

What do you think?

Moreover, may I ask you if the while loop is needed or not? In my mission I also have a "handledisconnect" EH, not in a loop but it works perfectly.. I'm not very good in using EH so by logic I put the loop, but if not needed it would be just a waste of cpu cycles.

 

Thank you again!

 

 

Share this post


Link to post
Share on other sites
On 11/30/2017 at 7:26 AM, Lorenz94 said:

PS: how can I pick up a random sound two play between two variants?

sound_array = ["sound1","sound2"];
random_sound = selectRandom sound_array;
[_randomPlayer,[random_sound,85,1]] remoteExec ["say3D",0];

An easy way to get random sound effects. I like remoteExec for MP sounds personally.

 

Share this post


Link to post
Share on other sites
7 hours ago, XianGrim said:

sound_array = ["sound1","sound2"];
random_sound = selectRandom sound_array;
[_randomPlayer,[random_sound,85,1]] remoteExec ["say3D",0];

An easy way to get random sound effects. I like remoteExec for MP sounds personally.

 

Thank you, Larrow also provided something similar! In this case I prefer to have the sound played from the nearest unit instead of a remoteExec, thank you!!

Share this post


Link to post
Share on other sites
On 11/30/2017 at 8:09 PM, Lorenz94 said:

Moreover, may I ask you if the while loop is needed or not?

Only if you are spawning civilians during your mission, which if you do is why I said previously you would be better off adding the event from where you spawn the civilians. If you dont then there is no need for the loop, just forEach through all civilians at mission start and add the event to them.

//initServer.sqf

TAG_fnc_addCivKilledEH = {
	params[ "_unit" ];

	//If the unit is a civilian AND has not had the EH added
	if ( side _unit == civilian && { !( _x getVariable [ "BRZ_hasKilledEH", false ] ) } ) then {

		//Add eventHandler
		_unit addMPEventHandler ["MPKilled", {
			params[
				"_killed",
				"_killer",
				"_instigator",
				"_useEffects"
			];

			//If we do not have an instigator
			if ( isNull _instigator ) then {
				//was the killer a controlled UAV
				_instigator = ( UAVControl vehicle _killer ) select 0;
				//If we still do not have an instigator
				if ( isNull _instigator ) then {
					//use the killer
					_instigator = _killer;
				};
			};

			//Get all units
			_unitsToCheck = ( [ switchableUnits, playableUnits ] select isMultiplayer ) - [ _instigator ];

			//Select those in range of _instigator
			_unitsInRange = _unitsToCheck select { alive _x && (_x distanceSqr _instigator < ( 25^2 )) };

			//Arrange the units ready for sorting by distance
			_unitsToSort = _unitsInRange apply { [ _x distanceSqr _instigator, _x ] };

			//The above could be done in one line, I have separated for easy reading
			//_unitsToSort = ( [ switchableUnits, playableUnits ] select isMultiplayer ) select { alive _x && (_x distanceSqr _instigator < ( 25^2 )) } apply { [ _x distanceSqr _instigator, _x ] };

			//Sort the units
			_unitsToSort sort true;

			//Select the nearest
			_nearestUnit = _unitsToSort select 0 select 1;

			//If we have a nearest unit
			if !( isNil "_nearestUnit" ) then {

				//Debug message
				format[ "Civ: %1\nKilled By: %2\nNearest unit: %3", _killed, _instigator, _nearestUnit ] remoteExec[ "hint", [ 0, -2 ] select isDedicated ];

				//Select a random sound to play
				_randomSound = selectRandom [ "hold_fire_1", "hold_fire_2" ];

				//Make nearest say _randomSound on all connected clients
				[ _nearestUnit, [_randomSound, 85, 1] ] remoteExec [ "say3D", [ 0, -2 ] select isDedicated ];
			};
		}];

		//Flag civilian as having event added
		_unit setVariable [ "BRZ_hasKilledEH", true ];
	};
};


//Loop to check for new civilian units every two seconds
[] spawn {
	while {true} do {
		//Does a check each 2s
		uiSleep 2;
		{
			[ _x ] call TAG_fnc_addCivKilledEH;
		} forEach allUnits;
	}
};

Ive changed the code a little...

The event is now added via a function so you can use it from where you spawn any civilians as describe above. If you have no need for continual checking for new civs just remove the while from the loop.

I've removed the killer from the close units check.

Changed say3D to be remoteExec'ed as the command has local effect and as it is being run from the server unless you are single player/host you would never hear it.

There may still be some edge cases that you will need to account for.

 

I think that was it, I've tried to post this several times over the last couple of days but the forums are so abysmal lately with slow loading and getting stuck opening code/quote boxes I've had to give up and try again later.

  • Like 2

Share this post


Link to post
Share on other sites

don't mp event handlers always execute local to the players?

 

Share this post


Link to post
Share on other sites
On 4/12/2017 at 12:57 PM, Larrow said:

I think that was it, I've tried to post this several times over the last couple of days but the forums are so abysmal lately with slow loading and getting stuck opening code/quote boxes I've had to give up and try again later.

No problem for the wait! Really thank you Larrow, you've done a great work! I'm sorry to not beeing able to point you further in the right direction, but as I said, this EV in particular has driven me crazy!

 

You code is fantastic and the proximity limit is something I was thinking about, but you beat me being faster!

 

One last thing, please: the sound is coming from my character! Even if I change _instigator to _killer at line 26 (I've seen line 21, but tried anyway). I can't understand why this happens since you took away who killed the civilian.

 

Moreover, is it possible somehow to add a timer, so that if two or more civilians are killed in fast succession the sound is played once?

 

Thank you, again for your time! 

Share this post


Link to post
Share on other sites
On 4/12/2017 at 12:57 PM, Larrow said:

later

Sorry to bother you again,

have you idea how to perform the above correction?

Thank you.

Share this post


Link to post
Share on other sites

The hint keeps desplaying civilian and killer as the same unit (killed and instigator), while _nearestunit returns the name of who shot down the civilian. The audio sometimes is played from the killer instead of other units.. I tried to modify this "_unitsToCheck = ( [ switchableUnits, playableUnits ] select isMultiplayer ) - [ _instigator ];", but no luck.

 

Thank you.

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

×