#using scripts\codescripts\struct;

#using scripts\shared\array_shared;
#using scripts\shared\clientfield_shared;
#using scripts\shared\flag_shared;
#using scripts\shared\fx_shared;
#using scripts\shared\math_shared;
#using scripts\shared\statemachine_shared;
#using scripts\shared\system_shared;
#using scripts\shared\turret_shared;
#using scripts\shared\util_shared;
#using scripts\shared\vehicle_death_shared;
#using scripts\shared\vehicle_shared;
#using scripts\shared\vehicle_ai_shared;

    	   	                                                                                                                                         	                                	                                                                                                                                                                                                                                                                                                                                                                    	        	     	              	    	   	               	                                              	                                                           	                               	                     	                                                                                                           	                                                                 	                                                              	                                                                                                                                             	                            	                                     	                                       	                                                                                                              	   	                  	       	                                                    	                   	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            	                                                                                                 	                                    	                                                                                        	           	                        	                                            	                                             	                                                   	                                                             	                                                         	                                                                    	                                                                                                                                                                                                                                	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  	    	         	                                                              	                                                          	                                   	                                   	                                                    	                                       	                                           	     	                                                                                                                                                                                                                                                      	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         	                                                               	        	                                                                                                                              	                                                                                                                     	                               	                                                      	                          
       

#namespace auto_turret;

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

function __init__()
{
	vehicle::add_main_callback( "auto_turret",							&turret_initialze );
}

function turret_initialze()
{
	self.health = self.healthdefault;

	if ( isdefined( self.scriptbundlesettings ) )
	{
		self.settings = struct::get_script_bundle( "vehiclecustomsettings", self.scriptbundlesettings );
	}
	else
	{
		self.settings = struct::get_script_bundle( "vehiclecustomsettings", "artillerysettings" );
	}

	sightfov = self.settings.sightfov;
	if ( !isdefined( sightfov ) )
	{
		sightfov = 0;
	}
	self.fovcosine = Cos( sightfov - 0.1 );
	self.fovcosinebusy = Cos( sightfov - 0.1 );

	if ( self.settings.disconnectpaths === true )
	{
		self DisconnectPaths();
	}

	if ( self.settings.ignoreme === true )
	{
		self.ignoreme = true;
	}

	if ( self.settings.laseron === true )
	{
		self laserOn();
	}

	// only auto aim if it can fire. if more specific situation comes we can separate aim assist into a separate GDT field
	if ( self.settings.disablefiring !== true )
	{
		self EnableAimAssist();
	}
	else
	{
		self.noCybercom = true;
	}

	self thread turret::track_lens_flare();

	self.overrideVehicleDamage =&turretCallback_VehicleDamage;
	self.allowFriendlyFireDamageOverride = &turretAllowFriendlyFireDamage;

	//disable some cybercom abilities
	if( IsDefined( level.vehicle_initializer_cb ) )
	{
    	[[level.vehicle_initializer_cb]]( self );
	}

	self.ignoreFireFly = true;
	self.ignoreDecoy = true;
	self vehicle_ai::InitThreatBias();

	defaultRole();
}

function defaultRole()
{
	self vehicle_ai::init_state_machine_for_role( "default" );

    self vehicle_ai::get_state_callbacks( "death" ).update_func = &state_death_update;
    self vehicle_ai::get_state_callbacks( "combat" ).update_func = &state_combat_update;
    self vehicle_ai::get_state_callbacks( "combat" ).exit_func = &state_combat_exit;
    self vehicle_ai::get_state_callbacks( "off" ).enter_func = &state_off_enter;
    self vehicle_ai::get_state_callbacks( "off" ).exit_func = &state_off_exit;
    self vehicle_ai::get_state_callbacks( "emped" ).enter_func = &state_emped_enter;
    self vehicle_ai::get_state_callbacks( "emped" ).update_func = &state_emped_update;
    self vehicle_ai::get_state_callbacks( "emped" ).exit_func = &state_emped_exit;

	self vehicle_ai::add_state( "unaware",
		undefined,
		&state_unaware_update,
		undefined );

	vehicle_ai::add_interrupt_connection( "unaware",	"scripted",	"enter_scripted" );
	vehicle_ai::add_interrupt_connection( "unaware",	"emped",	"emped" );
	vehicle_ai::add_interrupt_connection( "unaware",	"off",		"shut_off" );
	vehicle_ai::add_interrupt_connection( "unaware",	"driving",	"enter_vehicle" );
	vehicle_ai::add_interrupt_connection( "unaware",	"pain",		"pain" );

	vehicle_ai::add_utility_connection( "unaware",	"combat",	&should_switch_to_combat );
	vehicle_ai::add_utility_connection( "combat",	"unaware",	&should_switch_to_unaware );

	vehicle_ai::StartInitialState( "unaware" );
}

