/*
 * Class:  Elite_Shock
 * By: James Bishop A.K.A. *PingFre@K*
 * Copyright 1998-2009 Epic Games, Inc. All Rights Reserved.
*/

class Elite_Shock extends Elite_Weapon
	dependson(MutEM_XX);

/** headshot scale factor when moving slowly or stopped */
var float SlowHeadshotScale;

/** headshot scale factor when running or falling */
var float RunningHeadshotScale;

var class<UTDamageType> HeadShotDamageType;
var float HeadShotDamageMult;

/////////////////////////////////////////////////////////////////
// Bursting Vars
/////////////////////////////////////////////////////////////////

/** How many shots have been fired in burst */
var int BurstCnt;

/** How many shots max in burst before going to cool down */
var int BurstMax;

/** How long to cool down */
var float BurstCoolDownTime;

var Elite_Shock_ProJ ComboTarget;
var bool bWaitForCombo;
var bool bWasACombo;
var bool bRegisterTarget;
var vector ComboStart;
var() int InstaRecoil;


simulated function PostBeginPlay()
{
	super.PostBeginPlay();
	
   if ( class'MutEM_XX'.default.Config_Shock_Rifle.bDoubles )
   {
   BecomeDual();
   }

	if ( Role == ROLE_Authority )
		SetTimer(class'MutEM_XX'.default.Config_Shock_Rifle.fFireInterval * 2, true, 'AmmoRegen');
		
	FireInterval[0]=class'MutEM_XX'.default.Config_Shock_Rifle.fFireInterval;
	FireInterval[1]=class'MutEM_XX'.default.Config_Shock_Rifle.fSecFireInterval;

	AmmoCount=class'MutEM_XX'.default.Config_Shock_Rifle.iAmmoCount;
	LockerAmmoCount=class'MutEM_XX'.default.Config_Shock_Rifle.iAmmoCount;
	MaxAmmoCount=class'MutEM_XX'.default.Config_Shock_Rifle.iMaxAmmo;

//	AimingHelpRadius[0]=class'MutEM_XX'.default.Config_Shock_Rifle.iPriHelpRadius;
//	AimingHelpRadius[1]=class'MutEM_XX'.default.Config_Shock_Rifle.iPriHelpRadius;
//	AimError=class'MutEM_XX'.default.Config_Shock_Rifle.iAimError;

	ShotCost[0]=class'MutEM_XX'.default.Config_Shock_Rifle.iShotCost;
	ShotCost[1]=class'MutEM_XX'.default.Config_Shock_Rifle.iShotCost;

	AIRating=class'MutEM_XX'.default.Config_Shock_Rifle.fAIRating;
	MaxDesireability=class'MutEM_XX'.default.Config_Shock_Rifle.fAIRating;
	CurrentRating=class'MutEM_XX'.default.Config_Shock_Rifle.fAIRating;

	HeadShotDamageMult=class'MutEM_XX'.default.Config_Shock_Rifle.fHeadShotDmgMult;
	SlowHeadshotScale=class'MutEM_XX'.default.Config_Shock_Rifle.fSlowHeadshotScale;
	RunningHeadshotScale=class'MutEM_XX'.default.Config_Shock_Rifle.fRunningHeadshotScale;

//   ZoomedTargetFOV=class'MutEM_XX'.default.Config_Shock_Rifle.iZoomedTargetFOV;
//   ZoomedRate=class'MutEM_XX'.default.Config_Shock_Rifle.iZoomedRate;

   InstantHitDamage[0]=class'MutEM_XX'.default.Config_Shock_Rifle.iInstaDamage;
   InstaRecoil=class'MutEM_XX'.default.Config_Shock_Rifle.iInstaRecoil;
}

function AmmoRegen()
{
   if ( class'MutEM_XX'.default.Config_Shock_Rifle.bAmmoRegeneration )
   {
	   if ( Instigator != None && !IsFiring() && AmmoCount < class'MutEM_XX'.default.Config_Shock_Rifle.iMaxAmmo )
	   {
		   AddAmmo(1);
	   }
   }
}

/**
 * Detect that we are trying to pickup another link gun and switch in to dual mode.
 */
