#using scripts\codescripts\struct;

#using scripts\shared\_oob;
#using scripts\shared\array_shared;
#using scripts\shared\callbacks_shared;
#using scripts\shared\challenges_shared;
#using scripts\shared\clientfield_shared;
#using scripts\shared\hud_shared;
#using scripts\shared\killstreaks_shared;
#using scripts\shared\scoreevents_shared;
#using scripts\shared\system_shared;
#using scripts\shared\util_shared;
#using scripts\shared\weapons\_weapons;
#using scripts\shared\vehicle_ai_shared;
#using scripts\shared\vehicle_shared;
#using scripts\shared\vehicles\_amws;

#using scripts\mp\_challenges;
#using scripts\mp\_util;
#using scripts\mp\gametypes\_dev;
#using scripts\mp\gametypes\_spawning;
#using scripts\mp\gametypes\_spawnlogic;
#using scripts\mp\killstreaks\_dogs;
#using scripts\mp\killstreaks\_emp;
#using scripts\mp\killstreaks\_killstreak_bundles;
#using scripts\mp\killstreaks\_killstreak_detect;
#using scripts\mp\killstreaks\_killstreak_hacking;
#using scripts\mp\killstreaks\_killstreakrules;
#using scripts\mp\killstreaks\_killstreaks;
#using scripts\mp\killstreaks\_remote_weapons;
#using scripts\mp\killstreaks\_satellite;
#using scripts\mp\killstreaks\_supplydrop;
#using scripts\mp\killstreaks\_uav;
#using scripts\shared\visionset_mgr_shared;

  
                                                                                                   	  	                                                                    	                     	                 	                                                                         	                       	                                                      	                                                      	                                                       	                                                                                                  	                                                                                                                 	                                                   	                	                                          	                                      	       	  	             	                                                     	                                                                             	                         	                                                                	                                                             	                                                             	                                                                                      	                                                         	                                                         	                                                               	                                                               	                                                   	                                                                	                                                     	                                                	                                                	                                                        	                                                                                                  	                                                                             	                                            	                                                                                    	                                          	                     	                                              	                                        	                 	   
    	   	                                                                                                                                         	                                	                                                                                                                                                                                                                                                                                                                                                                    	        	     	              	    	   	               	                                              	                                                           	                               	                     	                                                                                                           	                                                                 	                                                              	                                                                                                                                             	                            	                                     	                                       	                                                                                                              	   	                  	       	                                                    	                   	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            	                                                                                                 	                                    	                                                                                        	           	                        	                                            	                                             	                                                   	                                                             	                                                         	                                                                    	                                                                                                                                                                                                                                	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  	    	         	                                                              	                                                          	                                   	                                   	                                                    	                                       	                                           	     	                                                                                                                                                                                                                                                      	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         	                                                               	        	                                                                                                                              	                                                                                                                     	                               	                                                      	                          
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         	   	                                                                                                                                                                                                                                  	                                                                                                                                                                                                                                                                                                                                                                                                                                                   

















	



#precache( "string", "KILLSTREAK_EARNED_AI_TANK_DROP" );
#precache( "string", "KILLSTREAK_AI_TANK_NOT_AVAILABLE" );
#precache( "string", "KILLSTREAK_AI_TANK_INBOUND" );
#precache( "string", "KILLSTREAK_AI_TANK_HACKED" );
#precache( "string", "KILLSTREAK_DESTROYED_AI_TANK" );
#precache( "string", "mpl_killstreak_ai_tank" );
#precache( "triggerstring", "MP_REMOTE_USE_TANK" );
#precache( "fx", "killstreaks/fx_agr_emp_stun" );
#precache( "fx", "killstreaks/fx_agr_rocket_flash_1p" );
#precache( "fx", "killstreaks/fx_agr_rocket_flash_3p" );
#precache( "fx", "killstreaks/fx_agr_damage_state" );
#precache( "fx", "killstreaks/fx_agr_explosion" );
#precache( "fx", "killstreaks/fx_agr_drop_box" );

#using_animtree ( "mp_vehicles" );
	
#namespace ai_tank;

function init()
{
	bundle = struct::get_script_bundle( "killstreak",  "killstreak_" + "ai_tank_drop" );

	level.ai_tank_minigun_flash_3p = "killstreaks/fx_agr_rocket_flash_3p";

	killstreaks::register( "ai_tank_drop", "ai_tank_marker", "killstreak_ai_tank_drop", "ai_tank_drop_used",&useKillstreakAITankDrop );

	killstreaks::register_alt_weapon( "ai_tank_drop", "amws_gun_turret" );
	killstreaks::register_alt_weapon( "ai_tank_drop", "amws_launcher_turret" );
	killstreaks::register_alt_weapon( "ai_tank_drop", "amws_gun_turret_mp_player" );
	killstreaks::register_alt_weapon( "ai_tank_drop", "amws_launcher_turret_mp_player" );

	killstreaks::register_remote_override_weapon( "ai_tank_drop", "killstreak_ai_tank" );
	killstreaks::register_strings( "ai_tank_drop", &"KILLSTREAK_EARNED_AI_TANK_DROP", &"KILLSTREAK_AI_TANK_NOT_AVAILABLE", &"KILLSTREAK_AI_TANK_INBOUND", undefined, &"KILLSTREAK_AI_TANK_HACKED" );
	killstreaks::register_dialog( "ai_tank_drop", "mpl_killstreak_ai_tank", "aiTankDialogBundle", "aiTankPilotDialogBundle", "friendlyAiTank", "enemyAiTank", "enemyAiTankMultiple", "friendlyAiTankHacked", "enemyAiTankHacked", "requestAiTank", "threatAiTank" );
	killstreaks::devgui_scorestreak_command( "ai_tank_drop", "Debug Routes", "set devgui_tank routes");

	// TODO: Move to killstreak data
	level.killstreaks["ai_tank_drop"].threatOnKill = true;
	
	remote_weapons::RegisterRemoteWeapon( "killstreak_ai_tank", &"MP_REMOTE_USE_TANK", &startTankRemoteControl, &endTankRemoteControl, false );
	
	level.ai_tank_fov				= Cos( 160 );
	level.ai_tank_turret_weapon		= GetWeapon( "ai_tank_drone_gun" );
	level.ai_tank_turret_fire_rate	= level.ai_tank_turret_weapon.fireTime;
	level.ai_tank_remote_weapon		= GetWeapon( "killstreak_ai_tank" );

	spawns = spawnlogic::get_spawnpoint_array( "mp_tdm_spawn" );
	
	level.ai_tank_damage_fx = "killstreaks/fx_agr_damage_state";
	level.ai_tank_explode_fx = "killstreaks/fx_agr_explosion";
	level.ai_tank_crate_explode_fx = "killstreaks/fx_agr_drop_box";

	anims = [];
	anims[ anims.size ] = %o_drone_tank_missile1_fire;
	anims[ anims.size ] = %o_drone_tank_missile2_fire;
	anims[ anims.size ] = %o_drone_tank_missile3_fire;
	anims[ anims.size ] = %o_drone_tank_missile_full_reload;

	if(!isdefined(bundle.ksMainTurretRecoilForceZOffset))bundle.ksMainTurretRecoilForceZOffset=0;
	if(!isdefined(bundle.ksWeaponReloadTime))bundle.ksWeaponReloadTime=0.5;
	
	visionset_mgr::register_info( "visionset", "agr_visionset", 1, 80, 16, true, &visionset_mgr::ramp_in_out_thread_per_player_death_shutdown, false  );
	
/#
	level thread tank_devgui_think();
#/
	thread register();
}

