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


#using_animtree( "animated_props" );
main()
{
	PreCacheModel( "mp_dam_large_caliber_turret");
		
	maps\mp\mp_dam_precache::main();
	maps\createart\mp_dam_art::main();
	maps\mp\mp_dam_fx::main();
	
	maps\mp\_load::main();
	maps\mp\mp_dam_lighting::main();
	
	maps\mp\_compass::setupMiniMap( "compass_map_mp_dam" );
	
	//setupCraneAnimations();

	game["attackers"] = "allies";
	game["defenders"] = "axis";
	
	level.aerial_pathnode_offset = 600;
	
	level.mapCustomKillstreakFunc = ::damCustomKillstreakFunc;

	// OSP overrides
	level.orbitalSupportOverrideFunc = ::damCustomOSPFunc;
	
	
	//Lighting items
	//setdvar("r_aodiminish", "0");
	setdvar( "r_mpRimColor", "1 1 1" );
	setdvar( "r_mpRimStrength", "1" );
	setdvar( "r_mpRimDiffuseTint", "1 1 1" );


	thread rotateGenerators();

	//ANIMATED CRANE MOVEMENT
	thread Crane1Movement();
	thread Crane2Movement();
	
	//Spawn Killstreak Turrets
	thread SetupKillstreakTurrets();
	
	//glass pathing
	thread handle_glass_pathing();
	
	//custom killstreak settings
	thread DamCustomAirstrike();

//////  Shutting off dynamic event	
//	thread onPlayerConnect();
//	thread SetupDynamicEvent();

}
/*
onPlayerConnect()
{
	for ( ;; )
	{
		level waittill ( "connected", player );
		
		player.numAreas = 0;
		player.numFireTriggers = 0;
		player thread WatchForSpawn();
	}
}
WatchForSpawn()
{
	self endon("disconnect");
	level endon("game_ended");
	
	self waittill ( "spawned_player" );
	
	self.numAreas = 0;
	self.numFireTriggers = 0;
	self.firedamge = 0;
}
SetupDynamicEvent()
{
	level.DynEventDam = SpawnStruct();
	
	level.DynEventDam.Turrets = SetupDynamicEventTurrets();
	level.DynEventDam.HeliGotos = GetHeliGotoArray();
	level.DynEventDam.StartPos = getstruct("dynamic_heli_path_start", "targetname");
	level.DynEventDam.Helicopter = GetEnt("dynamic_helicopter","targetname");
	level.DynEventDam.Helicopter.spin = false;
	level.DynEventDam.BeforeGate = GetEntArray("gate_before","targetname");
	level.DynEventDam.AfterGate = GetEntArray("gate_after","targetname");
	level.DynEventDam.Clip = GetEnt("dynamic_clip","targetname");
	level.DynEventDam.TriggerHurtFireArray = GetEntarray("dynamic_fire","targetname");
	level.DynEventDam.TunableSpeed = 1000;
	level.DynEventDam.EventStatus = false;
	level.DynEventDam.FireParticleArray = getstructarray("fire_large","targetname");
	level.DynEventDam.FireSpreadArray = getstructarray("fire_spread","script_noteworthy");
	level.DynEventDam.KillFireSpreadTriggers = false;
	level.DynEventDam.TriggerSecondWaveArray = GetEntArray("dynamic_fire_secondwave","targetname");
	
	level.DynEventDam.TowerCrash01Group = getentarray("power_tower_01","targetname");
	level.DynEventDam.TowerCrash01GroupParent = getent("power_tower_01_parent","targetname"); 
	foreach(part in level.DynEventDam.TowerCrash01Group)
	{
		part LinkToSynchronizedParent(level.DynEventDam.TowerCrash01GroupParent);
	}
	
	level.DynEventDam.TowerCrash02Group = getentarray("power_tower_02","targetname");
	level.DynEventDam.TowerCrash02GroupParent = getent("power_tower_02_parent","targetname"); 
	foreach(part in level.DynEventDam.TowerCrash02Group)
	{
		part LinkToSynchronizedParent(level.DynEventDam.TowerCrash02GroupParent);
	}
	
	level.DynEventDam.GroundPreExplosion01 = getent("terrain_pre_crash_01","targetname");
	level.DynEventDam.GroundPreExplosion01_Origin = getstruct("terrain_pre_crash_origin_01","targetname");
	level.DynEventDam.GroundPreExplosion02 = getent("terrain_pre_crash_02","targetname");
	level.DynEventDam.GroundPreExplosion02_Origin = getstruct("terrain_pre_crash_origin_02","targetname");
	level.DynEventDam.HeliCrashBody = getent("heli_body_01_collision","targetname");
	level.DynEventDam.HeliCrashBody_Origin = getstruct("heli_crash_origin","targetname");
	level.DynEventDam.HeliCrashTail = getent("heli_tail_01_collision","targetname");
	level.DynEventDam.HeliCrashTail_Origin = getstruct("heli_crash_tail_origin","targetname");
	level.DynEventDam.HeliCrashDebris = getent("heli_debris_01_collision","targetname");
	level.DynEventDam.HeliCrashDebris_Origin = getstruct("heli_crash_debris_01_origin","targetname");
	level.DynEventDam.HeliCrashBodyTriggerKill = getent("heli_crash_body_trigger_kill","targetname");
	level.DynEventDam.HeliCrashTailTriggerKill = getent("heli_crash_tail_trigger_kill","targetname");
	level.DynEventDam.HeliCrashDebrisTriggerKill = getent("heli_crash_debris_trigger_kill","targetname");
	
	
	
	
	
	
	level.DynEventDam.FireWallParticle_01 = LoadFX( "vfx/map/sanfran_b/sfb_fire_spot_directional_blacksmk_lg");  // replace with real particle
	level.DynEventDam.HeliExplosion_01 = LoadFX( "vfx/explosion/vehicle_fireball_explosion_01");  // replace with real particle
	level.DynEventDam.HeliTailFire = LoadFX( "vfx/map/sanfran_b/sfb_fire_spot_directional_blacksmk_lg");  // replace with real particle

		
	////  Hiding things that need to be hidden at start
	/// 
	MoveAndHideEventParts();

	
	level.dynamicSpawns = ::GetListOfGoodSpawnPoints;
	
	level thread DynamicEvent( ::dynamicEventStartFunc );
	
	thread CheckForCrouch();
}
MoveAndHideEventParts()
{
	MoveDist = (0,0,-10000);
	
	level.DynEventDam.Helicopter hide();
	level.DynEventDam.Clip thread MoveAndVisibility(MoveDist);
	
	foreach(part in level.DynEventDam.AfterGate)
	{
		part thread MoveAndVisibility(MoveDist,true);
	}
	
	level.DynEventDam.HeliCrashBodyTriggerKill thread MoveAndVisibility(MoveDist);
	level.DynEventDam.HeliCrashTailTriggerKill thread MoveAndVisibility(MoveDist);
	level.DynEventDam.HeliCrashDebrisTriggerKill thread MoveAndVisibility(MoveDist);
	level.DynEventDam.HeliCrashBody thread MoveAndVisibility(MoveDist,true);
	level.DynEventDam.HeliCrashTail thread MoveAndVisibility(MoveDist,true);
	level.DynEventDam.HeliCrashDebris thread MoveAndVisibility(MoveDist,true);
	
	level.DynEventDam.GroundPreExplosion01 DontInterpolate();
	level.DynEventDam.GroundPreExplosion02 DontInterpolate();
	level.DynEventDam.GroundPreExplosion01.origin = level.DynEventDam.GroundPreExplosion01_Origin.origin;
	level.DynEventDam.GroundPreExplosion02.origin = level.DynEventDam.GroundPreExplosion02_Origin.origin;
	
}
MoveAndVisibility(MoveVec, bHide)
{
	self DontInterpolate();
	self.origin += MoveVec;
	if(isdefined(bHide))
	{
		if(bHide == true)
		{
			self hide();
		}
		else if(bHide == false)
		{
			self show();
		}
	}
}
CheckForCrouch()
{
	CrouchTriggers = getentarray("force_crouch", "targetname");
	
	if (CrouchTriggers.size > 0)
	{
		foreach ( trigger in CrouchTriggers )
			trigger thread common_scripts\_dynamic_world::triggerTouchThink( ::playerEnterPipe, ::playerLeavePipe );	
	}
}

playerEnterPipe( trigger )
{
	self.numAreas++;
	
	if ( self.numAreas == 1 )
	{
		
	//	if(self GetStance() == "stand")
	//	{
	//		self SetStance("crouch");
	//	}
	}
}
playerLeavePipe( trigger )
{
	self.numAreas--;
	assert( self.numAreas >= 0 );
	
	if ( self.numAreas != 0 )
		return;
	
	self notify( "leftTrigger");
	
	//stand? 
}

/*
ForceCrouch(trigger)
{
	self endon("leftTrigger");
	while(true)
	{
		if(self istouching(trigger))
		{
			if(self GetStance() == "stand")
			{
				self SetStance("crouch");
				wait(0.5);
			}
		}
		else
		{
			wait(0.1);
			{
				if(self istouching(trigger))
				{
					if(self GetStance() == "stand")
					{
						self SetStance("crouch");
					}
				}
				else
				{
					break;
				}
			}
		}
		wait(0.05);
	}
}
*/


