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


main()
{
	//if ( getdvar( "r_reflectionProbeGenerate", "0" ) == "1" )
	//setdvar( "r_reflectionProbeRenderEnts", "1" ); // we want the reflection probes to show the prefab room that gets dropped by the airship
	
	maps\mp\mp_lab2_precache::main();
	maps\createart\mp_lab2_art::main();
	maps\mp\mp_lab2_fx::main();
	SetLightingState(1);
	maps\mp\_load::main();
	
	thread setup_audio();
	
	thread set_lighting_values();
	thread set_umbra_values();
	
	// Setting a map-specific OSP vision set.
	level.ospvisionset = "mp_lab2_osp";
	level.osplightset = "mp_lab2_osp";
	level.warbirdvisionset = "mp_lab2_osp";
	level.warbirdlightset = "mp_lab2_osp";
	level.vulcanvisionset = "mp_lab2_osp";
	level.vulcanlightset = "mp_lab2_osp";
	
	
	maps\mp\_compass::setupMiniMap( "compass_map_mp_lab2" );
	
//	setdvar( "r_lightGridEnableTweaks", 1 );
//	setdvar( "r_lightGridIntensity", 1.33 );
	
	//to help with dropped out spot lights
	setdvar("sm_minSpotLightScore", 0.0007);

	game["attackers"] = "allies";
	game["defenders"] = "axis";
	
	if ( level.nextgen )
		level.aerial_pathnode_group_connect_dist = 350;
	
	
	/////////////////////////////////////
	////////// PRE CACHE
	
	precachemodel( "lab2_cannister_holder_01" ); 
	precachemodel( "lab2_industrial_crane_01" ); 
	
	PrecacheMpAnim("lab2_dynamic_event_helicopter_anim");
	PrecacheMpAnim("lab2_dynamic_event_harness_anim");
	PrecacheMpAnim("lab2_dynamic_event_building_anim");
	PrecacheMpAnim("lab2_industrial_crane_anim");
	PrecacheMpAnim("lab2_dynamic_event_harness_invis_anim");
	
	
	
	PreCacheShellShock("mp_lab_gas");
	PreCacheShader( "lab_gas_overlay" );
	
	level.MissileParticles = SpawnStruct();
	
	level.MissileParticles.SprayMachine = LoadFX( "vfx/water/industrial_hot_water_sprayer");
	level.MissileParticles.SprayMachineDrips = LoadFX( "vfx/water/industrial_hot_water_sprayer_drips");
	level.MissileParticles.CanisterDrips = LoadFX( "vfx/map/mp_lab/canister_drips");
	level.MissileParticles.CanisterSteam = LoadFX( "vfx/map/mp_lab/canister_steam");
	level.MissileParticles.DryMachine = LoadFX( "vfx/map/mp_lab/industrial_dryer_fan");
	level.MissileParticles.SparkGreenLoop = LoadFX( "vfx/map/mp_lab/flare_sparks_ambient_green");
	level.MissileParticles.GreenCrazyLightLoop = LoadFX( "vfx/smoke/smoke_flare_marker_green_windy");
	level.MissileParticles.GreenSmokeLoop = LoadFX( "vfx/map/mp_lab/chem_smoke_green");
	level.MissileParticles.MissileExplosion = LoadFX( "vfx/explosion/poison_gas_canister_explosion");
	level.MissileParticles.CraneSparks = loadfx( "vfx/sparks/crane_scrape_sparks_small_looping" );
	level.alarmfx01 = loadfx("vfx/lights/mp_lab2/lab2_crane_red_alarm");
	
	
	//////////  
	//////////
	///////////////////////////////////////
	
	if ( IsDefined( level.createFX_enabled ) && level.createFX_enabled )
		return;		// save some ents for createfx
	

	thread SetupCraneChem();
	thread OnPlayerConnectFucntions();
	thread SetupDynamicEvent();
	thread setupRobotArmNotetracks();
	thread FindAndPlayAnims("animated_prop", true);
	thread SpecialGametypeScript();

	
	SetDvar( "r_reactivemotionfrequencyscale", .5 );
   	SetDvar( "r_reactivemotionamplitudescale", .5 ); 
   	
   	//Character Vis
//	setdvar( "r_mpRimColor", "1 1 " );
//	setdvar( "r_mpRimStrength", "1" );
//	setdvar( "r_mpRimDiffuseTint", "1 1 1" );
	
	//r_gunSightColorEntityScale needs to be set to tune the iron sights color shader (mtl_iron_sights_color). 
	//A change was made to fix the brightness, but causes untuned instances to be too bright. This will need to be tuned for every level.
	setdvar( "r_gunSightColorEntityScale", "7" );
	setdvar( "r_gunSightColorNoneScale", "0.8" );

	level.LabTempTuner1 = 9;
	level.LabTempTuner2 = 4;
	level.LabTempTuner3 = -2;

	// level.mapCustomKillstreakFunc = ::lab2CustomKillstreakFunc;
	
	// OSP overrides
	level.orbitalSupportOverrideFunc = ::labPaladinOverrides;
	level.orbitalLaserOverrideFunc = ::lab2CustomLaserStreakFunc;
	
	//airstrike overrides
	thread lab2CustomAirstrike();
	
	
}

set_umbra_values()
{
	SetDvar( "r_umbraAccurateOcclusionThreshold", 128 );
}

SpecialGametypeScript()
{
	thread waitCarryObjects();
	
	
		// b flag is prefab stamped and ring doesn't show up
	/*	
	DomRings = GetEntArray("dom_b_ring","targetname");

	foreach(ring in DomRings)
	{
		if(level.gameType  == "dom")
		{
			ring.origin = ring.origin + (0,0,256);
			ring show();
		}
		else
		{
			ring hide();
		}
	}
	*/
}


waitCarryObjects()
{
	level endon( "game_ended" );
	
	if ( level.gameType == "sd" )
	{
		while( !isDefined( level.sdBomb ) )
		{
			wait( 0.05 );
		}
		level.sdBomb thread watchCarryObjects();
	}
	else if ( level.gameType == "sab" )
	{
		while( !isDefined( level.sabBomb ) )
		{
			wait( 0.05 );
		}
		level.sabBomb thread watchCarryObjects();
	}
	else if ( level.gameType == "tdef" )
	{
		while( !isDefined( level.gameFlag ))
		{
			wait( 0.05 );
		}
		level.gameFlag thread watchCarryObjects();
	}	
	else if ( level.gameType == "ball" )
	{
		while( !isDefined( level.balls ))
		{
			wait( 0.05 );
		}
		foreach(ball in level.balls)
		{
			ball thread watchCarryObjects();
		}
	
	}
	else if ( level.gameType == "ctf" )
	{
		while( !isDefined( level.teamFlags ) || !isDefined( level.teamFlags[game["defenders"]] ) || !isDefined( level.teamFlags[game["attackers"]] ) )
			wait( 0.05 );
		level.teamFlags[game["defenders"]] thread watchCarryObjects();
		level.teamFlags[game["attackers"]] thread watchCarryObjects();		
	}
}

watchCarryObjects()
{	
	level endon( "game_ended" );
	
	while( true )
	{		
		self waittill( "dropped" );
		
		//	give a couple frames to let the setDropped() flow end
		wait( 0.1 );		
	
		if(self isOutOfBounds())
		{
			self maps\mp\gametypes\_gameobjects::returnHome();

			// self thread moveCarryObject( noDrop.safePos, noDrop.safeAngle );	
		}
		else if(isdefined(level.FlyingBuildingEnt) 
			    && level.FlyingBuildingEnt.flying == true 
			    && isdefined(level.FlyingBuildingEnt.TriggerHurtLower) 
			    && isdefined(level.FlyingBuildingEnt.TriggerHurtUpper))
		{
			while(level.FlyingBuildingEnt.flying == true)
			{
				if(self.visuals[0] istouching(level.FlyingBuildingEnt.TriggerHurtLower) || self.visuals[0] istouching(level.FlyingBuildingEnt.TriggerHurtUpper))
				{
					self maps\mp\gametypes\_gameobjects::returnHome();
					break;
				}	
				wait(0.05);
			}
		}
	}
}

