Location Settings: Difference between revisions

From The DarkMod Wiki
Jump to navigationJump to search
Demagogue (talk | contribs)
Demagogue (talk | contribs)
No edit summary
Line 184: Line 184:
  }
  }
</code>
</code>
{{tutorial-sound}}

Revision as of 22:47, 2 May 2009

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.

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

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, create two sets of 10 buttons, a "command" set (the "radio stations"), and a "play" set (the "songs"), so 20 buttons in all, set up in a blueroom (i.e., a room off to the side the player will never enter). You might put the buttons on a brush and light the room so you can put the StartingPoint inside and test the buttons later. Also, the command set would be your "machine" if you just wanted to use this method for machine sound-management. (Note, I'm working on a simpler setup has only the command buttons that I hope to edit in later; it's possible. But this works for now to get the principles across.)

Also set up 10 speakers there, each, with "s_waitfortrigger"/1, "s_global"/1, "s_looping"/1, "s_omni"/1, "s_shader" to the name of each ambient you want to use, and "s_volume" to whatever you want. I named the speakers "speaker_station1", "speaker_station2", etc, but it doesn't matter.

Name each command button whatever you want (factory_zone, streets_zone, forest, whatever), just remember what it is so you can "target" it with a trigger entity.

Add a "state_change_callback" property to each command button, with the value being "station_1", station_2", etc., sequentially for each button.

Name each "play" button sequentially "station1", "station2", etc. Add the "target" property to each play button, with the value of the speaker with the ambient you want for that station.

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. (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]

Be sure you cover every possible entry, even those you aren't sure the player can cross, and watch for things like teleports.

If you want no sound for an area (i.e., just turn the previous ambient off), have a trigger_multiple turn on the command button for station1 playing "nosound".

Once you do 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.

The Script

// 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.  

float station_state = 1;  
   // the number corresponds to the "current radio station playing" 
           
void main()
{
}

void station_1(entity button, boolean bOpen, boolean bLocked, boolean bInterrupted) 
{
if(bOpen)  // do the following if the button is open (pressed) 
    {
    button.Close(); // close the button (push it back out). 
    if (station_state == 1) // if the current station playing is #1
     { 
      sys.print("Radio station 1 is already playing.");  // station 1 is already on, so nothing happens
     }
    else if (station_state == 2)
     {
      $station1.activate($player1);  // push the button that turns station 1 music on     
      $station2.activate($player1);  // turn station 2 music off
      station_state = 1;
      sys.print("Radio station 1 is now playing.");
     }
    else if (station_state == 3)
     {
      $station1.activate($player1);  // turn station 1 music on
      $station3.activate($player1);  // turn station 3 music off
      station_state = 1;
      sys.print("Radio station 1 is now playing.");
    }
 }
}

void station_2(entity button, boolean bOpen, boolean bLocked, boolean bInterrupted) 
{
if(bOpen)  
{
   button.Close();
   if (station_state == 1)  
    {
     $station1.activate($player1);  // turn station 1 music off
     $station2.activate($player1);  // turn station 2 music on
     station_state = 2;
     sys.print("Radio station 2 is now playing.");
    }
   else if (station_state == 2) 
    {
     sys.print("Radio station 2 is already playing.");   // station 2 is already on, so nothing happens
    }
   else if (station_state == 3)
    {
     $station2.activate($player1);  // turn station 2 music on
     $station3.activate($player1);  // turn station 3 music off
     station_state = 2;
     sys.print("Radio station 2 is now playing.");
    }
 }
    
}


void station_3(entity button, boolean bOpen, boolean bLocked, boolean bInterrupted) 
{
if(bOpen)
{
   button.Close();
   if (station_state == 1)
    {
     $station1.activate($player1);  // turn station 1 music off
     $station3.activate($player1);  // turn station 3 music on
     station_state = 3;
     sys.print("Radio station 3 is now playing.");
    }
   else if (station_state == 2)
    {
     $station2.activate($player1);  // turn station 2 music off 
     $station3.activate($player1);  // turn station 3 music on
     station_state = 3;
     sys.print("Radio station 3 is now playing.");
    }
   else if (station_state == 3) 
    {
     sys.print("Radio station 3 is already playing.");   // station 3 is already on, so nothing happens
    }
  }
}

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 doesn't break, or get the toggles backwards or whatever. You could also put the StartingPoint in the blueroom to push buttons and make sure that all works.

The lines sys.print("Radio station X is now/already playing."); are there so you can go into the console and see how the triggers are working; once you have it set up and working, you can add "//" in front of them to turn them off.

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 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 outside area to have its own ambient, you'd create another 3 walls on the other side of that doorway with the ambient trigger outside and a "nosound" trigger outside, and its own speaker fading in its middle. Then the two speakers could even overlap 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 as each wall. I don't know if that's a real problem or not, just something to remember).

Getting rid of the Play Buttons and the Toggle-approach

I'm working on a method to get rid of the play buttons, so you only deal with command buttons. It's more tidy. But it is also a better approach because it turns the sounds absolutely "on" & "off" instead of toggling them. I haven't yet had a problem with getting the toggles backwards, as long as the triggers are cleanly shaped so the player can't pass through a gap or something (or too skinny they don't register, I imagine). But it's just better if even the possibility can be eliminated, so any time you touch a trigger everything always rights itself.

I'm still learning scripting myself, so don't have it working yet, but here's some of the code I've been working with, in case it helps other people figure this out.


// NOTE, this is BAD CODE; it doesn't work for me; just an example of what I'm thinking about doing.

void station_1(entity button, boolean bOpen, boolean bLocked, boolean bInterrupted) 
{
if(bOpen)  
{
   button.Close();
   if (station_state == 1)  // If station 1 is currently playing
    {
   sys.print("Radio station 1 is already playing.");
    }
   else if (station_state == 2) // If station 2 is currently playing, etc...
    {
     station_state = 1;
     sys.wait($speaker_station1.startSound( "snd_loop", SND_CHANNEL_BODY, false ));  // turn station 1 on, looping
     sys.wait($speaker_station2.startSound( "snd_stop", SND_CHANNEL_BODY, false ));  // turn station 2 off
        sys.print("Radio station 1 is now playing.");
    }
   else if (station_state == 3)
    {
   station_state = 1;
     sys.wait($speaker_station1.startSound( "snd_loop", SND_CHANNEL_BODY, false ));  // turn station 1 on, looping
     sys.wait($speaker_station3.startSound( "snd_stop", SND_CHANNEL_BODY, false ));  // turn station 3 off
        sys.print("Radio station 1 is now playing.");
    }
 }
}