/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////--------------------------------- DYNAMIC EVENT SART
/*
GetListOfGoodSpawnPoints(fullListOfSpawnPoints)
{
	goodpoints = [];
	
	// Getting all neutral spawns
	foreach(spawn in fullListOfSpawnPoints)
	{
		if( !IsDefined( spawn.targetname ) || ( spawn.targetname == "" ) )
		{
			goodpoints = add_to_array(goodpoints, spawn);
		}
		else if(spawn GetDynamicEventSpawns() == true)
		{
			goodpoints = add_to_array(goodpoints, spawn);
		}
	}
	return goodpoints;
}
GetDynamicEventSpawns()
{
	if(level.DynEventDam.EventStatus == false)
	{
		if(self.targetname == "dynamic_event_spawn")
		{
			return true;
		}
	}
	else if(level.DynEventDam.EventStatus == true)
	{
		if(self.targetname == "dynamic_event_spawn")
		{
			return false;
		}
	}
	return false;
}
dynamicEventStartFunc()
{
	
	level.DynEventDam.Helicopter DynamicHeliStart();
	level.DynEventDam.Helicopter HandleExplosion();
	
	/*
	thread StartAreaFire();
	CheckFireSpreadState(level.DynEventDam.FireSpreadArray);
	
	level notify("fire_trigger_large");
	wait(0.15); // waiing for spawned trigger_radii to be deleted.  FireTriggerWaitForRemove()
	
	FullAreaDeathTriggers();
	*/
	
	