function bool DenyPickupQuery(class<Inventory> ItemClass, Actor Pickup)
{
	if (ItemClass==class && DualMode != EDM_Dual)
	{
      if ( class'MutEM_XX'.default.Config_Shock_Rifle.bDoubles )
      {
		   DualMode = EDM_DualEquipping;
		   BecomeDual();			// Handle any animations/effects locally.
		}
	}
	return super.DenyPickupQuery(ItemClass, Pickup);
}

simulated event SetPosition(UTPawn Holder)
{
	local vector OldSmallWeaponsOffset;

	if (LeftMesh != None)
	{
		switch (GetHand())
		{
			case HAND_Left:
				LeftMesh.SetScale3D(default.Mesh.Scale3D);
            LeftMesh.SetRotation(default.Mesh.Rotation);
				break;
			case HAND_Right:
				LeftMesh.SetScale3D(default.Mesh.Scale3D * vect(1,-1,1));
				LeftMesh.SetRotation(default.Mesh.Rotation * -1);
				break;
			default:
				break;
		}
	}

	OldSmallWeaponsOffset = SmallWeaponsOffset;

		SmallWeaponsOffset.X = 16.0;   ////////////////<--- Change for Shock ///////////////////////
      SmallWeaponsOffset.Y = 0;//6.0; 0;
      SmallWeaponsOffset.Z = -6.0;
      PlayerViewOffset.X  = 17;
      PlayerViewOffset.Y  = 0;//10; 0;
      PlayerViewOffset.Z  = -8;
      FireOffset.X = 12;//0;//20;
      FireOffset.Y = 0;
      FireOffset.Z = 0;

	Super.SetPosition(Holder);

	SmallWeaponsOffset = OldSmallWeaponsOffset;
}

function ClearCombo()
{
	ComboTarget = None;
	bWaitForCombo = false;
}

simulated function StartFire(byte FireModeNum)
{
	if ( bWaitForCombo && (UTBot(Instigator.Controller) != None) )
	{
		if ( (ComboTarget == None) || ComboTarget.bDeleteMe )
			bWaitForCombo = false;
		else
			return;
	}
	Super.StartFire(FireModeNum);
}

function DoCombo()
{
	if ( bWaitForCombo )
	{
		bWaitForCombo = false;
		if ( (Instigator != None) && (Instigator.Weapon == self) )
		{
			StartFire(0);
		}
	}
}

simulated state SecondaryFire extends WeaponFiring
{

	simulated function PlayWeaponAnimation( Name Sequence, float fDesiredDuration, optional bool bLoop, optional SkeletalMeshComponent SkelMesh)
	{
		if (BurstCnt != 1)
		{
			return;
		}

		fDesiredDuration = 0.8667; // @FIXME - Match anims to shot speed  //works fine !Ping

		Global.PlayWeaponAnimation(Sequence, fDesiredDuration, bLoop, SkelMesh);
	}

	simulated function bool TryPutDown()
	{
		bWeaponPutDown = true;
		return true;
	}

	simulated function RefireCheckTimer()
	{
		// if out of ammo, then call weapon empty notification
		if( !HasAnyAmmo() )
		{
			WeaponEmpty();
		}
		else
		{
			// Check to see if we have shot our burst
			if (BurstCnt == BurstMax || !HasAmmo(CurrentFireMode))
			{
				GotoState('WeaponBurstCoolDown');
			}
			else
			{
				// If weapon should keep on firing, then do not leave state and fire again.
				BurstCnt++;
				FireAmmunition();
			}
		}
	}

	simulated function BeginState(name PrevStateName)
	{
		BurstCnt = 1;
		Super.BeginState(PrevStateName);
	}

	simulated function EndState(name NextStateName)
	{
		Super.EndState(NextStateName);
		Cleartimer('RefireCheckTimer');
	}
}

