#using scripts\codescripts\struct;

#using scripts\shared\callbacks_shared;
#using scripts\shared\challenges_shared;
#using scripts\shared\clientfield_shared;
#using scripts\shared\flagsys_shared;
#using scripts\shared\killcam_shared;
#using scripts\shared\player_shared;
#using scripts\shared\scoreevents_shared;
#using scripts\shared\system_shared;
#using scripts\shared\util_shared;
#using scripts\shared\visionset_mgr_shared;

#using scripts\shared\weapons\_weaponobjects;

    	   	                                                                                                                                         	                                	                                                                                                                                                                                                                                                                                                                                                                    	        	     	              	    	   	               	                                              	                                                           	                               	                     	                                                                                                           	                                                                 	                                                              	                                                                                                                                             	                            	                                     	                                       	                                                                                                              	   	                  	       	                                                    	                   	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            	                                                                                                 	                                    	                                                                                        	           	                        	                                            	                                             	                                                   	                                                             	                                                         	                                                                    	                                                                                                                                                                                                                                	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  	    	         	                                                              	                                                          	                                   	                                   	                                                    	                                       	                                           	     	                                                                                                                                                                                                                                                      	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         	                                                               	        	                                                                                                                              	                                                                                                                     	                               	                                                      	                          
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         	   	                                                                                                                                                                                                                                  	                                                                                                                                                                                                                                                                                                                                                                                                                                                   

       

#precache( "fx", "weapon/fx_lightninggun_arc" );



#namespace lightninggun;

function init_shared()
{
	level.weaponLightningGun = GetWeapon( "hero_lightninggun" );
	level.weaponLightningGunArc = GetWeapon( "hero_lightninggun_arc" );
	level.weaponLightningGunKillcamTime = GetDvarFloat( "scr_lightningGunKillcamTime", 0.35 );
	level.weaponLightningGunKillcamDecelPercent = GetDvarFloat( "scr_lightningGunKillcamDecelPercent", 0.25 );
	level.weaponLightningGunKillcamOffset = GetDvarFloat( "scr_lightningGunKillcamOffset", 150.0 );

	level.lightninggun_arc_range = 300;
	level.lightninggun_arc_range_sq = level.lightninggun_arc_range * level.lightninggun_arc_range;
	level.lightninggun_arc_speed = 650;
	level.lightninggun_arc_speed_sq = level.lightninggun_arc_speed * level.lightninggun_arc_speed;
	level.lightninggun_arc_fx_min_range = 1;
	level.lightninggun_arc_fx_min_range_sq = level.lightninggun_arc_fx_min_range * level.lightninggun_arc_fx_min_range;

	level._effect["lightninggun_arc"] = "weapon/fx_lightninggun_arc";

	callback::add_weapon_damage( level.weaponLightningGun, &on_damage_lightninggun );

/#
	level thread update_dvars();
#/
}

/#
function update_dvars()
{
	while(1)
	{
		wait(1);
		level.weaponLightningGunKillcamTime = GetDvarFloat( "scr_lightningGunKillcamTime", 0.35 );
		level.weaponLightningGunKillcamDecelPercent = GetDvarFloat( "scr_lightningGunKillcamDecelPercent", 0.25 );
		level.weaponLightningGunKillcamOffset = GetDvarFloat( "scr_lightningGunKillcamOffset", 150.0 );
	}
}
#/
	
function lightninggun_start_damage_effects( eAttacker )
{
	self endon( "disconnect" );

/#
	If ( IsGodMode( self ) )
	{
		return;
	}
#/

	self SetElectrifiedState( true );
	self.electrifiedBy = eAttacker;
	self PlayRumbleOnEntity( "lightninggun_victim" );
	
	wait( 2 );
	
	self.electrifiedBy = undefined;
	self SetElectrifiedState( false );
}