// }
/*
GetHeliGotoArray()
{
	StartPos = getstruct("dynamic_heli_path_start", "targetname");
	GotoArray = [];
	GotoArray[0] = StartPos;
	CurrentPos = StartPos;
	while(true)
	{
		if(isdefined(CurrentPos) && isdefined(CurrentPos.target))
		{
			NextPos = getstruct(CurrentPos.target, "targetname");
			GotoArray[GotoArray.size] = NextPos;
			CurrentPos = NextPos;
		}
		else
		{
			break;
		}
	}
	return GotoArray;
}
DynamicHeliStart()
{
	self show();
	
	///// X units a second
	MoveSpeed = level.DynEventDam.TunableSpeed;
	
	wait(0.05);
	
	foreach(location in level.DynEventDam.HeliGotos)
	{
		dis = Distance(self.origin, location.origin);
		Movetime = dis / MoveSpeed;
				
		if(isdefined(location.script_noteworthy))
		{
			self thread DoScriptNoteWorthy(location.script_noteworthy);
		}
		
		self moveto(location.origin, Movetime);
		if(self.spin == false)
		{
			self thread RotateHeli(location.angles, Movetime);
		}
		self waittill("movedone");
	}
	return;
}
DoScriptNoteWorthy(note)
{
	if(note == "start_battle")
	{
		foreach(turret in level.DynEventDam.Turrets)
		{
			turret thread ShootDynHeli();
		}
	}
	else if(note == "start_spin")
	{
		level.DynEventDam.EventStatus = true;
		self.spin = true;
		self thread TailFire();
		self thread SpinHeli();
	}
	else if(note == "crash_power_tower_01")
	{
		self thread KnockDownTower01();
	}
	else if(note == "crash_power_tower_02")
	{
		self thread KnockDownTower02();
	}
	else if(note == "crash")
	{
		self waittill("movedone");
	}
}
KnockDownTower01()
{
	thread SpawnParticleVFX(level.DynEventDam.HeliExplosion_01, self.origin, self.angles);
	
	level.DynEventDam.TowerCrash01GroupParent rotateto((60,230,-180), 4, 2, 1);
	
	// level.DynEventDam.TowerCrash01Group
}
KnockDownTower02()
{
	thread SpawnParticleVFX(level.DynEventDam.HeliExplosion_01, self.origin, self.angles);
	
	level.DynEventDam.TowerCrash02GroupParent rotateto((60,230,-180), 4, 2, 1);
	
	// level.DynEventDam.TowerCrash01Group
}
TailFire()
{
	self.TailFire = PlayFXOnTag(level.DynEventDam.HeliTailFire, self, "thruster_BL");
}
HandleExplosion()
{
	self thread HeliExplosion();
	thread KillPlayersNearDebris();
	wait(0.25);
	thread SwapGroundAndHeli();
	
	/*
	foreach(part in level.DynEventDam.AfterGate)
	{
		part DontInterpolate();
		part.origin += (0,0,10000);
	}
	
	// level.DynEventDam.Clip.origin += (0,0,10000);
	foreach(trigger in level.DynEventDam.TriggerHurtFireArray)
	{
		trigger.origin += (0,0,752);
		// trigger thread ShockPlayer();
		trigger thread FireTriggerKillSentientNonPlayer();
		trigger thread common_scripts\_dynamic_world::triggerTouchThink( ::playerEnterFireArea, ::playerLeaveFireArea );	
		trigger thread FireTriggerWaitForRemove();
	}
	foreach(part in level.DynEventDam.BeforeGate)
	{
		part delete();
	}
	foreach(part in level.DynEventDam.AfterGate)
	{
		part show();
	}
	*/
	
