Markeebo Posted July 17, 2014 Posted July 17, 2014 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
galevsky06 Posted July 18, 2014 Posted July 18, 2014 (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 July 18, 2014 by galevsky06
galevsky06 Posted July 18, 2014 Posted July 18, 2014 (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 July 18, 2014 by galevsky06
Markeebo Posted July 18, 2014 Author Posted July 18, 2014 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
galevsky06 Posted July 18, 2014 Posted July 18, 2014 (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. MarkeeboI 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 July 18, 2014 by galevsky06
Markeebo Posted July 19, 2014 Author Posted July 19, 2014 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
Stonehouse Posted July 20, 2014 Posted July 20, 2014 Do wav files actually work now? So far I've always used oog sound files.
Markeebo Posted July 21, 2014 Author Posted July 21, 2014 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
Coug4r Posted October 18, 2015 Posted October 18, 2015 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.
Wrecking Crew Posted October 19, 2015 Posted October 19, 2015 (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 October 19, 2015 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.
Recommended Posts