function register()
{
	clientfield::register( "vehicle", "ai_tank_death", 1, 1, "int" );
	clientfield::register( "vehicle", "ai_tank_missile_fire", 1, 2, "int" );	
	clientfield::register( "vehicle", "ai_tank_stun", 1, 1, "int" );
	clientfield::register( "toplayer", "ai_tank_update_hud", 1, 1, "counter" );
}

function useKillstreakAITankDrop(hardpointType)
{	
	team = self.team;
	
	if( !self supplydrop::isSupplyDropGrenadeAllowed( hardpointType ) )
	{
		return false;
	}

	killstreak_id = self killstreakrules::killstreakStart( hardpointType, team, false, false );
	if ( killstreak_id == -1 )
	{
		return false;
	}
	
	context = SpawnStruct();
	if ( !isdefined( context ) )
	{
		killstreak_stop_and_assert( hardpointType, team, killstreak_id, "Failed to spawn struct for ai tank." );
		return false;
	}
	
	context.radius = level.killstreakCoreBundle.ksAirdropAITankRadius;
	context.dist_from_boundary = 16;
	context.max_dist_from_location = 4;
	context.perform_physics_trace = true;
	context.check_same_floor = true;
	context.isLocationGood = &is_location_good;
	context.objective = &"airdrop_aitank";
	context.killstreakRef = hardpointType;
	context.validLocationSound = level.killstreakCoreBundle.ksValidAITankLocationSound;	
	context.tracemask = (1 << 0) | (1 << 2);
	context.dropTag = "tag_attach";
	context.dropTagOffset = ( -35, 0, 10 );
	
	result = self supplydrop::useSupplyDropMarker( killstreak_id, context );
	
	// the marker is out but the chopper is yet to come
	self notify( "supply_drop_marker_done" );

	if ( !isdefined(result) || !result )
	{
		//if( !self.supplyGrenadeDeathDrop )
			killstreakrules::killstreakStop( hardpointType, team, killstreak_id );
		return false;
	}

	self killstreaks::play_killstreak_start_dialog( "ai_tank_drop", self.team, killstreak_id );	
	self killstreakrules::displayKillstreakStartTeamMessageToAll( "ai_tank_drop" );
	self AddWeaponStat( GetWeapon( "ai_tank_marker" ), "used", 1 );

	return result;
}

function crateLand( crate, category, owner, team, context )
{
	// note: original context is being changed here
	context.perform_physics_trace = false;
	context.dist_from_boundary = 24;
	context.max_dist_from_location = 96;

	if ( !crate is_location_good( crate.origin, context ) || !isdefined( owner ) || team != owner.team || ( owner EMP::EnemyEMPActive() && !owner hasperk("specialty_immuneemp") ) )
	{
		killstreakrules::killstreakStop( category, team, crate.package_contents_id );
		wait( 10 );
		
		if ( isdefined( crate ) )
			crate delete();
		
		return;
	}

	origin = crate.origin;

	crateBottom = BulletTrace( origin, origin + (0, 0, -50), false, crate );
	if ( isdefined( crateBottom ) )
	{
		origin = crateBottom["position"] + (0,0,1);
	}
	
	PlayFX( level.ai_tank_crate_explode_fx, origin, (1, 0, 0), (0, 0, 1) );
	PlaySoundAtPosition( "veh_talon_crate_exp", crate.origin );

	level thread ai_tank_killstreak_start( owner, origin, crate.package_contents_id, category );

	crate delete();
}

function is_location_good( location, context )
{
	return supplydrop::IsLocationGood( location, context ) && valid_location( location );
}

function valid_location( location )
{
	if ( !isdefined( location ) )
		location = self.origin;

	// only do this check if we are not the player, intended for deploy box only
	if ( !isPlayer( self ) )	
	{
		start = self GetCentroid();
		end = location + ( 0, 0, 16 );
	
		trace = PhysicsTrace( start, end, ( 0, 0, 0 ), ( 0, 0, 0 ), self, (1 << 4) );
	
		if ( trace["fraction"] < 1 )
			return false;
	}
	
	if( self oob::IsTouchingAnyOOBTrigger() )
	{
		return false;
	}
	
	return true;
}