isOutOfBounds()
{
	radTriggers = getEntArray( "radiation", "targetname" );
	for ( index = 0; index < radTriggers.size; index++ )
	{
		if ( !self.visuals[0] isTouching( radTriggers[index] ) )
			continue;

		return true;
	}

	mineTriggers = getEntArray( "minefield", "targetname" );
	for ( index = 0; index < mineTriggers.size; index++ )
	{
		if ( !self.visuals[0] isTouching( mineTriggers[index] ) )
			continue;

		return true;
	}

	hurtTriggers = getEntArray( "trigger_hurt", "classname" );
	for ( index = 0; index < hurtTriggers.size; index++ )
	{
		if ( !self.visuals[0] isTouching( hurtTriggers[index] ) )
			continue;

		return true;
	}
	
	MapBorder = getEntArray( "boost_jump_border_trig", "targetname" );
	for ( index = 0; index < MapBorder.size; index++ )
	{
		if ( !self.visuals[0] isTouching( MapBorder[index] ) )
			continue;

		return true;
	}
		
	OutOfBounds = getEntArray( "object_out_of_bounds", "targetname" );
	for ( index = 0; index < OutOfBounds.size; index++ )
	{
		if ( !self.visuals[0] isTouching( OutOfBounds[index] ) )
			continue;

		return true;
	}
	
	return false;
}

/*
moveCarryObject( pos, angle )
{
	self notify( "stop_pickup_timeout" );
	self notify( "picked_up" );
	
	self.isResetting = true;

	for ( index = 0; index < self.visuals.size; index++ )
	{
		self.visuals[index].origin = pos;
		self.visuals[index].angles = angle;
		self.visuals[index] show();
	}
	self.trigger.origin = pos;
	
	self.curOrigin = self.trigger.origin;

	self maps\mp\gametypes\_gameobjects::clearCarrier();
	
	maps\mp\gametypes\_gameobjects::updateWorldIcons();
	maps\mp\gametypes\_gameobjects::updateCompassIcons();
	
	self.isResetting = false;	
}
*/

SetupDynamicEvent()
{
	//settting up the ground patch location for dynamic event
	groundShadowPatchBefore = GetEntArray("ground_shadow_patch_before", "targetname");
	groundShadowPatchAfter = GetEntArray("ground_shadow_patch_after", "targetname");
	fromEnt = GetEnt("teleport_from", "targetname");
	toEnt = GetEnt("teleport_to", "targetname");
	foreach( thing in groundShadowPatchBefore )
	{
		thing.origin += toent.origin - froment.origin;
	}
	foreach( thing in groundShadowPatchAfter )
	{
		thing hide();
	}
	SetLightingState(2);

	
	FlyingBuildingParts = GetEntArray("dynamic_building_master_prefab", "targetname");
	FlyingBuildingEnt = undefined;
//	AirStartPosition = GetEnt("dynamic_building_air_position", "targetname");
	parts = [];
	foreach(part in FlyingBuildingParts)
	{
		if(IsDefined(part.script_noteworthy) && part.script_noteworthy == "origin")
		{
			FlyingBuildingEnt = spawn("script_origin", part.origin);
		}
		else
		{
			parts[parts.size] = part;
		}
	}
	if(!IsDefined(FlyingBuildingEnt))
	{
		FlyingBuildingEnt = spawn("script_origin", FlyingBuildingParts[0].origin);
	}
	
	FlyingBuildingEnt.radiant_pos = FlyingBuildingEnt.origin;
	FlyingBuildingEnt.flying = false;
	FlyingBuildingEnt.parts = parts;
	FlyingBuildingEnt.TriggerHurtLower = getent("building_hurt_01","targetname");
	FlyingBuildingEnt.TriggerHurtUpper = getent("building_hurt_02","targetname");
	FlyingBuildingEnt.TriggerKillVehiclesHeli = getent("vehicle_kill_heli","targetname");
	FlyingBuildingEnt.TriggerKillVehiclesHeliOffset = (525,36,635); // trigger origin offset from heli origin
	
	
	FlyingBuildingEnt.TriggerKillVehiclesHeli.origin += (0,0,-10000);
	FlyingBuildingEnt.TriggerKillVehiclesBuilding = getent("vehicle_kill_building","targetname");
	//FlyingBuildingEnt.TriggerKillVehiclesBuildingOrigin = getstruct("vehicle_kill_building_origin", "targename");
	FlyingBuildingEnt.TriggerKillVehiclesBuildingOffset = (FlyingBuildingEnt.TriggerKillVehiclesBuilding.origin - FlyingBuildingEnt.origin);
	FlyingBuildingEnt.TriggerKillVehiclesBuilding.origin += (0,0,-10000);

	
	foreach(part in FlyingBuildingEnt.parts)
	{
		if(part.classname == "info_null_meter")
		{
			continue;
		}
		else if(isdefined(part.script_noteworthy) && part.script_noteworthy == "trigger_origin_01")
		{
			FlyingBuildingEnt.TriggerLowerOrigin = part;
		}
		else if(isdefined(part.script_noteworthy) && part.script_noteworthy == "trigger_origin_02")
		{
			FlyingBuildingEnt.TriggerUpperOrigin = part;
		}
		part LinkToSynchronizedParent(FlyingBuildingEnt);
	}
	
	FlyingBuildingEnt.DynamicPathBlock = getent("flying_building_paths_unblock", "targetname");
//	FlyingBuildingEnt.DynamicPathRamp = getent("flying_building_path_upper_floor", "targetname");
	FlyingBuildingEnt.DynamicPathRampSwitch = getent("flying_building_path_ramp_switch", "targetname");
	
	FlyingBuildingEnt.DynamicPathBlock LinkToSynchronizedParent(FlyingBuildingEnt);
	
	FlyingBuildingEnt.OG_spawn = (15959.85, -24712.881, 5209.891); // subtracted 5k for updated heli anim
	FlyingBuildingEnt.OG_heli_spawn = (15940.685, -24711.615, 5888.014); // subtracted 5k for updated heli anim
	
	/// just to get it away from the landing area.  This position is hidden by a large mountain.  It is the same location as the helicopter spawn.  
	FlyingBuildingEnt.origin = FlyingBuildingEnt.OG_spawn;
	wait(0.05);
	FlyingBuildingEnt.TriggerHurtLower.origin = FlyingBuildingEnt.TriggerLowerOrigin.origin;
	FlyingBuildingEnt.TriggerHurtLower.angles = FlyingBuildingEnt.TriggerLowerOrigin.angles;
	FlyingBuildingEnt.TriggerHurtUpper.origin = FlyingBuildingEnt.TriggerUpperOrigin.origin;
	FlyingBuildingEnt.TriggerHurtUpper.angles = FlyingBuildingEnt.TriggerUpperOrigin.angles;
	
	OpenDynamicBuildingPlatformPath(FlyingBuildingEnt);
	
	foreach(part in FlyingBuildingEnt.parts)
	{
		if(part.classname == "info_null_meter")
		{
			continue;
		}
		part hide();
	}
	
	FlyingBuildingEnt hide();
	
	level.FlyingBuildingEnt = FlyingBuildingEnt;
	
	level thread DynamicEvent( ::dynamicEventStartFunc, undefined, ::dynamicEventEndFunc);
	
}

OpenDynamicBuildingPlatformPath(FlyingBuildingEnt)
{

//	level.FlyingBuildingEnt.DynamicPathBlock.origin += (0,0,-10000);
//	level.FlyingBuildingEnt.DynamicPathRamp.origin += (0,0,-10000);
	FlyingBuildingEnt.DynamicPathRampSwitch.origin += (0,0,-10000);
	FlyingBuildingEnt.DynamicPathBlock ConnectPaths();
	foreach (part in FlyingBuildingEnt.parts)
	{
		if(IsDefined(part.script_noteworthy))
		{
			if(part.script_noteworthy == "flying_building_collision_shell" ||  part.script_noteworthy == "collision" || part.script_noteworthy == "building_brush_geo")
			{
				part ConnectPaths();
				if(part.script_noteworthy == "flying_building_collision_shell")
				{
					part SetAISightLineVisible(false);
				}
			}
		}
	}
	if( level.gametype == "dom" )
	{
		wait(0.05);	
		maps\mp\gametypes\dom::flagSetup();
	}
}
	
dynamicEventStartFunc()
{
	if(IsDefined(level.FlyingBuildingEnt) && !isdefined ( level.isHorde ) )
	{
		level.FlyingBuildingEnt MoveFlyingBuilding();
	}
}


