#include common_scripts\utility;
#include maps\mp\_utility;

// the nuke will kill the other team and emp them for 60 seconds, it will also change the visionset for the level

init()
{
	//level.nukeVisionSet = "aftermath";

	level._effect[ "nuke_flash" ] = loadfx( "vfx/explosion/dna_bomb_flash_mp" );
	level._effect[ "nuke_aftermath" ] = loadfx( "vfx/dust/nuke_aftermath_mp" );
	level._effect[ "dna_bomb_body_gas" ] = loadfx( "vfx/explosion/dna_bomb_body_gas" );

	game["strings"]["nuclear_strike"] = &"KILLSTREAKS_TACTICAL_NUKE";
	
	level.killstreakFuncs["nuke"] = ::tryUseNuke;
	level.killstreakWieldWeapons["nuke_mp"] = "nuke";

	SetDvarIfUninitialized( "scr_nukeTimer", 10 );
	SetDvarIfUninitialized( "scr_nukeCancelMode", 0 );
	
	level.nukeTimer = getDvarInt( "scr_nukeTimer" );
	level.cancelMode = getDvarInt( "scr_nukeCancelMode" );

	
	
	
	
//	if( level.multiTeamBased )
//	{
//		for( i = 0; i < level.teamNameList.size; i++ )
//		{
//			level.teamNukeEMPed[level.teamNameList[i]] = false;
//		}
//	}
//	else
//	{
//		level.teamNukeEMPed["allies"] = false;
//		level.teamNukeEMPed["axis"] = false;
//	}

	level.nukeEmpTimeout = 60.0;
	level.nukeEmpTimeRemaining = int( level.nukeEmpTimeout );
	level.nukeInfo = spawnStruct();
	level.nukeInfo.xpScalar = 2;
	level.nukeDetonated = undefined;

	//level thread nuke_EMPTeamTracker();

	level thread onPlayerConnect();

/#
	//SetDevDvarIfUninitialized( "scr_nuke_empTimeout", 60.0 );
	SetDevDvarIfUninitialized( "scr_nukeDistance", 5000 );
	SetDevDvarIfUninitialized( "scr_nukeEndsGame", true );
	SetDevDvarIfUninitialized( "scr_nukeDebugPosition", false );
#/
}

tryUseNuke( lifeId, modules, allowCancel )
{
	if( isDefined( level.nukeIncoming ) )
	{
		self iPrintLnBold( &"KILLSTREAKS_NUKE_ALREADY_INBOUND" );
		return false;	
	}

	if ( self isUsingRemote() )
		return false;

	if ( !isDefined( allowCancel ) )
		allowCancel = true;

	self thread doNuke( allowCancel );
	
	self maps\mp\_matchdata::logKillstreakEvent( "nuke", self.origin );
	
	return true;
}

delaythread_nuke( delay, func )
{
	level endon ( "nuke_cancelled" );

	maps\mp\gametypes\_hostmigration::waitLongDurationWithHostMigrationPause( delay );
	
	thread [[ func ]]();
}

doNuke( allowCancel )
{
	level endon ( "nuke_cancelled" );
	
	level.nukeInfo.player = self;
	level.nukeInfo.team = self.pers["team"];

	level.nukeIncoming = true;
	
	SetOmnvar( "ui_bomb_timer", 4 ); // Nuke sets '4' to avoid briefcase icon showing

	if( level.teambased )
	{
		thread teamPlayerCardSplash( "used_nuke", self, self.team );
	}
	else
	{
		if( !level.hardcoreMode )
			self IPrintLnBold( &"MP_FRIENDLY_TACTICAL_NUKE" );
	}

	level thread delaythread_nuke( (level.nukeTimer - 3.3), ::nukeSoundIncoming );
	level thread delaythread_nuke( level.nukeTimer, ::nukeSoundExplosion );
	level thread delaythread_nuke( level.nukeTimer, ::nukeSlowMo );
	level thread delaythread_nuke( (level.nukeTimer - 0.32 ), ::nukeEffects );
	level thread delaythread_nuke( (level.nukeTimer - 0.1), ::nukeVision );
	level thread delaythread_nuke( (level.nukeTimer + 0.5), ::nukeDeath );
	level thread delaythread_nuke( (level.nukeTimer + 1.5), ::nukeEarthquake );
	level thread nukeAftermathEffect();
	level thread update_ui_timers();

	if ( level.cancelMode && allowCancel )
		level thread cancelNukeOnDeath( self ); 

	// need objects to play sound off of, i'm keeping them on level so we don't spawn them more than once if multiple nukes get called in a match
	if( !IsDefined( level.nuke_clockObject ) )
	{
		level.nuke_clockObject = Spawn( "script_origin", (0,0,0) );
		level.nuke_clockObject hide();
	}
	if( !IsDefined( level.nuke_soundObject ) )
	{
		level.nuke_soundObject = Spawn( "script_origin", (0,0,1) );
		level.nuke_soundObject hide();
	}

	nukeTimer = level.nukeTimer;
	while( nukeTimer > 0 )
	{
		// TODO: get a new sound for this so we don't remind people of the old nuke
		level.nuke_clockObject playSound( "ks_dna_warn_timer" );
		wait( 1.0 );
		nukeTimer--;
	}
}