function HackedCallbackPre( hacker )
{
	drone = self;
	drone clientfield::set( "enemyvehicle", 2 );
	drone.owner stop_remote();
	drone.owner clientfield::set_to_player( "static_postfx", 0 );
	if( drone.controlled === true )
		visionset_mgr::deactivate( "visionset", "agr_visionset", drone.owner );
	drone.owner remote_weapons::RemoveAndAssignNewRemoteControlTrigger( drone.useTrigger );
	drone remote_weapons::EndRemoteControlWeaponUse( true );
	drone.owner unlink();	
	drone clientfield::set( "vehicletransition", 0 );
}

function HackedCallbackPost( hacker )
{
	drone = self;
	
	hacker remote_weapons::UseRemoteWeapon( drone, "killstreak_ai_tank", false );
	drone notify("WatchRemoteControlDeactivate_remoteWeapons");
	drone.killstreak_end_time = hacker killstreak_hacking::set_vehicle_drivable_time_starting_now( drone );
}

function ConfigureTeamPost( owner, isHacked )
{
	drone = self;
	drone thread tank_watch_owner_events();
}

function ai_tank_killstreak_start( owner, origin, killstreak_id, category )
{
	team = owner.team;
	
	waittillframeend;

	if ( level.gameEnded )
		return;
	
	drone = SpawnVehicle( "spawner_bo3_ai_tank_mp", origin, (0, 0, 0), "talon" );

	if ( !isdefined( drone ) )
	{
		killstreak_stop_and_assert( category, team, killstreak_id, "Failed to spawn ai tank vehicle." );
		return;
	}
	
	drone.settings = struct::get_script_bundle( "vehiclecustomsettings", drone.scriptbundlesettings );

	drone.customDamageMonitor = true;	// Disable the default monitor_damage_as_occupant thread 
	drone.avoid_shooting_owner = true;
	drone.avoid_shooting_owner_ref_tag = "tag_flash_gunner1";

	drone killstreaks::configure_team( "ai_tank_drop", killstreak_id, owner, "small_vehicle", undefined, &ConfigureTeamPost );
	drone killstreak_hacking::enable_hacking( "ai_tank_drop", &HackedCallbackPre, &HackedCallbackPost );
	
	drone killstreaks::setup_health( "ai_tank_drop", 1500, 0 );
	drone.original_vehicle_type = drone.vehicletype;

	drone clientfield::set( "enemyvehicle", 1 );
	drone SetVehicleAvoidance( true );
	drone clientfield::set( "ai_tank_missile_fire", ( 3 ) );
	drone.killstreak_id = killstreak_id;
	drone.type = "tank_drone";
	drone.dontDisconnectPaths = 1;
	drone.isStunned = false;
	drone.soundmod = "drone_land";
	drone.ignore_vehicle_underneath_splash_scalar = true;
	drone.treat_owner_damage_as_friendly_fire = true;
	drone.ignore_team_kills = true;

	drone.controlled = false;
	drone MakeVehicleUnusable();
	
	drone.numberRockets = ( 3 );
	drone.warningShots = 3;
	drone SetDrawInfrared( true );
	
	//set up number for this drone
	if (!isdefined(drone.owner.numTankDrones))
		drone.owner.numTankDrones=1;
	else
		drone.owner.numTankDrones++;
	drone.ownerNumber = drone.owner.numTankDrones;
	
	// make the drone targetable
	Target_Set( drone, (0,0,20) );
	Target_SetTurretAquire( drone, false );
	
	// setup target group for missile lock on monitoring
	drone vehicle::init_target_group();
	drone vehicle::add_to_target_group( drone );
	
	drone setup_gameplay_think( category );
	
	drone.killstreak_end_time = GetTime() + ( 120 * 1000 );
		
	owner remote_weapons::UseRemoteWeapon( drone, "killstreak_ai_tank", false );
	
	drone thread kill_monitor();
	drone thread deleteOnKillbrush( drone.owner );
	drone thread tank_rocket_watch_ai();
	level thread tank_game_end_think(drone);

/#
	drone thread tank_think_debug();
#/
		
/#
	//drone thread tank_debug_health();
#/
}

function get_vehicle_name( vehicle_version )
{	
	switch( vehicle_version )
	{
		case 2:
		default:
			return "spawner_bo3_ai_tank_mp";
			break;
		
		case 1:
			return "ai_tank_drone_mp";
			break;
	}
}

function setup_gameplay_think( category )
{
	drone = self;
	
	drone thread tank_abort_think();
	drone thread tank_team_kill();
	drone thread tank_too_far_from_nav_mesh_abort_think();
	drone thread tank_death_think( category );
	drone thread tank_damage_think();
	drone thread WatchWater();
}