//	return;
// }
/*
KillPlayersNearDebris()
{
	
	level.DynEventDam.HeliCrashBodyTriggerKill DontInterpolate();
	level.DynEventDam.HeliCrashTailTriggerKill DontInterpolate();
	level.DynEventDam.HeliCrashDebrisTriggerKill DontInterpolate();
	
	level.DynEventDam.HeliCrashBodyTriggerKill.origin += (0,0,10000);
	level.DynEventDam.HeliCrashTailTriggerKill.origin += (0,0,10000);
	level.DynEventDam.HeliCrashDebrisTriggerKill.origin += (0,0,10000);
	
	wait(1);
	
	level.DynEventDam.HeliCrashBodyTriggerKill.origin += (0,0,-10000);
	level.DynEventDam.HeliCrashTailTriggerKill.origin += (0,0,-10000);
	level.DynEventDam.HeliCrashDebrisTriggerKill.origin += (0,0,-10000);
}
SwapGroundAndHeli()
{
	level.DynEventDam.GroundPreExplosion01 delete();
	level.DynEventDam.GroundPreExplosion02 delete();
	
	level.DynEventDam.HeliCrashBody DontInterpolate();
	level.DynEventDam.HeliCrashTail DontInterpolate();
	level.DynEventDam.HeliCrashDebris DontInterpolate();
	
	level.DynEventDam.HeliCrashBody.origin = level.DynEventDam.HeliCrashBody_Origin.origin;
	level.DynEventDam.HeliCrashTail.origin = level.DynEventDam.HeliCrashTail_Origin.origin;
	level.DynEventDam.HeliCrashDebris.origin = level.DynEventDam.HeliCrashDebris_Origin.origin;
	
	level.DynEventDam.HeliCrashBody show();
	level.DynEventDam.HeliCrashTail show();
	level.DynEventDam.HeliCrashDebris show();
}

StartAreaFire()
{
	SpreadWait = 2.5;

	foreach(pos in level.DynEventDam.FireSpreadArray)
	{
		pos.is_burning = false;
	}
	
	
	foreach(pos in level.DynEventDam.FireParticleArray)
	{
		thread SpawnParticleVFX(level.DynEventDam.FireWallParticle_01, pos.origin, (-90,90,0));
		if(isdefined(pos.target))
		{
			NewFireArray = getstructarray(pos.target, "targetname");
			foreach(new_pos in NewFireArray)
			{
				new_pos thread FireSpreadThink(SpreadWait);
			}
		}
	}
}
CheckFireSpreadState(FireSpreadArray)
{
	WaitNum = FireSpreadArray.size;
	while(WaitNum > 0)
	{
		level waittill("fire_spread_event");
		WaitNum--;
	}
	return;
}
FullAreaDeathTriggers()
{
	foreach(player in level.players)
	{
		player.numFireTriggers = 0;
		player notify( "leftFireTrigger" );
	}
	
	wait(0.1); // wait for new triggers
	
	foreach(trigger in level.DynEventDam.TriggerSecondWaveArray)
	{
		trigger.origin += (0,0,752);
	//	trigger thread ShockPlayer();
		trigger thread common_scripts\_dynamic_world::triggerTouchThink( ::playerEnterFireArea, ::playerLeaveFireArea );	
		trigger thread FireTriggerKillSentientNonPlayer();
	}
	
	level.DynEventDam.Clip.origin += (0,0,10000);
	level.DynEventDam.KillFireSpreadTriggers = true;	
}
/*
ShockPlayer()
{
	self waittill("trigger", HitEnt);
	{
		if(IsSentient(HitEnt))
		{
			if(IsPlayer(HitEnt))
			{	
				HitEnt shellshock( "default", 2);
			}
		}
	}
}
*/
/*
FireSpread(SpreadWait)
{
	foreach(pos in level.DynEventDam.FireSpreadArray)
	{
		if(!isdefined(pos.targetname))
		{
			pos thread FireSpreadThink(SpreadWait);
		}
	}
}
*/
/*
FireSpreadThink(SpreadWait)
{
	// level.DynEventDam.FireSpreadArray
	wait(SpreadWait);
	
	
	self.is_burning = true;
	thread SpawnParticleVFX(level.DynEventDam.FireWallParticle_01, self.origin, (-90,90,0));
	self thread SpawnFireRadiusDmg();
	level notify("fire_spread_event");
	
	if(isdefined(self.target))
	{
		NewFireArray = getstructarray(self.target, "targetname");
		foreach(pos in NewFireArray)
		{
			pos thread FireSpreadThink(SpreadWait);
		}
	}
}
SpawnFireRadiusDmg()
{
	flags = 16;
	trigger_radius = 128;
	trigger_height = 256;
	
//	trigger = Spawn( "trigger_radius", dot.origin, dot.spawnflags, dot.radius, dot.height );
	FireDamageTrigger = spawn("trigger_radius",self.origin + (0,0,-32), flags, trigger_radius, trigger_height);
	if(isdefined(FireDamageTrigger))
	{
		FireDamageTrigger thread FireTriggerKillSentientNonPlayer();
		FireDamageTrigger thread FireTriggerWaitForRemove();
		FireDamageTrigger thread common_scripts\_dynamic_world::triggerTouchThink( ::playerEnterFireArea, ::playerLeaveFireArea );	
	}
}
FireTriggerWaitForRemove()
{
	while(true)
	{
		level waittill("fire_trigger_large");
		{
			self notify("deleted");
			wait(0.05);
			
			self delete();
			return;
		}
	}
}
FireTriggerKillSentientNonPlayer()
{
	level endon("fire_trigger_large");
	self endon("deleted");
	self endon("death");
	self waittill("trigger", HitEnt);
	{
		if(IsSentient(HitEnt))
		{
			if(!IsPlayer(HitEnt))
			{	
				// for sentry gun etc
				HitEnt DoDamage(100, HitEnt.origin);
			}
		}
	}
}

FireDamage()
{
	self endon( "disconnect" );
	self endon( "game_ended" );
	self endon( "death" );
	self endon( "leftFireTrigger" );
	
	if(!isdefined(self.firedamge))
	{
		self.firedamge = 0;
	}
	else if(self.firedamge >= 8)
	{
		self.firedamge = 7;
	}
//	self thread soundWatcher( self );
	
	while (1)
	{
		self.firedamge ++;
		
		switch( self.firedamge )
		{
			case 1:				  
				// playsound
				self ViewKick( 1, self.origin );
				self shellshock( "default", 2);
				self DoFireDamage(1);
				break;
			case 3:				  
				// playsound
				self shellshock( "default", 2);
				self ViewKick( 3, self.origin );
				self DoFireDamage(25);
				break;
			case 4:
				// playsound
				self shellshock( "default", 4);
				self ViewKick( 15, self.origin );
				self DoFireDamage(45);
				break;
			case 6:
				// playsound
				self shellshock( "default", 4);
				self ViewKick( 75, self.origin );
				self DoFireDamage(80);
				break;
			case 8:
				// playsound
				self shellshock( "default", 4);
				self ViewKick( 127, self.origin );
				self DoFireDamage(175);
				self.firedamge = 7; // looping just in case.

				break;
		}
		wait(0.5);
	}
}
DoFireDamage( iDamage )
{
	//if( !isdefined( level.mp_prison_killstreak.owner ) )
	//	return;
	
	//TODO:Handle friendly fire
	self thread [[ level.callbackPlayerDamage ]](
	self,// eInflictor The entity that causes the damage.( e.g. a turret )
	self,// eAttacker The entity that is attacking.
	iDamage,// iDamage Integer specifying the amount of damage done
	0,// iDFlags Integer specifying flags that are to be applied to the damage
	"MOD_SUICIDE",// sMeansOfDeath Integer specifying the method of death
	"mp_dam_fire",// sWeapon The weapon number of the weapon used to inflict the damage
	self.origin,// vPoint The point the damage is from?
	( 0,0,0 ) - self.origin,// vDir The direction of the damage
	"none",// sHitLoc The location of the hit
	0// psOffsetTime The time offset for the damage
	);
}
playerEnterFireArea( trigger )
{
	self.numFireTriggers++;
	self.poison = 1; // hack for level.callbackPlayerDamage, it requires player to have poison defined otherwise it will return early as vitcim and inflictor are the same
	
	if ( self.numFireTriggers == 1 )
		self FireDamage();
}
playerLeaveFireArea( trigger )
{
	
	self.numFireTriggers--;
	
	if ( self.numFireTriggers > 0 )
	{
		return;
	}
	else if ( self.numFireTriggers < 0 )
	{
		 self.numFireTriggers = 0;
	}
	
	self.poison = 0;
	self.firedamge = 0;
	self notify( "leftFireTrigger");
	/*
	if ( isDefined( self.gasOverlay ) )
		self.gasOverlay fadeoutBlackOut( .10, 0 );
		*/
//}