dynamicEventEndFunc()
{
	
	//unhide the ground shadow patch 
	groundShadowPatchBefore = GetEntArray("ground_shadow_patch_before", "targetname");
	groundShadowPatchAfter = GetEntArray("ground_shadow_patch_after", "targetname");
	groundShadowPatchAfter[0] show();
	groundShadowPatchBefore[0] hide();
	
	
	if(IsDefined(level.FlyingBuildingEnt))
	{
		level.FlyingBuildingEnt.DynamicPathBlock unlink();
		level.FlyingBuildingEnt.DynamicPathBlock.origin += (0,0,-10000);
		
		level.FlyingBuildingEnt DontInterpolate();
		level.FlyingBuildingEnt.origin = level.FlyingBuildingEnt.radiant_pos;
		
		wait(0.05);
		
		level.FlyingBuildingEnt.TriggerHurtLower DontInterpolate();
		level.FlyingBuildingEnt.TriggerHurtUpper DontInterpolate();
		level.FlyingBuildingEnt.TriggerHurtLower.origin += (0,0,-10000);
		level.FlyingBuildingEnt.TriggerHurtUpper.origin += (0,0,-10000);
		
	//	self.TriggerKillVehiclesHeli DontInterpolate();
	//	self.TriggerKillVehiclesBuilding DontInterpolate();
	//	self.TriggerKillVehiclesHeli.origin += (0,0,-10000);
	//	self.TriggerKillVehiclesBuilding.origin += (0,0,-10000);
		
		foreach (part in level.FlyingBuildingEnt.parts)
		{
			part Unlink();
			part show();
			part.unresolved_collision_kill = false;
			
			if(IsDefined(part.script_noteworthy))
			{
				if(part.script_noteworthy == "flying_building_collision_shell")
				{
					part DisconnectPaths();
					part SetAISightLineVisible(true);
				}
				else if(part.script_noteworthy == "collision")
				{
					part delete();
				}
			}
		}
		
		level.FlyingBuildingEnt.DynamicPathRampSwitch ConnectPaths();	
		
		level thread common_scripts\_exploder::activate_clientside_exploder(100);
	}
	
	
	if( level.gametype == "dom" )
	{
		dom_b_move();
	}
	
}

GetNetQuantizedAngle( angle )
{
	scaledAngle = angle / 360.0;
	result = ( scaledAngle - floor( scaledAngle ) ) * 360.0;
	result2 = result - 360.0;
	if ( result2 >= 0 )
		result = result2;
	compressedAngle = int( floor( (result * 4095/360) + 0.5 ) );
	angle = ( compressedAngle * 360 )/4095.0;
	return angle;
}

////Moves B Domination Flag into the elevator after the elevator has touched down.
dom_b_move()
{
	wait(0.05); // for connect paths
	
	post_event_flag_b_origin = getstruct("dom_point_b_location", "targetname");
	
	foreach( domFlag in level.flags )
	{
		if (domFlag.script_label == "_b")
		{
		//	data = level.dom_flag_data[next_zone_name][domFlag.useObj.label];
			domFlag.origin = post_event_flag_b_origin.origin;
			domFlag.useobj.visuals[0].origin = post_event_flag_b_origin.origin + (0,0,1.125);
			domFlag.useobj.visuals[0].baseorigin = post_event_flag_b_origin.origin + (0,0,1.125);
			domFlag.useobj.curorigin = post_event_flag_b_origin.origin + (0,0,1.125);
			domFlag.useobj.baseeffectpos = post_event_flag_b_origin.origin + (0,0,1.125);
		//	domFlag.useobj.baseeffectforward = data.baseeffectforward; 
			domFlag.useObj maps\mp\gametypes\dom::updateVisuals();
		//	domFlag.teleport_zone = next_zone_name;
		//	domflag.nodes = data.nodes;
			
			// minimap
			if( IsDefined( domflag.useobj.objIDAllies ) )
				Objective_Position(domflag.useobj.objIDAllies, post_event_flag_b_origin.origin);
			if( IsDefined( domflag.useobj.objIDAxis ) )
				Objective_Position(domflag.useobj.objIDAxis, post_event_flag_b_origin.origin);
			
			obj_icon_pos = post_event_flag_b_origin.origin + (0,0,100);
			foreach(team in level.teamnamelist)
			{
				opName = "objpoint_" + team + "_" + domFlag.useObj.entNum;			
				objPoint = maps\mp\gametypes\_objpoints::getObjPointByName( opName );
				objPoint.x = obj_icon_pos[0];
				objPoint.y = obj_icon_pos[1];
				objPoint.z = obj_icon_pos[2];
			}
		}
	}
	
	level notify("dom_flags_moved");
	
	maps\mp\gametypes\dom::flagSetup();
}



#using_animtree( "animated_props" );
MoveFlyingBuilding()
{	
	Zoffset = level.LabTempTuner1;
	Yoffset = level.LabTempTuner2;
	Xoffset = level.LabTempTuner3;
	self.heavy_lifter = spawn("script_model", self.OG_heli_spawn + (Xoffset,Yoffset,Zoffset));
	//self.heavy_lifter.angles = (0, 36.078, 0);
	angle = GetNetQuantizedAngle( 36.078 );
	self.heavy_lifter.angles = (0, 36.044, 0);	
	self.heavy_lifter SetModel("vehicle_heavy_lift_helicopter_01");
	
	
	self.harness = spawn("script_model", self.heavy_lifter GetTagOrigin("tag_crane"));
	self.harness.angles = self.heavy_lifter GetTagAngles("tag_crane") + (0,0,0);
	self.harness SetModel("heavy_lift_wires");
	
	
//	self.harness_invis = spawn("script_model", self.heavy_lifter GetTagOrigin("tag_crane"));
//	self.harness_invis.angles = self.heavy_lifter GetTagAngles("tag_crane") + (0,0,0);
//	self.harness_invis SetModel("heavy_lift_wires");
	
	
	self.building_bone = spawn("script_model", self.OG_spawn + (0,0,Zoffset));
	self.building_bone.angles = self.harness GetTagAngles("tag_cargo") + (0,180,0);
//	self.building_bone.angles = self.heavy_lifter.angles + (0,180,0);
	self.building_bone SetModel("tag_origin_animate");
	
	self.flying = true;
	
	wait(0.05);
	
	self.TriggerKillVehiclesHeli thread maps\mp\killstreaks\_aerial_utility::setup_kill_drone_trig(); // self.TriggerKillVehiclesHeli
	self.TriggerKillVehiclesBuilding thread maps\mp\killstreaks\_aerial_utility::setup_kill_drone_trig(); // self.TriggerKillVehiclesBuilding
//	self thread KillSentryGuns(self.TriggerKillVehiclesBuilding);
	self thread KillWarbirds(self.TriggerKillVehiclesBuilding);
	self thread KillWarbirds(self.TriggerKillVehiclesHeli);

	foreach (part in self.parts)
	{
		part show();
	}
	
	wait(0.05);

	foreach (mesh in self.parts)
	{
		mesh.unresolved_collision_kill = true;
	}
	
	

/////////////////////	self.origin = self.building_bone.origin;
///////////////////////////	self.angles = self.building_bone.angles;	
	
	
//	self.origin = self.harness GetTagOrigin("tag_cargo");
	self.origin =  self.OG_spawn + (0,0,Zoffset);
	self.angles = self.harness GetTagAngles("tag_cargo") + (0,180,0);
//	self LinkToSynchronizedParent(self.harness_invis,"tag_cargo");
	self LinkToSynchronizedParent(self.harness,"tag_cargo");
//	self LinkToSynchronizedParent(self.building_bone);
	
	wait(0.05);

	self.heavy_lifter ScriptModelPlayAnimDeltaMotion( "lab2_dynamic_event_helicopter_anim" , "building_unlink_notify");
	self.harness ScriptModelPlayAnimDeltaMotion( "lab2_dynamic_event_harness_anim" );
	
	//thread snd_play_linked_loop( "transport_chopper_close_lp", self.heavy_lifter );
	self.heavy_lifter thread aud_transport_chopper();
	
//	self.harness_invis ScriptModelPlayAnimDeltaMotion( "lab2_dynamic_event_harness_invis_anim" );
	self thread MoveBuildingDeathTriggers();
	
	self.heavy_lifter thread maps\mp\mp_lab2_fx::startHeavyLifterFX();

	self.heavy_lifter waittillmatch( "building_unlink_notify", "vfx_heligroundfx_start" );
	self.heavy_lifter thread maps\mp\mp_lab2_fx::startHeliGroundFX();
	
	self.heavy_lifter waittillmatch( "building_unlink_notify", "vfx_crane_sparks_start" );
	playfxontag(getfx("crane_sparks"), self.heavy_lifter, "TAG_CRANE");
//	self.building_bone ScriptModelPlayAnimDeltaMotion( "lab2_dynamic_event_building_anim" );

	
	self.heavy_lifter waittillmatch( "building_unlink_notify", "helicopter_descend" );

	parts = [];
	foreach (part in self.parts)
	{
		if(IsDefined(part.script_noteworthy) && part.script_noteworthy == "collision")
		{
			part Unlink();
			part delete();
		}
		else
		{
			parts[parts.size] = part;
		}
	}
	self.parts = parts;	
	
	self.DynamicPathBlock unlink();
	self.DynamicPathBlock delete();
	
	self.heavy_lifter thread aud_building_pre_drop();
	
	self.heavy_lifter waittillmatch( "building_unlink_notify", "vfx_crane_sparks_stop" );
	stopfxontag(getfx("crane_sparks"), self.heavy_lifter, "TAG_CRANE");
	
	//building land fx
	self.heavy_lifter waittillmatch( "building_unlink_notify", "vfx_building_land" );
	common_scripts\_exploder::activate_clientside_exploder(99);
	
	self.heavy_lifter waittillmatch( "building_unlink_notify", "drop_building" );
	self.harness thread maps\mp\mp_lab2_fx::clampReleaseFX();
	
	self.heavy_lifter thread aud_building_drop();

	//unhide the ground shadow patch 
	groundShadowPatchBefore = GetEntArray("ground_shadow_patch_before", "targetname");
	groundShadowPatchAfter = GetEntArray("ground_shadow_patch_after", "targetname");
	groundShadowPatchAfter[0] show();
	groundShadowPatchBefore[0] hide();

//	wait(2);
//	self.building_bone delete();
	
	self unlink();
	self.flying = false;
	foreach (part in self.parts)
	{
		if(isdefined(part))
		{
			part Unlink();
			part.unresolved_collision_kill = false;
			if(IsDefined(part.script_noteworthy))
			{
				if(part.script_noteworthy == "flying_building_collision_shell")
				{
					part DisconnectPaths();
					part SetAISightLineVisible(true);
				}
			}
		}
	}
	
//	self.DynamicPathRamp.origin += (0,0,10000);
	self.DynamicPathRampSwitch ConnectPaths();
	
	if( level.gametype == "dom" )
	{
		dom_b_move();
	}
	
	//turn on fx inside of building
	common_scripts\_exploder::activate_clientside_exploder(100);
	
	self.heavy_lifter waittillmatch( "building_unlink_notify", "vfx_heligroundfx_stop" );
	self.heavy_lifter thread maps\mp\mp_lab2_fx::stopHeliGroundFX();
	
	
	self.heavy_lifter waittillmatch( "building_unlink_notify", "helicopter_end" ); 

	self.heavy_lifter delete();
	self.harness delete();	
	

	
}

