#using scripts\codescripts\struct;

#using scripts\shared\callbacks_shared;
#using scripts\shared\fx_shared;
#using scripts\shared\sound_shared;
#using scripts\shared\system_shared;

    	   	                                                                                                                                         	                                	                                                                                                                                                                                                                                                                                                                                                                    	        	     	              	    	   	               	                                              	                                                           	                               	                     	                                                                                                           	                                                                 	                                                              	                                                                                                                                             	                            	                                     	                                       	                                                                                                              	   	                  	       	                                                    	                   	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            	                                                                                                 	                                    	                                                                                        	           	                        	                                            	                                             	                                                   	                                                             	                                                         	                                                                    	                                                                                                                                                                                                                                	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  	    	         	                                                              	                                                          	                                   	                                   	                                                    	                                       	                                           	     	                                                                                                                                                                                                                                                      	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         	                                                               	        	                                                                                                                              	                                                                                                                     	                               	                                                      	                          

#namespace exploder;

function autoexec __init__sytem__() {     system::register("exploder",&__init__,undefined,undefined);    }

function __init__()
{
	if( SessionModeIsCampaignGame() )
	{
		callback::on_localclient_connect( &player_init );
	}
}

function player_init( clientnum )
{
	//println("*** Init exploders...");	
	script_exploders = []; 

	ents = struct::get_array( "script_brushmodel", "classname" );
	//println("Client : s_bm " + ents.size);
	
	smodels = struct::get_array( "script_model", "classname" ); 
	//println("Client : sm " + smodels.size);

	for( i = 0; i < smodels.size; i++ )
	{
		ents[ents.size] = smodels[i]; 
	}

	for( i = 0; i < ents.size; i++ )
	{
		if( isdefined( ents[i].script_prefab_exploder ) )
		{
			ents[i].script_exploder = ents[i].script_prefab_exploder; 
		}
	}

	potentialExploders = struct::get_array( "script_brushmodel", "classname" ); 
	//println("Client : Potential exploders from script_brushmodel " + potentialExploders.size);
	
	for( i = 0; i < potentialExploders.size; i++ )
	{
		if( isdefined( potentialExploders[i].script_prefab_exploder ) )
		{
			potentialExploders[i].script_exploder = potentialExploders[i].script_prefab_exploder; 
		}
			
		if( isdefined( potentialExploders[i].script_exploder ) )
		{
			script_exploders[script_exploders.size] = potentialExploders[i]; 
		}
	}

	potentialExploders = struct::get_array( "script_model", "classname" ); 
	//println("Client : Potential exploders from script_model " + potentialExploders.size);
	
	for( i = 0; i < potentialExploders.size; i++ )
	{
		if( isdefined( potentialExploders[i].script_prefab_exploder ) )
		{
			potentialExploders[i].script_exploder = potentialExploders[i].script_prefab_exploder; 
		}

		if( isdefined( potentialExploders[i].script_exploder ) )
		{
			script_exploders[script_exploders.size] = potentialExploders[i]; 
		}
	}

	// Also support script_structs to work as exploders
	for( i = 0; i < level.struct.size; i++ )
	{
		if( isdefined( level.struct[i].script_prefab_exploder ) )
		{
			level.struct[i].script_exploder = level.struct[i].script_prefab_exploder; 
		}

		if( isdefined( level.struct[i].script_exploder ) )
		{
			script_exploders[script_exploders.size] = level.struct[i]; 
		}
	}

	if( !isdefined( level.createFXent ) )
	{
		level.createFXent = []; 
	}
	
	acceptableTargetnames = []; 
	acceptableTargetnames["exploderchunk visible"] = true; 
	acceptableTargetnames["exploderchunk"] = true; 
	acceptableTargetnames["exploder"] = true; 
	
	exploder_id = 1;
	
	for( i = 0; i < script_exploders.size; i++ )
	{
		exploder = script_exploders[i]; 
		ent = createExploder( exploder.script_fxid ); 
		ent.v = []; 
		
		//if(!isdefined(exploder.origin))
		//{
		//	println("************** NO EXPLODER ORIGIN." + i);
		//}
		
		ent.v["origin"] = exploder.origin; 
		ent.v["angles"] = exploder.angles; 
		ent.v["delay"] = exploder.script_delay; 
		ent.v["firefx"] = exploder.script_firefx; 
		ent.v["firefxdelay"] = exploder.script_firefxdelay; 
		ent.v["firefxsound"] = exploder.script_firefxsound; 
		ent.v["firefxtimeout"] = exploder.script_firefxtimeout; 
		ent.v["trailfx"] = exploder.script_trailfx; 
		ent.v["trailfxtag"] = exploder.script_trailfxtag; 
		ent.v["trailfxdelay"] = exploder.script_trailfxdelay; 
		ent.v["trailfxsound"] = exploder.script_trailfxsound; 
		ent.v["trailfxtimeout"] = exploder.script_firefxtimeout; 
		ent.v["earthquake"] = exploder.script_earthquake; 
		ent.v["rumble"] = exploder.script_rumble; 
		ent.v["damage"] = exploder.script_damage; 
		ent.v["damage_radius"] = exploder.script_radius; 
		ent.v["repeat"] = exploder.script_repeat; 
		ent.v["delay_min"] = exploder.script_delay_min; 
		ent.v["delay_max"] = exploder.script_delay_max; 
		ent.v["target"] = exploder.target; 
		ent.v["ender"] = exploder.script_ender; 
		ent.v["physics"] = exploder.script_physics; 
		ent.v["type"] = "exploder"; 
//		ent.v["worldfx"] = true; 

		if( !isdefined( exploder.script_fxid ) )
		{
			ent.v["fxid"] = "No FX"; 
		}
		else
		{
			ent.v["fxid"] = exploder.script_fxid; 
		}
		ent.v["exploder"] = exploder.script_exploder; 
	//	assert( isdefined( exploder.script_exploder ), "Exploder at origin " + exploder.origin + " has no script_exploder" ); 

		if( !isdefined( ent.v["delay"] ) )
		{
			ent.v["delay"] = 0; 
		}

		// MikeD( 4/14/2008 ): Attempt to use the fxid as the sound reference, this way Sound can add sounds to anything
		// without the scripter needing to modify the map
		if( isdefined( exploder.script_sound ) )
		{
			ent.v["soundalias"] = exploder.script_sound; 
		}
		else if( ent.v["fxid"] != "No FX"  )
		{
			if( isdefined( level.scr_sound ) && isdefined( level.scr_sound[ent.v["fxid"]] ) )
			{
				ent.v["soundalias"] = level.scr_sound[ent.v["fxid"]]; 
			}
		}		

		fixup_set = false;

		if(isdefined(ent.v["target"]))
		{					
			ent.needs_fixup = exploder_id;
			exploder_id++;
			fixup_set = true;
			
/*			temp_ent = GetEnt(0, ent.v["target"], "targetname" ); 
 * if( isdefined( temp_ent ) )
			{
				org = temp_ent.origin; 
			}
			else */
			{
				temp_ent = struct::get( ent.v["target"], "targetname" );
				if (isdefined(temp_ent) )
				{
					org = temp_ent.origin; 
				}
			}

			if(isdefined(org))
			{
				ent.v["angles"] = VectorToAngles( org - ent.v["origin"] ); 	
			}
			//else		
			//{
					//println("*** Client : Exploder " + exploder.script_fxid + " Failed to find target ");
			//}
			
			if(isdefined(ent.v["angles"]))
			{
				ent fx::set_forward_and_up_vectors();
			}
			//else
			//{
				//println("*** Client " + exploder.script_fxid + " has no angles.");
			//}

		}
		
		
		// this basically determines if its a brush/model exploder or not
		if( (isdefined(exploder.classname) && exploder.classname == "script_brushmodel") || isdefined( exploder.model ) )
		{
			//if(isdefined(exploder.model))
			//{
				//println("*** exploder " + exploder_id + " model " + exploder.model);
			//}
			ent.model = exploder; 
			//ent.model.disconnect_paths = exploder.script_disconnectpaths; 
			if(fixup_set == false)
			{
				ent.needs_fixup = exploder_id;
				exploder_id++;
			}
		}
		
		if( isdefined( exploder.targetname ) && isdefined( acceptableTargetnames[exploder.targetname] ) )
		{
			ent.v["exploder_type"] = exploder.targetname; 
		}
		else
		{
			ent.v["exploder_type"] = "normal"; 
		}		
	}

	level.createFXexploders = [];

	for(i = 0; i < level.createFXent.size;i ++ )
	{
		ent = level.createFXent[i];
		
		if(ent.v["type"] != "exploder")
			continue;
			
		ent.v["exploder_id"] = exploder::getexploderid( ent );
		
		if(!isdefined(level.createFXexploders[ent.v["exploder"]]))
		{
			level.createFXexploders[ent.v["exploder"]] = [];
		}
		
		level.createFXexploders[ent.v["exploder"]][level.createFXexploders[ent.v["exploder"]].size] = ent;
		
	}
	
	reportexploderids();
	
	
//	println("*** Client : " + script_exploders.size + " exploders.");	
}