/*
HeliExplosion()
{
	ExplosionLocation = self.origin;
	ExplosionAngles = self.angles;
	if(isdefined(self.TailFire))
	{
		self.TailFire delete();
	}
	wait(0.05);
	self delete();
	thread SpawnParticleVFX(level.DynEventDam.HeliExplosion_01, ExplosionLocation, ExplosionAngles);
	
}
SpawnParticleVFX(particle, position, particle_angles)
{
	SpawnedFX = SpawnFx( particle, position, AnglesToForward(particle_angles), AnglesToUp(particle_angles));
	TriggerFX( SpawnedFX);
}
ShootDynHeli()
{
	self thread TrackDynTarget();
	self thread ShootDynTarget();
}
TrackDynTarget()
{
	level.DynEventDam.Helicopter endon("death");
	level.DynEventDam.Helicopter endon("delete");
//	while(true)
//	{
		self ClearTargetEntity();
		wait(0.05);
		// ClearTurretTarget
		self SetTargetEntity( level.DynEventDam.Helicopter );
//		wait(0.25);
//	}
}
ShootDynTarget()
{
	level.DynEventDam.Helicopter endon("death");
	level.DynEventDam.Helicopter endon("delete");
	while(true)
	{
		self ShootTurret();
		wait(2);
	}
}
SpinHeli()
{
	self endon("death");
	self endon("delete");
	while(true)
	{
		self RotateYaw(360, 4);
		self waittill("rotatedone");
	}
}
RotateHeli(angles, time)
{
	time = time * 0.75;
	self RotateTo(angles, time );
}

SetupDynamicEventTurrets()
{
	DynamicTurrets = [];
	railgun_script_origin = GetEnt( "dynamic_railgun_attachpoint0", "targetname" );
	turret = railgun_script_origin SpawnDamTurret( "dam_turret_mp", "mp_dam_large_caliber_turret", "tag_player_mp" );
	DynamicTurrets = array_add(DynamicTurrets,turret);
	
	
	railgun_script_origin = GetEnt( "dynamic_railgun_attachpoint1", "targetname" );
	turret = railgun_script_origin SpawnDamTurret( "dam_turret_mp", "mp_dam_large_caliber_turret", "tag_player_mp" );
	DynamicTurrets = array_add(DynamicTurrets,turret);

//	railgun_script_origin = GetEnt( "railgun_attachpoint2", "targetname" );
//	turret = railgun_script_origin SpawnDamTurret( "dam_turret_mp", "mp_dam_large_caliber_turret", "tag_player_mp" );
//	Turrets = array_add(Turrets,turret);	
	
	return DynamicTurrets;
}


*/
//////-----------------------------------  DYNAMIC EVENT END
////////////////////////////////////////////////////////////////////////////////////////////////////



DamCustomAirstrike()
{
	if(!isdefined(level.airstrikeoverrides))
	{
		level.airstrikeoverrides = SpawnStruct();
	}
	
	level.airstrikeoverrides.spawnHeight = 1750;
}

damCustomKillstreakFunc()
{
	level.killstreakWeildWeapons["mp_dam_railgun"] 	= true;
	level.killstreakWeildWeapons["dam_turret_mp"] 	= true;
	
	level thread maps\mp\killstreaks\streak_mp_dam::init();
}

damCustomOSPFunc()
{
	level.orbitalsupportoverrides.spawnOrigin 	= ( 1544, 1016, 200 );
	level.orbitalsupportoverrides.spawnAngle 	= 120;			// Default Random(360)
	level.orbitalsupportoverrides.spawnRadius 	= undefined;
	level.orbitalsupportoverrides.spawnHeight 	= undefined;
}

SetupKillstreakTurrets()
{
	Turrets = [];
	railgun_script_origin = GetEnt( "railgun_attachpoint0", "targetname" );
	turret = railgun_script_origin SpawnDamTurret( "dam_turret_mp", "mp_dam_large_caliber_turret", "tag_player_mp" );
	Turrets = array_add(Turrets,turret);
	
	railgun_script_origin = GetEnt( "railgun_attachpoint1", "targetname" );
	turret = railgun_script_origin SpawnDamTurret( "dam_turret_mp", "mp_dam_large_caliber_turret", "tag_player_mp" );
	Turrets = array_add(Turrets,turret);

//	railgun_script_origin = GetEnt( "railgun_attachpoint2", "targetname" );
//	turret = railgun_script_origin SpawnDamTurret( "dam_turret_mp", "mp_dam_large_caliber_turret", "tag_player_mp" );
//	Turrets = array_add(Turrets,turret);	
	
	level.DamTurrets = Turrets;
}

SpawnDamTurret( turretweaponinfo, modelname, linktotag )
{
	
	spawned_turret = SpawnTurret( "misc_turret", self.origin, turretweaponinfo, false );
	spawned_turret.attachpoint = self;
	spawned_turret.angles = flat_angle(self.angles);
	spawned_turret SetModel( modelname );
	spawned_turret SetDefaultDropPitch( 45.0 );
	spawned_turret.health = 99999;
	spawned_turret.maxHealth = 1000;
	spawned_turret.damageTaken = 0;
	spawned_turret.stunned = false;
	spawned_turret.stunnedTime = 0.0;
	spawned_turret SetCanDamage( false );
	spawned_turret SetCanRadiusDamage( false );
	spawned_turret SetMode( "manual" );

	
	level.DamDefaultAimEnt = GetEnt( "DamTurretDefaultTarget", "targetname" );
	spawned_turret SetTargetEntity( level.DamDefaultAimEnt );
	
	return spawned_turret;
}

#using_animtree("animated_props");
setupCraneAnimations()
{
	PrecacheMpAnim("dam_crane01_idle_l");
	PrecacheMpAnim("dam_crane01_idle_r");
	PrecacheMpAnim("dam_crane01_l_2_r");
	PrecacheMpAnim("dam_crane01_r_2_l");
	PrecacheMpAnim("dam_crane02_idle_l");
	PrecacheMpAnim("dam_crane02_idle_r");
	PrecacheMpAnim("dam_crane02_l_2_r");
	PrecacheMpAnim("dam_crane02_r_2_l");
	
	PrecacheMpAnim("dam_crane01_tag_idle_l");
	PrecacheMpAnim("dam_crane01_tag_idle_r");
	PrecacheMpAnim("dam_crane01_tag_l_2_r");
	PrecacheMpAnim("dam_crane01_tag_r_2_l");
	PrecacheMpAnim("dam_crane02_tag_idle_l");
	PrecacheMpAnim("dam_crane02_tag_idle_r");
	PrecacheMpAnim("dam_crane02_tag_l_2_r");
	PrecacheMpAnim("dam_crane02_tag_r_2_l");
	
	PrecacheMpAnim("dam_crane01_collisiontest");
}