/*KillSentryGuns(trigger)
{
	if(isdefined(trigger))
	{
		while(self.flying == true)
		{
			if(isdefined(level.turrets))
			{
				foreach(turret in level.turrets)
				{
					if(isdefined(turret))
					{
						if(turret IsTouching(trigger))
						{
							turret thread KillTurret(turret.origin);
						}
					}
				}
			}
			wait(0.05);
		}
	}
}*/

KillWarbirds(trigger)
{
	if(isdefined(trigger))
	{
		while(self.flying == true)
		{
			if(isdefined(level.SpawnedWarbirds))
			{
				foreach(warbird in level.SpawnedWarbirds)
				{
					if(isdefined(warbird))
					{
						if(warbird IsTouching(trigger))
						{
							warbird thread maps\mp\killstreaks\_aerial_utility::heli_explode( true );
						}
					}
				}
			}
			wait(0.05);
		}
	}
}

/*KillTurret(turret_origin)
{
	self.fast_death = true;
	wait(0.05);
	if(IsDefined(self))
	{
		self notify("death");
	}
}*/

MoveBuildingDeathTriggers()
{	
	while(self.flying == true)
	{	
		self.TriggerHurtLower.origin = self.TriggerLowerOrigin.origin;
		self.TriggerHurtLower.angles = self.TriggerLowerOrigin.angles;
		
		self.TriggerHurtUpper.origin = self.TriggerUpperOrigin.origin;
		self.TriggerHurtUpper.angles = self.TriggerUpperOrigin.angles;
		
		
		heli_angles = self.heavy_lifter GetTagAngles("body_animate_jnt");
		heli_angles_x = 360 - heli_angles[0];
		heli_angles_y = heli_angles[1] + 180;
		heli_angles_z = 360 - heli_angles[2];
		
		self.TriggerKillVehiclesHeli.angles = (heli_angles_x, heli_angles_y, heli_angles_z);
		self.TriggerKillVehiclesHeli.origin = self.heavy_lifter.origin + self.TriggerKillVehiclesHeliOffset;
		
		self.TriggerKillVehiclesBuilding.origin = self.origin + self.TriggerKillVehiclesBuildingOffset;
		self.TriggerKillVehiclesBuilding.angles = self.angles;
		
		wait(0.05);
	}
	self.TriggerHurtLower DontInterpolate();
	self.TriggerHurtUpper DontInterpolate();
	self.TriggerKillVehiclesHeli DontInterpolate();
	self.TriggerKillVehiclesBuilding DontInterpolate();
	self.TriggerHurtLower.origin += (0,0,-10000);
	self.TriggerHurtUpper.origin += (0,0,-10000);
	self.TriggerKillVehiclesHeli.origin += (0,0,-10000);
	self.TriggerKillVehiclesBuilding.origin += (0,0,-10000);

}

/*
lab2CustomKillstreakFunc()
{
	level thread maps\mp\killstreaks\streak_mp_lab2::init();
}
*/

labPaladinOverrides()
{
	// tuned so you have to look around
	level.orbitalsupportoverrides.spawnAngleMin = 70;	// Default Random(360)
	level.orbitalsupportoverrides.spawnAngleMax = 150;	// Default Random(360)
	level.orbitalsupportoverrides.spawnHeight 	= 7500;
	level.orbitalsupportoverrides.spawnRadius = 5000;
	level.orbitalsupportoverrides.leftArc		= 30;
	level.orbitalsupportoverrides.rightArc		= 30;
	level.orbitalsupportoverrides.topArc		= -42;
	level.orbitalsupportoverrides.bottomArc		= 67;	
}

lab2CustomLaserStreakFunc()
{
	heliAnchor = maps\mp\killstreaks\_aerial_utility::getHeliAnchor();
	level.orbitallaseroverrides.spawnHeight = heliAnchor.origin[ 2 ] + 2724;
}

lab2CustomAirstrike()
{
	if(!isdefined(level.airstrikeoverrides))
	{
		level.airstrikeoverrides = SpawnStruct();
	}
	
	level.airstrikeoverrides.spawnHeight = 1700;
}

OnPlayerConnectFucntions()
{
	level endon("game_ended");
	while(true)
	{
		level waittill("connected", player);
		{
			player.GasTime = 0;
			player thread CreateGasTrackingOverlay();
		//	player thread TrackGasDamage();
		}
	}
}


set_lighting_values()
{
    if ( IsUsingHDR() )
    {        while (true)
        {
          level waittill("connected", player);               // we need to set the dvars for each player as he connects.
                     player SetClientDvars(
                "r_tonemap", "1"               
           );
           /*   player SetClientDvars(
                "r_tonemap", "1",
                "r_tonemapadaptspeed", ".07",
                "r_tonemapkey", "0",
                "r_veil", "1",
                "r_veilstrength", ".087",
                "r_tonemapexposure", "-10" 
              );
            
            //For setting the max exposure so we can get contrast back into the map without blowing everything out
            setdvar ("r_tonemapmaxexposure", "-10");
            
            //Controling how much SSAO there is in the scene
            setdvar ("r_ssaoPower", "3.5");
            setdvar ("r_ssaoBlurRadius", "1.5");
           */ 
        }
    }
}


/////////////////////////////////////////
/////////////  HOLO ROTATION

RotateMeshes(time)
{
	while(1)
	{
		self RotateYaw( 360, time);
		wait(time);
	}
}

////////   HOLO ROTATION
////////////////////////////////////////////////////



/////////////////////////////////////////////////////////////////////////////////////////////
//////// MISSILE MOVER



