Location Settings: Difference between revisions

From The DarkMod Wiki
Jump to navigationJump to search
Line 38: Line 38:
::For each snd_station* property, you need to enter the value as the soundshader name of the sound you want to play.  Since you cannot add separate play instructions like a normal speaker (like looping, global, omni, etc), this information needs to be in the soundshader itself.  I have created a soundshader with these instructions that covers all of the Darkmod ambients_ambienace which you can download (custom_ambient_trig.sndshd link) and drop into the Darkmod/sound folder.  For its naming convention, it basically uses the normal ambient name (listed in sound/tdm_ambient_ambience.sndshd), and adds the suffix "_trig" so there isn't a conflict.   
::For each snd_station* property, you need to enter the value as the soundshader name of the sound you want to play.  Since you cannot add separate play instructions like a normal speaker (like looping, global, omni, etc), this information needs to be in the soundshader itself.  I have created a soundshader with these instructions that covers all of the Darkmod ambients_ambienace which you can download (custom_ambient_trig.sndshd link) and drop into the Darkmod/sound folder.  For its naming convention, it basically uses the normal ambient name (listed in sound/tdm_ambient_ambience.sndshd), and adds the suffix "_trig" so there isn't a conflict.   


You can listen to the Darkmod ambients in the folder "Darkmod\sound\ambient\ambience" to choose the one you like (if your music player can play .ogg's), then the snd_station* value is (typically) going to be the filename plus the "_trig" suffix after it.  But the name is literally defined in the custom_ambient_trig.sndshd file I linked to above.   
::You can listen to the Darkmod ambients in the folder "Darkmod\sound\ambient\ambience" to choose the one you like (if your music player can play .ogg's), then the snd_station* value is (typically) going to be the filename plus the "_trig" suffix after it.  But the name is literally defined in the custom_ambient_trig.sndshd file I linked to above.   


::So a typical property/value in your speaker_ambient_music entity might be:
::So a typical property/value in your speaker_ambient_music entity might be:

Revision as of 21:08, 4 May 2009

written by demagogue

This describes a method of doing ambient sounds in which a trigger turns on an omni ambient when you enter a zone, then turns it off when you leave, possibly starting a new ambient for the new zone. It uses a script and a some in-map entities.

It's useful for situations when you want one ambient sound to cover a very large or complex area that might be unweildy with multiple overlapping speakers, or any other situation where using speakers causes an issue. On the other hand, in a lot of situations it's much easier to just use speakers, so it's not for every use. (For the method using speakers, see this tutorial: Adding_ambient_Sounds_to_your_Map#Localized_Ambient_Sounds_in_one_Area_.28with_Speakers.29).

  • Pros: A robust way to keep sound from leaking into areas you don't want it, or losing sound where you do. For a very big area, or inside buildings or winding paths, a few triggers will fully cover the whole area with one seamless ambient, whereas it might take many speakers that have to overlap and aren't as seamless. Also, you can change the ambient for a whole area by changing the property of one button (as opposed to many speakers).
  • Cons: More involved setup than a speaker. An ambient fading in at the start is possible but easier with speakers. You need to make sure the player can't enter/leave the area without going through a trigger to turn on/off the ambient (a speaker doesn't care). And at the beginning you should test it some to make sure everything is working (speakers are more drop and go).

Mechnically, it works like a radio, where touching the trigger changes the station. For that reason, the method is also a good template for any type of machine with various "states" that each have their own sound, e.g., pressing different buttons turns on their own unique sound, stopping the previous ones, including a button to turn all sounds off. But I'll only deal with using it for zoning ambient sounds here.

Set up

The Blueroom

Say there are 10 ambients you want to use in your map with the zone approach (it's easy to change the number once you get the principles, but it's good to set up for more than you might actually need. You don't have to use every channel, but it's set up in case you want to add some more ambients later).
In your map, make a blueroom (i.e., a room off to the side the player will never enter) and create a set of 10 "command" buttons in it, the "radio stations". Create a button by right-click in the map window, create model, darkmod->mechanical->numberwheel_button.lwo->ok, then change the classname to "atdm:mover_button", then copy it as many times as you need.
Also set up an ambient speaker (right-click, create-entity, Darkmod->Sound->speaker_ambient_music).
(Two asides: 1. You might put the buttons on a brush and light the blueroom so you can put the StartingPoint inside and test the buttons later, but all that's optional. 2. The buttons would be your "machine" if you just wanted to use this method for machine sound-management.)
  • The Ambient Speaker
Name the ambient speaker you created "ambient_player" (If you want a different name, you'll need to change the name in the script below to correspond.)
The ambient speaker, at least for the purposes of this tutorial, works differently from a normal speaker. Instead of each speaker having its own individual soundshader to play using the s_shader property, our one ambient speaker is going to contain multiple properties covering all the sounds we want to play with the zone method. Again, it's like one radio with multiple stations.
Now you're going to add consecutive properties in the following form for as many ambients as you want to use with this approach, with values that I will explain below.
snd_station1
snd_station2
snd_station3
etc.
For each snd_station* property, you need to enter the value as the soundshader name of the sound you want to play. Since you cannot add separate play instructions like a normal speaker (like looping, global, omni, etc), this information needs to be in the soundshader itself. I have created a soundshader with these instructions that covers all of the Darkmod ambients_ambienace which you can download (custom_ambient_trig.sndshd link) and drop into the Darkmod/sound folder. For its naming convention, it basically uses the normal ambient name (listed in sound/tdm_ambient_ambience.sndshd), and adds the suffix "_trig" so there isn't a conflict.
You can listen to the Darkmod ambients in the folder "Darkmod\sound\ambient\ambience" to choose the one you like (if your music player can play .ogg's), then the snd_station* value is (typically) going to be the filename plus the "_trig" suffix after it. But the name is literally defined in the custom_ambient_trig.sndshd file I linked to above.
So a typical property/value in your speaker_ambient_music entity might be:

snd_station1             alien01_loop_trig

Do this for each snd_station* that you want, and that's all you have to do with the ambient speaker itself. You're done with it. Everything else will be handled by the soundshader and the script. (I hope to add a feature in the future to handle things like looping and volume in the ambient_player, however).
You will typically use the name of a shader from that file (which you can open with any text-reader) for the value of your snd_stationX property. But you can use others, or even make your own; just be sure they will work like you want. I'll discuss more about a Sound Shader below to help you with that.

(Note to self: put an example picture here)

  • Command Buttons
Name each command button (except for one exception below) whatever you want (e,g., the name of the zone it's covering, like: factory_zone, streets_zone, forest, whatever), just remember what it is so you can "target" it with a trigger entity later.
The one exception is that the first button, which is "station 0", should be reserved for turning all sounds off, that is, radio silence. This is important because it is the initial state of the setup when the game starts. Name it something that lets you know it is for having no ambient sound, such as "silence" or "nosound".
Add a "state_change_callback" property to each command button, with the value being "station_0", "station_1", "station_2", etc., sequentially for each button. This name needs to be *exactly* like that (including the underscore; and don't forget that the first button is station_0).
Here's what the blueroom I've been testing with looks like: (picture coming)

The Gameworld

You trigger ambients in the gameworld with a trigger_multiple. To make one, first create a brush the size of the entrance to the zone you want to do (e.g., door-sized, or cave-entrance sized, or street-wide-to-the-sky-sized). It should be quite thick so that they player cannot run through it without it registring a hit.
Footnote: Roughly speaking, a trigger checks in pulses, and if the player is inside during a pulse there's a hit. To get an idea of how quickly the checks pulse, when you have everything set up you can stand inside of one and watch how fast a message like "Station 2 is already on." repeats itself. Try to make it thick enough that a player could not get lucky and run through without that pulse registering him inside it. I'm still experimenting myself with the ideal thickness, 8 occassionally misses if I try, so maybe something like 16 or 24 or 32 just to be safe? (I will update this with a recommended number as I test more.)
Note you can also make multiple trigger_multiple's to cover the entrance how you want, e.g., if it's L-shaped or something. It doesn't have to be just one wall. Whatever works. It also doesn't have to be a perfect fit (like a visPortal), just that the player cannot possibly enter the zone without touching a trigger, but it doesn't hurt making it a perfect fit either.
Texture it with common/trigmulti, then with the brush highlighted in Dark Radiant, right click on it, create-entity, Darkmod/Triggers/Trigger_multiple, ok. If you have others the same size (e.g., door sized) you can copy-paste it for them.
In the map, set up a trigger_multiple entity at every entrance to an area you want covered by a single omni ambient sound, completely covering the entrance so the player has to pass through it to get in the area, each targeting the command button of the station you want to play in that zone (e.g., property/value "target"/factory_zone, or whatever you named the command button you want to use). (Do not add a "wait" property). When you exit the area, have another trigger_multiple at the entrance of the new area target the command button for a new station.
Here's an image of that for reference: [1] (Note to self: Update this pic with a thicker trigger, as described above).
Be sure you cover every possible entry even those you aren't sure the player can cross, and match every entry-trigger with a mirroring exit-trigger for the adjacent area, and watch for possible busts like teleports (where you can just make sure the teleport process includes activating the command button for the ambient it's teleporting into).
If you want no sound for an area (i.e., just turn the previous ambient off), have a trigger_multiple turn on the first command button, which I recommended you name something like "silence".
There's one special case. If you want the player to start in an area with an ambient playing, place a trigger right over the area where the player starts, targeting the command button for the sound you want to use (except for the first button, "silence", which would be redundant). (Note to self: Test this to make sure it works well.)

The Script

Once you have all that set up, you need to create a script. Remember to name it the name of your map "mapname.script" (and that you don't accidentally name it mapname.script.txt), and put it into the same folder as your map.

The following only creates three stations, but it should be enough so that you know how to create more by changing the code accordingly. You can just copy it right into your script and it should work.

// ZONED AMBIENT SYSTEM (demagogue)
//
// Description:  This script allows a method in which a trigger turns on an omni ambient when you enter a zone, then turns it off when you leave, possibly starting a new ambient for the new zone. 
// The set up is described at http://modetwo.net/darkmod/wiki/index.php?title=Ambient_Sounds%2C_a_zone_approach.  
 

void station_0(entity button, boolean bOpen, boolean bLocked, boolean bInterrupted) //Reserved for turning ambients off
{
 if(bOpen)  
 {
   button.Close();
   if (station_state != 0)  // If any station other than "off" (0) is playing
    {
	station_state = 0;
       $ambient_player.stopSound( SND_CHANNEL_BODY, false );   // stops any currently playing sound
	sys.print("The radio is now turned off.");
    }
   else  
    {
	sys.print("The radio is already off.");
    }
  }
}

void station_1(entity button, boolean bOpen, boolean bLocked, boolean bInterrupted) 
{
 if(bOpen)  
 {
   button.Close();
   if (station_state != 1)  // If any station other than #1 is playing, etc.
    {
	station_state = 1;
       $ambient_player.startSound( "snd_station1", SND_CHANNEL_BODY, false );  // starts station 1 looping 
	sys.print("Radio station 1 is now playing.");
    }
   else  
    {
	sys.print("Radio station 1 is already playing.");
    }
  }
}

void station_2(entity button, boolean bOpen, boolean bLocked, boolean bInterrupted) 
{
 if(bOpen)  
 {
   button.Close();
   if (station_state != 2)  
    {
      station_state = 2;
      $ambient_player.startSound( "snd_station2", SND_CHANNEL_BODY, false );  // starts station 2 looping 
      sys.print("Radio station 2 is now playing.");
    }
   else  
    {
	sys.print("Radio station 2 is already playing.");
    }
  }
} 



void station_3(entity button, boolean bOpen, boolean bLocked, boolean bInterrupted) 
{
 if(bOpen)  
 {
   button.Close();
   if (station_state != 3)  
    {
	station_state = 3;
       $ambient_player.startSound( "snd_station3", SND_CHANNEL_BODY, false );  // starts station 3 looping 
	sys.print("Radio station 3 is now playing.");
    }

   else  
    {
	sys.print("Radio station 3 is already playing.");
    }
  }
}

In a future edition I hope to explain all the parts of this script in more detail here.

For now I should make the probably obvious point that if you want to add more stations, you can use the three stations I set up here as a template, to add more "void" entries in the script, e.g., changing things like "station_3", "station_state != 3", "station_state = 3" "snd_station3", etc, and replacing all the 3's with, say 4's if it's for the 4th ambient you want covered. You can even just copy and paste an entire "void" entry and just change the numbers.


Tips and Issues

General Tips

It probably goes without saying, but be sure to test your set up by running back and forth across two zones over and over, to make sure the ambients turn on and off when they're supposed to and it doesn't break or the player gets through without it triggering.
If there is a problem, you can put the StartingPoint in the blueroom to push command buttons and make sure the sounds turn on, and replace each other as they should, and that the first button stops all sound.
Some typical problems might be, if the buttons work but the triggers don't, make sure the trigger spells the name of the button correctly in its "target" property. Also make sure you spell the buttons' "state_change_callback" value correctly.
The lines sys.print("Radio station X is now/already playing."); are there so you can go into the console and see exactly when and how the triggers are working. If you don't see that line in the console when you touch a trigger, it means the script isn't working, so check things like the trigger's target spells the command button's name correctly, and the command button spells the state_change_callback value properly. Once you have it set up and working, you can add "//" in front of the sys.print lines to turn them off.

Soundshaders and Modifying or Custom Sounds

As I mentioned above, I've made a template "ambient trigger" soundshader for general use with this method you can download from the link above. But you may want to change some of its instructions or add custom ambients, so I'll describe a little about soundshaders here. You can browse some soundshaders in the Darkmod/sound folder to get an idea of how they look.
A typical entry looks like this:

alien01_loop_trig
{
	description "Made by Muze"
	global
	omnidirectional
	looping
	sound/ambient/ambience/alien01_loop.ogg
} 

For reference, the functions in the soundshader are:
  • The first line is the name of the shader that you will use as your snd_station* values, as you can tell by looking at the example property/value I gave above.
  • "Global" means it will be heard everywhere in the map.
  • "omnidirectional" means it will be heard from all directions (i.e., not from the direction of the speaker itself).
  • "looping" means when the ambient is finished, it will start over (not always appropriate for every ambient).
  • And the final line is the address of the actual sound file played. As you can see, you can listen to all the Darkmod ambients in the folder "sound/ambient/ambience" to help you choose one (if you have a soundplayer that can play .ogg's).
If you want to modify some of these properties for your own purposes (e.g., deleting the looping, or adjusting the volume), or add a custom ambient sound, you can easily make a new soundshader by making a new text file with the file extension .sndshd and add an entry using the above example as a template, with your fan mission's name (or a simplified version) in the title, such as patent_ambient.sndshd (what I use; make sure you don't accidentally save it something like YourMapName_ambient.sndshd.txt). Be sure if you modify an existing ambient that you use a different name, e.g., if I modified alien01_loop_trig, I might name it alien01_loop_patent.
A typical modification would be the volume. To change the volume, add a new line "volume" with a number (positive or negative), such as "volume 10" or "volume -10". You can test the different volumes by changing your custom soundshader, then starting in the blueroom pushing command buttons to listen to it in-game.
If you wanted to use a custom ambient, and note it has to be in either .ogg or .wav format, just make a custom soundshader with an entry for it using the template above, with its own unique name, and the address pointing to where your custom soundfile will be when packaged for release (I need to learn about this myself, and I'll add that information sometime; but the information on that is hopefully somewhere on the wiki or forums.)


Ambient Fades and Blends

If you want the ambient to fade in, as with a speaker, but still use this method, instead of shaping the trigger_multiples like 2 walls on each side of the entrance, you can shape them like a box (three walls around the entrance, with an inside layer and an outside layer, so 6 brushes altogether) and place a normal speaker inside ("waitfortrigger"/0, "global"/0, "looping"/1, "omni"/1, "s_mindistance" & "s_maxdistance" set appropriately, remember there is a button in Dark Radiant to see the speaker radius).
Here's an image of that for reference: [2]
It just uses 2 walls (four brushes), with the third being a brick wall.
The speaker will fade the ambient in, the trigger will turn on the ambient, and as the speaker fades out the ambient continues. One issue, the ambient sound will duplicate in the overlap between speaker and trigger-on. Depending on the ambient that may sound strange. You may adjust the speaker radius and trigger locations to minimize that, though (better than I did for my screenshot above).
In testing this, I found it good to have the ambient trigger be the outside layer and a "nosound" trigger (i.e., station1) the inside, the speaker radius does the fade in the nosound area in the middle. Then if you wanted the area on the other side of that door to have its own ambient, you'd create another 3 walls on the other side of that doorway with the ambient trigger an outside layer and a "nosound" trigger an inside layer, and its own speaker fading in its middle (basically just mirroring the screenshot I took for the other side of the doorway). Then the two speakers could even overlap in the middle so you get a nice blending gradient between the two ambients.
(Also when testing this, I had some problems creating three walls as one trigger_multiple and had better luck creating three separate trigger_multiples, each as a single wall-brush. I don't know if that's a real problem or not, just something to remember).
Note to self, there is a script function called "fadeSound" which may fade the new ambient in automatically in the script, which would be incredibly convienent. I will test this (and you the author can test it as well), to hopefully figure out how it works. For reference, the short discription id gave for it is:
Fades the sound on this entity to a new level over a period of time.
Use SND_CHANNEL_ANY for all currently playing sounds.
scriptEvent void fadeSound( float channel, float newLevel, float fadeTime );