function tank_think_debug()	// self == drone
{
	self endon ( "death" );

	server_frames_to_persist = 1;
	text_scale = 0.5;
	text_alpha = 1.0;
	text_color = ( 1, 1, 1 );

	while ( 1 )
	{
		if ( GetDvarInt( "scr_ai_tank_think_debug" ) == 0 )
		{
			wait 5;
			continue;
		}

		target_name = "unknown";
		target_entity = undefined;

		tank_is_idle = !isdefined( self.enemy ); // NOTE: enemy is set by code-side ai system
		target_entity = self.enemy;
	
		if ( isdefined( target_entity ) && !tank_is_idle )
		{
			if ( isdefined ( target_entity.name ) )
			{
				target_name = target_entity.name;
			}	
			else if ( isdefined ( target_entity.remotename ) )
			{
				target_name = target_entity.remotename;
			}
		}
		
		target_text = ( ( tank_is_idle ) ? "Target: none" : "Target: " + target_name );
		/# Print3d( self.origin, target_text, text_color, text_alpha, text_scale, server_frames_to_persist ); #/
		
		duration_text = "Duration: " + ( (self.killstreak_end_time - GetTime()) * 0.001 );
		/# Print3d( self.origin + ( 0, 0, 12 ), duration_text, text_color, text_alpha, text_scale, server_frames_to_persist ); #/
		
		can_see_text = "Can see: ";
		if ( tank_is_idle )
		{
			can_see_text += "---";
		}
		else
		{
			can_see_text += ( ( self VehCanSee( target_entity ) ) ? "yes" : "no" );
		}
		/# Print3d( self.origin + ( 0, 0, -12 ), can_see_text, text_color, text_alpha, text_scale, server_frames_to_persist ); #/
		
		movement_type_text = "Movement: ";
		if ( isdefined( self.debug_ai_movement_type ) )
		{
			movement_type_text += self.debug_ai_movement_type;
		}
		else
		{
			movement_type_text += "---";
		}
		/# Print3d( self.origin + ( 0, 0, -24 ), movement_type_text, text_color, text_alpha, text_scale, server_frames_to_persist ); #/			
	
		if ( isdefined( self.debug_ai_move_to_point ) )
		{
			/# util::debug_sphere( self.debug_ai_move_to_point + ( 0, 0, 16 ), 10, ( 0.1, 0.95, 0.1 ), 0.9, server_frames_to_persist ); #/
				
			if ( isdefined( self.debug_ai_move_to_points_considered ) )
			{
				foreach( point in self.debug_ai_move_to_points_considered )
				{
					point_color = ( 0.65, 0.65, 0.65 ); // grey-ish
					
					if ( isdefined( point.score ) )
					{
						if ( point.score != 0 )
						{
						    if ( point.score < 0 )
							{
								point_color = ( 0.65, 0.1, 0.1 ); //dark red-ish
							}
						    else if ( point.score > 50 )
						    {
						    	point_color = ( 0.1, 0.65, 0.1 ); // dark green-ish
						    }
						    else
						    {
								point_color = ( 0.95, 0.95, 0.1 ); // yellow-ish
						    }
						    
						    score_text_scale = text_scale;
						  	score_text_color = text_color;
							if ( point.origin != self.debug_ai_move_to_point )
							{
								score_text_scale *= 0.67;
							}
							else
							{
								score_text_scale *= 1.5;
								score_text_color = ( 0.05, 0.98, 0.05 ); // green-ish
							}
						    
							/# Print3d( point.origin + ( 0, 0, 16 ), point.score, score_text_color, text_alpha, score_text_scale, server_frames_to_persist ); #/
						}
					}
						
					if ( point.origin != self.debug_ai_move_to_point )
					{
						/# util::debug_sphere( point.origin + ( 0, 0, 16 ), 3, point_color, 0.5, server_frames_to_persist ); #/
					}
				}
			}
		}
		
		{wait(.05);};
	}
}

function tank_team_kill()
{
	self endon( "death" );
	self.owner waittill( "teamKillKicked" );
	self notify ( "death" );
}

function kill_monitor()
{
	self endon( "death" );
	
	last_kill_vo = 0;
	kill_vo_spacing = 4000;
	
	while(1)
	{
		self waittill( "killed", victim );		

		if ( !isdefined( self.owner ) || !isdefined( victim ) )
			continue;
			
		if ( self.owner == victim )
			continue;
		
		if ( level.teamBased && self.owner.team == victim.team )
			continue;
			
		if ( !self.controlled && last_kill_vo + kill_vo_spacing < GetTime() )
		{
			self killstreaks::play_pilot_dialog_on_owner( "kill", "ai_tank_drop", self.killstreak_id );
		
			last_kill_vo = GetTime();	
		}
	}
}

function tank_abort_think()
{
	tank = self;	

	tank thread killstreaks::WaitForTimeout( "ai_tank_drop", ( 120 * 1000 ), &tank_timeout_callback, "death", "emp_jammed" );
}

function tank_timeout_callback()
{
	self killstreaks::play_pilot_dialog_on_owner( "timeout", "ai_tank_drop" );
	
	self.timed_out = true;

	self notify( "death" );
}

function tank_watch_owner_events()
{
	self notify( "tank_watch_owner_events_singleton" );
	self endon ( "tank_watch_owner_events_singleton" );
	self endon( "death" );
	
	self.owner util::waittill_any( "joined_team", "disconnect", "joined_spectators" );

	self MakeVehicleUsable();
	self.controlled = false;
	
	if ( isdefined( self.owner ) )
	{
		self.owner unlink();
		self clientfield::set( "vehicletransition", 0 );
	}
	
	self MakeVehicleUnusable();
	
	if ( isdefined( self.owner ) && ( self.controlled === true ) )
	{
		visionset_mgr::deactivate( "visionset", "agr_visionset", self.owner );
		self.owner stop_remote();
	}
	
	self.abandoned = true;

	self notify( "death" );
}

function tank_game_end_think(drone)
{
	drone endon( "death" );
	
	level waittill("game_ended");

	drone notify( "death" );
}


function stop_remote() // dead
{
	if ( !isdefined( self ) )
		return;

	self killstreaks::clear_using_remote();
	self remote_weapons::destroyRemoteHUD();	
	self util::clientNotify( "nofutz" );
}


function tank_hacked_health_update( hacker )
{
	tank = self;
	hackedDamageTaken = tank.defaultMaxHealth - tank.hackedHealth;
	assert ( hackedDamageTaken > 0 );
	if ( hackedDamageTaken > tank.damageTaken )
	{
		tank.damageTaken = hackedDamageTaken;
	}
}