simulated State WeaponBurstCoolDown
{
	simulated function EndState(name NextStateName)
	{
		super.EndState(NextStateName);
		ClearTimer('WeaponReady');
	}

	simulated function BeginState(name PrevStateName)
	{

		local float CoolDowntime;

		if ( UTPawn(Owner) == None || UTPawn(Owner).FireRateMultiplier==1.0 )
		{
			CoolDownTime = BurstCoolDowntime;
		}
		else
		{
			CoolDownTime = BurstCoolDowntime*0.3125;
		}

		SetTimer(CoolDowntime,false,'WeaponReady');

	}

	simulated function WeaponReady()
	{
		// if switching to another weapon, abort firing and put down right away
		if( bWeaponPutDown )
		{
			PutDownWeapon();
		}
		else if ( PendingFire(1) )
		{
			SendToFiringState(1);
		}
		else
		{
			GotoState('Active');
		}
	}
}

simulated state ShockFire extends WeaponFiring
{
	simulated event RefireCheckTimer()
	{
		if ( bWaitForCombo && (UTBot(Instigator.Controller) != None) )
		{
			if ( (ComboTarget == None) || ComboTarget.bDeleteMe )
				bWaitForCombo = false;
			else
			{
				StopFire(CurrentFireMode);
				GotoState('Active');
				return;
			}
		}

		Super.RefireCheckTimer();
	}
}

/**
* Overriden to use GetPhysicalFireStartLoc() instead of Instigator.GetWeaponStartTraceLocation()
* @returns position of trace start for instantfire()
*/
simulated function vector InstantFireStartTrace()
{
	return GetPhysicalFireStartLoc();
}

/**
 * I override GetPhysicalFireStartLoc to allow firing to alternate between Left and Right hand.
 */
simulated function vector GetPhysicalFireStartLoc(optional vector AimDir)
{
	local UTPlayerController PC;
	local vector FireStartLoc, HitLocation, HitNormal, FireDir, FireEnd, ProjBox;
	local Actor HitActor;
	local rotator FireRot;
	local class<Projectile> FiredProjectileClass;
	local int TraceFlags;

	if( Instigator != none )
	{
		PC = UTPlayerController(Instigator.Controller);

        if( UseLeftBarrel() )
        {
            PC.WeaponHand = HAND_Left;
        }
        else
        {
            PC.WeaponHand = HAND_Right;
        }


		FireRot = Instigator.GetViewRotation();
		FireDir = vector(FireRot);
		if (PC == none || PC.bCenteredWeaponFire || PC.WeaponHand == HAND_Centered || PC.WeaponHand == HAND_Hidden)
		{
			FireStartLoc = Instigator.GetPawnViewLocation() + (FireDir * FireOffset.X);
		}
		else if (PC.WeaponHand == HAND_Left)
		{
			FireStartLoc = Instigator.GetPawnViewLocation() + ((FireOffset * vect(1,-1,1)) >> FireRot);           //reverse me
		}
		else
		{
			FireStartLoc = Instigator.GetPawnViewLocation() + (FireOffset >> FireRot);                             //reverse me
		}

		if ( (PC != None) || (CustomTimeDilation < 1.0) )
		{
			FiredProjectileClass = GetProjectileClass();
			if ( FiredProjectileClass != None )
			{
				FireEnd = FireStartLoc + FireDir * ProjectileSpawnOffset;
				TraceFlags = bCollideComplex ? TRACEFLAG_Bullet : 0;
				if ( FiredProjectileClass.default.CylinderComponent.CollisionRadius > 0 )
				{
					FireEnd += FireDir * FiredProjectileClass.default.CylinderComponent.Translation.X;
					ProjBox = FiredProjectileClass.default.CylinderComponent.CollisionRadius * vect(1,1,0);
					ProjBox.Z = FiredProjectileClass.default.CylinderComponent.CollisionHeight;
					HitActor = Trace(HitLocation, HitNormal, FireEnd, Instigator.Location, true, ProjBox,,TraceFlags);
					if ( HitActor == None )
					{
						HitActor = Trace(HitLocation, HitNormal, FireEnd, FireStartLoc, true, ProjBox,,TraceFlags);
					}
					else
					{
						FireStartLoc = Instigator.Location - FireDir*FiredProjectileClass.default.CylinderComponent.Translation.X;
						FireStartLoc.Z = FireStartLoc.Z + FMin(Instigator.EyeHeight, Instigator.CylinderComponent.CollisionHeight - FiredProjectileClass.default.CylinderComponent.CollisionHeight - 1.0);
						PC.WeaponHand = HAND_Right;
						return FireStartLoc;
					}
				}
				else
				{
					HitActor = Trace(HitLocation, HitNormal, FireEnd, FireStartLoc, true, vect(0,0,0),,TraceFlags);
				}
				PC.WeaponHand = HAND_Right;
				return (HitActor == None) ? FireEnd : HitLocation - 3*FireDir;
			}
		}
		PC.WeaponHand = HAND_Right;
		return FireStartLoc;
	}
	PC.WeaponHand = HAND_Right;
   	return Location;
}