CraneCollisionTest()
{
	Crane2 = getent("Crane_02", "targetname");
	Crane2PipeCollision = getent( "crane2PipeCollision", "targetname" );
	Crane2PipeCollision linkto(Crane2,"j_tube_01_c");
	
	while(1)
	{
		Crane2 ScriptModelPlayAnimDeltaMotion( "dam_crane01_collisiontest" );
		wait 20;
	}		
}

TempCraneIdleSetup()
{
	Crane1 = getent("Crane_01", "targetname");
	Crane1PipeCollision = getent( "crane1PipeCollision", "targetname" );
	Crane1PipeCollision linkto(Crane1,"j_tube_01_c");
	
	Crane2 = getent("Crane_02", "targetname");
	Crane2PipeCollision = getent( "crane2PipeCollision", "targetname" );
	Crane2PipeCollision linkto(Crane2,"j_tube_01_c");
	
	Crane1 ScriptModelPlayAnimDeltaMotion( "dam_crane02_idle_l" );
	Crane2 ScriptModelPlayAnimDeltaMotion( "dam_crane01_idle_l" );
}

Crane1Movement()
{
	Crane1Tag = GetEnt( "Crane_01_TagProxy", "targetname");
	Crane1 = getent("Crane_01", "targetname");
	Crane1PipeCollision = getent( "crane1PipeCollision", "targetname" );
	Crane1PipeBcsTrigger = getent( "crane_01_bcs_trigger", "targetname" );
	
	Crane1TagBase = GetEnt( "Crane_01_TagBaseProxy", "targetname");
	Crane1Collision = getent( "crane1Collision", "targetname" );
		
	Crane1PipeCollision LinkToSynchronizedParent(Crane1Tag,"tag_origin");
	Crane1PipeBcsTrigger handle_trigger_updateto( Crane1PipeCollision );
	
	Crane1Collision.angles = Crane1Collision.angles + ( 0, -249.215, 0 );
	Crane1Collision LinkToSynchronizedParent(Crane1TagBase,"tag_origin");
	
	waittime = 20;
	crane1_aud_org = ( 2181, -1069, 1407 );
	thread aud_play_crane_sfx( crane1_aud_org, waittime, "crane_01" );
	
	while(1)
	{	
		Crane1Tag ScriptModelClearAnim();
		Crane1Tag.origin = Crane1.origin;
		Crane1Tag.angles = Crane1.angles;
		
		Crane1TagBase ScriptModelClearAnim();
		
		Crane1 ScriptModelPlayAnimDeltaMotion( "dam_crane01_l_2_r" );
		Crane1Tag ScriptModelPlayAnimDeltaMotion( "dam_crane01_tag_l_2_r");
		Crane1TagBase ScriptModelPlayAnimDeltaMotion( "dam_crane01_tag_base_l_2_r");

		wait waittime;
		
		Crane1Tag ScriptModelClearAnim();
		Crane1Tag.origin = Crane1.origin;
		Crane1Tag.angles = Crane1.angles;
		
		Crane1TagBase ScriptModelClearAnim();
		
		Crane1 ScriptModelPlayAnimDeltaMotion( "dam_crane01_r_2_l" );
		Crane1Tag ScriptModelPlayAnimDeltaMotion( "dam_crane01_tag_r_2_l");
		Crane1TagBase ScriptModelPlayAnimDeltaMotion( "dam_crane01_tag_base_r_2_l");
		wait waittime;
	}
}

Crane2Movement()
{
	Crane2Tag = GetEnt( "Crane_02_TagProxy", "targetname");
	Crane2 = getent("Crane_02", "targetname");
	Crane2PipeCollision = getent( "crane2PipeCollision", "targetname" );
	Crane2PipeBcsTrigger = getent( "crane_02_bcs_trigger", "targetname" );
	
	Crane2TagBase = GetEnt( "Crane_02_TagBaseProxy", "targetname");
	Crane2Collision = getent( "crane2Collision", "targetname" );	//TODO: link this to anims once colin checks them in
	
	waittime = 20;
	crane2_aud_org = ( 849, 2315, 1455 );
	thread aud_play_crane_sfx( crane2_aud_org, waittime, "crane_02" );
		
	Crane2PipeCollision LinkToSynchronizedParent(Crane2Tag,"tag_origin");
	Crane2PipeBcsTrigger handle_trigger_updateto( Crane2PipeCollision );
	
	Crane2Collision.angles = Crane2Collision.angles + ( 0, -117.312, 0 );
	Crane2Collision LinkToSynchronizedParent(Crane2TagBase,"tag_origin");
	
	while(1)
	{
		Crane2Tag ScriptModelClearAnim();
		Crane2Tag.origin = Crane2.origin;
		Crane2Tag.angles = Crane2.angles;
		
		Crane2TagBase ScriptModelClearAnim();
		
		Crane2 ScriptModelPlayAnimDeltaMotion( "dam_crane02_l_2_r" );
		Crane2Tag ScriptModelPlayAnimDeltaMotion( "dam_crane02_tag_l_2_r");
		Crane2TagBase ScriptModelPlayAnimDeltaMotion( "dam_crane02_tag_base_l_2_r");
		wait waittime;
	
		Crane2Tag ScriptModelClearAnim();
		Crane2Tag.origin = Crane2.origin;
		Crane2Tag.angles = Crane2.angles;
		
		Crane2TagBase ScriptModelClearAnim();
		
		Crane2 ScriptModelPlayAnimDeltaMotion( "dam_crane02_r_2_l" );
		Crane2Tag ScriptModelPlayAnimDeltaMotion( "dam_crane02_tag_r_2_l");
		Crane2TagBase ScriptModelPlayAnimDeltaMotion( "dam_crane02_tag_base_r_2_l");
		wait waittime;
	}
}