function tank_damage_think()
{
	self endon( "death" );

	assert( isdefined( self.maxhealth ) );
	self.defaultMaxHealth = self.maxhealth;
	maxhealth = self.maxhealth; // actual max heath should be set now.

	self.maxhealth = 999999;
	self.health = self.maxhealth;
	self.isStunned = false;
	
	self.hackedHealthUpdateCallback = &tank_hacked_health_update;
	self.hackedHealth = killstreak_bundles::get_hacked_health( "ai_tank_drop" );
	
	low_health = false;
	self.damageTaken = 0;

	for ( ;; )
	{
		self waittill( "damage", damage, attacker, dir, point, mod, model, tag, part, weapon, flags, inflictor, chargeLevel );		
		
		self.maxhealth = 999999;
		self.health = self.maxhealth;

/#
		self.damage_debug = ( damage + " (" + weapon.name + ")" );
#/

		if ( weapon.isEmp && (mod == "MOD_GRENADE_SPLASH"))
		{
			emp_damage_to_apply = killstreak_bundles::get_emp_grenade_damage( "ai_tank_drop", maxhealth );
			
			if ( !isdefined( emp_damage_to_apply ) )
				emp_damage_to_apply = ( maxhealth / 2 );

			self.damageTaken += emp_damage_to_apply;
			damage = 0;
			if ( !self.isStunned && emp_damage_to_apply > 0 )
			{
				self.isStunned = true;
				challenges::stunnedTankWithEMPGrenade( attacker );
				self thread tank_stun( 4 );
			}
		}
		
		if ( !self.isStunned )
		{
			if ( weapon.doStun && (mod == "MOD_GRENADE_SPLASH" || mod == "MOD_GAS") )
			{
				self.isStunned = true;
				self thread tank_stun( 1.5 );
			}
		}
		
		weapon_damage = killstreak_bundles::get_weapon_damage( "ai_tank_drop", maxhealth, attacker, weapon, mod, damage, flags, chargeLevel );		
		
		if ( !isdefined( weapon_damage ) )
		{
			if ( mod == "MOD_RIFLE_BULLET" || mod == "MOD_PISTOL_BULLET" || weapon.name == "hatchet" || (mod == "MOD_PROJECTILE_SPLASH" && weapon.bulletImpactExplode) )
			{
				if ( isPlayer( attacker ) )
				    if ( attacker HasPerk( "specialty_armorpiercing" ) )
						damage += int( damage * level.cac_armorpiercing_data );
				
				if ( weapon.weapClass == "spread")
					damage = damage * 1.5;
				
				weapon_damage = damage * .8;
			}
			
			if ( ( mod == "MOD_PROJECTILE" || mod == "MOD_GRENADE_SPLASH" || mod == "MOD_PROJECTILE_SPLASH" ) && damage != 0 && !weapon.isEmp && !weapon.bulletImpactExplode)
			{				
				weapon_damage = damage * 1;
			}
			
			if ( !isdefined( weapon_damage ) )
			{
				weapon_damage = damage;
			}
		}		

		self.damageTaken += weapon_damage;

		if ( self.controlled )
		{
			self.owner SendKillstreakDamageEvent( int( weapon_damage ) );
			self.owner vehicle::update_damage_as_occupant( self.damageTaken, maxhealth );
		}
		
		if ( self.damageTaken >= maxhealth )
		{
			if( isdefined( self.owner ) )
				self.owner.dofutz = true;
			
			self.health = 0;
			self notify( "death", attacker, mod, weapon );
			return;
		}

		if ( !low_health && self.damageTaken > maxhealth / 1.8 )
		{
			self killstreaks::play_pilot_dialog_on_owner( "damaged", "ai_tank_drop", self.killstreak_id );
			
			self thread tank_low_health_fx();
			low_health = true;
		}
	}
}

function tank_low_health_fx()
{
	self endon( "death" );
	
	self.damage_fx = spawn( "script_model", self GetTagOrigin("tag_origin") + (0,0,-14) );
	if ( !isdefined( self.damage_fx ) )
	{
		// intentionally not adding an AssertMsg() here
		return;
	}

	self.damage_fx SetModel( "tag_origin" );
	self.damage_fx LinkTo(self, "tag_turret", (0,0,-14), (0,0,0) );
	wait ( 0.1 );
	PlayFXOnTag( level.ai_tank_damage_fx, self.damage_fx, "tag_origin" );	
}

function deleteOnKillbrush(player)
{
	player endon("disconnect");
	self endon("death");
		
	killbrushes = GetEntArray( "trigger_hurt","classname" );

	while(1)
	{
		for (i = 0; i < killbrushes.size; i++)
		{
			if (self istouching(killbrushes[i]) )
			{
				if ( isdefined(self) )
				{
					self notify( "death", self.owner );
				}

				return;
			}
		}
		wait( 0.1 );
	}
	
}

function tank_stun( duration )
{	
	self endon( "death" );
	self notify( "stunned" );
	
	self ClearVehGoalPos();
	forward = AnglesToForward( self.angles );
	forward = self.origin + forward * 128;
	forward = forward - ( 0, 0, 64 );
	self SetTurretTargetVec( forward );
	self DisableGunnerFiring( 0, true );
	self LaserOff();
	
	if (self.controlled)
	{
		self.owner FreezeControls( true );
		
		self.owner SendKillstreakDamageEvent( 400 );
	}
	if (isdefined(self.owner.fullscreen_static))
	{
		self.owner thread remote_weapons::stunStaticFX( duration );
	}
	
	self clientfield::set( "ai_tank_stun", 1 );
	
	if( self.controlled )
		self.owner clientfield::set_to_player( "static_postfx", 1 );
	
	wait ( duration );
	
	self clientfield::set( "ai_tank_stun", 0 );
	
	if( self.controlled )
		self.owner clientfield::set_to_player( "static_postfx", 0 );

	if (self.controlled)
	{
		self.owner FreezeControls( false );
	}

	self DisableGunnerFiring( 0, false );
	self.isStunned = false;
}

function emp_crazy_death()
{
	self clientfield::set( "ai_tank_stun", 1 );
	self notify ("death");
	
	time = 0;
	randomAngle = RandomInt(360);
	while (time < 1.45)
	{
		self SetTurretTargetVec(self.origin + AnglesToForward((RandomIntRange(305, 315), int((randomAngle + time * 180)), 0)) * 100);
		if (time > 0.2)
		{
			self FireWeapon( 1 );
			if ( RandomInt(100) > 85)
			{
				rocket = self FireWeapon( 0 );

				if ( isdefined( rocket ) )
				{
					rocket.from_ai = true;
				}
			}
		}
		time += 0.05;
		{wait(.05);};
	}
	self clientfield::set( "ai_tank_death", 1 );

	PlayFX( level.ai_tank_explode_fx, self.origin, (0, 0, 1) );
	PlaySoundAtPosition( "wpn_agr_explode", self.origin );
	{wait(.05);};
	self hide();
}