function SetComboTarget(Elite_Shock_ProJ S)
{
	if ( !bRegisterTarget || (UTBot(Instigator.Controller) == None) || (Instigator.Controller.Enemy == None) )
		return;

	bRegisterTarget = false;
	bWaitForCombo = true;
	ComboStart = Instigator.Location;
	ComboTarget = S;
	ComboTarget.Monitor(UTBot(Instigator.Controller).Enemy);
}

simulated function ImpactInfo CalcWeaponFire(vector StartTrace, vector EndTrace, optional out array<ImpactInfo> ImpactList)
{
	local ImpactInfo II;
	II = Super.CalcWeaponFire(StartTrace, EndTrace, ImpactList);
	bWasACombo = (II.HitActor != None && Elite_Shock_ProJ(II.HitActor) != none );
	return ii;
}

simulated function ProcessInstantHit( byte FiringMode, ImpactInfo Impact )
{
	local float Scaling;
	local int HeadDamage;

	if( (Role == Role_Authority) && !bUsingAimingHelp )
	{
		if (Instigator == None || VSize(Instigator.Velocity) < Instigator.GroundSpeed * Instigator.CrouchedPct)
		{
			Scaling = SlowHeadshotScale;
		}
		else
		{
			Scaling = RunningHeadshotScale;
		}

		HeadDamage = InstantHitDamage[FiringMode]* HeadShotDamageMult;
		if ( (UTPawn(Impact.HitActor) != None && UTPawn(Impact.HitActor).TakeHeadShot(Impact, HeadShotDamageType, HeadDamage, Scaling, Instigator.Controller)) ||
			(UTVehicleBase(Impact.HitActor) != None && UTVehicleBase(Impact.HitActor).TakeHeadShot(Impact, HeadShotDamageType, HeadDamage, Scaling, Instigator.Controller)) )
		{
			SetFlashLocation(Impact.HitLocation);
			return;
		}
	}

   //Recoil
   if (Instigator != None)
   {
	   Instigator.AddVelocity( Normal(Instigator.Location - Impact.HitLocation) * class'MutEM_XX'.default.Config_Shock_Rifle.iInstaRecoil / Instigator.Mass,
	   Instigator.Location,
	   InstantHitDamageTypes[0] );
   }

	super.ProcessInstantHit( FiringMode, Impact );
}

//-----------------------------------------------------------------
// AI Interface
function float GetAIRating()
{
	local UTBot B;

	B = UTBot(Instigator.Controller);
	if ( (B == None) || (B.Enemy == None) || Pawn(B.Focus) == None )
		return AIRating;

	if ( bWaitForCombo )
		return 1.5;
	if ( !B.ProficientWithWeapon() )
		return AIRating;
	if ( B.Stopped() )
	{
		if ( !B.LineOfSightTo(B.Enemy) && (VSize(B.Enemy.Location - Instigator.Location) < 60) )
			return (AIRating + 0.5);
		return (AIRating + 0.3);
	}
	else if ( VSize(B.Enemy.Location - Instigator.Location) > 2000 )
		return (AIRating + 0.1);
	else if ( B.Enemy.Location.Z > B.Location.Z + 200 )
		return (AIRating + 0.15);

	return AIRating;
}

function float SuggestAttackStyle()
{
	return -0.4;
}

function bool RecommendRangedAttack()
{
	local UTBot B;

	B = UTBot(Instigator.Controller);
	if ( (B == None) || (B.Enemy == None) )
		return true;

	return ( VSize(B.Enemy.Location - Instigator.Location) > 2000 * (1 + FRand()) );
}

