--- /home/te/games/tdm/script/tdm_location_settings.script.ol2	2014-09-22 12:43:07.000000000 +0200
+++ /home/te/games/tdm/script/tdm_location_settings.script	2014-09-22 14:15:14.000000000 +0200
@@ -55,12 +55,14 @@
 	boolean speaker_on; 	// checks the turning on/off of channels so that channel-1 only gets turned off once when needed, first time after a transition (not every round)
 	float volumeFactor;		// A placeholder variable for the decibel-decimal conversion math
 	float db_factor;		// Pre-computes the conversion factor from ln to log2 for decibel conversion.
+	
+	boolean	m_invalid_zone;	// to run some actions only the first time we enter an invalid location
 
 	// Tels: save the old value of the tdm_music_volume CVAR so we can track when it changes in a location
 	float music_volume;
 
 	/* Tels: Additional members for the ambient light changing: */
-	boolean m_al_no_fade;	
+	boolean m_al_no_fade;
 	float   m_al_fade_time;	
 	float   m_al_fade_time_default;
 
@@ -98,14 +100,17 @@
 	void		RestoreScriptObject();
 	float		getCurrentVolume(entity locEnt);		// compute volume of current playing ambient from "volume" spawnarg and menu cvar
 	void		updateLoop();
-	void		updateAmbientLight( entity locEnt );
-	void		fadeAmbientLight();
+	void		updateAmbientLight( entity locEnt );						// update the settings on location change
+	void		fadeAmbientLight();											// compute new light color based on location and time
+	void		fadeAmbientLightColor(vector targetColor, float fadeTime);	// fade straight to the new color
 };
 
 void speaker_zone_ambient::init() 
 {
 	sys.println ("speaker_zone_ambient::init() called");
 
+	m_invalid_zone = false;
+
 	m_updatePeriod = getFloatKey( "update_period" );
 	// if == 0?
     if (m_updatePeriod < 0.001)
@@ -131,9 +136,11 @@
 
 	/* Tels: Init the ambient light part: */
 	m_al_no_fade = false;
+	boolean global_no_fade = false;
 	if (getBoolKey( "no_ambient_light_fade" ))
 	{
 		m_al_no_fade = true;
+		global_no_fade = true;
 		sys.println ("Global no_ambient_light_fade = true, will not fade the main ambient light.");
 		// but continue, because the current location might want to fade the light again
 	}
@@ -147,7 +154,6 @@
 
 	// grayman #3132 - the main ambient light doesn't have to be named 'ambient_world',
 	// so ask which one has been assigned the job, if any
-
 	entity ambientWorld = sys.getMainAmbientLight();
 	if ( ambientWorld != $null_entity )
 	{
@@ -168,7 +174,23 @@
 	m_al_dynamic_z = 0;
 	m_al_dynamic_old = m_al_dynamic;
 
-	updateAmbientLight( $player1.getLocation() );
+	entity curLoc = $player1.getLocation();
+	// skip if we start in an invalid zone
+	if (curLoc != $null_entity)
+	{
+		updateAmbientLight( curLoc );
+		if (global_no_fade && m_al_no_fade)
+		{
+			// we started in a location that has "no_ambient_light_fade", so set the value at least once
+			sys.println("Starting location has no_ambient_light_fade true, setting ambient light once to " + m_al_base_target);
+			vector al_def = curLoc.getVectorKey("ambient_light");
+			fadeAmbientLightColor( al_def, 0 );
+		}
+	}
+	else
+	{
+		m_invalid_zone = true;
+	}
 
 	// now run in a loop:
 	updateLoop();	
@@ -299,13 +321,15 @@
 	// setting changed in this location?
 	if (no_fade && !m_al_no_fade)
 	{
-		sys.println ("speaker_zone_ambient: no_ambient_light_fade = true, stop fading ambient light.");
+		sys.println ("speaker_zone_ambient: no_ambient_light_fade = true, stopping fading ambient light.");
 		m_al_no_fade = true;
 		// If we stop fading the ambient light, at least set the ambient for the new zone, so we
 		// are not stuck with the old values. After this initial set here, the ambient light will be
 		// left alone and can be controlled by scripts:
-		m_al_fade_start = 0; 	// avoid a ambient_fade_time > 0 preventing this setting here
-		fadeAmbientLight();
+		m_al_base = m_al_base_target;
+		// avoid getting stuck at the old dynamic value
+		m_al_dynamic = '0 0 0';
+		fadeAmbientLightColor( m_al_base, m_updatePeriod * 2 );	// avoid too abrupt changes
 	}
 	else
 	{
@@ -317,6 +341,33 @@
 	}
 
 }
+	
+// fade the ambient light to the new color (or set it for "fast ambient")
+void speaker_zone_ambient::fadeAmbientLightColor(vector targetColor, float fadeTime)
+{
+	if ( sys.getcvar("tdm_ambient_method") == "0")
+	{
+		// grayman #3132 - retrieve the main ambient light
+		entity ambientWorld = sys.getMainAmbientLight();
+		if ( ambientWorld != $null_entity )
+		{
+			ambientWorld.fadeToLight( targetColor, fadeTime );
+		}
+	}
+    // Tels: if the "fast ambient" method is used, do not fade the light, or
+    // 		 it would be turned on and interfere:
+    else
+	{
+		// C++ code has this:
+		// gameLocal.globalShaderParms[2] = ambient_color.x * 1.5f;
+		// gameLocal.globalShaderParms[3] = ambient_color.y * 1.5f;
+		// gameLocal.globalShaderParms[4] = ambient_color.z * 1.5f;
+		// so do the same here:
+		sys.setShaderParm( 2, targetColor_x * 1.5 );
+		sys.setShaderParm( 3, targetColor_y * 1.5 );
+		sys.setShaderParm( 4, targetColor_z * 1.5 );
+	}
+}
 
 // compute the current base ambient light based on: old color, target color, elapsed time
 void speaker_zone_ambient::fadeAmbientLight( )
@@ -359,41 +410,16 @@
 		}
 	}
 