SetupCraneChem()
{
	level.AlarmSystem = SpawnStruct();
	level.AlarmSystem.SpinnerArray = GetEntArray("horizontal_spinner", "targetname");
	level.AlarmSystem.AlarmSoundEnt = GetEnt("alarm_missile_sound01","targetname");
//	foreach(spinner in level.AlarmSystem.SpinnerArray)
//	{
//		spinner hide();
//	}
	
	level.GasMachine = SpawnStruct();
	level.GasMachine.TotalSpawned = [];
	level.GasMachine.CraneCollisionTotal = [];
	level.GasMachine.CraneChemCollisionTotal = [];
	level.GasMachine.ExplosionOffset = 72;
	level.GasMachine.ExplosionAngleOffset = (-90,0,0);
	level.GasMachine.MachineSparkArray = GetEntArray("sparkgroup","targetname");
	level.GasMachine.SprayerDripArray = GetEntArray("dripgroup","targetname");
	level.GasMachine.PartcileDryLocation = getstruct("particle_dryer", "targetname");
//	level.GasMachine.chemical_rackCollision = GetEnt("rack_collision_clone01","targetname");
//	level.GasMachine.CraneCollision = GetEnt("crane_collision01","targetname");
	level.GasMachine.chemical_rackPauseTime = 0;
	level.GasMachine.chemical_racksActive = true;
	level.GasMachine.chemical_rackGotosArray = getstructarray("missile_rack_start01","targetname");
//	level.GasMachine.MissileSpawnArray = getstructarray("missile_spawn_loc_rack","targetname");
	level.GasMachine.DamageRadius = 375;
	level.GasMachine.MaxDamageAmount = 300;
	level.GasMachine.MinDamageAmount = 75;
//	level.GasMachine.SprayScreenTriggerArray = GetEntArray("spray_screen_trigger","targetname");
	level.GasMachine.SpraySheetState = 1;
	level.GasMachine.TotalChemCanHealth = 100;
	level.GasMachine.ParticleSpawnOriginOffset = (0,0,0);
	level.GasMachine.DryerFan = GetEnt("dryer_fan","targetname");
	level.GasMachine.DryerFanRotateVelocity = (0,1400,0);
	level.GasMachine.GasRange = 170;


	
			
	
	CurrentStruct = level.GasMachine.chemical_rackGotosArray[0];
	while(true)
	{
		if(IsDefined(CurrentStruct.target))
		{
			FoundStruct = getstruct(CurrentStruct.target,"targetname");
			level.GasMachine.chemical_rackGotosArray = add_to_array(level.GasMachine.chemical_rackGotosArray,FoundStruct);
			CurrentStruct = FoundStruct;
			continue;
		}
		else
		{
			break;
		}
		wait(0.05);
	}
	
	level.GasMachine.CraneCollisionTotal = GetEntArray("crane_collision01", "targetname");
	level.GasMachine.CraneCollision = level.GasMachine.CraneCollisionTotal;	
	foreach(mesh in level.GasMachine.CraneCollisionTotal)
	{
		mesh.unresolved_collision_kill = true;
	}
	
	level.GasMachine.CraneChemCollisionTotal = GetEntArray("rack_collision01", "targetname");
	level.GasMachine.CraneChemCollision = level.GasMachine.CraneChemCollisionTotal;	
	foreach(mesh in level.GasMachine.CraneChemCollisionTotal)
	{
		mesh.unresolved_collision_kill = true;
	}
	
	CraneThink(level.GasMachine.chemical_rackGotosArray);
}


AddToTotalSpawned()
{
	level.GasMachine.TotalSpawned = add_to_array(level.GasMachine.TotalSpawned, self);		
}
RemoveFromTotalSpawned()
{
//	level.GasMachine.TotalSpawned array_remove(level.GasMachine.TotalSpawned, self);
	wait(0.05);
	level.GasMachine.TotalSpawned = array_removeUndefined(level.GasMachine.TotalSpawned);	
} 

CraneThink(RackGotos)
{
	// for shutting of gas can spawning if dynamic event is disabled..... if we want that
	/* 
	 wait(0.05);
	{
		if ( IsDefined( level.dynamicEventsType ) )
		{
			if ( level.dynamicEventsType != 0)
			{
				// shut off the whole move gas can system.
				return;
			}
		}
	}
	*/
	
	Movetime = 5;
	WaitTime = 5;

	while(true)
	{
		if(level.GasMachine.chemical_racksActive == true)
		{
			if(level.GasMachine.CraneCollision.size > 0)
			{
				RandomNum = RandomInt(100);
				if(RandomNum > 40 )
				{	
					
					Crane = SpawnCrane(RackGotos, true);
					if(isdefined(Crane))
					{  
						Crane thread StartNoteListen(WaitTime, Movetime);
					}
				}
				/*
				else if(RandomNum > 25 )
				{
					Crane = SpawnCrane(RackGotos, false);
					if(isdefined(Crane))
					{
						Crane thread StartNoteListen(WaitTime, Movetime);
					}
				}
				
				else if(RandomNum > 0 )
				{
					//// no rack no missiles
				}
				*/
			}
			wait(Movetime + WaitTime + RandomFloatRange(3.0,7.0));
		}
		else
		{
			wait(1);
		}
	}
}
StartNoteListen(WaitTime,Movetime)
{
	/*
	self thread WatchCraneNoteTrack(WaitTime, Movetime, "crane_move_start");
	self thread WatchCraneNoteTrack(WaitTime, Movetime, "crane_move_stop");
	self thread WatchCraneNoteTrack(WaitTime, Movetime, "crane_wiggle_stop");
	self thread WatchCraneNoteTrack(WaitTime, Movetime, "crane_particle_01");
	self thread WatchCraneNoteTrack(WaitTime, Movetime, "crane_particle_02");
	self thread WatchCraneNoteTrack(WaitTime, Movetime, "crane_particle_03");
	self thread WatchCraneNoteTrack(WaitTime, Movetime, "rotate_start");
	self thread WatchCraneNoteTrack(WaitTime, Movetime, "rotate_stop");
	self thread WatchCraneNoteTrack(WaitTime, Movetime, "rotate_start");
	self thread WatchCraneNoteTrack(WaitTime, Movetime, "crane_finish");
	*/
	
	self thread WatchCraneNoteTrack(WaitTime, Movetime);
}
#using_animtree( "animated_props" );
WatchCraneNoteTrack(WaitTime, Movetime)
{
//	self thread CraneParticle_01_Note();

	self endon("death");
	self endon("deleted");
	while(1)
	{
	//	self waittillmatch( "crane_note_track", note );
		self waittill( "crane_note_track", note );
		
		
		if(note == "crane_move_start")
		{
			if(level.GasMachine.chemical_racksActive == false)
			{
				if(isdefined(self) && self.paused == false)
				{
					self ScriptModelPauseAnim(true);
					self.paused = true;
					self CheckForUnpause();
				}
			}
			else
			{
				thread snd_play_linked("emt_conveyor_belt_gears", self );
				thread snd_play_linked("emt_conveyor_belt_sparks", self );
				PlayFxOnTag(level.MissileParticles.CraneSparks, self, "TAG_ORIGIN");
			}
		}
		else if(note == "crane_move_stop")
		{
			self thread StopCraneSound();
			StopFxOnTag(level.MissileParticles.CraneSparks, self, "TAG_ORIGIN");
		}
		else if(note == "crane_wiggle_stop")
		{
			
		}
		else if(note == "crane_particle_01" || note == "crane_particle_02" || note == "crane_particle_03")
		{
			self thread SprayCans(WaitTime, note);
		}
		else if(note == "rotate_start")
		{
			self thread RotateThink(WaitTime);
		}
		else if(note == "rotate_stop")
		{
			self thread StopCraneSound();
		}
		else if(note == "crane_finish")
		{
			self thread RemoveRack();
		}
	}
}
CheckForUnpause()
{
	self endon("death");
	self endon("deleted");
	while(true)
	{
		if(isdefined(self))
		{
			if(level.GasMachine.chemical_racksActive == true)
			{
				if(self.paused == true)
				{
					self ScriptModelPauseAnim(false);	
					self.paused = false;	
					
					thread snd_play_linked("emt_conveyor_belt_gears", self );
					thread snd_play_linked("emt_conveyor_belt_sparks", self );
					PlayFxOnTag(level.MissileParticles.CraneSparks, self, "TAG_ORIGIN");	
					
					break;
				}
			}
		}
		else
		{
			break;
		}
		wait(0.5);
	}
}
setupRobotArmNotetracks()
{
	robotArms = getEntArray("lab2_robot_arm", "targetname");
	foreach(arm in robotArms)
	{
		wait(RandomFloatRange(0.0, 1));
		arm ScriptModelPlayAnimDeltaMotion( "lab2_robot_arm_01_idle_anim" , "emt_servo_sparks");
		arm thread WatchRobotArmNotetrack();
	}
}
	
WatchRobotArmNotetrack()
{
	self endon("death");
	self endon("deleted");
	while(1)
	{
		self waittill( "emt_servo_sparks", note );
		if ( isDefined( note ) && note == "robot_arm_sparks_on" )
		{
			playfxontag(getfx("welding_sparks"), self, "wristSwivel");
		}
		else if ( isDefined( note ) && note == "emt_servo_sparks" )
		{
			thread snd_play_linked("emt_servo_sparks", self );
		}
	}
}

StopCraneSound()
{
	self StopSounds();
	wait(0.05);
	thread snd_play_linked("mp_lab_missilerack_stop01", self );
}
RotateThink(WaitTime)
{
	if(self.has_chemicals == true)
	{
		if(level.GasMachine.chemical_racksActive == true)
		{
			thread snd_play_in_space( "emt_air_blast_turn", level.GasMachine.PartcileDryLocation.origin );
			thread snd_play_in_space( "emt_air_blast_clean", level.GasMachine.PartcileDryLocation.origin );
			level.GasMachine.PartcileDryLocation thread ParticleSpray(level.MissileParticles.DryMachine,level.GasMachine.PartcileDryLocation.angles,3 );
			self thread StartCanisterFX(level.MissileParticles.CanisterSteam,WaitTime);
			thread RotateDryerFan();
		}
	}
}