// ----------------------------------------------
// State: death
// ----------------------------------------------
function state_death_update( params )
{
	self endon( "death" );

	owner = self GetVehicleOwner();
	if ( isdefined( owner ) )
	{
		self waittill( "exit_vehicle" );
	}

	self SetTurretSpinning( false );
	self turret::toggle_lensflare( false );
	
	params.death_type = "default"; // only do default death for now

	self thread turret_idle_sound_stop();
	self playsound("veh_sentry_turret_dmg_hit");
	self.turretRotScale = 2;
	self rest_turret( params.resting_pitch );
	self vehicle_ai::defaultstate_death_update( params );
}
// death-----------------------------------------


// ----------------------------------------------
// State: unaware
// ----------------------------------------------
function should_switch_to_unaware( current_state, to_state, connection )
{
	if ( !isdefined( self.enemy ) || !self VehSeenRecently( self.enemy, 1.5 ) )
	{
		return 100;
	}

	return 0;
}

function state_unaware_update( params )
{
	self endon( "death" );
	self endon( "change_state" );

	turret_left = true;
	relativeAngle = 0;

	self thread turret_idle_sound();
	self playsound ("mpl_turret_startup");
	self ClearTargetEntity();

	while( true )
	{
		rotScale = self.settings.scanning_speedscale;
		if ( !isdefined( rotScale ) )
		{
			rotScale = 0.01;
		}
		self.turretRotScale = rotScale;

		scanning_arc = self.settings.scanning_arc;
		if ( !isdefined( scanning_arc ) )
		{
			scanning_arc = 0;
		}
		limits = self GetTurretLimitsYaw();
		scanning_arc = min( scanning_arc, limits[0] - 0.1 );
		scanning_arc = min( scanning_arc, limits[1] - 0.1 );

		if ( scanning_arc > 179 )
		{
			if ( self.turretontarget )
			{
				relativeAngle += 90;
				if ( relativeAngle > 180 )
				{
					relativeAngle -= 360;
				}
			}
			scanning_arc = relativeAngle;
		}
		else
		{
			if ( self.turretontarget )
			{
				turret_left = !turret_left;
			}

			if ( !turret_left )
			{
				scanning_arc *= -1;
			}
		}

		scanning_pitch = self.settings.scanning_pitch;
		if ( !isdefined( scanning_pitch ) )
		{
			scanning_pitch = 0;
		}
		self SetTurretTargetRelativeAngles( ( scanning_pitch, scanning_arc, 0 ) );

		self vehicle_ai::evaluate_connections();
		wait 0.5;
	}
}
// unaware---------------------------------------

// ----------------------------------------------
// State: combat
// ----------------------------------------------
function should_switch_to_combat( current_state, to_state, connection )
{
	if ( isdefined( self.enemy ) && isAlive( self.enemy ) && self VehCanSee( self.enemy ) )
	{
		return 100;
	}

	return 0;
}

function state_combat_update( params )
{
	self endon( "death" );
	self endon( "change_state" );
	
	if( isdefined( self.enemy ) )
	{	
		sentry_turret_alert_sound();
		wait 0.5;
	}

	while( 1 )
	{		
		if( isdefined( self.enemy ) && self VehCanSee( self.enemy ) )
		{
			self.turretRotScale = 1;

			if ( isdefined( self.enemy ) && self HasPart( "tag_minigun_spin" ) )
			{
				self SetTurretTargetEnt( self.enemy );
				self SetTurretSpinning( true );
				wait 0.5;
			}

			for( i = 0; i < 3; i++ )
			{
				if( isdefined( self.enemy ) && IsAlive( self.enemy ) && self VehCanSee( self.enemy ) )
				{
					self SetTurretTargetEnt( self.enemy );
					wait 0.1;
					waitTime = RandomFloatRange( 0.4, 1.5 );
					if ( self.settings.disablefiring !== true )
					{
						self sentry_turret_fire_for_time( waitTime, self.enemy );
					}
					else
					{
						wait waitTime;
					}
				}
				
				if( isdefined( self.enemy ) && IsPlayer( self.enemy ) )
					wait RandomFloatRange( 0.3, 0.6 );
				else
					wait RandomFloatRange( 0.3, 0.6 ) * 2;
			}

			self SetTurretSpinning( false );
			
			if( isdefined( self.enemy ) && IsAlive( self.enemy ) && self VehCanSee( self.enemy ) )
			{
				if( IsPlayer( self.enemy ) )
					wait RandomFloatRange( 0.5, 1.3 );
				else
					wait RandomFloatRange( 0.5, 1.3 ) * 2;
			}
		}

		self vehicle_ai::evaluate_connections();
		wait 0.5;
	}
}

function state_combat_exit( params )
{
	self SetTurretSpinning( false );
}

