Location Settings
Introduction
This article describes how to setup locations (also called "location zones" or "zones") in your level, and then use these to:
- fade to different ambient light levels for each zone
- fade between different ambient sounds in each zone
- run scripts automatically when the player enters or exits a zone
You need to use four types of entities in your map:
- a special global entity (e.g. add only one, the position does not matter): atdm:location_settings
- a special global light entity named ambient_world
- multiple info_location and info_locationseparation entities
- Note: Two alternative ways to get ambient sounds in your map are using speakers (Adding ambient Sounds to your Map), and using triggers (Ambient Sounds - Zone (using triggers)). Speakers are good if you only want your ambient to cover a definite radius and have a very simple setup. Triggers are basically obsoleted by the method in this tutorial. The only time you might still want to use a trigger-system is if you want a ambient sound to begin at a place where for some reason you can't create a portal to mark the zone boundary, but you can still have a trigger brush. There are some issues with a trigger system, too (f.i. their CPU and memory usage), that make the method in this tutorial superior.
The atdm:location_settings entity
Create a atdm:location_settings entity in your blueroom (i.e., a room off to the side the player will never enter) or somewhere else in your map:
-> Create entity -> Darkmod -> Info -> atdm:location_settings
Default values
The location_settings entity takes a few default spawnargs related to the ambient light settings:
For their meaning and values, please refer to their sections.
update_period
The spawnarg update_period specifies the time in seconds between updates. A good value is 0.2, e.g. 5 times per second. That avoids to run the script too often, and still allows seamless transitions.
Sound Shaders
In the entity's spawnargs, put the names of all the ambient sounds you want to play in your map. (This pre-loads the sounds into the speaker so there isn't a pause when they start playing.) Put it in one of these property/value forms (without the quote marks):
"snd_streets" "city_night01_loop_z"
"snd_mansion" "sound/ambient/ambience/mansion_tense01a.ogg"
The left hand spawnarg should have a "snd_" prefix, and any name, but most useful is probably the name of the area it is for. You'll use this name again when you place the location markers.
The right hand value points to the actual sound file that will play. You can enter either the soundshader name, or the address where the sound file is (but see footnote). You can see the soundshader names of ambient-ready sounds in the sub-folder "Darkmod/sound/tdm_ambient_ambience_zoned.sndshd". You can find the address of the sound files in "Darkmod/sound/ambient/ambience" (remember to start the address with "sound" in the spawnarg). You can also listen to the sounds at that location. They are are in .ogg format.
Edit:Baddcog-Running through this first time, leaving notes to be fixed/editted later. Hint on sounds, you can also create a speaker (left-click>speaker) and it will give you a sound directory where you can play sound files and find the names. No searching through sound folders outside of DR.
- Note that it is very easy to add custom ambients with this system. Just create a folder in your .pk4 (a .zip file renamed to .pk4) and name the folder "sound", with another folder inside it named after your FM or an abbreviation. Put your custom sound inside that second folder. (E.g., I have a custom ambient named Frozen.ogg, and my FM's name is Patently Dangerous. So in my .pk4 was "sound/patent/frozen.ogg". Note that ambients must be in either .ogg or .wav format. Now in your speaker_zone_ambient, just put the sound's address in the spawnarg (but see footnote). In my case, I have "snd_warehouse" "sound/patent/frozen.ogg".
It is worth noting that one special "sound" is already loaded by default.
"snd_silence" "silence"
You can see it if you check "Show Inherited Properties". This is the sound you use to turn "off" the ambient sounds playing, so there is silence in the zone.
On Shader Names
One footnote on the sound shader names. The shader tdm_ambient_ambience_zoned.sndshd has a special command ("leadin") for its sounds that begins the ambient with a short pause. This is to pre-empt a possible *pop* of sound for loud ambients which can occur when the player's system slows down (and only occasionally, at that), so the player never hears the pop. (It's a quirk of how Doom3 does fade-ins; when you start a new sound, you have to rapidly fade it out first, like .001 seconds, then slowly fade back in. But if the system slows and the ambient starts loud, it might stretch that .001 to something audible.)
Edit:Baddcog- These seem to now have been appended with a _z if you look at sound names in speaker dialog.
If you alternatively use the address or the shader name from "Darkmod/sound/tdm_ambient_ambience.sndshd" (which lack the "leadin" property) it will otherwise work fine, but you won't be protected from that occasional little pop (at least until we find another fix). For ambients that start quietly or areas that won't slow the system down, it will probably never even be a problem and the player will never hear it, so using the address is fine, or using the tdm_ambient_ambience shader name if you don't want the tiny pause for whatever reason. But if you want to control it, use the tdm_ambient_ambience_zoned name, and for a custom sound, to pre-empt the pop you'll need to use a custom shader with the "leadin" line. Use the "Darkmod/sound/tdm_ambient_ambience_zoned.sndshd" as a template to do that, and name the custom shader file something like YourFMsName.sndshd, and put it in the "sound" folder in your .pk4.
Sound Properties
Regarding properties, the speaker (the atdm:location_settings entity is a speaker in disguise :) has by default the properties "omni", "global", and "looping" already turned on, so that all sounds played are heard everywhere, from no direction, and will loop. If you change these properties (e.g., for one ambient) the change will apply to all ambients on the speaker. So you probably don't want to turn these properties off.
"volume" is another potential property; but it has been left off as a default. You can change the volume of sounds played on the speaker with the property, but again it will apply to all the ambients on the speaker. It is better to defined individual "volume" spawnargs on each info_location entity, and there put the value between "-60" ("silence") and "0" (full volume) in decibels (so around "-10" is about half volume). See the section below on "volume" for more detail and some warnings about positive volume values.
Your entity will look like this:
You are finished with the ambient sound part now.
The Ambient Light
You need to create an ambient light in your level. This will cover the entire level, and provide a minimum default light for when there is no other light covering a surface:
- -> Create light
- Move the light's origin to the center of your map, and drag it's size so that it covers your entire map, and then some more. Remember to increase the size of that light when you build more area into your map!
- Open the light inspector (default shortcut L) and set the light texture to lights/ambientlightnfo
- Set the color of the light to a reasonable default, f.i. "8 8 8" This value will be used when a zone has no other ambient light settings
- Open the entity inspector (default shortcut N) and set the name of the light to ambient_world
The last step is important!
You are done now with the global ambient light.
The Location Entities
Now you need to set up the location system so the game knows where the zones are, and their boundaries where changes will happen. A location is basically any area that's closed in by brushes and marked portals and contains an info_location entity. Unlike a vis-portaled area (which is one area between vis_portals, a.k.a. a "leaf"), a zone can cover more than one portaled area ("leaves").
As an aside, locations are also used for setting the EAX properties in the area (e.g., the echo-y-ness of a big hall or cave, or the dullness of a small carpeted room). So you have a good reason to have them even in addition to handling ambient sounds and lights.
info_locationseparator
As I suggested above, you have to mark all the portals leading in and out of a zone by hand. You do this with an entity called a info_locationseparator. Create one so it touches the portal you want as a boundary.
-> Create entity -> Darkmod -> Info -> info_locationseparator
If you don't touch a portal with this entity, than it will not register in the game as the boundary to a new zone, and the zone will continue into the area on the other side of the portal. This happens even if you have a second info_location (described below) on the other side (the game will just pick one and use that for the whole zone). This can be a good thing because, say you have a mansion with 30 portals inside. You can cover the whole area inside it by just marking the 2 or 3 portals leading into the mansion area through the doors and open windows, and everything inside that marked area will be counted as one location (just don't miss marking an exit, or have an un-portaled gap to the outside between brushes, or the location will leak outside. It has to be hermetically sealed).
I have read discussion that a door touching a portal marks it as a location boundary, but in my experiments the door did not create a new location and I still had to use a info_locationseparator over the portal to register it as a boundary.
info_location
Now, inside the zone you want to have, create an info_location entity:
-> Create entity -> Darkmod -> Info -> info_location
Anywhere in the space of the zone is fine. Name it the name of the zone you want (to make it easy to find when you push J).
Settings per location/zone
On each info_location, you can set multiple spawnargs that adjust the light or sound for that location, as well as run scripts. We cover them next:
Ambient sound
Now create a spawnarg property of "ambient" with the value being the speaker-name of the sound you used in the location_settings entity above (NOT the soundshader name or file name). For example,
"ambient" "snd_streets"
This will send a command to the location_settings (in its speaker capacity) to play the ambient it has registered under "snd_streets" that you entered. When you enter a new zone, in turn, the new info_location sends a command to the speaker to turn off that ambient and start a new one.
If you wanted to have no ambient playing in the zone (and turn off any ambient started from another zone), you would use "snd_silence" as the value to command the speaker to turn off. Also, if you have an info_location with no "ambient" value at all, it will also turn off the ambient (in the present version of this system). That means if you make a new location but want the same ambient playing in it as the location next to it, you still need to add the ambient name for the already-playing ambient for it to continue playing into the new zone; otherwise it will turn off.
Examples
Here are two info_locations on two sides of a portal, with an info_locationseparator touching the portal (more like piercing it), and with each info_location containing the name of the ambient that will play in its respective zone.
That's basically it. The ambients will now turn on when you enter a zone and turn off when you enter a new zone, turning on the new ambient in that new zone. If you open up the console, you should see a message saying that a new ambient is now playing in your current location, naming the ambient and location.
Sound Fading
Finally, there are a few other spawnargs on the info_locations that you usually don't have to worry about (with the possible exception of "volume"), but you can use them if you like, so I will mention them. They concern the properties of the ambient fading. Check the "Show Inhereted Properties" to see their default values. Entering a new value will over-write the default value, but only for that one object.
fiduration
"Fade in duration". This is the length of time in seconds it takes for the in-coming ambient (the one for this zone) to completely fade-in. The default value is 4 seconds. You can, e.g., make the fade last much longer with a larger value.
If you don't want your ambient to fade in at all, but start immediately at full volume, change this value to ".001" (NOT zero).
foduration
"Fade out duration". This is the length of time in seconds it takes for the out-going ambient (the one from the zone you're leaving) to completely fade-out. Again, if you want it to cut right off without fading, use a value of ".001".
fidelay
"Fade in Delay". You can delay the beginning of the in-coming ambient's fade-in after you enter the new area. You might want to do this, for example, if you want the out-going ambient to completely fade out before you begin fading in the new ambient. So you would set fidelay to the same time as the foduration. By default it is set to .001 so that there is no delay and the fade in starts immediately. If the out-going fade-out also starts immediately (which happens by default), then they blend together in a nice transition fade.
fodelay
"Fade out Delay". Similarly you can delay the beginning of the out-going ambient's fade out. You might want to do this if you wanted the in-coming ambient to completely fade in before you started the fade out of the old ambient. Then you would set it to fiduration. Like fidelay, it is set to .001 so there is no delay and the fade out starts immediately.
fovolume
"Fade out volume". This sets the volume to which the out-going ambient fades to. -60 turns it off, which is the default (0 means no decrease in volume at all). If you go any higher than -60, than it will leave the old ambient still playing at a lower volume under the new ambient (at least until you enter a 3rd new zone). Not sure why you'd ever want to do that, so you probably don't want to change it.
volume
This sets the volume to which the in-coming ambient fades into (when the ambient volume slider in the menu is set at 100%). The scale is -60..0 in decibels (a log scale), where -60 is silence, 0 is the maximum (full native volume of the sound), and around -10 is about half the volume. The default volume is 0. (If you're looking at the screenshot above, note it's an old version where the default was "60", which is bad bad bad! It's "0" now.) It is possible to set a positive value -- the engine will over-max the volume, i.e., make it louder than its native volume -- but be aware if you set it too high this may lead to artifacts and volume clipping (i.e., the engine causes it to play very quietly to avoid over-driving the computer's speakers), and generally it gets very loud very quickly. Some have advised to keep the volume not much higher than 0 if you try this. (Here are two more wiki entries going into more detail about volume issues: Setting Up Speakers#volume/ s_volume & Volume Issues; don't worry about the part where the player loses the direction of the sound since ambients are already non-directional, "omni", to begin with, but the rest you can worry about). Anyway, like anything else, just be sure to test in-game to make sure it's a comfortable volume and works for your scene.
These last two (foduration_2foip and fiduration_2foip) are pretty obscure situations, so you probably don't need to ever mess with them unless you want to completely get rid of ambient fades (then you can set them to .001 like the other 'fade duration' properties).
foduration_2foip
"Fade-out duration during a '2 Fade-outs in progress' situation". This provides a shorter fade-out duration (in seconds) for when the player quickly runs into a 3rd location, such that the 1st and 2nd ambients from areas the player just left are still fading out (hence the 2 fade-outs). But the quickend-fade-out only applies to the 1st ambient fading out. (i.e., not of the ambient you just left, but the one you left just before that -- unless you're backtracking, then it just fades the prev-prev ambient back in). Fading out that prev-prev ambient more quickly in turn quickens the time the new fade-in can start (because you can't have 3 sounds on at the same time on the zone speaker, only 2). So it in effect reduces the gap of quiet that happens before the newest ambient fully fades-in by enabling it to start its fade-in faster. The default is 1 second.
fiduration_2foip
"Fade-in duration during a '2 Fade-outs in progress' situation". Like its counterpart, this sets a shorter duration of a fade-in of a new ambient (in seconds) when you run into a 3rd location, while the ambients from the 1st and 2nd locations are fading out. Again, because so many ambients are fading out, it can leave a gap of silence for a bit until the new 3rd ambient fades in. So setting a shorter duration than usual for the newest ambient to fully fade in helps shorten the quiet space. The default is 2 seconds (as opposed to a normal default fade-in duration of 4 seconds).
Example of Location with No Fading Transition
As mentioned above, if you wanted a set-up that turned off all fades so that the out-going ambient shut directly off and the in-coming ambient turns directly on, you'd change all the duration properties to .001, like the following image. (Note that this modifies the transition only for entering this one location. All the other info_locations maintain their default values unless you also change them by hand.)
Ambient light settings
These spawnargs can be set on atdm:info_location entities and apply to the current zone then:
"ambient_light"
This spawnarg specifies the ambient light color for this zone. Setting it f.i. to "0.10 0.02 0.02" would fade the ambient light to a slightly reddish color. This can be useful for covering a lava cave. Other examples are slightly blue light for moonlit outsides, greenish cast for caves or underwater areas etc.
If you do not set this on an info_location entity, the default value of the global "ambient_world" entity will be used.
Notes:
- You need to set the color values as fractions between 0 and 1, e.g. "0.08 0.08 0.02" and NOT as integers like so
"8 8 2", or it will not work.
- You need to set the color values as fractions between 0 and 1, e.g. "0.08 0.08 0.02" and NOT as integers like so
- If the color change between two zones is too big, the fading and change can become obvious to the player and spoil the subtlety. This can happen for instance if you zoom from a bluish-lit outside directly to a reddish-glowing cave inside. To help the transition, consider adding an intermidiate zone with a light color that is either in between the two, or a more neutral grey. Making it not possible to look from one zone to the other also helps, this way they player can't see that f.i. the outside ground suddenly also glows reddish when looking back from the cave entrance to the outside.
"ambient_light_fade_time"
This specifies the time in seconds it will take to fade from the current ambient light color to the one specified for this location. A slower fade means more gradual light changes, so they don't become too obvious to the player. Use at least 3, better 5 or 7 seconds.
If set to -1, the default time specified at the atdm:location_settings entity will be used.
"ambient_light_fade_delay"
This specifies the time in seconds the fading will be delayed when the player changes location.
Useful to prevent fades toggling back and forth when the player stands in a doorway and goes a nudge forward/backwards. A good value is at least 1 second.
If set to -1, the default time specified at the atdm:location_settings entity will be used.
"ambient_light_dynamic"
This is a factor, all lights in the current area will be summed together and scaled by this value.
If set to a value other than "0 0 0", the lights in the current zone will be all summed together and then added to the current base ambient light. This happens with the frequency of update_period.
The basic effect is that a roaring fire also slightly makes the walls flicker, and extinguishing all lights in a room would decrease the ambient light slightly.
The factor should be set up so that for large and dark rooms (e.g. caves) the dynamic part is small, while for small, bright rooms (white walls) the dynamic part is bigger. Examples are: "0.05 0.05 0.05" and "0.1 0.1 0.1".
Note that setting the dynamic factor to high can result in the player being busted by lights that are turned on in the room even when the player is in the shadow.
See also the article about Dynamic ambient light.
"ambient_light_dynamic_cap"
Used to cap the dynamic ambient light part. If set to 0, will be ignored, so to have a very very small cap, set to "0.01", e.g. if you want only the red part to be dynamic, set it f.i. "0.15 0.01 0.01".
See also the article about Dynamic ambient light.
"ambient_light_dynamic_falloff"
Possible values are:
- -1 on info_location: use the value from the atdm:location_settings entity
- 0 - no dynamic falloff
- 0.5 - small, based on square root of distance
- 1 - medium, linear dynamic falloff (should be used as it looks best)
- 2 - high, square of distance based falloff
See also the article about Dynamic ambient light.
"ambient_light_dist_scale"
A factor to scale the distance before applying a dynamic light falloff. Only used then ambient_light_dynamic_falloff is not 0. Good valuesa are around 1.0.
See also the article about Dynamic ambient light.
Script calls
The next four spawnargs all specify scripts to call when the player enters or exits a zone. Note that the very first zone is also "entered" by the player when the map starts. That means "call_once_on_entry" for the start zone should be called at start-time.
"call_once_on_exit"
Called only once when the zone is left by the player.
"call_once_on_entry"
Called only once when the zone is entered by the player.
"call_on_exit"
Always called when the player leaves that zone.
"call_on_entry"
Always called when the player enters that zone.
Example scripts
Here is an example script that spawns an object where the info_location entity is for the zone the player just left. You can call this script by setting:
"call_once_on_exit" "spawn_pear"
on your info_location entity.
void spawn_pear( entity old_zone ) { // Get the name of the location that the player just left: string location_name = old_zone.getName(); // and display it on the console for debugging sys.print ("Spawning pear after leaving " + location_name + "\n"); // spawn the pear entity entity pear = sys.spawn("atdm:moveable_food_pear"); // and now get the position of the old location entity: vector origin = old_zone.getOrigin(); // finally move the pear to the point of the info_location pear.setOrigin( origin ); // so once the player exits this location, ONE pear will spawn and fall down }