RotateDryerFan()
{
	level.GasMachine.DryerFan RotateVelocity(level.GasMachine.DryerFanRotateVelocity, 7,1,5);
}

SprayCans(WaitTime, note)
{
	if(self.has_chemicals == true)
	{
		if(level.GasMachine.chemical_racksActive == true)
		{
			thread ParticleSprayMultipleNode(note,WaitTime);
		//	thread SprayPlayerScreen(note,WaitTime);
			self thread StartCanisterFX(level.MissileParticles.CanisterDrips,WaitTime);
		}
	}
}
SpawnCrane(RackGotos, HasCans)
{
	SpawnZOffset = -210;

	Crane = spawn("script_model", RackGotos[0].origin + (0,0,SpawnZOffset));
	
	Crane PlayCraneSpawnVfX(); // wait for this to finish
	
	
	////////////////////////// ???? WTF makes crane invis??
//	Crane CloneBrushmodelToScriptmodel(level.GasMachine.CraneCollision);
	CollisionData = GetCollision(level.GasMachine.CraneCollision);
	if(IsDefined(CollisionData) && IsDefined(CollisionData.Collision))
	{
		Crane SetModel("lab2_industrial_crane_01");
		Crane.paused = false;
		Crane.CraneCollision = CollisionData.Collision;
		level.GasMachine.CraneCollision = CollisionData.pool;
		Crane.CraneCollision.origin = Crane.origin;
		Crane.CraneCollision.angles = Crane.angles;
		Crane.CraneCollision LinkToSynchronizedParent(Crane);
		Crane Solid();
	}
	else
	{
		if(isdefined(Crane))
		{
			Crane delete();
		}
		return undefined;
	}
	
//	CraneChemCollisionTotal
	
	Crane AddToTotalSpawned();
	
	//attaching vfx lights to the crane
	wait 0.5;
	PlayFxOnTag(getfx("lab_crane_arm_01_lights"), Crane, "TAG_ORIGIN");
	PlayFxOnTag(level.MissileParticles.CraneSparks, Crane, "TAG_ORIGIN");
	//triggerFx(craneFX);
	//----------------------------------------\
	if(	HasCans == true)
	{
		CollisionData = GetCollision(level.GasMachine.CraneChemCollision);
		if(IsDefined(CollisionData) && IsDefined(CollisionData.Collision))
		{
			Crane.chemical_rack = spawn("script_model",Crane GetTagOrigin("tag_cargo"));
			Crane.exploding = false;
			Crane.chemical_rack SetModel("lab2_cannister_holder_01");
			Crane.chemical_rack linkto(Crane, "tag_cargo");
			Crane.chemical_rack AddToTotalSpawned();
			Crane.has_chemicals = true;
			Crane.chemical_rack solid();

			
			//vfx for canister liquid
		//	Crane.chemical_rack_fx = spawn_tag_origin();
		//	Crane.chemical_rack_fx show();
		//	wait .05;
		//	Crane.chemical_rack_fx.origin = (0,0,0);
			//Crane.chemical_rack_fx = spawn("script_model",Crane GetTagOrigin("tag_cargo"));
		//	Crane.chemical_rack_fx LinkToSynchronizedParent (Crane.chemical_rack, "tag_origin", (0,0,0), (0,0,0));
			
			thread PlayOrangeGoo(Crane.chemical_rack);
	
			Crane.chemical_rack.DamageRadius = level.GasMachine.DamageRadius;
			Crane.chemical_rack.MaxDamageAmount = level.GasMachine.MaxDamageAmount;
			Crane.chemical_rack.MinDamageAmount = level.GasMachine.MinDamageAmount;
			
			Crane.chemical_rack thread WatchDamageChemical(Crane);
			
			//	Crane.chemical_rack CloneBrushmodelToScriptmodel(level.GasMachine.chemical_rackCollision);
			Crane.chemical_rack.CraneChemCollision = CollisionData.Collision;
			level.GasMachine.CraneChemCollision = CollisionData.pool;
			Crane.chemical_rack.CraneChemCollision thread entity_path_disconnect_thread(1);
			Crane.chemical_rack.CraneChemCollision.origin = Crane.chemical_rack.origin;
			Crane.chemical_rack.CraneChemCollision.angles = Crane.chemical_rack.angles;
			Crane.chemical_rack.CraneChemCollision LinkToSynchronizedParent(Crane.chemical_rack);
		}
		else
		{
			Crane.has_chemicals = false;
		}
	}
	else
	{
		Crane.has_chemicals = false;
	}
	
	Crane ScriptModelPlayAnimDeltaMotion( "lab2_industrial_crane_anim" , "crane_note_track");

	
	return Crane;
}

PlayOrangeGoo(chemical_rack)
{
	waitframes = 3;
	
	for(i = 0; i < waitframes; i++)
	{
		wait(0.05);
		if(isdefined(chemical_rack) && !IsRemovedEntity(chemical_rack))
		{
			chemical_rack show();
			if(i == 2)
			{
				vfx = playfxontag( getfx( "lab_canister_liquid_orange" ), chemical_rack, "tag_origin");
				chemical_rack show();
			}
		}
		else
		{
			return;
		}
	}
}