-    // Tels: if the "fast ambient" method is used, do not fade the light, or
-    // 		 it would be turned on and interfere:
-	if ( sys.getcvar("tdm_ambient_method") == "0")
-	{
-		// this call will do nothing if the light is already at the right color
-		// fade the light until we update it next:
-		// bug #2326: if m_al_fade_time is shorter than m_updatePeriod, use it instead
-		float f_time = m_updatePeriod;
-		if (m_al_fade_time < f_time)
-		{
-			f_time = m_al_fade_time;
-		}
-		//sys.print( "Fading light to '" + m_al_base);
-		//sys.print( "' plus '" + m_al_dynamic );
-		//sys.print( "' in '" + f_time + "' seconds.\n");
-
-		// grayman #3132 - retrieve the main ambient light
-		entity ambientWorld = sys.getMainAmbientLight();
-		if ( ambientWorld != $null_entity )
-		{
-			ambientWorld.fadeToLight( m_al_base + m_al_dynamic, f_time );
-		}
-	}
-    else
-	{
-		// C++ code has this:
-		// gameLocal.globalShaderParms[2] = ambient_color.x * 1.5f;
-		// gameLocal.globalShaderParms[3] = ambient_color.y * 1.5f;
-		// gameLocal.globalShaderParms[4] = ambient_color.z * 1.5f;
-		// so do the same here:
-		vector al_combined = m_al_base + m_al_dynamic;
-		sys.setShaderParm( 2, al_combined_x * 1.5 );
-		sys.setShaderParm( 3, al_combined_y * 1.5 );
-		sys.setShaderParm( 4, al_combined_z * 1.5 );
-	}
+	// bug #2326: if m_al_fade_time is shorter than m_updatePeriod, use it instead
+	float f_time = m_updatePeriod;
+	if (m_al_fade_time < f_time)
+	{
+		f_time = m_al_fade_time;
+	}
+	//sys.print( "Fading light to '" + m_al_base);
+	//sys.print( "' plus '" + m_al_dynamic );
+	//sys.print( "' in '" + f_time + "' seconds.\n");
+	fadeAmbientLightColor( m_al_base + m_al_dynamic, f_time );
 /*
 	sys.print( "Old ambient light is: '" + m_al_base_old + "'. \n" );
 	sys.print( "New target ambient light is: '" + m_al_base_target + "'. \n" );
@@ -415,11 +441,30 @@
 		// bug #2326
 		if (locEnt == $null_entity)
 		{
+		 	if (!m_invalid_zone)
+		   	{
+				// Tels: #3694: when first entering an invalid zone, fade the ambient light back to the default value
+				sys.println("Entered invalid zone - missing no info_location entity!\n Setting ambient light:" + m_al_default_color);
+			 	m_invalid_zone = true;
+				m_al_dynamic = '0 0 0';
+				m_al_dynamic_old = '0 0 0';
+				m_al_base =	m_al_default_color;
+				m_al_base_target = m_al_default_color;
+				fadeAmbientLightColor( m_al_default_color, m_updatePeriod * 2 );	// avoid too abrupt changes
+				// TODO: fade out music?
+			}
 			// invalid zone, wait and try again
 			wait( m_updatePeriod );
 			continue;
 		}
 
+		if (m_invalid_zone)
+		{
+			sys.println("Left invalid zone, entered " + locEnt.getName());
+			// TODO: fade music in again if we faded it out?
+			m_invalid_zone = false;
+		}
+		
 		// sys.println( "Ambient script check, music_volume " + music_volume + " in location " + locEnt.getName() );
 
 		// now fade the ambient light until the next update