function lightninggun_arc_killcam( arc_source_pos, arc_target, arc_target_pos, original_killcam_ent, waitTime )
{
	arc_target.killcamKilledByEnt = create_killcam_entity( original_killcam_ent.origin, original_killcam_ent.angles, level.weaponLightningGunArc );
	arc_target.killcamKilledByEnt killcam::store_killcam_entity_on_entity(original_killcam_ent);

	arc_target.killcamKilledByEnt killcam_move( arc_source_pos, arc_target_pos, waitTime );
}

function lightninggun_arc_fx( arc_source_pos, arc_target, arc_target_pos, distanceSq, original_killcam_ent )
{
	if ( !isdefined( arc_target ) || !isdefined( original_killcam_ent ) )
		return;
	
	waitTime = 0.25;
	if ( level.lightninggun_arc_speed_sq > 100 && distanceSq > 1 )
	{
		waitTime = distanceSq / level.lightninggun_arc_speed_sq;
	}
	
	lightninggun_arc_killcam( arc_source_pos, arc_target, arc_target_pos, original_killcam_ent, waitTime );
	killcamEntity = arc_target.killcamKilledByEnt;
	
	if ( !isdefined( arc_target ) || !isdefined( original_killcam_ent ) )
		return;
	
	if ( distanceSq < level.lightninggun_arc_fx_min_range_sq )
	{
		wait( waitTime );
		
		killcamEntity delete();
		
		if ( isdefined( arc_target ) )
		{
			arc_target.killcamKilledByEnt = undefined;
		}
		//Not playing arcing FX. Enemies too close
		return;
	}

	// this needs to be clientsided.
	fxOrg = spawn( "script_model", arc_source_pos );
	fxOrg SetModel( "tag_origin" );

	fx = PlayFxOnTag( level._effect["lightninggun_arc"], fxOrg, "tag_origin" );
	playsoundatposition( "wpn_lightning_gun_bounce", fxOrg.origin );
	
	fxOrg MoveTo( arc_target_pos, waitTime );
	fxOrg waittill( "movedone" );
	util::wait_network_frame();
	util::wait_network_frame();
	util::wait_network_frame();
	fxOrg delete();
	
	killcamEntity delete();
	
	if ( isdefined( arc_target ) )
	{
		arc_target.killcamKilledByEnt = undefined;
	}
}

function lightninggun_arc( delay, eAttacker, arc_source, arc_source_origin, arc_source_pos, arc_target, arc_target_pos, distanceSq )
{
	if ( delay )
	{
		wait( delay );
		
		if ( !IsDefined( arc_target ) || !IsAlive( arc_target ) )
		{
			return;
		}
		
		// make sure we're still in range after the delay
		distanceSq = DistanceSquared( arc_target.origin, arc_source_origin );
		if ( distanceSq > level.lightninggun_arc_range_sq )
		{
			return;
		}
	}
	
	if ( !isdefined( arc_source ) )
	{
		return;
	}
	
	if ( !isdefined( arc_source.killcamKilledByEnt ) )
	{
		return;
	}

	level thread lightninggun_arc_fx( arc_source_pos, arc_target, arc_target_pos, distanceSq, arc_source.killcamKilledByEnt );
	arc_target thread lightninggun_start_damage_effects( eAttacker );
	arc_target DoDamage( arc_target.health, arc_source_pos, eAttacker, arc_source, "none", "MOD_PISTOL_BULLET", 0, level.weaponLightningGunArc );
}

// arc_source_origin is the origin of the player initially hit, arc_source_pos is the pos of the tag the arc will be emanating from
function lightninggun_find_arc_targets( eAttacker, arc_source, arc_source_origin, arc_source_pos )
{
	delay = 0.05;
	
	if ( !isdefined( eAttacker ) )
		return;

	allEnemyAlivePlayers = util::get_other_teams_alive_players_s( eAttacker.team );
		
	closestPlayers = ArraySort( allEnemyAlivePlayers.a, arc_source_origin, true );

	foreach( player in closestPlayers )
	{
		if ( IsDefined( arc_source ) && player == arc_source )
		{
			continue;
		}

		if ( player player::is_spawn_protected() )
		{
			continue;
		}
		
		distanceSq = DistanceSquared( player.origin, arc_source_origin );
		if ( distanceSq > level.lightninggun_arc_range_sq )
		{
			break;
		}

		if ( eAttacker != player && weaponobjects::friendlyFireCheck( eAttacker, player ) )
		{
			if ( isdefined( self ) && !player DamageConeTrace( arc_source_pos, self ) )
			{
				continue;
			}

			level thread lightninggun_arc( delay, eAttacker, arc_source, arc_source_origin, arc_source_pos, player, player GetTagOrigin( "j_spineupper" ), distanceSq );
			delay += 0.05;
		}
	}
}