function getExploderId( ent )
{
	if(!isdefined(level._exploder_ids))
	{
		level._exploder_ids = [];
		level._exploder_id = 1;
	}

	if(!isdefined(level._exploder_ids[ent.v["exploder"]]))
	{
		level._exploder_ids[ent.v["exploder"]] = level._exploder_id;
		level._exploder_id ++;
	}

	return level._exploder_ids[ent.v["exploder"]];
}

function reportExploderIds()
{
	if(!isdefined(level._exploder_ids))
		return;
		
	keys = GetArrayKeys( level._exploder_ids ); 

	//println("Client Exploder dictionary : ");
	//for( i = 0; i < keys.size; i++ )
	//{
	//	println(keys[i] + " : " + level._exploder_ids[keys[i]]);
	//}
}

//Note: specific client number only supported for radiant based exploders as ID based is now legacy
function exploder( exploder_id, n_localclientnumber )
{
	if( IsInt( exploder_id ) )
	{
		activate_exploder( exploder_id );
	}
	else//This is a radiant exploder
	{
		activate_radiant_exploder( exploder_id, n_localclientnumber );
	}	
}

function activate_exploder( num )
{
	num = int( num ); 
	
	if(isdefined(level.createFXexploders) && isdefined(level.createFXexploders[num]))	
	{
		for(i = 0; i < level.createFXexploders[num].size; i ++)
		{
			level.createFXexploders[num][i] activate_individual_exploder();
		}
	}
	
	if(exploder_is_lightning_exploder(num))
	{
		if(isdefined(level.lightningNormalFunc) && isdefined(level.lightningFlashFunc))
		{
			thread fx::lightning(level.lightningNormalFunc, level.lightningFlashFunc);
		}
	}
	
}