handle_trigger_updateto( parent )
{
	assertex( isDefined( parent ), "must have a parent entity to know where the water trigger should be" );
	
	level endon( "game_ended" );
	
	parent_offset = self.origin - parent.origin;
	parent_offset_angles = self.angles - parent.angles;
	self childthread MoveTrig( parent, parent_offset, parent_offset_angles );
}

MoveTrig( parent, offset, offset_angles )
{
	while( true )
	{
		self.origin = (parent.origin + offset);
		self.angles = (parent.angles - offset_angles );
		wait( .05 );
	}
}

aud_play_crane_sfx( org, waittime, crane_inst )
{
	crane_motor_pos = org;
	crane_ent = spawn( "script_origin", crane_motor_pos );
}

rotateGenerators()
{
	fans = getentarray( "generator_fan", "targetname" );

	foreach( fan in fans )
	{
		fan thread rotateFan();
	}
}

rotateFan()
{
	
	if ( !IsDefined( level.genrotatespeed ) )
	{
		level.genrotatespeed = -180;
	}
	
	previousgenrotatespeed = 0;
	while( 1 )
	{
		//self rotateto( ( self.angles[0], self.angles[1] + 180, self.angles[2] ), level.genrotatetime );
		if( previousgenrotatespeed != level.genrotatespeed )
		{
			
			self RotateVelocity( ( 0, level.genrotatespeed, 0 ), 3600 ); // rotate for 1h until told otherwise
			previousgenrotatespeed = level.genrotatespeed;
		}
		wait 0.5;	// check every 0.5 second if the genrotatespeed has been changed
	}
}


/*
=============
///ScriptDocBegin
"Name: rotateCrane()"
"Summary: rotates a crane in mp_dam"
"Module: Entity"
"CallOn: level"
"Example: level.crane1 thread rotateCrane();
"SPMP: MP"
///ScriptDocEnd
=============
*/
rotateCrane()
{
	level endon( "game_ended" );
	
	while ( 1 )
	{
		//Swings back...
		self.cab RotateTo( ( 0, GetDvarInt( self.end_angle_dvar, 180 ) , 0 ), GetDvarInt( self.time_dvar, 10 ), 1, 1 );
		
		self.platform RotateTo( ( 0, GetDvarInt( self.end_angle_dvar, 180 ), 0 ), GetDvarInt( self.time_dvar, 10 ), 1, 1 );
		
		self.pipe RotateTo( ( 0, GetDvarInt( self.end_angle_dvar, 180 ), 0 ), GetDvarInt( self.time_dvar, 10 ), 1, 1 );
		
		self.pulley RotateTo( ( 0, GetDvarInt( self.end_angle_dvar, 180 ), 0 ), GetDvarInt( self.time_dvar, 10 ), 1, 1 );
		
		self.hook RotateTo( ( 0, GetDvarInt( self.end_angle_dvar, 180 ), 0 ), GetDvarInt( self.time_dvar, 10 ), 1, 1 );
		
		self.heightOscillator MoveTo( (0, 0, GetDvarInt( self.pipe_end_height_dvar, 0 ) ), GetDvarInt( self.time_dvar, 10 ), 1, 1 );
		
		self.radiusOscillator MoveTo( (0, 0, GetDvarInt( self.pipe_end_radius_dvar, 0 ) ), GetDvarInt( self.time_dvar, 10 ), 1, 1 );
		
		wait( GetDvarInt( self.time_dvar, 10 ) + 5 );
		
		//Swings forth...
		self.cab RotateTo( ( 0, GetDvarInt( self.start_angle_dvar, 130 ), 0 ), GetDvarInt( self.time_dvar, 10 ), 1, 1 );
		
		self.platform RotateTo( ( 0, GetDvarInt( self.start_angle_dvar, 130 ), 0 ), GetDvarInt( self.time_dvar, 10 ), 1, 1 );
		
		self.pipe RotateTo( ( 0, GetDvarInt( self.start_angle_dvar, 130 ), 0 ), GetDvarInt( self.time_dvar, 10 ), 1, 1 );
		
		self.pulley RotateTo( ( 0, GetDvarInt( self.start_angle_dvar, 130 ), 0 ), GetDvarInt( self.time_dvar, 10 ), 1, 1 );
		
		self.hook RotateTo( ( 0, GetDvarInt( self.start_angle_dvar, 130 ), 0 ), GetDvarInt( self.time_dvar, 10 ), 1, 1 );
		
		self.heightOscillator MoveTo( (0, 0, GetDvarInt( self.pipe_start_height_dvar, 0 ) ), GetDvarInt( self.time_dvar, 10 ), 1, 1 );
		
		self.radiusOscillator MoveTo( (0, 0, GetDvarInt( self.pipe_start_radius_dvar, 0 ) ), GetDvarInt( self.time_dvar, 10 ), 1, 1 );
		
		wait( GetDvarInt( self.time_dvar, 10 ) + 5 );
	}
}


/*
=============
///ScriptDocBegin
"Name: moveCranePipe()"
"Summary: moves the crane pipe to match the rotation of crane cab and platform."
"Module: Entity"
"CallOn: a crane struct that contains a 'pipe' script_brushmodel"
"Example: level.crane1 thread moveCranePipe();"
"SPMP: MP"
///ScriptDocEnd
=============
*/
moveCranePipe()
{
	level endon( "game_ended" );
	
	while ( 1 )
	{
		temp_origin_vec = ( Cos( self.platform.angles[1] + 90 ) * self.radiusoscillator.origin[2] + self.cab.origin[0], Sin( self.platform.angles[1] + 90 ) * self.radiusoscillator.origin[2] + self.cab.origin[1], self.heightOscillator.origin[2] );
//		level.crane1pipe.origin = temp_origin_vec;
		self.pipe MoveTo( temp_origin_vec, 0.05, 0.025, 0.025 );
		
		//Do not move the pulley on the z-axis. The crane does not tilt up and down.
		self.pulley MoveTo( ( temp_origin_vec[0], temp_origin_vec[1], self.pulley.origin[2] ), 0.05, 0.025, 0.025 );
		
		self.hook MoveTo( temp_origin_vec + ( 0, 0, 270 ), 0.05, 0.025, 0.025 );
		
		wait( 0.05 );
	}
}