defaultproperties
{
	// Weapon SkeletalMesh
	Begin Object Name=FirstPersonMesh
		SkeletalMesh=SkeletalMesh'WP_ShockRifle.Mesh.SK_WP_ShockRifle_1P'
		Materials(0)=MaterialInterface'EM_XX_Content.Shock_Final'
		AnimSets(0)=AnimSet'WP_ShockRifle.Anim.K_WP_ShockRifle_1P_Base'
		Animations=MeshSequenceA
		Rotation=(Yaw=-16384)
		FOV=60.0
	End Object

	// Pickup staticmesh
	Components.Remove(PickupMesh)
	Begin Object Name=PickupMesh
		SkeletalMesh=SkeletalMesh'EM_XX_Content.Mesh.ShockRifle_3P'
      Materials(0)=MaterialInterface'EM_XX_Content.Shock_Final'
	End Object

   InstantHitDamageTypes(0)=Class'EM_XX.Elite_Shock_DMG'

   SlowHeadshotScale=2.000000
   RunningHeadshotScale=2.000000
   HeadShotDamageType=Class'EM_XX.Elite_Shock_HeadShot'
   HeadShotDamageMult=1.000000
   BurstMax=1
   BurstCoolDownTime=0.000010
   DualIconCoordinates=(U=728.000000,V=382.000000,UL=162.000000,VL=45.000000)
   
   DualMode=EDM_DualEquipping

   AmmoCount=20
   LockerAmmoCount=30
   MaxAmmoCount=420
   
	EquipTime=+0.2
	PutDownTime=+0.2

   IconX=400
   IconY=129
   IconWidth=22
   IconHeight=48
   IconCoordinates=(U=728.000000,V=382.000000,UL=162.000000,VL=45.000000)
   CrossHairCoordinates=(V=0.000000)
   InventoryGroup=4
   AttachmentClass=Class'EM_XX.Elite_Shock_Attach'
   QuickPickGroup=0
   WeaponFireAnim(0)="WeaponFireInstiGib"
   WeaponFireAnim(1)="WeaponFireInstiGib"
   WeaponFireSnd(0)=SoundCue'A_Weapon_ShockRifle.Cue.A_Weapon_SR_InstagibFireCue'
   WeaponFireSnd(1)=SoundCue'A_Weapon_ShockRifle.Cue.A_Weapon_SR_AltFireCue'
   WeaponPutDownSnd=SoundCue'A_Weapon_ShockRifle.Cue.A_Weapon_SR_LowerCue'
   WeaponEquipSnd=SoundCue'A_Weapon_ShockRifle.Cue.A_Weapon_SR_RaiseCue'
   WeaponColor=(B=0,G=0,R=255,A=255)

   MuzzleFlashSocket="MF"
   MuzzleFlashPSCTemplate=ParticleSystem'EM_XX_Content.Shock_Muz'
   MuzzleFlashLightClass=None//class'UTGame.UTShockMuzzleFlashLight'

   MuzzleFlashAltPSCTemplate=ParticleSystem'WP_ShockRifle.Particles.P_ShockRifle_MF_Alt'
   MuzzleFlashColor=(B=255,G=120,R=200,A=255)

   PlayerViewOffset=(X=17.000000,Y=10.000000,Z=-8.000000)
   LockerRotation=(Pitch=32768,Yaw=0,Roll=16384)
   WeaponFireTypes(1)=EWFT_Projectile
   FiringStatesArray(0)="ShockFire"
   FiringStatesArray(1)="SecondaryFire"
   WeaponProjectiles(1)=Class'EM_XX.Elite_Shock_ProJ'
   FireInterval(0)=0.700000
   FireInterval(1)=0.530000
   InstantHitDamage(0)=45.000000

   FireOffset=(X=12.000000,Y=10.000000,Z=-10.000000)

   Mesh=FirstPersonMesh
   Priority=900.7
   AIRating=1.540000
   ItemName="Elite Insta-Gib"
   PickupMessage="Elite Insta-Gib"
   PickupSound=SoundCue'A_Pickups.Weapons.Cue.A_Pickup_Weapons_Shock_Cue'
   bExportMenuData=True
   DroppedPickupMesh=PickupMesh
   PickupFactoryMesh=PickupMesh
   Name="Elite Insta-Gib"
}