cancelNukeOnDeath( player )
{
	player waittill_any( "death", "disconnect" );

//	if ( isDefined( player ) && level.cancelMode == 2 )
//		player thread maps\mp\killstreaks\_emp::EMP_Use( 0, 0 );

	SetOmnvar( "ui_bomb_timer", 0 ); // Nuke sets '4' to avoid briefcase icon showing
	level.nukeIncoming = undefined;

	level notify ( "nuke_cancelled" );
}

nukeSoundIncoming()
{
	level endon ( "nuke_cancelled" );

	if( IsDefined( level.nuke_soundObject ) )
		level.nuke_soundObject PlaySound( "ks_dna_incoming" );
}

nukeSoundExplosion()
{
	level endon ( "nuke_cancelled" );

	if( IsDefined( level.nuke_soundObject ) )
	{
		level.nuke_soundObject PlaySound( "ks_dna_explosion" );
		level.nuke_soundObject PlaySound( "ks_dna_wave" );
	}
}

nukeEffects()
{
	level endon ( "nuke_cancelled" );

	//SetOmnvar( "ui_bomb_timer", 0 );

	//level.nukeDetonated = true;

	foreach( player in level.players )
	{
		playerForward = anglestoforward( player.angles );
		playerForward = ( playerForward[0], playerForward[1], 0 );
		playerForward = VectorNormalize( playerForward );
	
		nukeDistance = 300;
		// /# nukeDistance = getDvarInt( "scr_nukeDistance" );	#/

		nukeEnt = Spawn( "script_model", player.origin + ( playerForward * nukeDistance ) );
		nukeEnt setModel( "tag_origin" );
		nukeEnt.angles = ( 0, (player.angles[1] + 180), 90 );

		/#
		if ( getDvarInt( "scr_nukeDebugPosition" ) )
		{
			lineTop = ( nukeEnt.origin[0], nukeEnt.origin[1], (nukeEnt.origin[2] + 500) );
			thread draw_line_for_time( nukeEnt.origin, lineTop, 1, 0, 0, 10 );
		}
		#/

		nukeEnt thread nukeEffect( player );
	}
}

nukeEffect( player )
{
	level endon ( "nuke_cancelled" );

	player endon( "disconnect" );

	waitframe();
	PlayFXOnTagForClients( level._effect[ "nuke_flash" ], self , "tag_origin", player );
}

nukeAftermathEffect()
{
	level endon ( "nuke_cancelled" );

	level waittill ( "spawning_intermission" );
	
	afermathEnt = getEntArray( "mp_global_intermission", "classname" );
	afermathEnt = afermathEnt[0];
	up = anglestoup( afermathEnt.angles );
	right = anglestoright( afermathEnt.angles );

	PlayFX( level._effect[ "nuke_aftermath" ], afermathEnt.origin, up, right );
}

nukeSlowMo()
{
	level endon ( "nuke_cancelled" );
	
	SetOmnvar( "ui_bomb_timer", 0 );
	
	SetSlowMotion( 1.0, 0.25, 0.5 );
	level waittill( "nuke_death" );
	SetSlowMotion( 0.25, 1, 2.0 );
}

