Jump to content

Recommended Posts

Posted

Working on a trigger and I'm hitting a wall here.

 

I have a mission that has ~80 units that are all spawned in turn via the F10 menus. This is easy and works fine.

 

My problem is that I am trying to get a short .WAV file to play upon each units death.

 

I'm trying to create a single trigger that will detect a units death and play the wav file. Depending upon how I do it, it either only happens once, doesn't happen at all, or plays in a continual loop.

 

I guess I could create a 80+ ONCE trigger for each of the 80+ units with a single units death in the conditions column, but that seems to be huge overkill and very inefficient.

 

Can some learned soul here help a brother out and give me some pointers?

 

Markeebo

Posted (edited)

Sure, use the more flexible lua scripting instead.

 

With Mist, you can write such things:

 

 

WARNING: code written on-the-fly, should be tested/debugged, not production-ready.

local function playSound (event)
   if event.id == world.event.S_EVENT_DEAD and event.target then  -- only if event is death of any unit
       targetName = event.target.name
       if  String.match(targetName, 'p_') -- only if destroyed unit name is starting with 'p_'  to avoid playing sound for others[i]
           trigger.action.outSound(targetName..'.wav') [/i]-- play the file ${targetName}.wav if you need to specify a different WAV per unit
[i]             trigger.action.outSound('my_unique_sound_file.wav') [/i]-- play a unique file for all prefixed units
       end
   end     
end

mist.addEventHandler(playSound) 

 

Don't forget to prefix the units names with 'p_' into the mission editor.

Edited by galevsky06
Posted (edited)

Better and more generic implementation here below:

 

WARNING: code written on-the-fly, should be tested/debugged, not production-ready.

prefix2Sound = {     
   ['a_']  = 'a.wav',
   ['b_']  = 'b.wav',
   ['c_']  = 'c.ogg',
   ['d_']  = 'd.ogg',
    -- .... as many sound files as you want
}

function playSound(unitName) 
   for prefix, sound in pairs(prefix2Sound) do         
       if string.match(unitName, '^'..prefix) then 
           trigger.action.outSound(sound)
           return
       end
   end 
end

local function playSoundOnDeath (event)
    if event.id == world.event.S_EVENT_DEAD and event.target then
       playSound(event.target.name)
   end     
end

mist.addEventHandler(playSoundOnDeath)

Then assign the sound file that you want to the units death by prefixing their names.

Edited by galevsky06
Posted

Thanks for the input. To be honest, I am a COMPLETE LUA RETARD.

 

I've tried to catch on a few times but have never really been able to actually apply it to something useful like the above examples that you have provided.

 

I can vaguely interpret the first example, but the second mystifies me.

 

 

Line by line on the first example

 

1. "Local Function" I think I get. You are creating a function named playSound (Though I dont unterstand the "(event)" part)

 

2 and 3. not sure about the syntax "event.id" but I would assume that its related to the (event) in line 1. Looks like if something dies AND (Not understanding "event.target"), then get that units name that just died.

 

4. check to see if the destroyed units' name from line 2&3 began with "p_". (makes sense)

 

5. If line 4 is true, then play a sound. (not understanding how to define a different .wav per unit)

 