function create_killcam_entity( origin, angles, weapon )
{
	killcamKilledByEnt = spawn( "script_model", origin );
	killcamKilledByEnt SetModel( "tag_origin" );
	killcamKilledByEnt.angles = angles;
	killcamKilledByEnt SetWeapon( weapon );
	return killcamKilledByEnt;
}

function killcam_move( start_origin, end_origin, time )
{
	delta = end_origin - start_origin;
	dist = Length( delta );
	delta = VectorNormalize( delta );
	move_to_dist = dist - level.weaponLightningGunKillcamOffset;
	
	end_angles = (0,0,0);
	
	if ( move_to_dist > 0 )
	{
		move_to_pos = start_origin + (delta * move_to_dist);
		self MoveTo( move_to_pos, time, 0, time * level.weaponLightningGunKillcamDecelPercent );
		end_angles = VectorToAngles( delta );	
	}
	else
	{
		delta = end_origin - self.origin;
		end_angles = VectorToAngles( delta );	
	}

	//self RotateTo( end_angles, time, 0, time * level.weaponLightningGunKillcamDecelPercent );
}

function lightninggun_damage_response( eAttacker, eInflictor, weapon, meansOfDeath, damage )
{
	source_pos = eAttacker.origin;
	bolt_source_pos = eAttacker GetTagOrigin( "tag_flash" );

	arc_source = self;
	arc_source_origin = self.origin;
	arc_source_pos = self GetTagOrigin( "j_spineupper" );

	delta = arc_source_pos - bolt_source_pos;
	angles = (0,0,0); //VectorToAngles( delta );
		
	arc_source.killcamKilledByEnt = create_killcam_entity( bolt_source_pos, angles, weapon );
	arc_source.killcamKilledByEnt killcam_move( bolt_source_pos, arc_source_pos, level.weaponLightningGunKillcamTime );
	killcamEntity = arc_source.killcamKilledByEnt;
	
	self thread lightninggun_start_damage_effects( eAttacker );
//	self DoDamage( self.health, source_pos, eAttacker, eAttacker, "none", "MOD_PISTOL_BULLET", 0, level.weaponLightningGunArc );

	wait( 2 );

	if ( !IsDefined( self ) )
	{
		self thread lightninggun_find_arc_targets( eAttacker, undefined, arc_source_origin, arc_source_pos );
		return;
	}

	// get latest positioning
	if ( IsDefined( self.body ) )
	{
		arc_source_origin = self.body.origin;
		arc_source_pos = self.body GetTagOrigin( "j_spineupper" );
	}

	self thread lightninggun_find_arc_targets( eAttacker, arc_source, arc_source_origin, arc_source_pos );

	// wait the maximum amount of time that we could still be arcing.  The other players 
	// will use this killcamEntity
	wait( 0.05 * 9 );
	killcamEntity delete();
	
	if ( IsDefined( arc_source ) )
	{
		arc_source.killcamKilledByEnt = undefined;
	}
}

function on_damage_lightninggun( eAttacker, eInflictor, weapon, meansOfDeath, damage )
{
	if ( "MOD_PISTOL_BULLET" != meansOfDeath && "MOD_HEAD_SHOT" != meansOfDeath )
		return;

	// no additional lightning gun damage response if the player has armor on for now.
//	if ( self flagsys::get( "gadget_armor_on" ) )
//		return;
  	
	self thread lightninggun_damage_response( eAttacker, eInflictor, weapon, meansOfDeath, damage );
}