function activate_individual_exploder()
{
	if(!isdefined(self.v["angles"]))
	{
		self.v["angles"] = (0,0,0);
		self fx::set_forward_and_up_vectors();
	}	
	
	if( isdefined( self.v[ "firefx" ] ) )
		self thread fire_effect();

	if( isdefined( self.v[ "fxid" ] ) && self.v[ "fxid" ] != "No FX" )
		self thread cannon_effect();

	if( isdefined( self.v[ "earthquake" ] ) )
	{
		self thread exploder_earthquake();
	}
}

//TODO T7 - update this if other functionality comes online for the new system
function activate_radiant_exploder( string, n_localclientnumber )
{
	if( isdefined( n_localclientnumber ) )
	{
		PlayRadiantExploder( n_localclientnumber, string );
	}
	else
	{
		for ( localClientNum = 0; localClientNum < level.localPlayers.size; localClientNum++ )
		{
			PlayRadiantExploder( localClientNum, string );
		}
	}
}

//Note: specific client number only supported for radiant based exploders as ID based is now legacy
function stop_exploder( exploder_id, n_localclientnumber )
{
	//println("*** Client : Delete exploder " + num);
	if( IsString( exploder_id ) )
	{
		if( isdefined( n_localclientnumber ) )
		{
			StopRadiantExploder( n_localclientnumber, exploder_id );	
		}
		else
		{		   
			for ( localClientNum = 0; localClientNum < level.localPlayers.size; localClientNum++ )
			{
				StopRadiantExploder( localClientNum, exploder_id );
			}
		}
		return;
	}	
	
	num = int( exploder_id );
	
	if(isdefined(level.createFXexploders[exploder_id]))	
	{
		for(i = 0; i < level.createFXexploders[exploder_id].size; i ++)
		{
			ent = level.createFXexploders[exploder_id][i];

			if( isdefined(ent.loopFX) )
			{
				for(j = 0; j < ent.loopFX.size; j ++)
				{
					if( isdefined( ent.loopFX[j] ) )
					{
						StopFX( j, ent.loopFX[j] );
						ent.loopFX[j] = undefined;
					}
				}
				
				ent.loopFX = [];
			}
		}
	}
}