function tank_death_think( hardpointName )
{	
	team = self.team;
	killstreak_id = self.killstreak_id;

	self waittill( "death", attacker, damageFromUnderneath, weapon );
	//	self waittill( "death", attacker, damageFromUnderneath, weapon, point, dir, modType );

	if ( !isdefined( self ) )
	{
		killstreak_stop_and_assert( hardpointName, team, killstreak_id, "Failed to handle death. A." );
		return;
	}

	self.dead = true;
	self LaserOff();
	
	self ClearVehGoalPos();
	
	not_abandoned = ( !isdefined( self.abandoned ) || !self.abandoned );

	if ( self.controlled == true )
	{
		self.owner SendKillstreakDamageEvent( 600 );
		self.owner remote_weapons::destroyRemoteHUD();	
	}

	self clientfield::set( "ai_tank_death", 1 );
	stunned = false;
	
	settings = self.settings;

	if ( isdefined( settings ) && ( self.timed_out === true || self.abandoned === true ) )
	{
		fx_origin = self GetTagOrigin( (isdefined(settings.timed_out_death_tag_1)?settings.timed_out_death_tag_1:"tag_origin") );
		PlayFx( (isdefined(settings.timed_out_death_fx_1)?settings.timed_out_death_fx_1:level.ai_tank_explode_fx), (isdefined(fx_origin)?fx_origin:self.origin), ( 0, 0, 1 ) );
		PlaySoundAtPosition( (isdefined(settings.timed_out_death_sound_1)?settings.timed_out_death_sound_1:"wpn_agr_explode"), self.origin );
	}
	else
	{
		PlayFX( level.ai_tank_explode_fx, self.origin, ( 0, 0, 1 ) );
		PlaySoundAtPosition( "wpn_agr_explode", self.origin );
	}


	if ( not_abandoned )
	{
		util::wait_network_frame();
		
		if ( !isdefined( self ) )
		{
			killstreak_stop_and_assert( hardpointName, team, killstreak_id, "Failed to handle death. B." );
			return;
		}
	}

	if ( self.controlled )
	{
		self Ghost(); // keep the view for player with the dead by using ghost, otherwise, will end up at feet of player
	}
	else
	{
		self Hide();
	}

	if (isdefined(self.damage_fx))
	{
		self.damage_fx delete();
	}
	
	attacker = self [[ level.figure_out_attacker ]]( attacker );

	if ( isdefined( attacker ) && IsPlayer( attacker ) && isdefined( self.owner ) && attacker != self.owner )
	{
		if ( self.owner util::IsEnemyPlayer( attacker ) )
		{
			
			scoreevents::processScoreEvent( "destroyed_aitank", attacker, self.owner, weapon );
			LUINotifyEvent( &"player_callout", 2, &"KILLSTREAK_DESTROYED_AI_TANK", attacker.entnum );		
			attacker AddWeaponStat( weapon, "destroyed_aitank", 1 );
			controlled = false;
			if ( isdefined( self.wasControlledNowDead ) && self.wasControlledNowDead )
			{
				attacker AddWeaponStat( weapon, "destroyed_controlled_killstreak", 1 );
				controlled = true;
			}
			
			attacker challenges::destroyScoreStreak( weapon, controlled, true );
			attacker challenges::destroyNonAirScoreStreak_PostStatsLock( weapon );
			attacker AddWeaponStat( weapon, "destroy_aitank_or_setinel", 1 );
			
			self killstreaks::play_destroyed_dialog_on_owner( "ai_tank_drop", self.killstreak_id );
		}
		else
		{
			//Destroyed Friendly Killstreak 
		}
	}

	if ( not_abandoned )
	{
		self util::waittill_any_timeout( 2.0, "remote_weapon_end" );
	
		if ( !isdefined( self ) )
		{
			killstreak_stop_and_assert( hardpointName, team, killstreak_id, "Failed to handle death. C." );
			return;
		}		
	}
		
	killstreakrules::killstreakStop( hardpointName, team, self.killstreak_id );

	if ( isdefined( self.aim_entity ) )
		self.aim_entity delete();

	self delete();
}

function killstreak_stop_and_assert( hardpoint_name, team, killstreak_id, assert_msg )
{
	killstreakrules::killstreakStop( hardpoint_name, team, killstreak_id );
	AssertMsg( assert_msg );
}
	
function tank_too_far_from_nav_mesh_abort_think()
{
	self endon( "death" );

	not_on_nav_mesh_count = 0;

	for ( ;; )
	{
		wait( 1 );

		not_on_nav_mesh_count = ( isdefined( GetClosestPointOnNavMesh( self.origin, ( 40 * 12 ) ) ) ? 0 : not_on_nav_mesh_count + 1 );

		if ( not_on_nav_mesh_count >= 4 )
		{
			self notify( "death" );
		}
	}
}

function tank_has_radar()
{
	if ( level.teambased )
	{
		return ( uav::HasUAV( self.team ) || satellite::HasSatellite( self.team ) );
	}

	return ( uav::HasUAV( self.entnum ) || satellite::HasSatellite( self.entnum ) );
}

function tank_get_player_enemies( on_radar )
{
	enemies = [];
	
	if ( !isdefined( on_radar ) )
	{
		on_radar = false;
	}

	if ( on_radar )
	{
		time = GetTime();
	}
	
	foreach( teamKey, team in level.alivePlayers )
	{
		if ( level.teambased && teamKey == self.team )
		{
			continue;
		}

		foreach( player in team )
		{
			if ( !valid_target( player, self.team, self.owner ) )
			{
				continue;
			}
			
			if ( on_radar )
			{
				if ( time - player.lastFireTime > 3000 && !tank_has_radar() )
				{
					continue;
				}
			}

			enemies[ enemies.size ] = player;
		}
	}

	return enemies;
}