/*
=============
///ScriptDocBegin
"Name: handlePowerSurge()"
"Summary: starts VFX, sound and other events associated with the mp_dam power surge"
"Module: Entity"
"CallOn: An entity"
"Example: thread handlePowerSurge()"
"SPMP: MP"
///ScriptDocEnd
=============
*/
handlePowerSurge()
{
	while ( true )
	{
		//The gap in time between surges.
		wait( GetDvarInt( "mp_dam_surge_interval", 50 ) );
		
		//Start harmless sparks without damage. This is a warning for players to run!
		//Play spark vfx on spark tag origins.
		foreach( sparktag in level.spark_origin_tags )
		{
			PlayFXOnTag( level.mp_dam_fx[ "dam_surge_sparks" ], sparktag, "tag_origin" );
		}
		foreach( pasystemtag in level.surge_vo_origin_tags )
		{
			pasystemtag thread play_sound_on_tag( level.pa_warning0, "tag_origin" );
		}
		
		
		
		//Wait another 5 seconds before triggering electric arcs and damage.
		wait( GetDvarInt( "mp_dam_surge_delay", 7 ) );
		
		level.power_surge_active = true;
		
		//Double the rotation speed of the generators.
		level.genrotatespeed = level.genrotatespeed * 2;
		
		//Play electric arc vfx on spark tag origins.
		foreach( sparktag in level.spark_origin_tags )
		{
			PlayFXOnTag( level.mp_dam_fx[ "dam_surge_arcs" ], sparktag, "tag_origin" );
		}
		foreach( smoketag in level.smoke_origin_tags )
		{
//			PlayFXOnTag( level.mp_dam_fx[ "dam_surge_smoke" ], smoketag, "tag_origin" );
			
			//Start SFX associated with the faster fan rotation.
//			smoketag thread play_loop_sound_on_entity( level.surge_fan_noise );
		}
		foreach( sparksfxtag in level.elec_sparks_origin_tags )
		{
			sparksfxtag thread play_loop_sound_on_entity( level.surge_sparks_noise );
		}
		foreach( pasystemtag in level.surge_vo_origin_tags )
		{
			pasystemtag thread play_sound_on_tag( level.pa_warning1, "tag_origin" );
		}
		
		
		
		wait( GetDvarInt( "mp_dam_surge_duration", 30 ) );
		
		level.power_surge_active = false;
		
		//Reset generator rotation speed.
		level.genrotatespeed = level.genrotatespeed / 2;
		
		//Stop spark vfx on spark tag origins.
		foreach( sparktag in level.spark_origin_tags )
		{
			StopFXOnTag( level.mp_dam_fx[ "dam_surge_sparks" ], sparktag, "tag_origin" );
			StopFXOnTag( level.mp_dam_fx[ "dam_surge_arcs" ], sparktag, "tag_origin" );
		}
		foreach( smoketag in level.smoke_origin_tags )
		{
//			StopFXOnTag( level.mp_dam_fx[ "dam_surge_smoke" ], smoketag, "tag_origin" );
			
			//Stop SFX associated with the faster fan rotation.
//			smoketag thread stop_loop_sound_on_entity( level.surge_fan_noise );
		}
		foreach( sparksfxtag in level.elec_sparks_origin_tags )
		{
			sparksfxtag thread stop_loop_sound_on_entity( level.surge_sparks_noise );
		}
		
		wait( 0.05 );
	}
}


/*
=============
///ScriptDocBegin
"Name: handlePowerSurgeDamage()"
"Summary: checks whether the power surge is currently underway. If yes, damages players touching surge triggers."
"Module: Entity"
"CallOn: An entity"
"Example: thread handlePowerSurgeDamage()"
"SPMP: MP"
///ScriptDocEnd
=============
*/
handlePowerSurgeDamage()
{
	while ( true )
	{
		if ( level.power_surge_active == true )
		{
			foreach( player in level.players )
			{
				foreach( trigmult in level.dam_surge_triggers )
				{
					if ( player IsTouching( trigmult ) )
					{
						player PlayRumbleOnEntity( "damage_heavy" );
						player shellshock( "orbital_laser_mp", 1 );		//TODO: add a solar reflector .shock file if we ultimately want to keep that effect.
						player DoDamage( 5, player.origin );
					}
				}
			}
		}
		wait( 0.05 );
	}
}

handle_glass_pathing()
{
	skylights = GetGlassArray( "skylights" );
	skylight_ents = GetEntArray( "skylights", "targetname" );
	pathnode_orgs = GetEntArray( "glass_pathing", "targetname" );
	
	if( !isDefined( skylight_ents ) )
		return false;
	
	threashold = 8;
	
	//build glass array
	foreach( skylight in skylights )
	{
		origin = GetGlassOrigin( skylight );
		foreach( skylight_ent in skylight_ents )
		{
			if( distance( origin, skylight_ent.origin ) <= threashold )
			{
				skylight_ent.glass_id = skylight;
				break;
			}
		}
	}
	
	array_thread( skylight_ents, ::handle_pathing_on_glass );
}

handle_pathing_on_glass()
{
	level endon( "game_ended" );
	
	pathing_blocker = GetEnt( self.target, "targetname" );
	if( !isDefined( pathing_blocker ) )
		return false;
	
	pathing_blocker trigger_off();
	pathing_blocker ConnectPaths();
	
	waittill_glass_break( self.glass_id );
	
	pathing_blocker trigger_on();
	pathing_blocker DisconnectPaths();
	pathing_blocker trigger_off();
}

waittill_glass_break( skylight )
{
	level endon( "game_ended" );
	
	while( true )
	{
		if( IsGlassDestroyed( skylight ) )
			return true;
		wait( .05 );
	}
}