function kill_exploder( exploder_id )
{
	//println("*** Client : Delete exploder " + num);
	if( IsString( exploder_id ) )
	{
		for ( localClientNum = 0; localClientNum < level.localPlayers.size; localClientNum++ )
		{
			KillRadiantExploder( localClientNum, exploder_id );
		}
		return;
	}
	assertmsg( "unhandled exploder type, only radiant exploders are handled: " + exploder_id );
}

function exploder_delay()
{
	if( !isdefined( self.v[ "delay" ] ) )
		self.v[ "delay" ] = 0;

	min_delay = self.v[ "delay" ];
	max_delay = self.v[ "delay" ] + 0.001;// cant randomfloatrange on the same #
	if( isdefined( self.v[ "delay_min" ] ) )
		min_delay = self.v[ "delay_min" ];

	if( isdefined( self.v[ "delay_max" ] ) )
		max_delay = self.v[ "delay_max" ];

	if( min_delay > 0 )
		waitrealtime( randomfloatrange( min_delay, max_delay ) );
}

function exploder_playSound()
{
	if( !isdefined( self.v[ "soundalias" ] ) || self.v[ "soundalias" ] == "nil" )
		return;
	
	sound::play_in_space( 0, self.v[ "soundalias" ], self.v[ "origin" ] );
}

function exploder_earthquake()
{
	self exploder_delay();
	eq = level.earthquake[ self.v[ "earthquake" ] ];
	
	if(isdefined(eq))
	{
		GetLocalPlayers()[0] earthquake( eq[ "magnitude" ], eq[ "duration" ], self.v[ "origin" ], eq[ "radius" ] );
	}
}

function exploder_is_lightning_exploder(num)
{
	if (isdefined(level.lightningExploder))
	{
		for(i = 0; i < level.lightningExploder.size; i ++)
		{
			if(level.lightningExploder[i] == num)
			{
				return true;
			}
		}
	}
		
	return false;
}

function stopLightLoopExploder( exploderIndex )
{
	num = Int(exploderIndex);
	
	if(isdefined(level.createFXexploders[num]))	
	{
		for(i = 0; i < level.createFXexploders[num].size; i ++)
		{
			ent = level.createFXexploders[num][i];

			if ( !isdefined( ent.looperFX ) ) 
			{
				ent.looperFX = [];
			}
	
	    for( clientNum = 0; clientNum < level.max_local_clients; clientNum++ )
	    {
		    if( localClientActive( clientNum ) )
		    {
					if ( isdefined( ent.looperFX[clientNum] ) )
					{
						for( looperFXCount = 0; looperFXCount < ent.looperFX[clientNum].size; looperFXCount++ )
						{
							deletefx( clientNum, ent.looperFX[clientNum][looperFXCount] );
						}
					}
				}
				
				ent.looperFX[clientNum] = [];
			}
			
			ent.looperFX = [];
		}
	}
}