nukeVision()
{
	level endon ( "nuke_cancelled" );

	level.nukeVisionInProgress = true;
	foreach (player in level.players)
	{
		player SetClientTriggerVisionSet("dna_bomb", 0.5 );
		player thread maps\mp\_flashgrenades::applyFlash( 1.6, 0.35 );
	}

	level waittill( "nuke_death" );
	
	//time for fog to linger
	wait 3.0;
	foreach (player in level.players)
		player SetClientTriggerVisionSet("", 10 );
	// turn off nuke vision set
	level.nukeVisionInProgress = undefined;

	
}

nukeDeath()
{
	level endon ( "nuke_cancelled" );

	level notify( "nuke_death" );
	
	maps\mp\gametypes\_hostmigration::waitTillHostMigrationDone();
	
	AmbientStop(1);

	counter = 0;
	foreach( player in level.players )
	{
		// don't kill teammates
		if( level.teambased )
		{
			if( IsDefined( level.nukeInfo.team ) && player.team == level.nukeInfo.team )
				continue;
		}
		// ffa, don't kill the player who called it
		else
		{
			if( IsDefined( level.nukeInfo.player ) && player == level.nukeInfo.player )
				continue;
		}

		player.nuked = true;	
		if ( isAlive( player ) )
		{
			player thread maps\mp\gametypes\_damage::finishPlayerDamageWrapper( level.nukeInfo.player, level.nukeInfo.player, 999999, 0, "MOD_EXPLOSIVE", "nuke_mp", player.origin, player.origin, "none", 0, 0 );
			
			if ( IsDefined( player.isJuggernaut ) && player.isJuggernaut == true )
			{
				player DoDamage( 1, player.origin, level.nukeInfo.player, level.nukeInfo.player, "MOD_EXPLOSIVE", "nuke_mp" );
			}
			
			//play vfx on corpses, use counter delay so all players don't get called on same frame
			delayThread( counter + 1, ::bodyGasFX, player.body );
			counter += 0.05;
		}
	}

	// emp jam them after death, if we do before then the timing is off
	level thread nuke_EMPJam();

	// since the nuke death happened, the nuke is no longer incoming
	level.nukeIncoming = undefined;
}

bodyGasFX( ent )
{
	if ( isDefined(ent) )
		playfxontag( getfx( "dna_bomb_body_gas" ), ent, "J_SPINELOWER" );
}	

nukeEarthquake()
{
	level endon ( "nuke_cancelled" );

	level waittill( "nuke_death" );

	// TODO: need to get a different position to call this on
	//earthquake( 0.6, 10, nukepos, 100000 );

	//foreach( player in level.players )
		//player PlayRumbleOnEntity( "damage_heavy" );
}


nuke_EMPJam()
{
	level endon ( "game_ended" );

	// since nukes do emp damage, might as well emp jam for a little while also

	// set this up to end itself if called again
	level notify( "nuke_EMPJam" );
	level endon( "nuke_EMPJam" );
   if( level.multiTeamBased )
    {
        //nuke all other teams
        for( i = 0; i < level.teamNameList.size; i++ )
        {
            if( level.nukeInfo.team != level.teamNameList[i] )
            {
                level maps\mp\killstreaks\_emp::destroyActiveVehicles( level.nukeInfo.player, level.teamNameList[i] );
            }
        }
    }
	else if( level.teambased )
	{
		level maps\mp\killstreaks\_emp::destroyActiveVehicles( level.nukeInfo.player, getOtherTeam( level.nukeInfo.team ) );
    }
	else
	{
		level maps\mp\killstreaks\_emp::destroyActiveVehicles( level.nukeInfo.player, getOtherTeam( level.nukeInfo.team ) );
	}

	level notify( "nuke_emp_update" );

/#
	level.nukeEmpTimeout = GetDvarFloat( "scr_nuke_empTimeout" );
#/
	/*level thread keepNukeEMPTimeRemaining();
	maps\mp\gametypes\_hostmigration::waitLongDurationWithHostMigrationPause( level.nukeEmpTimeout );

	if( level.multiTeamBased )
    {
        //nuke all other teams
        for( i = 0; i < level.teamNameList.size; i++ )
        {
            if( level.nukeInfo.team != level.teamNameList[i] )
            {
                level.teamNukeEMPed[level.teamNameList[i]] = false;                             
            }
        }
    }
	else if( level.teambased )
	{
		level.teamNukeEMPed[ getOtherTeam( level.nukeInfo.team ) ] = false;
	}
	else
	{
		level.teamNukeEMPed[ level.nukeInfo.team ] = false;
		level.teamNukeEMPed[ getOtherTeam( level.nukeInfo.team ) ] = false;
	}

	foreach( player in level.players )
	{
		if( level.teambased && player.team == level.nukeInfo.team )
			continue;

		player.nuked = undefined;
	}

	// we want the nuke vision to last the rest of this match, leaving here in case we change our minds :)
	level.nukeVisionInProgress = undefined;
	VisionSetNaked( "", 5.0 ); // go to default visionset*/

	level notify( "nuke_emp_update" );
	level notify ( "nuke_emp_ended" );
}

