Hi,
I'm working on a wildlife sounds system for Tonal island, using authentic SE African bird and animal sounds.
There were three main elements I wanted:
1. Many different ambient loops running from a single fauna.sqs script, that start only when the player is within audible distance, cannot be re-triggered once the script is running, and exit when the player goes out of range.
2. Inner trigger areas for each loop area, where an alarm call will play rather than the main sound, or the sound will just stop, until the inner area is clear.
3. Wildlife will "flee" from unsilenced gunshots or explosions in their area, giving panic alarm calls and not returning to the area for 5-10 minutes.
Parts 1 and 2 are now working nicely, but I'm out of my depth with 3...
BackgroundEach ambient loop needs a set of 1 logic and 2 triggers, all with unique names. I've load tested with 100 of these sets on the map and plan to have about 50 running without excessive lag. I'll probably optimise it all later by moving the conditions from the triggers to a looping checker script.
_logic is just a gamelogic. It is a reference to check the player's distance so the script can be initialised. Once the script is initalised for the set, the script moves _logic away to [0,0,0] so the script can't be initialised for that set again until the player has moved away and it has exited.
_innertrigger is a small trigger that the script uses to check whether any men have entered the "alarm call/stop singing" area.
It is also the trigger that starts the fauna.sqs when the player gets near _logic,
condition field: player distance uniquelogicname < 500
(the triggering part)Anybody, present, repeatedly
(so the script can detect units in the trigger area)_innertrigger is the only element in the set which is not moved around by the script at some point. Thus it is also an anchorpoint for returning the other elements to their original position.
_main is a larger trigger. It's main purpose is to actually emit the ambient sound. The script also uses its distance from the player and from _innertrigger to determine whether the player is still in the area and/or whether "flyoff.sqs" has been triggered for the set (more on that later).
_main's other purpose is to add a fired eventhandler to all units within its radius. In order to catch any new units that have entered the area and add the EH to them, fauna.sqs zaps _main to [0,0,0] and back at the end of each ambient loop.
condition field: "man" countType thislist > 0
So the trigger can deactivate/reactivate when moved back and forthAnybody, present, repeatedly
activation field:
the addingEH partFlyOffReady1 = true; {_x addEventHandler ["fired",{if (FlyOffReady1) then {[uniquemainname, uniquelogicname, uniqueinnertrigname,"creaturetype"] exec "flyoff.sqs",FlyOffReady1 = false}}]} forEach thislist
Thus, when a unit fires, the set will be passed to flyoff.sqs which will make _main play a panic alarm sound then zap it to [0,0,0], closely followed by _logic (which will probably be there anyway).
_main and _logic will be held at [0,0,0] for, say, 5 minutes. In that time, fauna.sqs detects that _main is abnormally far from the _innertrigger anchorpoint and exits.
When the 5 minutes are up, flyoff.sqs repositions _main and _logic back at _innertrigger's location, leaving the full set in place and ready to start fauna.sqs again, if the player is still in the area.
The ProblemI can't find a way to remove the fired eventhandlers that _main adds to its array, without removing any other firedEHs the mission maker has given the units.
I can start the flyoff.sqs with
A:{_x removeallEventHandlers "fired"} forEach list _main
or
B:{_x removeEventHandler ["fired",0]} forEach list _main
or
C:{_x removeEventHandler ["fired",1]} forEach list _main
...but none of these give predictable or desirable results, as you can imagine.
As you can see from _main's activation field, I've worked around this by using variables to make that firedEH ineffectual once one unit has fired. The moment one of the units in the trigger area fires, flyoff.sqs execs and FlyOffReady1 is set to false. As FlyOffReady1 is a condition of the firedEH, flyoff.sqs cannot be triggered again until the 5 minute period is up and flyoff.sqs returns _main to its original position. Once that has happened, FlyOffReady1 will be reset and new firedEHs will be added to all units in the trigger area, so the process can happen again.
This works fine at the moment, but with 50 sets and many units on the map, all firing happily away, I worry about the firedEHs piling up. Even though they only actually
do anything once or twice for every hundred shots, they're never being removed and could stack up into the thousands over the course of a mission.
Is there anything I can/should do about this?
The ideal solution would be to be able to give each firedEH a unique identity and thus be able to remove it after first use. However, I don't think this is possible
Thanks in advance for any advice, and thank you for keeping this great resource going
CH