function playLightLoopExploder( exploderIndex )
{
	num = Int(exploderIndex);
	
	if(isdefined(level.createFXexploders[num]))	
	{
		for(i = 0; i < level.createFXexploders[num].size; i ++)
		{
			ent = level.createFXexploders[num][i];

			if ( !isdefined( ent.looperFX ) ) 
			{
				ent.looperFX = [];
			}

	    for( clientNum = 0; clientNum < level.max_local_clients; clientNum++ )
	    {
		    if( localClientActive( clientNum ) )
		    {
			    if ( !isdefined( ent.looperFX[clientNum] ) ) 
			    {
				    ent.looperFX[clientNum] = [];
			    }
					ent.looperFX[clientNum][ent.looperFX[clientNum].size] = ent playExploderFX( clientNum );
		    }
	    }
		}
	}
}

function createExploder( fxid )
{
	ent = fx::create_effect( "exploder", fxid );
	ent.v[ "delay" ] = 0;
	ent.v[ "exploder_type" ] = "normal";
	return ent;
}

function cannon_effect()
{
	if( isdefined( self.v[ "repeat" ] ) )
	{
		for( i = 0;i < self.v[ "repeat" ];i ++ )
		{
			players = getlocalplayers();	
			
			for(player = 0; player < players.size; player ++)
			{
				PlayFX( player, level._effect[ self.v[ "fxid" ] ], self.v[ "origin" ], self.v[ "forward" ], self.v[ "up" ] );
			}

			self exploder_delay();
		}
		return;
	}
	
	self exploder_delay();

	players = getlocalplayers();	

	if ( isdefined( self.loopFX ) )
	{
		for(i = 0; i < self.loopFX.size; i ++)
		{
			StopFX( i, self.loopFX[i] );
		}
		
		self.loopFX = [];
	}

	if(!isdefined(self.loopFX))
	{
		self.loopFX = [];
	}

	if(!isdefined(level._effect[self.v["fxid"]]))
	{
		assertmsg("*** Client : Effect " + self.v["fxid"] + " not precached in level_fx.csc.");
		return;
	}

	for(i = 0; i < players.size; i ++)
	{
		if( isdefined( self.v["fxid"] ) )
		{
			self.loopFX[i] = PlayFX( i , level._effect[ self.v[ "fxid" ] ], self.v[ "origin" ], self.v[ "forward" ], self.v[ "up" ] );
		}
	}
		
	self exploder_playSound();
}

function fire_effect()
{
	forward = self.v[ "forward" ];
	if( !isdefined( forward ) )
	{
		forward = anglestoforward( self.v["angles"] );
	}
	up = self.v[ "up" ];
	if( !isdefined( up ) )
	{
		up = anglestoup( self.v["angles"] );
	}	

	//org = undefined;

	firefxSound = self.v[ "firefxsound" ];
	origin = self.v[ "origin" ];
	firefx = self.v[ "firefx" ];
	ender = self.v[ "ender" ];
	if( !isdefined( ender ) )
		ender = "createfx_effectStopper";

	fireFxDelay = 0.5;
	if( isdefined( self.v[ "firefxdelay" ] ) )
		fireFxDelay = self.v[ "firefxdelay" ];

	self exploder_delay();

	players = GetLocalPlayers();
	
	for(i = 0; i < players.size; i ++)
	{
		if( isdefined( firefxSound ) )
		{
			level thread sound::loop_fx_sound( i, firefxSound, origin, ender );
		}
		playfx( i, level._effect[ firefx ], self.v[ "origin" ], forward, up, 0, self.v[ "primlightfrac" ], self.v[ "lightoriginoffs" ] );
	}
}

// self is the exploder entity
function playExploderFX( clientNum )
{
/# 
	if ( !isdefined( self.v[ "origin" ] ) )
		return;	
	if ( !isdefined( self.v[ "forward" ] ) )
		return;
	if ( !isdefined( self.v[ "up" ] ) )
		return;
#/
	return playfx( clientNum, level._effect[ self.v[ "fxid" ] ], self.v[ "origin" ], self.v[ "forward" ], self.v[ "up" ], 0, self.v[ "primlightfrac" ], self.v[ "lightoriginoffs" ] );
}


function stop_after_duration( name, duration )
{
	wait( duration );
	stop_exploder( name );
}


function exploder_duration( name, duration )
{
	if ( !( isdefined( duration ) && duration ) )
	{
		return;
	}

	exploder( name );
	
	level thread stop_after_duration( name, duration );
}