6. Same as 5 above. If line 4 is true, then play a sound. (This make a bit more sense than line 5 but I'm quite confused as to how both could be in the same IF statement.

 

7-10. end

 

11. Looks like its placed into a package called playSound that is handed off to MIST to watch for.....(was I even close? LOL)

 

 

Seriously, you have gone above and beyond by simply responding constructively. So if you don't want to delve any deeper with a LUA-Deficient retard, S'ok.

 

I need to refine my wording a bit though.

 

I would like to play a .wav file to the opposing force when an enemy unit is killed.

 

ie Blue unit dies.....Play .wav to Red side

 

Red Unit dies...Play .wav file to Blue side.

 

Should have been more specific from the start, but I actually didnt think it would lead to scripting. Though I'm happy it did. As stated above, I have never really been able to apply scripting to something that is relevant to my needs at that moment. OR the scripting that I try to deconstruct in order to understand is so huge and complex that I just cant wrap my head around it due to lack of experience/comprehension.

 

 

 

Markeebo

Posted (edited)
Thanks for the input. To be honest, I am a COMPLETE LUA RETARD.

 

No matter, the original Scripting Engine library is not what we -devs- call a masterpiece to imitate. :smilewink:

 

 

Line by line on the first example

Ok, let's go ! :smartass:

 

1. "Local Function" I think I get. You are creating a function named playSound (Though I dont unterstand the "(event)" part)

Lua script are interpreted line by line, top to bottom. We could imagine to execute a series of instructions straight-forward, but we will split up the code into different functions for reusable code without duplication.

 

local function itsName(parameterOne, ParameterTwo, ...)

theInstructionsContainedInsideTheFunctionInsideUsingParametersIfAny

end

 

local: I don't want to explain this part, let's say that it is optional, and don't need it. Good practises require it, but not so important right now.

 

functions may have zero, one, or two, or as many parameters as your function requires. You choose. But please avoid using more than 5, it ruins the code visibility. Also avoid writing too long functions, and split the big one into smaller unitary functions.

 

 

2 and 3. not sure about the syntax "event.id" but I would assume that its related to the (event) in line 1. Looks like if something dies AND (Not understanding "event.target"), then get that units name that just died.

You have to read the library documentation, there is nothing magic here:

 

From Mist v3.2 pdf:

mist.addEventHandler

number mist.addEventHandler (function handler)

This is a simplified version of the simulator scripting engine’s world.addEventHandler function.

handler must a function that expects a single variable of a world simulator event. It also returns a number id for this event handler (for use with mist.removeEventHandler). For more information on

world events, see the Simulator Scripting Engine documentation for world events.

Examples:

[...]

So let's write the function handler, that takes a single parameter in input:

 

function playSoundOnDeath(event)

end

I am giving sensible names, but it is just for code visibility. If you want, you can choose:

 

function functionOne(paramOne)

end

but it is stupid for code readability. Now let's see what is the single variable of a world simulator event

 

From Simulator Scripting Engine documentation:

 

Event = { id = enum world.event, time = Time, initiator = Unit, target = Unit, place = Unit, subPlace = enum world.BirthPlace, weapon = Weapon }With enum world.Event:

 

world.event = { S_EVENT_SHOT, S_EVENT_HIT, S_EVENT_TAKEOFF, S_EVENT_LAND, S_EVENT_CRASH, S_EVENT_EJECTION, S_EVENT_REFUELING, S_EVENT_DEAD, S_EVENT_PILOT_DEAD, S_EVENT_BASE_CAPTURED, S_EVENT_MISSION_START, S_EVENT_MISSION_END, S_EVENT_TOOK_CONTROL, S_EVENT_REFUELING_STOP, S_EVENT_BIRTH, S_EVENT_HUMAN_FAILURE, S_EVENT_ENGINE_STARTUP, S_EVENT_ENGINE_SHUTDOWN, S_EVENT_PLAYER_ENTER_UNIT, S_EVENT_PLAYER_LEAVE_UNIT }

So, our function will be called when every event happens, with the input parameter (called event) containing information... all fields are not fillled depending on the event: if it is a BIRTH event, I guess that event.weapon will be empty (an empty field has the null value, or in lua nil).

 

So let's do something on the event that you have chosen:

 

function functionOne(paramOne)

if event.id == world.event.S_EVENT_DEAD and event.target ~= nil then
  -- do something 
end

We check the type event, plus the field target, that cannot be nil since we will use it the line after !

 

There is different ways to write the same thing in lua:

 

if variable == nil then 
  -- executed only if the variable was null
end

if variable ~= nil then 
  -- executed only if the variable was NOT null
end

if variable then 
  -- executed only if the variable was NOT null but in simpler manner
end


4. check to see if the destroyed units' name from line 2&3 began with "p_". (makes sense)

 

Yep, I want some criteria to filter the units: we may not want that absolutely all units in the game will play the sound at destruction. (human aircrafts, for example). So I decided to base the filter on a naming convention: prefix in the unit name is perfect for that kind of filtering.

 

5. If line 4 is true, then play a sound. (not understanding how to define a different .wav per unit)
Look at the function documentation:

 

function trigger.action.outSound(string soundFile)
The function is called with one parameter of type string (means characters),

 

so you can hard-code the file name like:

 

trigger.action.outSound('myFile.wav')

Or you can use a variable that contains the string:

 

 

myFileNameInVariable = 'myFile.wav'
trigger.action.outSound(myFileNameInVariable)

Let's imagine now that we will use the name of the target destroyed as the file name !

 

function functionOne(paramOne)
   if event.id == world.event.S_EVENT_DEAD and event.target ~= nil then
       trigger.action.outSound(event.target.name..'.wav')
   end
end

The file to play will have the name of the unit destroyed plus .wav at the end

 

string1..string2 will concatenate the two string into one:

 

greetings = 'Hello '
sentence = greetings..'Mark !'
-- the variable sentence contains now the string 'Hello Mark !'

So How did I guessed the event.target.name part ?

 

the event provided in input contains a target field which is a Unit variable, according to the world.event definition. Now let's see what is a Unit ?

 

From Scripting Engine doc:

 

Unit extends CoalitionObject.... that extends Object itself. And Object have a name attribute. I don't want to discuss about the different ways to retrieve the name attribute because there are numerous, but we can do .name to get its name

6. Same as 5 above. If line 4 is true, then play a sound. (This make a bit more sense than line 5 but I'm quite confused as to how both could be in the same IF statement.
Not both together, pick-up just the one that suits your needs best ! :thumbup:

 

7-10. end

 

11. Looks like its placed into a package called playSound that is handed off to MIST to watch for.....(was I even close? LOL)
Please read the Mist documentation: it registers the function in parameter (here playSound) as part of the functions to be called to handle events whenever they happen.

 

Seriously, you have gone above and beyond by simply responding constructively. So if you don't want to delve any deeper with a LUA-Deficient retard, S'ok.

I cannot teach you the whole thing, but hope it makes you go ahead to read examples/docs and so on :)

 

I need to refine my wording a bit though.

 

I would like to play a .wav file to the opposing force when an enemy unit is killed.

 

ie Blue unit dies.....Play .wav to Red side

 

Red Unit dies...Play .wav file to Blue side.

 

Should have been more specific from the start, but I actually didnt think it would lead to scripting. Though I'm happy it did. As stated above, I have never really been able to apply scripting to something that is relevant to my needs at that moment. OR the scripting that I try to deconstruct in order to understand is so huge and complex that I just cant wrap my head around it due to lack of experience/comprehension.

 

Markeebo

I let you try to enhance the function !

 

Tips: the function

 function trigger.action.outSoundForCoalition(enum coalition.side coalition, string soundFile)
-- plays sound file to all players on a specific coalition.

exists :thumbup:

Edited by galevsky06
Posted

My head hurts now. LOL

 

Thanks for the details. I'm going to need a few days to sort through this post and form newer questions. Many of your answers caused many other questions.

 

Grateful to you for taking your time to explain this.

 

Markeebo

Posted

OK....I work out of town so I will be posting slowly as I digest things.

 

Will post a couple observations.

 

 

 

local ----I have read enough about this to semi understand that this basically is a one-time run through the function and that nothing will be retained for future use. Essentially cleans house so as to not clutter the code with sh1t that's not needed and will make it less efficient later on.

 

Close enough?

 

Still don't really understand the "and event.target" portion of line 2. What does "event" refer to? The "event" as in playSound(EVENT)? Or as in event.id? Lets me ask it this way.....If the function were called playSound(paramOne), would event.target be renamed "paramOne.target"?

 

It's clearer though as I must have read your last post at least 10 times.

 

You referred to the Sim Scripting Documentation and in that line there was this buried in the top line:

 

target=Unit

 

So "event.target" AND the remark that you left "only if event is death of any unit" makes more sense. Could you have left the "event.target" out because you further refine your query below that with the String.match statement? Or is it required here? Just not clear on if event is an actual sim event or simply the parameter returned in the function as in playSound (event).

 

 

Final question, and this yet again will completely display my ignorance.

 

Line 4 in the Parameters portion of the IF statement shows 'p_'

 

That to me says any unit named 'p_'. NOT starts with 'p_' I'm referring to the DOS or Windows syntax of anything beginning with 'p_' would be typed as 'p_*'

 

The asterisk being the wildcard here allowing for ANYTHING that starts with 'p_'.

 

Again, thanks for taking the time to educate the ignorant. This is definitely making more sense. as I go along though.

 

Markeebo

  • 1 year later...
Posted

So... this event is giving me a headache, how come you check the target here when the documentation states the initiator is the unit that is dead?

-

If man were meant to fly he'd be filled with helium.

Posted (edited)
I guess I could create a 80+ ONCE trigger for each of the 80+ units with a single units death in the conditions column, but that seems to be huge overkill and very inefficient.

 

Too bad I didn't see this back when. This ^^^ 80 event approach works fine and it could have been completed within a couple of hours at most. Each event can be cloned and the next event would need the next unit selected in the condition. The same flag would be turned on in each event.

 

And a Switched Condition event would detect that flag and turn it off and play the sound file.

 

WC

Edited by Wrecking Crew

Visit the Hollo Pointe DCS World server -- an open server with a variety of COOP & H2H missions including Combined Arms. All released missions are available for free download, modification and public hosting, from my Wrecking Crew Projects site.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...