keepNukeEMPTimeRemaining()
{
	level notify( "keepNukeEMPTimeRemaining" );
	level endon( "keepNukeEMPTimeRemaining" );

	level endon( "nuke_emp_ended" );

	// we need to know how much time is left for the unavailable string
	level.nukeEmpTimeRemaining = int( level.nukeEmpTimeout );
	while( level.nukeEmpTimeRemaining )
	{
		wait( 1.0 );
		level.nukeEmpTimeRemaining--;
	}
}

nuke_EMPTeamTracker()
{
	level endon ( "game_ended" );

	for ( ;; )
	{
		level waittill_either ( "joined_team", "nuke_emp_update" );

		foreach ( player in level.players )
		{
			if ( player.team == "spectator" )
				continue;

			if( level.teambased )
			{
				if( IsDefined( level.nukeInfo.team ) && player.team == level.nukeInfo.team )
					continue;
			}
			else
			{
				if( IsDefined( level.nukeInfo.player ) && player == level.nukeInfo.player )
					continue;
			}

			// if this nuke emp is over, let's do an extra check to make sure we shouldn't be regular emped, isEmped() does the extra emp check
			if( !level.teamNukeEMPed[ player.team ] && !player isEMPed() )
				player SetEMPJammed( false );
			else
				player SetEMPJammed( true );
		}
	}
}

onPlayerConnect()
{
	for(;;)
	{
		level waittill("connected", player);
		player thread onPlayerSpawned();
	}
}

onPlayerSpawned()
{
	self endon("disconnect");

	for(;;)
	{
		self waittill( "spawned_player" );

		if( isDefined ( level.nukeVisionInProgress ) )
		{
			self SetClientTriggerVisionSet("dna_bomb" );
			waitframe();
			self SetClientTriggerVisionSet("", 10 );
		}
		/*if( level.teamNukeEMPed[ self.team ] )
		{
			if( level.teambased )
				self SetEMPJammed( true );
			else
			{
				if( !IsDefined( level.nukeInfo.player ) || ( IsDefined( level.nukeInfo.player ) && self != level.nukeInfo.player ) )
					self SetEMPJammed( true );
			}
		}

		// make sure the vision set stays on between deaths
		if( IsDefined( level.nukeDetonated ) )
			self VisionSetNakedForPlayer( level.nukeVisionSet, 0 );
		*/
	}
}

update_ui_timers()
{
	level endon ( "game_ended" );
	level endon ( "disconnect" );
	level endon ( "nuke_cancelled" );
	level endon ( "nuke_death" );

	nukeEndMilliseconds = (level.nukeTimer * 1000) + gettime();
	SetOmnvar( "ui_nuke_end_milliseconds", nukeEndMilliseconds );

	level waittill( "host_migration_begin" );

	timePassed = maps\mp\gametypes\_hostmigration::waitTillHostMigrationDone();

	if ( timePassed > 0 )
	{
		SetOmnvar( "ui_nuke_end_milliseconds", nukeEndMilliseconds + timePassed );
	}
}