PlayCraneSpawnVfX()
{
	// edit level.GasMachine.ParticleSpawnOriginOffset to change particle spawn location.  You can live tune this with debugger attached
	
	TimeToWaitBeforeMeshSpawn = 0.05; // change this to how long you want to wait before mesh is visible. 
	origin_offset = level.GasMachine.ParticleSpawnOriginOffset;
	
	wait(0.05);
	
	if(!isdefined(self))
	{
		return;
	}
	
	vfx_origin = self.origin + origin_offset;
	
	///////////  play VFX here, play particle at vfx_origin
	// 
	// PlayFX( Particle, vfx_origin);  // replace or edit this line to play spawn vfx
	//
	/////////////
	
	wait(TimeToWaitBeforeMeshSpawn); // waiting to let vfx play before mesh spawn
	
	
	// Clean up
	// if you spawn a script_origin or a tag_origin to play the VFX make sure to clean it up here!!!
	//
	// delete(); 
	
	
	return;  // mesh now spawns
}
GetCollision(pool)
{
	if(pool.size > 0)
	{
		CollisionData = SpawnStruct();
		CollisionData.Collision = pool[pool.size - 1];
		pool = array_remove(pool, CollisionData.Collision);
		pool = array_remove_duplicates(pool); // should also remove undefined...
		CollisionData.pool = pool;
		return CollisionData;
	}
	else
		return;
}
AddCollisionToPool(pool)
{
	self notify("entity_path_disconnect_thread"); // for pieces that are rack only but should be okay on top crane collision too
	self unlink();
	self.origin = (0,0,-5000);
	pool = add_to_array(pool, self);
	return pool;
}
WatchDamageChemical(Crane)
{
	self endon("deleted");
	self endon("death");
//	self thread WatchMissileDebug();
	//////////// has to have .health to take damage?  But also don't want auto death notify when .health = 0
	self.health = 10000000;
	self.fakehealth = level.GasMachine.TotalChemCanHealth;
	self setcandamage(true);
	self SetCanRadiusDamage(true);
	self.leaking = false;

		
	while(true)
	{
		if(IsDefined(self))
		{
			
			self waittill("damage", amount, attacker, direction, point, means_of_death, model, tag, part_name, damage_flags, weapon_name);
			if(IsDefined(weapon_name))
			{
				shortWeaponName = maps\mp\_utility::strip_suffix( weapon_name, "_lefthand" );

				switch( shortWeaponName )
				{
					case "concussion_grenade_mp":
					case "flash_grenade_mp":
					case "smoke_grenade_mp":
					case "mp_lab_gas":
					case "mp_lab_gas_explosion":
					case "paint_grenade_mp":
						continue;
				}
				
				if(IsSubStr(weapon_name, "m990"))
				{
					if(means_of_death == "MOD_PISTOL_BULLET")
					{
						amount = 50;
					}
					else if(means_of_death == "MOD_EXPLOSIVE")
					{
						amount = 100;
					}
				}
			}
			if(IsDefined(means_of_death))
			{
				if ( isMeleeMOD(means_of_death) || means_of_death == "MOD_TRIGGER_HURT" )
				{
					continue;
				}
			}
			
			if(IsDefined(attacker))
			{
				attacker maps\mp\gametypes\_damagefeedback::updateDamageFeedback("standard");
			}

			if(Crane.exploding == false)
			{
				self.fakehealth = self.fakehealth + (amount *-1);
				if(self.fakehealth <= 0)
				{
					thread PauseRackSystem();
					self thread BlowItUp(Crane, attacker);
					level notify("Chemical_Exploded");
					break;
				}
				/*
				else if(self.fakehealth <= level.TotalChemicalHealth -10)
				{
					if(self.leaking == false)
					{
						self.leaking = true;
						self thread TimeBomb(attacker);
					}
				}
				*/
			}
			else if(Crane.exploding == true)
			{
				break;
			}
		}
		else if(!IsDefined(self))
		{
			break;
		}
	}
}
/*
WatchMissileDebug()
{
	self waittill("death");
	IPrintLnBold("DEATH EVENT HEALTH ZERO");
}
*/
TimeBomb(attacker)
{
	self endon("deleted");
	self endon("death");
	self thread TimeBombParticle(level.MissileParticles.SparkGreenLoop);
	DamageValue = level.GasMachine.TotalChemCanHealth * 0.05;
	DamageValue = Int(DamageValue);
	while(IsDefined(self))
	{
		wait(1);
		self notify("damage", DamageValue, attacker);
	}
}
TimeBombParticle(Particle)
{
	self thread play_loop_sound_on_entity( "mp_lab_gas_leak_loop01", (0,0,64));
//	PlayFXOnTag(Particle, self,"tag_mid_bottom");
	PlayFXOnTag(Particle, self,"tag_origin");

	
//////////// It should auto stop sound when it dies
//	self waittill("death");
//	self StopLoopSound("mp_lab_gas_leak_loop01");
}
BlowItUp(Crane,attacker)
{
	Crane endon("death");
			    
	DeleteDelay = 0.1;
	Crane.exploding = true;
	
	RackOrigin = self.origin;
	
	if(IsDefined(self) && !IsRemovedEntity(self))
	{
		if(IsDefined(self.CraneChemCollision))
		{
			self notify("entity_path_disconnect_thread");
			self.CraneChemCollision ConnectPaths();
		}
	}
	
	offset = level.GasMachine.ExplosionOffset;
	angle_offset = level.GasMachine.ExplosionAngleOffset;
	ExplosionTag = thread spawn_tag_origin();
	ExplosionTag show();
	ExplosionTag DontInterpolate();
	ExplosionTag.origin = Crane.origin + (0,0,offset);
	ExplosionTag.angles = angle_offset;
	ExplosionTag LinkToSynchronizedParent(Crane, "tag_origin");
	
	PlayFXOnTag(level.MissileParticles.MissileExplosion,ExplosionTag,"tag_origin");
	ExplosionTag thread DeleteExplosionTag(crane, self, 0.05);
	
	sfx_pos = Crane.origin + (0,0,offset);	
	thread aud_play_tank_explosion( sfx_pos );
	
	wait(0.05);
	
	if(IsDefined(self) && !IsRemovedEntity(self))
	{
		if(IsDefined(self.CraneChemCollision))
		{
			level.GasMachine.CraneChemCollision = self.CraneChemCollision AddCollisionToPool(level.GasMachine.CraneChemCollision);
		}
		killfxontag(getfx( "lab_canister_liquid_orange" ), self, "tag_origin" );
		
		//pause so we don't pop out at before explosion
		self delayThread(DeleteDelay ,::unlinkAndDelete);
		//deletes liquid vfx in canisters
		// noself_delayCall( .05, ::killfxontag, getfx( "lab_canister_liquid_orange" ), Crane.chemical_rack_fx, "tag_origin" ); // this doesn't work because the tag gets deleted same time/before the vfx is stopped and it errors
	}
	if(IsDefined(Crane) && !IsRemovedEntity(Crane)) // incase the crane was leaving the area its rack was blowing up
	{
		Crane.has_chemicals = false;
	//	if(IsDefined(Crane.chemical_rack_fx) && !IsRemovedEntity(Crane.chemical_rack_fx))
	//	{
		
			// Crane.chemical_rack_fx thread KillChemRackVFX();
	//	}
	}
	
	wait(DeleteDelay + 0.05);
	
	thread MissileExplosion(attacker, RackOrigin);
	thread MissileChem(level.MissileParticles.GreenSmokeLoop, RackOrigin + (0,0,-70), attacker);

}

DeleteExplosionTag(crane, rack, time)
{	
	rack waittill_any("death" , "deleted");
	wait(time);
	if(isdefined(self) && !IsRemovedEntity(self))
	{
		self delete();
	}
}

KillChemRackVFX()
{
	self endon ("death");
	wait(0.05);
	if(isdefined(self) && !IsRemovedEntity(self))
	{
		killfxontag(getfx( "lab_canister_liquid_orange" ), self, "tag_origin" );
		wait(0.05);
		if(isdefined(self) && !IsRemovedEntity(self))
		{
			self delete();
		}
	}
}
unlinkAndDelete()
{
	if(isdefined(self) && !IsRemovedEntity(self)) // because this gets called after a delaythread
	{
		self Unlink();
		self delete();
	}
}

MissileExplosion(attacker, RackOrigin)
{	
	if(IsDefined(attacker))
	{
	//	wait(0.05);
		RadiusDamage(RackOrigin + (0,0,-44), level.GasMachine.DamageRadius, level.GasMachine.MaxDamageAmount, level.GasMachine.MinDamageAmount, attacker, "MOD_EXPLOSIVE","mp_lab_gas_explosion");
	}
	else
	{
	//	wait(0.05);
		RadiusDamage(RackOrigin + (0,0,-44), level.GasMachine.DamageRadius, level.GasMachine.MaxDamageAmount, level.GasMachine.MinDamageAmount, undefined, "MOD_EXPLOSIVE","mp_lab_gas_explosion");
	}

}
MissileChem(Particle, ChemicalOrigin, attacker)
{
	level.GasParticleTime = level.PauseTime * 0.15;
	SpawnedFX = SpawnFx( Particle, ChemicalOrigin + (0,0,0));

	GasCloud = spawn("script_origin", ChemicalOrigin);
	thread ChemDamageThink(GasCloud, ChemicalOrigin, attacker);
	//TriggerFX(SpawnedFX);
			
	wait(level.GasParticleTime);

	//SpawnedFX delete();
	wait(5);
	GasCloud notify("Gas_Particle_Gone");
	wait(1);
	
	GasCloud DeleteDefined();
	SpawnedFX DeleteDefined();
}
DeleteDefined()
{
	if(isdefined(self))
	{
		self delete();
	}
}
ChemDamageThink(GasCloud, ChemicalOrigin, attacker)
{
	GasCloud endon("Gas_Particle_Gone");
	while(true)
	{
		if(IsDefined(attacker))
		{
			attacker RadiusDamage(ChemicalOrigin,level.GasMachine.GasRange,10,10,attacker,"MOD_TRIGGER_HURT","mp_lab_gas");
		}
		else
		{
			RadiusDamage(ChemicalOrigin,level.GasMachine.GasRange,10,10,undefined,"MOD_TRIGGER_HURT","mp_lab_gas");
		}
		thread FindShockVictims(ChemicalOrigin);
		
		wait(1);
	}
/*	
//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_prison_gas",// 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
	);
	*/
}
FindShockVictims( location )
{
	damageRange = level.GasMachine.GasRange * level.GasMachine.GasRange;
	
	foreach( player in level.players )
	{
		if(!player isUsingRemote())
		{
			Dist2 = DistanceSquared( player.origin, location );
			
			if( (Dist2 < damageRange) && (!player _hasPerk("specialty_stun_resistance")) )
			{
				player thread ShockThink();
			}
		}
	}
}
ShockThink()
{
	if(self.GasTime <= 0)
	{
		self thread fadeInOutGasTrackingOverlay();
		self thread RempveOverlayDeath();
	}
	self.GasTime = 2;
	self shellshock( "mp_lab_gas", 1);
	while(self.GasTime > 0)
	{
		self.GasTime--;
		wait(1);	
	}
	self notify("gas_end");
	self EndGasTrackingOverlay();
}
RempveOverlayDeath()
{
	self endon("gas_end");
	self waittill("death");
	self thread EndGasTrackingOverlayDeath();
}

////////////////////  DONT NEED ANYMORE BECAUSE I NEED TO SHOCK ON PLAYERS INCLUDING FRIENDLY
/*
TrackGasDamage()
{
	while(true)
	{
		if(level.GasMachine.chemical_racksActive == false)
		{
			self waittill("damage", amount, attacker, direction, point, means_of_death, model, tag, part_name, damage_flags, weapon_name);
			if(IsDefined(weapon_name))
			{
				if(weapon_name == "mp_lab_gas")
				{
					 self shellshock( "mp_lab_gas", 4);
				}
			}
		}
		wait(0.25);
	}	
}
*/
ParticleSprayMultipleNode(note,Time)
{
	//Time = Time * 0.25; level.GasMachine.SprayScreenTriggerArray
	
	foreach(pos in level.GasMachine.MachineSparkArray)
	{
		if(pos.script_noteworthy == note)
		{
			self PlaySound("emt_water_spray_hard");
			pos thread ParticleSpray(level.MissileParticles.SprayMachine, pos.angles, Time );
		}
	}
	
	foreach(pos in level.GasMachine.SprayerDripArray)
	{
		if(pos.script_noteworthy == note)
		{
			pos thread SprayerDrip(level.MissileParticles.SprayMachineDrips, pos.angles, Time );
		}
	}
}