function sentry_turret_fire_for_time( totalFireTime, enemy )
{
	self endon( "death" );
	self endon( "change_state" );
	
	sentry_turret_alert_sound();
	wait .1;//giving time for the alert to play
	
	weapon = self SeatGetWeapon( 0 );
	fireTime = weapon.fireTime;
	time = 0;
	
	is_minigun = false;
	if ( IsSubStr( weapon.name, "minigun" ) )
	{
		is_minigun = true;
		self SetTurretSpinning( true );
		wait 0.5;
	}
	
	while( time < totalFireTime )
	{
		self FireWeapon(0, enemy);
		
		wait fireTime;
		time += fireTime;
	}
	
	if( is_minigun )
	{
		self SetTurretSpinning( false );
	}
}
// combat----------------------------------------

// ----------------------------------------------
// State: off
// ----------------------------------------------
function state_off_enter( params )
{
	self vehicle_ai::defaultstate_off_enter( params );

	self.turretRotScale = 0.5;
	self rest_turret( params.resting_pitch );
}

function state_off_exit( params )
{
	self vehicle_ai::defaultstate_off_exit( params );

	self.turretRotScale = 1.0;
	self playsound ("mpl_turret_startup");
}

function rest_turret( resting_pitch )
{
	if ( !isdefined( resting_pitch ) )
	{
		resting_pitch = self.settings.resting_pitch;
	}
		
	if ( !isdefined( resting_pitch ) )
	{
		resting_pitch = 0;
	}
	
	angles = self GetTagAngles( "tag_turret" ) - self.angles;

	self SetTurretTargetRelativeAngles( ( resting_pitch, angles[1], 0 ) );
}
// off-------------------------------------------

// ----------------------------------------------
// State: emped
// ----------------------------------------------
function state_emped_enter( params )
{
	self vehicle_ai::defaultstate_emped_enter( params );
	PlaySoundAtPosition( "veh_sentry_turret_emp_down", self.origin );
	self.turretRotScale = 0.5;
	self rest_turret( params.resting_pitch );

	params.laserOn = IsLaserOn( self );

	self LaserOff();
	self vehicle::lights_off();

	if ( !isdefined( self.abnormal_status ) )
	{
		self.abnormal_status = spawnStruct();
	}

	self.abnormal_status.emped = true;
	self.abnormal_status.attacker = params.notify_param[1];
	self.abnormal_status.inflictor = params.notify_param[2];

	self vehicle::toggle_emp_fx( true );
}

function state_emped_update( params )
{
	self endon ("death");
	self endon ("change_state");
	
	time = params.notify_param[0];
	assert( isdefined( time ) );
	vehicle_ai::Cooldown( "emped_timer", time );

	while( !vehicle_ai::IsCooldownReady( "emped_timer" ) )
	{
		timeLeft = max( vehicle_ai::GetCooldownLeft( "emped_timer" ), 0.5 );
		wait timeLeft;
	}

	self.abnormal_status.emped = false;
	self vehicle::toggle_emp_fx( false );
	self vehicle_ai::emp_startup_fx();
	self rest_turret( 0 );
	wait 1;

	self vehicle_ai::evaluate_connections();
}

function state_emped_exit( params )
{
	self vehicle_ai::defaultstate_emped_exit( params );

	self.turretRotScale = 1.0;
	self playsound ("mpl_turret_startup");
}
// emped-----------------------------------------

// ----------------------------------------------
// State: scripted
// ----------------------------------------------
function state_scripted_update( params )
{
	self.turretRotScale = 1;
}
// scripted--------------------------------------

function turretAllowFriendlyFireDamage( eInflictor, eAttacker, sMeansOfDeath, weapon )
{
	if ( isdefined( eAttacker ) && isdefined( sMeansOfDeath ) && sMeansOfDeath == "MOD_EXPLOSIVE" )
	{
		return true;
	}

	return false;
}

function turretCallback_VehicleDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, damageFromUnderneath, modelIndex, partName, vSurfaceNormal )
{
	iDamage = vehicle_ai::shared_callback_damage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, damageFromUnderneath, modelIndex, partName, vSurfaceNormal );

	//self HidePart( "tag_shield" );
	return iDamage;
}

function sentry_turret_alert_sound()
{
	self playsound ("veh_turret_alert");
}

function turret_idle_sound()
{
	if ( !isdefined( self.sndloop_ent ) )
	{
		self.sndloop_ent = Spawn("script_origin", self.origin);
		self.sndloop_ent linkto (self);
		self.sndloop_ent PlayLoopSound ("veh_turret_idle");
	}
}

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

	if ( isdefined( self.sndloop_ent ) )
	{
		self.sndloop_ent stoploopsound( .5 );
		wait( 2 );
		self.sndloop_ent delete();
	}
}