function tank_compute_enemy_position()
{
	enemies = tank_get_player_enemies( false );
	position = undefined;

	if ( enemies.size )
	{
		x = 0;
		y = 0;
		z = 0;
		
		foreach( enemy in enemies )
		{
			x += enemy.origin[0];
			y += enemy.origin[1];
			z += enemy.origin[2];
		}

		x /= enemies.size;
		y /= enemies.size;
		z /= enemies.size;

		position = ( x, y, z );
	}

	return position;
}

function valid_target( target, team, owner )
{
	if ( !isdefined( target ) )
	{
		return false;
	}

	if ( !IsAlive( target ) )
	{
		return false;
	}

	if ( target == owner )
	{
		return false;
	}
	
	if ( IsPlayer( target ) )
	{
		if ( target.sessionstate != "playing" )
		{
			return false;
		}

		if ( isdefined( target.lastspawntime ) && GetTime() - target.lastspawntime < 3000 )
		{
			return false;
		}
		
		if ( target hasPerk( "specialty_nottargetedbyaitank" ) )
		{
			return false;
		}

/#
		if ( target IsInMoveMode( "ufo", "noclip" ) )
		{
			return false;
		}
#/
	}

	if ( level.teambased )
	{
		if ( isdefined( target.team ) && team == target.team )
		{
			return false;
		}
	}

	if ( isdefined( target.owner ) && target.owner == owner )
	{
		return false;
	}

	if ( isdefined( target.script_owner ) && target.script_owner == owner )
	{
		return false;
	}
	
	if ( ( isdefined( target.dead ) && target.dead ) )
	{
		return false;
	}

	if ( isdefined( target.targetname ) && target.targetname == "riotshield_mp" )
	{
		if ( isdefined( target.damageTaken ) && target.damageTaken >= GetDvarInt( "riotshield_deployed_health" ) )
		{
			return false;
		}
	}

	return true;
}

function startTankRemoteControl( drone ) // self == player
{
	drone MakeVehicleUsable();
	drone ClearVehGoalPos();
	drone ClearTurretTarget();
	drone LaserOff();
	
	drone.treat_owner_damage_as_friendly_fire = false;
	drone.ignore_team_kills = false;
	
	if ( isdefined( drone.PlayerDrivenVersion ) )
		drone SetVehicleType( drone.PlayerDrivenVersion );

	drone usevehicle( self, 0 );
	drone clientfield::set( "vehicletransition", 1 );
	

	drone MakeVehicleUnusable();
	drone SetBrake( false );

	drone thread tank_rocket_watch( self );
	drone thread vehicle::monitor_missiles_locked_on_to_me( self );
	
	self vehicle::set_vehicle_drivable_time( ( 120 * 1000 ), drone.killstreak_end_time );
	self vehicle::update_damage_as_occupant( (isdefined(drone.damageTaken)?drone.damageTaken:0), (isdefined(drone.defaultmaxhealth)?drone.defaultmaxhealth:100) );
	drone update_client_ammo( drone.numberRockets, true );
	
	visionset_mgr::activate( "visionset", "agr_visionset", self, 1, 90000, 1 );
}

function endTankRemoteControl( drone, exitRequestedByOwner )
{
	not_dead = !( isdefined( drone.dead ) && drone.dead );

	if ( isdefined( drone.owner ) )	
	{
		drone.owner remote_weapons::destroyRemoteHUD();
	}
	
	drone.treat_owner_damage_as_friendly_fire = true;
	drone.ignore_team_kills = true;
	
	if( drone.classname == "script_vehicle")
		drone MakeVehicleUnusable();

	if ( isdefined( drone.original_vehicle_type ) && not_dead )
		drone SetVehicleType( drone.original_vehicle_type );
	
	if ( isdefined( drone.owner ) )
		drone.owner vehicle::stop_monitor_missiles_locked_on_to_me();

	if( exitRequestedByOwner && not_dead )
	{
		drone vehicle_ai::set_state( "combat" );
	}
	
	if ( drone.cobra === true && not_dead )
		drone thread amws::cobra_retract();

	if ( isdefined( drone.owner ) && ( drone.controlled === true ) )
		visionset_mgr::deactivate( "visionset", "agr_visionset", drone.owner );
	
	drone clientfield::set( "vehicletransition", 0 );
}

function perform_recoil_missile_turret( player ) // self == drone
{
	bundle = level.killstreakBundle["ai_tank_drop"];
	Earthquake( 0.4, 0.5, self.origin, 200 );
	self perform_recoil( "tag_barrel",  ( ( ( isdefined( self.controlled ) && self.controlled ) ? bundle.ksMainTurretRecoilForceControlled : bundle.ksMainTurretRecoilForce ) ), bundle.ksMainTurretRecoilForceZOffset );
	
	if ( self.controlled && isdefined( player ) )
	{
		player PlayRumbleOnEntity( "sniper_fire" );
	}
}

function perform_recoil( recoil_tag, force_scale_factor, force_z_offset ) // self == drone
{
	angles = self GetTagAngles( recoil_tag );
	dir = AnglesToForward( angles );
	self LaunchVehicle( dir * force_scale_factor, self.origin + ( 0, 0, force_z_offset ), false );
}

function update_client_ammo( ammo_count, driver_only_update = false ) // self == vehicle
{
	if ( !driver_only_update )
	{
		self clientfield::set( "ai_tank_missile_fire", ammo_count );
	}

	if ( self.controlled )
	{
		self.owner clientfield::increment_to_player( "ai_tank_update_hud", 1 );
	}
}