/*
SprayPlayerScreen(note,Time)
{
	startpoint = 0; // to do even players check then odd player check to save cycles
	TotalTime = Time;
	WaitTime = 0.05;
	
	foreach(trigger in level.GasMachine.SprayScreenTriggerArray)
	{
		if(trigger.script_noteworthy == note)
		{
			while(TotalTime > 0)
			{
				for(i = startpoint; i < level.players.size; i = i + 2)
				{
					if(Isdefined(level.players[i]) && IsAlive(level.players[i]) && level.players[i] IsTouching(trigger))
					{
						// do vfx here
						// level.players[i] SetWaterSheeting(level.GasMachine.SpraySheetState, 1);
					}
				}
				if(startpoint == 0)
				{
					startpoint = 1;
				}
				else
				{
					startpoint = 0;
				}
				wait(WaitTime);
				TotalTime = TotalTime - WaitTime;
			}
		}
	}
}
*/

StartCanisterFX(fx,waitTime)
{
	wait waitTime;
	
	dripTime = 0;
	loopTime = 0.1;
	
	while(dripTime < 4.25)
	{
		if(isdefined(self) && self.has_chemicals == true)
		{
			fxOrg = self.origin + (0, 0, -8);
			fxAngle = self.angles + (270, 0, 0);
			playfx(fx, fxOrg, AnglesToForward(fxAngle), AnglesToUp(fxAngle));
			wait loopTime;
			dripTime += loopTime;
		}
		else
		{
			return;
		}
	}
}
	
ParticleSpray(Particle,ParticleAngles,Time)
{
	SpawnedFX = SpawnFx( Particle, self.origin, AnglesToForward(ParticleAngles), AnglesToUp(ParticleAngles));
	TriggerFX( SpawnedFX);
	
	if(IsDefined(Time))
	{
		wait(Time);
	} 

	if(IsDefined(SpawnedFX))
	{
		SpawnedFX delete();
	}
}

SprayerDrip(Particle,ParticleAngles,Time)
{
	
	
	if(IsDefined(Time))
	{
		wait(Time);
	} 
	
	PlayFX( Particle, self.origin, AnglesToForward(ParticleAngles), AnglesToUp(ParticleAngles));

	
}

RemoveRack()
{
	if(isdefined(self) && !IsRemovedEntity(self))
	{
		if(isdefined(self.chemical_rack) && !IsRemovedEntity(self.chemical_rack))
		{
			KillFXOnTag( getfx( "lab_canister_liquid_orange" ) ,self.chemical_rack, "tag_origin");		
		}
		wait(0.05);
		
		if(isdefined(self) && !IsRemovedEntity(self))
		{
			if(isdefined(self.chemical_rack) && !IsRemovedEntity(self.chemical_rack))
			{
				if(IsDefined(self.chemical_rack.CraneChemCollision))
				{
					level.GasMachine.CraneChemCollision = self.chemical_rack.CraneChemCollision AddCollisionToPool(level.GasMachine.CraneChemCollision);
				}
			//	self.chemical_rack_fx delete();
				self.chemical_rack unlink();
				self.chemical_rack delete();
			}
			level.GasMachine.CraneCollision = self.CraneCollision AddCollisionToPool(level.GasMachine.CraneCollision);
			self notify("deleted");	
			self delete();
		}
	}
	thread RemoveFromTotalSpawned();

}
PauseRackSystem()
{
	if( !IsDefined(level.PauseTime) )
	{
		level.PauseTime = 20;
	}
	
	
	level.GasMachine.chemical_rackPauseTime = level.PauseTime;
	if (level.GasMachine.chemical_racksActive == true)
	{
			array_thread(level.AlarmSystem.SpinnerArray, ::SpinAlarmsStart);
	}

	
	/////// IF FIRST TIME PAUSED BEFORE BEING RE-PAUSED
	if(level.GasMachine.chemical_racksActive == true)
	{
		thread PlayAlarmLoop();
	}
	else
	{
		// Rack already paused and effects playing. No need to do anything else
		return;
	}
	
	////NOW STOP THE RACK MOVE
	level.GasMachine.chemical_racksActive = false;
	
	while(level.GasMachine.chemical_rackPauseTime > 0)
	{
		wait(1);
		level.GasMachine.chemical_rackPauseTime --;
	}
	
	array_thread(level.AlarmSystem.SpinnerArray, ::SpinAlarmsStop);
	level.GasMachine.chemical_racksActive = true;
	level notify("Restarting_System");
	
	
}

//showemergencylights()
//{
//	horizontal_spinner = GetEnt("horizontal_spinner", "targetname");
//	horizontal_spinner show();
//}

SpinAlarmsStart()
{
	//self show();
	self hide();
	//self RotateVelocity( (0,1440,0), level.PauseTime );
	//wait(0.1);
	//playfxontag(getfx("lab2_crane_red_alarm_2"), self, "TAG_EmergencyLight");
	level thread common_scripts\_exploder::activate_clientside_exploder(200);
}

SpinAlarmsStop()
{
	//self hide();
	self show();
	//wait(0.1);
	//KillFXOnTag(getfx("lab2_crane_red_alarm_2"), self, "TAG_EmergencyLight");
	StopClientExploder(200);
}

PlayAlarmLoop()
{
	TempSoundEnt = spawn("script_origin", level.AlarmSystem.AlarmSoundEnt.origin);
	TempSoundEnt PlayLoopSound("mp_lab_alarm_shutdown01");
	wait(5);
	TempSoundEnt StopSounds();
	wait(0.05);
	TempSoundEnt delete();
}

CreateGasTrackingOverlay()
{
	if ( !IsDefined( self.GasTrackingOverlay ) )
	{
		self.GasTrackingOverlay = newClientHudElem( self );
		self.GasTrackingOverlay.x = 0;
		self.GasTrackingOverlay.y = 0;
		self.GasTrackingOverlay setshader( "lab_gas_overlay", 640, 480 );
		self.GasTrackingOverlay.alignX = "left";
		self.GasTrackingOverlay.alignY = "top";
		self.GasTrackingOverlay.horzAlign = "fullscreen";
		self.GasTrackingOverlay.vertAlign = "fullscreen";
		self.GasTrackingOverlay.alpha = 0;
	}
}
fadeInOutGasTrackingOverlay()
{

	level endon( "game_ended" );
	self endon( "gas_end" );
	self endon( "death" );
	
	if (IsDefined( self.GasTrackingOverlay ) )
	{
		while ( true )
		{
			self.GasTrackingOverlay FadeOverTime( 0.4 );
			self.GasTrackingOverlay.alpha = 1;
			wait( 0.5 );
			self.GasTrackingOverlay FadeOverTime( 0.4 );
			self.GasTrackingOverlay.alpha = 0.5;
			wait( 0.5 );
		}
	}
}
EndGasTrackingOverlay()
{
	if (IsDefined( self.GasTrackingOverlay ) )
	{
		self.GasTrackingOverlay FadeOverTime( 0.2 );
		self.GasTrackingOverlay.alpha = 0.0;
	}
}
EndGasTrackingOverlayDeath()
{
	if (IsDefined( self.GasTrackingOverlay ) )
	{
	//	self.GasTrackingOverlay FadeOverTime( 0.0 );
		self.GasTrackingOverlay.alpha = 0.0;
	}
}

///////////////////////////////////////////////  END MISSILE MOVER
//////////////////////////////////////////////////////////////////////////////////////////////////


/*
######################
## AUDIO FUNCTIONS ##
######################
 */

setup_audio()
{
	// Level Audio Setup.
}

aud_play_tank_explosion( sfx_pos )
{
	//thread snd_play_linked( "lab2_tank_exp", self );
	thread snd_play_in_space( "lab2_tank_exp", sfx_pos );
}

///////////////// LAB DYNAMIC EVENT
aud_transport_chopper()
{
	heli_ent = self;
	heli_sfx_loop = "veh_drone_heavy_lifter_lp";
	thread snd_play_linked_loop( heli_sfx_loop, heli_ent );
	heli_ent thread aud_warning_vo( );
}

aud_warning_vo()
{
	wait(32);
	
	thread snd_play_linked( "vo_heli_warn_ext", self );
	
	wait(6.5);
	
	thread snd_play_linked( "vo_heli_warn_ext", self );
}
aud_building_pre_drop()
{
	thread snd_play_linked( "lab2_building_sway", self );	
}

aud_building_drop()
{
	thread snd_play_linked( "lab2_building_drop", self );
}