function tank_rocket_watch( player )
{
	self endon( "death" );
	player endon( "stopped_using_remote");

	if ( self.numberRockets <= 0 )
	{
		self reload_rockets( player );
	}

	if ( !self.isStunned )
	{
		self DisableDriverFiring( false );
	}
		
	while( true )
	{
		player waittill( "missile_fire", missile );
		missile.ignore_team_kills = self.ignore_team_kills;
		
		self.numberRockets--;
		self update_client_ammo( self.numberRockets );

		self perform_recoil_missile_turret( player );
		
		if ( self.numberRockets <= 0 )
		{
			self reload_rockets( player );
		}
	}
}

function tank_rocket_watch_ai()
{
	self endon( "death" );
	
	while( true )
	{
		self waittill( "missile_fire", missile );
		missile.ignore_team_kills = self.ignore_team_kills;
		missile.killCamEnt = self;
	}
}

function reload_rockets( player )
{
	bundle = level.killstreakBundle["ai_tank_drop"];
	self DisableDriverFiring( true );
	
	// setup the "reload" time for the player's vehicle HUD
	weapon_wait_duration_ms = Int( bundle.ksWeaponReloadTime * 1000 );
	player SetVehicleWeaponWaitDuration( weapon_wait_duration_ms );
	player SetVehicleWeaponWaitEndTime( GetTime() + weapon_wait_duration_ms );

	wait ( bundle.ksWeaponReloadTime );

	self.numberRockets = ( 3 );
	self update_client_ammo( self.numberRockets );

	wait (0.4);

	if ( !self.isStunned )
	{
		self DisableDriverFiring( false );
	}
}













function WatchWater()
{
	self endon( "death" );
			
	inWater = false;
	while( !inWater )
	{
		wait ( 0.3 );
		trace = physicstrace( self.origin + ( 0, 0, ( 42 ) ), self.origin + ( 0, 0, ( 12 ) ), ( -2, -2, -2 ), (  2,  2,  2 ), self, ( (1 << 2) ));
		inWater = ( trace["fraction"] < ( (( 42 ) - ( 36 )) / ( ( 42 ) - ( 12 ) ) ) && trace["fraction"] != 1.0 );
		
		waterTraceDistanceFromEnd = ( ( 42 ) - ( 12 ) ) - ( trace["fraction"] * ( ( 42 ) - ( 12 ) ) );
		static_alpha = min( 1.0, waterTraceDistanceFromEnd / ( ( 36 ) - ( 12 ) ) );

		// design does not want beeping audio for when water is an issue, maybe a different kind of audio?
		if ( isdefined( self.owner ) && self.controlled )
			self.owner clientfield::set_to_player( "static_postfx", ( ( static_alpha > 0.0 ) ? 1 : 0 ) );
	}

	if( isdefined( self.owner ) )
		self.owner.dofutz = true;

	self notify( "death" );
}

/#
function tank_devgui_think()
{
	SetDvar( "devgui_tank", "" );

	for ( ;; )
	{
		wait( 0.25 );

		level.ai_tank_turret_fire_rate = level.ai_tank_turret_weapon.fireTime;

		if ( GetDvarString( "devgui_tank" ) == "routes" )
		{
			devgui_debug_route();
			SetDvar( "devgui_tank", "" );
		}
	}
}

function tank_debug_patrol( node1, node2 )
{
	self endon( "death" );
	self endon( "debug_patrol" );

	for( ;; )
	{
		self SetVehGoalPos( node1.origin, true );
		self waittill( "reached_end_node" );

		wait( 1 );

		self SetVehGoalPos( node2.origin, true );
		self waittill( "reached_end_node" );

		wait( 1 );
	}
}

function devgui_debug_route()
{
	iprintln( "Choose nodes with 'A' or press 'B' to cancel" );
	nodes = dev::dev_get_node_pair();

	if ( !isdefined( nodes ) )
	{
		iprintln( "Route Debug Cancelled" );
		return;
	}

	iprintln( "Sending talons to chosen nodes" );

	tanks = GetEntArray( "talon", "targetname" );

	foreach( tank in tanks )
	{
		tank notify( "debug_patrol" );
		tank thread tank_debug_patrol( nodes[0], nodes[1] );
	}
}

function tank_debug_hud_init()
{
	host = util::getHostPlayer();

	while ( !isdefined( host ) )
	{
		wait( 0.25 );
		host = util::getHostPlayer();
	}

	x = 80;
	y = 40;

	level.ai_tank_bar = NewClientHudElem( host );
	level.ai_tank_bar.x = x + 80;
	level.ai_tank_bar.y = y + 2;
	level.ai_tank_bar.alignX = "left";
	level.ai_tank_bar.alignY = "top";
	level.ai_tank_bar.horzAlign = "fullscreen";
	level.ai_tank_bar.vertAlign = "fullscreen";
	level.ai_tank_bar.alpha = 0;
	level.ai_tank_bar.foreground = 0;
	level.ai_tank_bar setshader( "black", 1, 8 );

	level.ai_tank_text = NewClientHudElem( host );
	level.ai_tank_text.x = x + 80;
	level.ai_tank_text.y = y;
	level.ai_tank_text.alignX = "left";
	level.ai_tank_text.alignY = "top";
	level.ai_tank_text.horzAlign = "fullscreen";
	level.ai_tank_text.vertAlign = "fullscreen";
	level.ai_tank_text.alpha = 0;
	level.ai_tank_text.fontScale = 1;
	level.ai_tank_text.foreground = 1;
}

function tank_debug_health()
{
	self.damage_debug = "";

	level.ai_tank_bar.alpha = 1;
	level.ai_tank_text.alpha = 1;
	
	for ( ;; )
	{
		{wait(.05);};

		if ( !isdefined( self ) || !IsAlive( self ) )
		{
			level.ai_tank_bar.alpha = 0;
			level.ai_tank_text.alpha = 0;
			return;
		}

		width = self.health / self.maxhealth * 300;
		width = int( max( width, 1 ) );
		level.ai_tank_bar setShader( "black", width, 8 );

		str = ( self.health + "  Last Damage: " + self.damage_debug );
		level.ai_tank_text SetText( str );
	}
}

#/
