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

class Elite_Rocket_Launcher extends UTWeap_RocketLauncher
	dependson(MutEM_XX);

enum EDualMode
{
	EDM_SingleWeapon,
	EDM_DualEquipping,
	EDM_Dual,
	EDM_Max
};

// Dual Stuff  *****************************************************

/** This holds the maximum number of shots that can be queued with 2 Guns */
//var int MaxDualLoadCount;

/** if true, we are a dual Elite_Weapon */
var repnotify EDualMode	DualMode;

var UIRoot.TextureCoordinates DualIconCoordinates;

/** The Left Handed Mesh */
var() editinline UTSkeletalMeshComponent LeftMesh;

var protected UTSkeletalMeshComponent OverlayLeftMesh;
/** timeseconds when last fired */
var float LastFireTime;

/** if the last shot was fired from the left Elite_Weapon*/
var bool bLastFiredLeft;

/** If true this weapon won't play the reload anim */
var bool bLoaded;

var name WeaponDualEqipAnim;

/** Amount of time it takes to equip the left gun */
var float DualEquiptime;

/** Used internally to track which gun to fire */
var int ShotCount;

/** If we become a dual while firing, force return to the active state in order to properly re-initialize */
var bool bForceReturnToActive;

var MaterialInstanceConstant WeaponMaterialInstance;
var MaterialInstanceConstant LeftWeaponMaterialInstance;
/** Left versions of everything */

/** Muzzle flash PSC and Templates*/
var UTParticleSystemComponent	EliteMachine_MuzzleFlashPSC[2];

/** dynamic light */
var	UTExplosionLight		EliteMachine_MuzzleFlashLight[2];

/** anim played for left mesh when idling */
var name LeftIdleAnim;

/** The Recoil */
var int RocketRecoil;

// Rocket Stuff  ******  Redefined  **********************************
var bool 				bLoctOnTarget;
var Actor 				LoctTarget;

replication
{
	if (bNetDirty)
		DualMode;
	// Server->Client properties
	if (Role == ROLE_Authority)
		bLoctOnTarget, LoctTarget;
}

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

	if ( Role == ROLE_Authority )
		SetTimer(class'MutEM_XX'.default.Config_RL_BFG.fPriFireInterval * 2, true, 'AmmoRegen');

	FireInterval[0]=class'MutEM_XX'.default.Config_RL_BFG.fPriFireInterval;
	FireInterval[1]=class'MutEM_XX'.default.Config_RL_BFG.fSecFireInterval;
	
	AltFireQueueTimes[0]=class'MutEM_XX'.default.Config_RL_BFG.fSecFireInterval;
	AltFireQueueTimes[1]=class'MutEM_XX'.default.Config_RL_BFG.fSecFireInterval;
	AltFireQueueTimes[2]=class'MutEM_XX'.default.Config_RL_BFG.fSecFireInterval;
	AltFireQueueTimes[3]=class'MutEM_XX'.default.Config_RL_BFG.fSecFireInterval;
	AltFireQueueTimes[4]=class'MutEM_XX'.default.Config_RL_BFG.fSecFireInterval;
	AltFireQueueTimes[5]=class'MutEM_XX'.default.Config_RL_BFG.fSecFireInterval;
	AltFireQueueTimes[6]=class'MutEM_XX'.default.Config_RL_BFG.fSecFireInterval;
	AltFireQueueTimes[7]=class'MutEM_XX'.default.Config_RL_BFG.fSecFireInterval;
	AltFireQueueTimes[8]=class'MutEM_XX'.default.Config_RL_BFG.fSecFireInterval;
	AltFireQueueTimes[9]=class'MutEM_XX'.default.Config_RL_BFG.fSecFireInterval;
	AltFireLaunchTimes[0]= class'MutEM_XX'.default.Config_RL_BFG.fSecFireInterval;
	AltFireLaunchTimes[1]= class'MutEM_XX'.default.Config_RL_BFG.fSecFireInterval;
	AltFireLaunchTimes[2]= class'MutEM_XX'.default.Config_RL_BFG.fSecFireInterval;
	AltFireLaunchTimes[3]= class'MutEM_XX'.default.Config_RL_BFG.fSecFireInterval;
	AltFireLaunchTimes[4]= class'MutEM_XX'.default.Config_RL_BFG.fSecFireInterval;
	AltFireLaunchTimes[5]= class'MutEM_XX'.default.Config_RL_BFG.fSecFireInterval;
	AltFireLaunchTimes[6]= class'MutEM_XX'.default.Config_RL_BFG.fSecFireInterval;
	AltFireLaunchTimes[7]= class'MutEM_XX'.default.Config_RL_BFG.fSecFireInterval;
	AltFireLaunchTimes[8]= class'MutEM_XX'.default.Config_RL_BFG.fSecFireInterval;
	AltFireLaunchTimes[9]= class'MutEM_XX'.default.Config_RL_BFG.fSecFireInterval;
	AltFireEndTimes[0]=class'MutEM_XX'.default.Config_RL_BFG.fSecFireInterval;
	AltFireEndTimes[1]=class'MutEM_XX'.default.Config_RL_BFG.fSecFireInterval;
	AltFireEndTimes[2]=class'MutEM_XX'.default.Config_RL_BFG.fSecFireInterval;
	AltFireEndTimes[3]=class'MutEM_XX'.default.Config_RL_BFG.fSecFireInterval;
	AltFireEndTimes[4]=class'MutEM_XX'.default.Config_RL_BFG.fSecFireInterval;
	AltFireEndTimes[5]=class'MutEM_XX'.default.Config_RL_BFG.fSecFireInterval;
	AltFireEndTimes[6]=class'MutEM_XX'.default.Config_RL_BFG.fSecFireInterval;
	AltFireEndTimes[7]=class'MutEM_XX'.default.Config_RL_BFG.fSecFireInterval;
	AltFireEndTimes[8]=class'MutEM_XX'.default.Config_RL_BFG.fSecFireInterval;
	AltFireEndTimes[9]=class'MutEM_XX'.default.Config_RL_BFG.fSecFireInterval;

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

	SpreadDist=class'MutEM_XX'.default.Config_RL_BFG.ispreaddist;
	GrenadeSpreadDist=class'MutEM_XX'.default.Config_RL_BFG.igrenadespreaddist;

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

	AimingHelpRadius[0]=class'MutEM_XX'.default.Config_RL_BFG.iHelpRadius;
	AimingHelpRadius[1]=class'MutEM_XX'.default.Config_RL_BFG.iHelpRadius;
	AimError=class'MutEM_XX'.default.Config_RL_BFG.iAimError;

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

	ConsoleLockAim=class'MutEM_XX'.default.Config_RL_BFG.iHelpRadius;
	LockAim=class'MutEM_XX'.default.Config_RL_BFG.iHelpRadius;
	LockChecktime=class'MutEM_XX'.default.Config_RL_BFG.fAcquireTime;
	LockAcquireTime=class'MutEM_XX'.default.Config_RL_BFG.fAcquireTime;
	LockRange=class'MutEM_XX'.default.Config_RL_BFG.iLockRange;	

	RocketRecoil=class'MutEM_XX'.default.Config_RL_BFG.iRocketRecoil;
}

function AmmoRegen()
{
   if ( class'MutEM_XX'.default.Config_RL_BFG.bAmmoRegeneration )
   {
	   if ( Instigator != None && !IsFiring() && AmmoCount < class'MutEM_XX'.default.Config_RL_BFG.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_RL_BFG.bDoubles )
      {
		   DualMode = EDM_DualEquipping;
		   BecomeDual();			// Handle any animations/effects locally.
		}
	}
	return super.DenyPickupQuery(ItemClass, Pickup);
}

/**
  * Adjust weapon equip and fire timings so they match between PC and console
  * This is important so the sounds match up.
  */
/*simulated function AdjustWeaponTimingForConsole()
{
	local int i;

	Super.AdjustWeaponTimingForConsole();

	For ( i=0; i<AltFireQueueTimes.Length; i++ )
	{
		AltFireQueueTimes[i] = AltFireQueueTimes[i]/1.1;
	}
	For ( i=0; i<AltFireEndTimes.Length; i++ )
	{
		AltFireEndTimes[i] = AltFireEndTimes[i]/1.1;
	}
	For ( i=0; i<AltFireLaunchTimes.Length; i++ )
	{
		AltFireLaunchTimes[i] = AltFireLaunchTimes[i]/1.1;
	}

	DualEquipTime = DualEquipTime/1.1;
}
*/
/*********************************************************************************************
 * Target Locking
 *********************************************************************************************/

/**
 * The function checks to see if we are locked on a target
 */

simulated function FireAmmunition()
{
	Super.FireAmmunition();

	if ( Role == ROLE_Authority )
	{
		AdjustLockTarget( none );
		LastValidTargetTime = 0;
		PendingLockedTarget = None;
		LastLockedOnTime = 0;
		PendingLockedTargetTime = 0;
	}
}

/**
 *  This function is used to adjust the LockTarget.
 *  Called by UpdateLockTarget() only when NewLockTarget is different from LockTarget
 */
event AdjustLockTarget(actor NewLockTarget)
{
	if (NewLockTarget == None)
	{
		// Clear the lock
		if (bLoctOnTarget)
		{
			LoctTarget = None;

			bLoctOnTarget = false;

			if (LockLostSound != None && Instigator != None && Instigator.IsHumanControlled() )
			{
				PlayerController(Instigator.Controller).ClientPlaySound(LockLostSound);
			}
		}
	}
	else
	{
		// Set the lock
		bLoctOnTarget = true;
		LoctTarget = NewLockTarget;
		LockedTargetPRI = (Pawn(NewLockTarget) != None) ? Pawn(NewLockTarget).PlayerReplicationInfo : None;
		if ( LockAcquiredSound != None && Instigator != None  && Instigator.IsHumanControlled() )
		{
			PlayerController(Instigator.Controller).ClientPlaySound(LockAcquiredSound);
		}
	}
}

/**
 * Given an actor (TA) determine if we can lock on to it.  By default only allow locking on
 * to pawns.  Some weapons may want to be able to lock on to other actors.
 */
//native function bool CanLockOnTo(Actor TA);

auto simulated state Inactive
{
	simulated function BeginState(name PreviousStateName)
	{
		Super.BeginState(PreviousStateName);

		if ( Role == ROLE_Authority )
		{
			bTargetLockingActive = false;
			AdjustLockTarget(None);
		}
	}

	simulated function EndState(Name NextStateName)
	{
		Super.EndState(NextStateName);

		if ( Role == ROLE_Authority )
		{
			bTargetLockingActive = true;
		}
	}
}

simulated event Destroyed()
{
	AdjustLockTarget(none);
	super.Destroyed();
}

/**
 * Access to HUD and Canvas.
 * Event always called when the InventoryManager considers this Inventory Item currently "Active"
 * (for example active weapon)
 *
 * @param	HUD			- HUD with canvas to draw on
 */
simulated function ActiveRenderOverlays( HUD H )
{
	local UTPlayerController PC;

	PC = UTPlayerController(Instigator.Controller);
	if ( PC == None )
	{
		return;
	}
	if ( PC.bNoCrosshair )
	{
		return;
	}
	if ( PC.bSimpleCrosshair )
	{
		CrossHairCoordinates = SimpleCrosshairCoordinates;
		super.DrawWeaponCrosshair( H );
	}
	else
	{
		CrossHairCoordinates = default.CrosshairCoordinates;
		DrawWeaponCrosshair( H );
	}
	if ( bLoctOnTarget && (LoctTarget != None) && (Instigator != None) )
	{
		if ( (LocalPlayer(PC.Player) == None) || !LocalPlayer(PC.Player).GetActorVisibility(LoctTarget) )
		{
			return;
		}
		DrawLockedOn( H );
	}
	else
	{
		bWasLocked = false;
	}
}

/**
 * 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);

		//  Here I reversed what couldn't be reversed fixing which gun the proj comes from
		if (DualMode == EDM_Dual)
		{
		   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 >> FireRot);
		   }
		   else
		   {
			   FireStartLoc = Instigator.GetPawnViewLocation() + ((FireOffset * vect(1,-1,1)) >> FireRot);
		   }
		}
      else
		{
		   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);
		   }
		   else
		   {
			   FireStartLoc = Instigator.GetPawnViewLocation() + (FireOffset >> FireRot);
		   }
		}

		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;
}

/*********************************************************************************************
 * Load more than 3 rockets
 *********************************************************************************************/

simulated function DrawLFMData(HUD Hud)
{
	local string s;
	local vector2d CrosshairSize;
	local float XL, YL, x,y,PickupScale, ScreenX, ScreenY;
	local UTHUD	H;
	local int DrawLoaded;
	local rotator CrosshairRotation;
	local float TimeRemaining;

	if ( LoadedShotCount == 0 )
	{
		Global.DrawWeaponCrosshair(HUD);
		return;
	}

	H = UTHUD(HUD);
	if ( H == None )
		return;

	// Apply pickup scaling
	if ( H.LastPickupTime > WorldInfo.TimeSeconds - 0.3 )
	{
		if ( H.LastPickupTime > WorldInfo.TimeSeconds - 0.15 )
		{
			PickupScale = (1 + 5 * (WorldInfo.TimeSeconds - H.LastPickupTime));
		}
		else
		{
			PickupScale = (1 + 5 * (H.LastPickupTime + 0.3 - WorldInfo.TimeSeconds));
		}
	}
	else
	{
		PickupScale = 1.0;
	}

	DrawLoaded = Min(LoadedShotCount-1, MaxLoadCount);
	if ( DrawLoaded > 2 )
	{
		DrawLoaded = DrawLoaded - 3;
	}

 	CrosshairSize.Y = H.ConfiguredCrosshairScaling * CrosshairScaling * LoadedIconCoords[DrawLoaded].VL * PickupScale * H.Canvas.ClipY/768;
  	CrosshairSize.X = CrosshairSize.Y * LoadedIconCoords[DrawLoaded].UL/LoadedIconCoords[DrawLoaded].VL;

	X = H.Canvas.ClipX * 0.5;
	Y = H.Canvas.ClipY * 0.5;
	ScreenX = X - (CrosshairSize.X * 0.5);
	ScreenY = Y - (CrosshairSize.Y * 0.5);

	TimeRemaining = GetTimerCount('RefireCheckTimer');
	if ( LoadedShotCount < MaxLoadCount )
	{
		CrosshairRotation.Yaw = 21845.3333 * (LoadedShotCount - 1.0 + FMin(1.0,2.0*TimeRemaining/GetFireInterval(1)));
	}
	H.Canvas.DrawColor = H.BlackColor;
	H.Canvas.SetPos(ScreenX, ScreenY);
	H.Canvas.DrawRotatedTile(CrosshairImage, CrosshairRotation, CrosshairSize.X, CrosshairSize.Y, LoadedIconCoords[DrawLoaded].U, LoadedIconCoords[DrawLoaded].V, LoadedIconCoords[DrawLoaded].UL,LoadedIconCoords[DrawLoaded].VL);

	H.Canvas.DrawColor = UTHUD(HUD).bGreenCrosshair ? UTHUD(HUD).Default.LightGreenColor : Default.CrosshairColor;
	H.Canvas.SetPos(ScreenX, ScreenY);
	H.Canvas.DrawRotatedTile(CrosshairImage, CrosshairRotation, CrosshairSize.X, CrosshairSize.Y, LoadedIconCoords[DrawLoaded].U, LoadedIconCoords[DrawLoaded].V, LoadedIconCoords[DrawLoaded].UL,LoadedIconCoords[DrawLoaded].VL);

	if (LoadedFireMode != RFM_Spread)
	{
		S = (LoadedFireMode == RFM_Spiral) ? SpiralString : GrenadeString;

		H.Canvas.Font = class'UTHUD'.static.GetFontSizeIndex(0);
		H.Canvas.StrLen(S,XL,YL);
		H.Canvas.SetPos( 0.5*H.Canvas.ClipX - 0.5*XL, 0.5*H.Canvas.ClipY + 0.71*CrosshairSize.Y);
		H.Canvas.DrawText(s);
	}
}

/*********************************************************************************************
 * Fire more than 3 rockets
 *********************************************************************************************/

function FireLoad()
{
	local int i,j,k;
	local vector SpreadVector;
	local rotator Aim;
	local float theta;
   	local vector Firelocation, RealStartLoc, X,Y,Z;
	local Projectile	SpawnedProjectile;
	local Elite_Rocket_Loaded FiredRockets[10];
	local bool bCurl;
	local byte FlockIndex;

	// this is to get the location of the "popped up" rocket launcher tube
	if(LoadedShotCount == 1 && CurrentFireMode == 1)
	{
		RealStartLoc = GetPhysicalFireStartLoc() + vect(0,0,3);
	}
	else
	{
		// this is the location where the projectile is spawned
		RealStartLoc = GetPhysicalFireStartLoc();
	}


	Aim = GetAdjustedAim( RealStartLoc );			// get fire aim direction

	GetViewAxes(X,Y,Z);

	for (i = 0; i < LoadedShotCount; i++)
	{
		if (LoadedFireMode == RFM_Grenades || LoadedFireMode == RFM_Spread)
		{
			// Give them some gradual spread.
			theta = GetSpreadDist() * PI / 32768.0 * (i - float(LoadedShotCount - 1) / 2.0);
			SpreadVector.X = Cos(theta);
			SpreadVector.Y = Sin(theta);
			SpreadVector.Z = 0.0;

			SpawnedProjectile = Spawn(GetProjectileClass(),,, RealStartLoc, Rotator(SpreadVector >> Aim));
			if ( SpawnedProjectile != None )
			{
				if (LoadedFireMode == RFM_Grenades)
				{
					UTProjectile(SpawnedProjectile).TossZ += (frand() * 200 - 100);
				}
				SpawnedProjectile.Init(SpreadVector >> Aim);
			}
		}
		else
		{
			Firelocation = RealStartLoc - 2 * ((Sin(i * 2 * PI / MaxLoadCount) * 8 - 7) * Y - (Cos(i * 2 * PI / MaxLoadCount) * 8 - 7) * Z ) - X * 8 * FRand();
			SpawnedProjectile = Spawn(GetProjectileClass(),,, FireLocation, Aim);
			if ( SpawnedProjectile != None )
			{
				SpawnedProjectile.Init(vector(Aim));
				FiredRockets[i] = Elite_Rocket_Loaded(SpawnedProjectile);
			}
		}

		if (LoadedFireMode != RFM_Grenades && bLoctOnTarget && Elite_Rocket_Seeking(SpawnedProjectile) != None)
		{
			Elite_Rocket_Seeking(SpawnedProjectile).Seeking = LoctTarget;
		}
	}

	// Initialize the rockets so they flock towards each other
	if ( !bLoctOnTarget && (LoadedFireMode == RFM_Spiral) )
	{
		FlockIndex++;
		bCurl = false;

		// To get crazy flying, we tell each projectile in the flock about the others.
		for ( i = 0; i < LoadedShotCount; i++ )
		{
			if ( FiredRockets[i] != None )
			{
				FiredRockets[i].bCurl = bCurl;
				FiredRockets[i].FlockIndex = FlockIndex;

				j=0;
				for ( k=0; k<LoadedShotCount; k++ )
				{
					if ( (i != k) && (FiredRockets[k] != None) )
					{
						FiredRockets[i].Flock[j] = FiredRockets[k];
						j++;
					}
				}
				bCurl = !bCurl;
				if ( WorldInfo.NetMode != NM_DedicatedServer )
				{
					FiredRockets[i].SetTimer(0.1, true, 'FlockTimer');
				}
			}
		}
	}
}

/**
 * If we are locked on, we need to set the Seeking projectiles LoctTarget.
 */

simulated function Projectile ProjectileFire()
{
	local Projectile SpawnedProjectile;

	SpawnedProjectile = super.ProjectileFire();
	if (bLoctOnTarget && Elite_Rocket_Seeking(SpawnedProjectile) != None)
	{
		Elite_Rocket_Seeking(SpawnedProjectile).Seeking = LoctTarget;
	}

	return SpawnedProjectile;
}

/**
 * We override GetProjectileClass to swap in a Seeking Rocket if we are locked on.
 */

function class<Projectile> GetProjectileClass()
{
	if (CurrentFireMode == 1 && LoadedFireMode == RFM_Grenades)
	{
		return GrenadeClass;
	}
	else if (bLoctOnTarget)
	{
		return SeekingRocketClass;
	}
	else if ( LoadedShotCount > 1 )
	{
		return LoadedRocketClass;
	}
	else
	{
		return WeaponProjectiles[CurrentFireMode];
	}
}

simulated function PlayFiringSound()
{
	if (CurrentFireMode == 1 && LoadedFireMode == RFM_Grenades)
	{
		MakeNoise(1.0);
		WeaponPlaySound(GrenadeFireSound);
	}
	else
	{
		Super.PlayFiringSound();
	}
}

simulated event ReplicatedEvent(name VarName)
{
	if (VarName == 'DualMode')
	{
		BecomeDual();
	}
	else if ( VarName == 'AmmoCount')
	{
		UpdateAmmoVisibility();
	}

	Super.ReplicatedEvent(VarName);
}


/*********************************************************************************************
 * States
 *********************************************************************************************/


/*********************************************************************************************
 * State WeaponLoadAmmo
 * In this state, ammo will continue to load up until MaxLoadCount has been reached.  It's
 * similar to the firing state
 *********************************************************************************************/

simulated state WeaponLoadAmmo
{
	simulated function RefireCheckTimer()
	{
		// Epic hardcoded this to 3 here so here is our hack to allow for more
		// If we have ammo, load a shot
		if ( HasAmmo(CurrentFireMode) && (LoadedShotCount >= 3 && LoadedShotCount < MaxLoadCount) )
		{
			// Play Loading Sound
			MakeNoise(0.1);

			WeaponPlaySound(WeaponLoadedSnd);
			WeaponPlaySound(RocketLoadedSound);
			LoadedShotCount++;
			ConsumeAmmo(CurrentFireMode);
		}

		super.RefireCheckTimer();
	}

// @ FIX ME I want the Dual Animations


	simulated function AddProjectile()
	{
		WeaponPlaySound(AltFireSndQue[Clamp(LoadedShotCount, 0, AltFireSndQue.Length - 1)]);

		// Play the que animation
		if ( Instigator.IsFirstPerson() && (LoadedShotCount < 10) )
		{
			PlayWeaponAnimation( LoadUpAnimList[LoadedShotCount], AltFireQueueTimes[LoadedShotCount]);
			if ( DualMode == EDM_Dual )
		    {
			PlayWeaponAnimation( LoadUpAnimList[LoadedShotCount], AltFireQueueTimes[LoadedShotCount],,LeftMesh);
		    }
		}
		TimeWeaponFiring(1);
	}
}

/*********************************************************************************************
 * State WeaponPlayingFire
 * In this state, the weapon will have already spawned the projectiles and is just playing out
 * the firing animations.  When finished, it returns to the Active state
 *
 * We use 2 animations, one for firing and one of spin down in order to allow better tweaking of
 * the timing.
 *********************************************************************************************/

simulated State WeaponPlayingFire
{
	simulated function PlayFiringAnim()
	{
	local int index;

	// Allow animations to work with more than 3 rockets
	index = max(LoadedShotCount,1);
	if ( index > 3 )
		{
		index = index - 3;
		}

	PlayWeaponAnimation( WeaponAltFireLaunch[Index-1], AltFireLaunchTimes[Index-1]);
    if ( DualMode == EDM_Dual )
		{
		PlayWeaponAnimation( WeaponAltFireLaunch[Index-1], AltFireLaunchTimes[Index-1],,LeftMesh);
		}

	SetTimer(AltFireLaunchTimes[Index-1],false,'FireAnimDone');
	}

	simulated function PlayFiringEndAnim()
	{
	local int index;

	// Allow animations to work with more than 3 rockets
	index = max(LoadedShotCount,1);
	if ( index > 3 )
		{
		index = index - 3;
		}

	PlayWeaponAnimation( WeaponAltFireLaunchEnd[Index-1], AltFireEndTimes[Index-1],,LeftMesh);
	if ( DualMode == EDM_Dual )
		{
		PlayWeaponAnimation( WeaponAltFireLaunchEnd[Index-1], AltFireEndTimes[Index-1],UseLeftBarrel(),LeftMesh);
		}

	SetTimer(AltFireEndTimes[Index-1],false,'FireAnimEnded');
	}
}


/////////////////////////////////////////////////////////////////////
// Dual Equip from Enforcer
// This code will work with most Skeletal Meshes
/////////////////////////////////////////////////////////////////////

// * Set the Overlay Meshes

simulated function CreateOverlayMesh()
{
	local UTPawn P;

	if ( WorldInfo.NetMode != NM_Client )
	{
		P = UTPawn(Instigator);
		if ( (P == None) || !P.bUpdateEyeHeight )
		{
			return;
		}
	}

	Super.CreateOverlayMesh();

	if (WorldInfo.NetMode != NM_DedicatedServer && LeftMesh != None && OverlayLeftMesh == None)
	{
		OverlayLeftMesh = new(outer) LeftMesh.Class;
		if (OverlayLeftMesh != None)
		{
			OverlayLeftMesh.SetScale(1.0);
			OverlayLeftMesh.SetOwnerNoSee(LeftMesh.bOwnerNoSee);
			OverlayLeftMesh.SetDepthPriorityGroup(SDPG_Foreground);
			OverlayLeftMesh.SetSkeletalMesh(LeftMesh.SkeletalMesh);
			OverlayLeftMesh.AnimSets = LeftMesh.AnimSets;
			OverlayLeftMesh.SetParentAnimComponent(LeftMesh);
			OverlayLeftMesh.SetFOV(LeftMesh.FOV);
		}
//		else
//		{
//			`Warn("Could not create Weapon Overlay mesh for" @ self @ LeftMesh);
//		}
	}
}


// * Setup the overlay skins

simulated function SetSkin(Material NewMaterial)
{
	local int i,Cnt;

	Super.SetSkin(NewMaterial);

	if ( LeftMesh != none && NewMaterial == None )	// Clear the materials
	{
		if ( default.Mesh.Materials.Length > 0 )
		{
			Cnt = Default.Mesh.Materials.Length;
			for (i=0;i<Cnt;i++)
			{
				LeftMesh.SetMaterial( i, Default.Mesh.GetMaterial(i) );
			}
		}
		else if (LeftMesh.Materials.Length > 0)
		{
			Cnt = LeftMesh.Materials.Length;
			for ( i=0; i < Cnt; i++ )
			{
				LeftMesh.SetMaterial(i,none);
			}
		}
	}
	else if( LeftMesh != none )
	{
		if ( default.LeftMesh.Materials.Length > 0 || Leftmesh.GetNumElements() > 0 )
		{
			Cnt = default.LeftMesh.Materials.Length > 0 ? default.LeftMesh.Materials.Length : LeftMesh.GetNumElements();
			for ( i=0; i < Cnt; i++ )
			{
				LeftMesh.SetMaterial(i,NewMaterial);
			}
		}
	}

	if( NewMaterial==none )
	{
			WeaponMaterialInstance = MaterialInstanceConstant(Mesh.Materials[0]);
			if(WeaponMaterialInstance == none)
			{
				WeaponMaterialInstance = Mesh.CreateAndSetMaterialInstanceConstant(0);
			}

			// if we have a leftmesh
			if( LeftMesh != none )
			{
				LeftWeaponMaterialInstance = MaterialInstanceConstant(LeftMesh.Materials[0]);
				if(LeftWeaponMaterialInstance == none)
				{
					LeftWeaponMaterialInstance = LeftMesh.CreateAndSetMaterialInstanceConstant(0);
				}
			}
	}
}


// * Extend support to allow for multiple muzzle flashes

simulated function AttachMuzzleFlash()
{
	local int i;

	bMuzzleFlashAttached = true;
	if (MuzzleFlashPSCTemplate != none)
	{
		EliteMachine_MuzzleFlashPSC[0]  = new(Outer) class'UTParticleSystemComponent';
		EliteMachine_MuzzleFlashPSC[1]  = new(Outer) class'UTParticleSystemComponent';

		for (i=0;i<2;i++)
		{
			EliteMachine_MuzzleFlashPSC[i].SetDepthPriorityGroup(SDPG_Foreground);
			EliteMachine_MuzzleFlashPSC[i].DeactivateSystem();
			EliteMachine_MuzzleFlashPSC[i].SetColorParameter('MuzzleFlashColor', MuzzleFlashColor);
		}

		EliteMachine_MuzzleFlashPSC[0].SetFOV(UTSkeletalMeshComponent(Mesh).FOV);
		SkeletalMeshComponent(Mesh).AttachComponentToSocket(EliteMachine_MuzzleFlashPSC[0], MuzzleFlashSocket);
		if (LeftMesh != None)
		{
			EliteMachine_MuzzleFlashPSC[1].SetFOV(LeftMesh.FOV);
			LeftMesh.AttachComponentToSocket(EliteMachine_MuzzleFlashPSC[1], MuzzleFlashSocket);
		}
	}
}

// * Detach weapon from skeletal mesh
// *
// * @param	SkeletalMeshComponent weapon is attached to.

simulated function DetachMuzzleFlash()
{
	bMuzzleFlashAttached = false;
	if (EliteMachine_MuzzleFlashPSC[0] != None)
	{
		SkeletalMeshComponent(Mesh).DetachComponent(EliteMachine_MuzzleFlashPSC[0]);
		EliteMachine_MuzzleFlashPSC[0] = None;
	}
	if (EliteMachine_MuzzleFlashPSC[1] != None)
	{
		if (LeftMesh != None)
		{
			LeftMesh.DetachComponent(EliteMachine_MuzzleFlashPSC[1]);
		}
		EliteMachine_MuzzleFlashPSC[1] = None;
	}
}


// This function is called from the pawn when the visibility of the weapon changes

simulated function ChangeVisibility(bool bIsVisible)
{
//	local UTPawn UTP;

	Super.ChangeVisibility(bIsVisible);

	if (DualMode != EDM_SingleWeapon)
	{
		if (LeftMesh != None)
		{
			LeftMesh.SetHidden(!bIsVisible);
		}
		if (OverlayLeftMesh != none)
		{
			OverlayLeftMesh.SetHidden(!bIsVisible);
		}
	}
}



// * When the Pawn's WeaponOverlay flag changes, handle it here

simulated function SetWeaponOverlayFlags(UTPawn OwnerPawn)
{
	local MaterialInterface InstanceToUse;
	local byte Flags;
	local int i;
	local UTGameReplicationInfo GRI;

	Super.SetWeaponOverlayFlags(OwnerPawn);

	if ( DualMode != EDM_SingleWeapon )
	{
		GRI = UTGameReplicationInfo(WorldInfo.GRI);
		if (GRI != None)
		{
			Flags = OwnerPawn.WeaponOverlayFlags;
			for (i = 0; i < GRI.WeaponOverlays.length; i++)
			{
				if (GRI.WeaponOverlays[i] != None && bool(Flags & (1 << i)))
				{
					InstanceToUse = GRI.WeaponOverlays[i];
					break;
				}
			}
		}

		if (InstanceToUse != none)
		{
			if ( OverlayLeftMesh != none )
			{
				for (i=0;i<OverlayLeftMesh.GetNumElements(); i++)
				{
					OverlayLeftMesh.SetMaterial(i, InstanceToUse);
				}

				if (!OverlayLeftMesh.bAttached)
				{
					AttachComponent(OverlayLeftMesh);
					OverlayLeftMesh.SetHidden(false);
				}
			}
		}
		else if (OverlayLeftMesh != none && OverlayLeftMesh.bAttached)
		{
			OverlayLeftMesh.SetHidden(true);
			DetachComponent(OverlayLeftMesh);
		}
	}
}


// * Turns the MuzzleFlashlight off

simulated event MuzzleFlashOff(int Index)
{
	if ( EliteMachine_MuzzleFlashPSC[Index] != none )
	{
		EliteMachine_MuzzleFlashPSC[Index].DeactivateSystem();
	}
}

simulated event MuzzleFlashTimerLeft()
{
	MuzzleFlashOff(1);
}

simulated event MuzzleFlashTimerRight()
{
	MuzzleFlashOff(0);
}



// * Causes the muzzle flashlight to turn on

simulated event CauseMuzzleFlashLight()
{
	local int Index;

	if ( WorldInfo.bDropDetail )
		return;

	Index = UseLeftBarrel() ? 1 : 0;

	if ( EliteMachine_MuzzleFlashLight[Index] != None )
	{
		EliteMachine_MuzzleFlashLight[Index].ResetLight();
	}
	else if ( MuzzleFlashLightClass != None )
	{
		EliteMachine_MuzzleFlashLight[Index] = new(Outer) MuzzleFlashLightClass;
		if ( Index == 1 )
			LeftMesh.AttachComponentToSocket(EliteMachine_MuzzleFlashLight[Index],MuzzleFlashSocket);
		else
			SkeletalMeshComponent(Mesh).AttachComponentToSocket(EliteMachine_MuzzleFlashLight[Index],MuzzleFlashSocket);
	}
}


// * Causes the muzzle flashlight to turn on and setup a time to
// * turn it back off again.

simulated event CauseMuzzleFlash()
{
	local int Index;
	local UTPawn P;

	if ( WorldInfo.NetMode != NM_Client )
	{
		P = UTPawn(Instigator);
		if ( (P == None) || !P.bUpdateEyeHeight )
		{
			return;
		}
	}
	if ( !bMuzzleFlashAttached )
	{
		AttachMuzzleFlash();
	}
	CauseMuzzleFlashLight();

	if (GetHand() != HAND_Hidden)
	{
		Index = UseLeftBarrel() ? 1 : 0;

		if (EliteMachine_MuzzleFlashPSC[Index] != none)
		{
			EliteMachine_MuzzleFlashPSC[Index].SetTemplate(MuzzleFlashPSCTemplate);
			EliteMachine_MuzzleFlashPSC[Index].SetVectorParameter('MFlashScale',Vect(0.5,0.5,0.5));
			EliteMachine_MuzzleFlashPSC[Index].ActivateSystem();
		}

		// Set when to turn it off.
		if (Index > 0 )
		{
			SetTimer(MuzzleFlashDuration,false,'MuzzleFlashTimerLeft');
		}
		else
		{
			SetTimer(MuzzleFlashDuration,false,'MuzzleFlashTimerRight');
		}
	}
}

simulated event StopMuzzleFlash()
{
	ClearTimer('MuzzleFlashTimerLeft');
	ClearTimer('MuzzleFlashTimerRight');
	MuzzleFlashOff(0);
	MuzzleFlashOff(1);
}


// * Become a dual firing weapon.  Right now this isn't important unless the instigator is the local client.
// * If it is, then show the second mesh and play any needed "Equipping" animations

simulated function BecomeDual()
{
	local UTPawn P;

	IconCoordinates = (DualMode == EDM_SingleWeapon) ? default.IconCoordinates : DualIconCoordinates;
	if ( DualMode == EDM_DualEquipping )
	{
//		MaxAmmoCount = 2 * class'Mut_Elite_Akimbo'.default.Config_RL_BFG.iMaxAmmo;
//		MaxAmmoCount = 2 * Default.MaxAmmoCount;
		if (LeftMesh == None)
		{
			LeftMesh = UTSkeletalMeshComponent(new(self) Mesh.Class(Mesh));
			LeftMesh.SetScale3D(Mesh.Scale3D * vect(1,-1,1));
			AttachComponent(LeftMesh);
		}
		P = UTPawn(Instigator);
		if (P != None)
		{
			if (P.WeaponOverlayFlags != 0)
			{
				CreateOverlayMesh();
			}
			SetWeaponOverlayFlags(P);
		}
		SetTimer(DualEquiptime, false, 'DualEquipDone');
		if (P != None)
		{
			if (!Mesh.HiddenGame)
			{
				LeftMesh.SetHidden(false);
				if (WorldInfo.NetMode != NM_DedicatedServer && Instigator.Weapon == self)
				{
					bUsesOffhand = true;
				}
			}

			P.bDualWielding = true;
			if (P.CurrentWeaponAttachment != None)
			{
				P.CurrentWeaponAttachment.SetDualWielding(true);
			}
		}
		if (EliteMachine_MuzzleFlashPSC[1] != None)
		{
			EliteMachine_MuzzleFlashPSC[1].SetFOV(LeftMesh.FOV);
			LeftMesh.AttachComponentToSocket(EliteMachine_MuzzleFlashPSC[1], MuzzleFlashSocket);
		}
		PlayWeaponAnimation( WeaponDualEqipAnim, DualEquiptime,, LeftMesh );
	}
}

simulated function AttachWeaponTo(SkeletalMeshComponent MeshCpnt, optional Name SocketName )
{
	local UTPawn UTP;

	UTP = UTPawn(Instigator);
	if (UTP != None)
	{
		if (DualMode != EDM_SingleWeapon)
		{
			UTP.bDualWielding = true;
			if (UTP.CurrentWeaponAttachment != None)
			{
				UTP.CurrentWeaponAttachment.SetDualWielding(true);
			}
		}
		if(UTP.IsFirstPerson())
		{
			if( LeftMesh != none )
			{
				LeftMesh.SetLightEnvironment(UTP.LightEnvironment);
			}
		}
	}
	Super.AttachWeaponTo(MeshCpnt, SocketName);
}

simulated function DetachWeapon()
{
	if( LeftMesh != none )
	{
		LeftMesh.SetLightEnvironment(None);
	}

	super.DetachWeapon();
}


// * The equip animation is done, notify the weapon and become usuable

simulated function DualEquipDone()
{
	ShotCount = 0;
	DualMode = EDM_Dual;
	BecomeDual();
}

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

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

	OldSmallWeaponsOffset = SmallWeaponsOffset;

	if (DualMode != EDM_SingleWeapon)
	{
	    SmallWeaponsOffset.Y = -1.0;
	    PlayerViewOffset.Y = -1.0;
	}

	Super.SetPosition(Holder);

	SmallWeaponsOffset = OldSmallWeaponsOffset;
}

// * Returns the rate at which the weapon fires.  If in dual mode, 1/2 the rate
// *
// * @See Weapon.GetFireInterval()

simulated function float GetFireInterval(byte FireModeNum)
{
	local float FI;

	FI = Super.GetFireInterval(FireModeNum);

	if (FireModeNum == 0 && DualMode == EDM_Dual)
	{
		FI = class'MutEM_XX'.default.Config_RL_BFG.fPriFireInterval;
	}

	if (FireModeNum == 1 && DualMode == EDM_Dual)
	{
		FI = class'MutEM_XX'.default.Config_RL_BFG.fSecFireInterval;
	}
	return FI;
}

simulated function vector GetEffectLocation()
{
	local vector SocketLocation;

	if (bLastFiredLeft && GetHand() != HAND_Hidden)
	{
		if (LeftMesh!=none && EffectSockets[CurrentFireMode]!='')
		{
			if (!LeftMesh.GetSocketWorldLocationAndrotation(EffectSockets[CurrentFireMode], SocketLocation))
			{
				SocketLocation = Location;
			}
		}
		else if (LeftMesh!=none)
		{
			SocketLocation = LeftMesh.Bounds.Origin + (vect(45,0,0) >> Rotation);
		}
		else
		{
			SocketLocation = Location;
		}

 		return SocketLocation;
	}
	else
	{
		return super.GetEffectLocation();
	}
}


// * By default, we track each shot so that the 2nd weapon will work.  Bursting overrides this function

simulated function TrackShotCount()
{
	ShotCount++;
}


// * Determine which gun to use

simulated function bool UseLeftBarrel()
{
	return ( DualMode == EDM_Dual && (ShotCount % 2 > 0 ) );
}


// * Returns the name of the firing animation

simulated function name GetFireAnim(int FireModeNum)
{
	return WeaponFireAnim[FireModeNum];
	return LoadUpAnimList[FireModeNum];
	return WeaponAltFireLaunch[FireModeNum];
	return WeaponAltFireLaunchEnd[FireModeNum];

}

// * We override PlayFireEffects to reoffset the animation rate.  When in dual mode, all firing speeds
// * are 1/2 but we want the animations to play as normal.
// *
// * @See PlayFireEffects

simulated function PlayFireEffects( byte FireModeNum, optional vector HitLocation )
{
	local float Rate;
	// Play Weapon fire animation

	Rate = GetFireInterval(FireModeNum);

	// If we are in dual mode, we want to back it out to the normal speed

	if (DualMode == EDM_Dual)
	{
		Rate *= 2;
	}

	if ( FireModeNum < WeaponFireAnim.Length && WeaponFireAnim[FireModeNum] != '' )
	{
		PlayWeaponAnimation( GetFireAnim(FireModeNum), Rate,, UseLeftBarrel() ? LeftMesh : None );
		bLastFiredLeft=UseLeftBarrel();
	}

	// Start muzzle flash effect
	CauseMuzzleFlash();
	ShakeView();
	TrackShotCount();
	ProcessRecoil();
}

/* I'm making the recoil being handled in this function */
simulated function ProcessRecoil()
{
   if (Instigator != None)
   {
      Instigator.AddVelocity( Normal(vector(Rotation) * -1 ) * class'MutEM_XX'.default.Config_RL_BFG.iRocketRecoil / Instigator.Mass,
      Instigator.Location,
	   InstantHitDamageTypes[0] );
   }
}

// * Look to see if bLoaded (ie: has been brought up once) is true and decide which animation to play
simulated function PlayWeaponEquip()
{
	local name Anim;
	local SoundCue EquipSound;

	// Play the animation for the weapon being put down
	if (bLoaded)
	{
		Anim = WeaponEquipAnim;
		EquipSound = WeaponEquipSnd;
	}

	if ( Anim != '' )
	{
		PlayWeaponAnimation( Anim, GetEquipTime() );
		if ( DualMode == EDM_Dual )
		{
			PlayWeaponAnimation( Anim, GetEquipTime(),,LeftMesh);
		}
	}

	// play any assoicated sound
	if (EquipSound != None)
	{
		WeaponPlaySound(EquipSound);
	}
}

// * Added support for handling the 2nd gun

simulated function PlayWeaponPutDown()
{
	// Play the animation for the weapon being put down

	if ( WeaponPutDownAnim != '' )
	{
		PlayWeaponAnimation( WeaponPutDownAnim, PutDownTime );
		if ( DualMode == EDM_Dual )
		{
			PlayWeaponAnimation( WeaponPutDownAnim, PutDownTime,,LeftMesh);
		}
	}

	// play any associated sound
	if ( WeaponPutDownSnd != None )
		WeaponPlaySound( WeaponPutDownSnd );
}

simulated state WeaponEquipping
{
	simulated function WeaponEquipped()
	{
		if( bWeaponPutDown )
		{
			// if switched to another weapon, put down right away
			PutDownWeapon();
			return;
		}
		else
		{
			GotoState('Active');
		}
	}
	simulated function EndState(Name NextStateName)
	{
		Super.EndState(NextStateName);
		bLoaded = true;
	}
}

simulated state WeaponFiring
{

	simulated function BecomeDual()
	{
		Global.BecomeDual();
		if ( DualMode == EDM_Dual )
		{
			bForceReturnToActive=true;
		}
	}

	simulated event ReplicatedEvent(name VarName)
	{
		//Overridden here to update the ammo visibility (UTWeapon::WeaponFiring::ReplicatedEvent just returns)
		if ( VarName == 'AmmoCount' && !HasAnyAmmo() )
		{
			UpdateAmmoVisibility();
		}
	if (VarName == 'DualMode')
	{
		BecomeDual();
	}
		Super.ReplicatedEvent(VarName);
	}
}

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

simulated state Active
{
	simulated function int LagRot(int NewValue, int LastValue, float MaxDiff, int Index)
	{
		local int RotDiff;
		local float LeadMag, DeltaTime;

		if ( NewValue ClockWiseFrom LastValue )
		{
			if ( LastValue > NewValue )
			{
				LastValue -= 65536;
			}
		}
		else
		{
			if ( NewValue > LastValue )
			{
				NewValue -= 65536;
			}
		}

		DeltaTime = WorldInfo.TimeSeconds - LastRotUpdate;
		RotDiff = NewValue - LastValue;
		if ( DualMode != EDM_DualEquipping )
		{
			if ( (RotDiff == 0) || (OldRotDiff[Index] == 0) )
			{
				LeadMag = ShouldLagRot() ? OldLeadMag[Index] : 0.0;
				if ( (RotDiff == 0) && (OldRotDiff[Index] == 0) )
				{
					OldMaxDiff[Index] = 0;
				}
			}
			else if ( (RotDiff > 0) == (OldRotDiff[Index] > 0) )
			{
				if (ShouldLagRot())
				{
					MaxDiff = FMin(1, Abs(RotDiff)/(12000*DeltaTime)) * MaxDiff;
					if ( OldMaxDiff[Index] != 0 )
						MaxDiff = FMax(OldMaxDiff[Index], MaxDiff);

					OldMaxDiff[Index] = MaxDiff;
					LeadMag = (NewValue > LastValue) ? -1* MaxDiff : MaxDiff;
				}
				else
				{
					LeadMag = 0;
				}
				if ( DeltaTime < 1/RotChgSpeed )
				{
					LeadMag = (1.0 - RotChgSpeed*DeltaTime)*OldLeadMag[Index] + RotChgSpeed*DeltaTime*LeadMag;
				}
				else
				{
					LeadMag = 0;
				}
			}
			else
			{
				LeadMag = 0;
				OldMaxDiff[Index] = 0;
				if ( DeltaTime < 1/ReturnChgSpeed )
				{
					LeadMag = (1 - ReturnChgSpeed*DeltaTime)*OldLeadMag[Index] + ReturnChgSpeed*DeltaTime*LeadMag;
				}
			}
		}
		else
		{
			LeadMag = 0;
			OldMaxDiff[Index] = 0;
			if ( DeltaTime < 1/ReturnChgSpeed )
			{
				LeadMag = (1 - ReturnChgSpeed*DeltaTime)*OldLeadMag[Index] + ReturnChgSpeed*DeltaTime*LeadMag;
			}
		}
		OldLeadMag[Index] = LeadMag;
		OldRotDiff[Index] = RotDiff;

		return NewValue + LeadMag;
	}

	simulated function bool ShouldLagRot()
	{
		return (DualMode != EDM_Dual);
	}

	simulated event OnAnimEnd(optional AnimNodeSequence SeqNode, optional float PlayedTime, optional float ExcessTime)
	{
		Super.OnAnimEnd(SeqNode, PlayedTime, ExcessTime);

		if (WorldInfo.NetMode != NM_DedicatedServer && DualMode == EDM_Dual)
		{
			PlayWeaponAnimation(LeftIdleAnim, 0.0, true, LeftMesh);
		}
	}

	simulated event BeginState(name PreviousStateName)
	{
		bForceReturnToActive = false;

		if (Instigator != None)
		{
			Instigator.SetFiringMode(0);
		}

		Super.BeginState(PreviousStateName);
	}
}

/*********************************************************************************************
 * AI Interface
 *********************************************************************************************/

function float SuggestAttackStyle()
{
	local float EnemyDist;

	if (Instigator.Controller.Enemy != None)
	{
		// recommend backing off if target is too close
		EnemyDist = VSize(Instigator.Controller.Enemy.Location - Owner.Location);
		if ( EnemyDist < 750 )
		{
			return (EnemyDist < 500) ? -1.5 : -0.7;
		}
		else if (EnemyDist > 1600)
		{
			return 0.5;
		}
	}

	return -0.1;
}

// tell bot how valuable this weapon would be to use, based on the bot's combat situation
// also suggest whether to use regular or alternate fire mode
function float GetAIRating()
{
	local UTBot B;
	local float EnemyDist, Rating, ZDiff;
	local vector EnemyDir;

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

	// if standing on a lift, make sure not about to go around a corner and lose sight of target
	// (don't want to blow up a rocket in bot's face)
	if ( (Instigator.Base != None) && (Instigator.Base.Velocity != vect(0,0,0))
		&& !B.CheckFutureSight(0.1) )
		return 0.1;

	EnemyDir = B.Enemy.Location - Instigator.Location;
	EnemyDist = VSize(EnemyDir);
	Rating = AIRating;

	// don't pick rocket launcher if enemy is too close
	if ( EnemyDist < 360 )
	{
		if ( Instigator.Weapon == self )
		{
			// don't switch away from rocket launcher unless really bad tactical situation
			if ( (EnemyDist > 250) || ((Instigator.Health < 50) && (Instigator.Health < B.Enemy.Health - 30)) )
				return Rating;
		}
		return 0.05 + EnemyDist * 0.001;
	}

	// rockets are good if higher than target, bad if lower than target
	ZDiff = Instigator.Location.Z - B.Enemy.Location.Z;
	if ( ZDiff > 120 )
		Rating += 0.25;
	else if ( ZDiff < -160 )
		Rating -= 0.35;
	else if ( ZDiff < -80 )
		Rating -= 0.05;
	if ( (B.Enemy.Weapon != None) && B.Enemy.Weapon.bMeleeWeapon && (EnemyDist < 2500) )
		Rating += 0.25;

	return Rating;
}

/* BestMode()
choose between regular or alt-fire
*/
function byte BestMode()
{
	local UTBot B;

	if (IsFiring())
	{
		return CurrentFireMode;
	}

	B = UTBot(Instigator.Controller);
	if (B == None || B.Enemy == None)
	{
		return 0;
	}

	return (FRand() < 0.3 && !B.IsStrafing() && Instigator.Physics != PHYS_Falling) ? 1 : 0;
}

defaultproperties
{
	// First Gun
	Begin Object class=AnimNodeSequence Name=MeshSequenceA
	End Object

	// Second Gun
	Begin Object class=AnimNodeSequence Name=MeshSequenceB
	End Object

	Begin Object Name=FirstPersonMesh
		SkeletalMesh=SkeletalMesh'WP_RocketLauncher.Mesh.SK_WP_RocketLauncher_1P'
//		Materials(0)=Material''
		PhysicsAsset=None
		AnimTreeTemplate=AnimTree'WP_RocketLauncher.Anims.AT_WP_RocketLauncher_1P_Base'
		AnimSets(0)=AnimSet'WP_RocketLauncher.Anims.K_WP_RocketLauncher_1P_Base'
		Translation=(X=0,Y=0,Z=0)
		Rotation=(Yaw=0)
		scale=1.0//scale=1.2
		FOV=60.0
	End Object
	SkeletonFirstPersonMesh = FirstPersonMesh;
	AttachmentClass=class'EM_XX.Elite_Rocket_Attach'

	// Pickup staticmesh
	Begin Object Name=PickupMesh
		SkeletalMesh=SkeletalMesh'WP_RocketLauncher.Mesh.SK_WP_RocketLauncher_3P'
//		Materials(0)=Material''		
	End Object

	WeaponColor=(R=255,G=0,B=0,A=255)
	FireInterval(0)=+1.0
	FireInterval(1)=+1.05
	PlayerViewOffset=(X=0.0,Y=0.0,Z=0.0)
	SmallWeaponsOffset=(X=16.0,Y=6.0,Z=-6.0)

	WeaponLoadedSnd=SoundCue'A_Weapon_RocketLauncher.Cue.A_Weapon_RL_Load_Cue'
	WeaponFireSnd[0]=SoundCue'A_Weapon_RocketLauncher.Cue.A_Weapon_RL_Fire_Cue'
	WeaponFireSnd[1]=SoundCue'A_Weapon_RocketLauncher.Cue.A_Weapon_RL_Fire_Cue'
	AltFireModeChangeSound=SoundCue'A_Weapon_RocketLauncher.Cue.A_Weapon_RL_AltModeChange_Cue'
	RocketLoadedSound=SoundCue'A_Weapon_RocketLauncher.Cue.A_Weapon_RL_RocketLoaded_Cue'
	GrenadeFireSound=SoundCue'A_Weapon_RocketLauncher.Cue.A_Weapon_RL_GrenadeFire_Cue'

   WeaponPutDownSnd=SoundCue'A_Weapon_Sniper.Sniper.A_Weapon_Sniper_Lower_Cue'
   WeaponEquipSnd=SoundCue'A_Weapon_RocketLauncher.Cue.A_Weapon_RL_Raise_Cue'
   PickupSound=SoundCue'A_Pickups.Weapons.Cue.A_Pickup_Weapons_Rocket_Cue'

	AltFireSndQue(0)=SoundCue'A_Weapon_RocketLauncher.Cue.A_Weapon_RL_AltFireQueue1_Cue'
	AltFireSndQue(1)=SoundCue'A_Weapon_RocketLauncher.Cue.A_Weapon_RL_AltFireQueue2_Cue'
	AltFireSndQue(2)=SoundCue'A_Weapon_RocketLauncher.Cue.A_Weapon_RL_AltFireQueue3_Cue'

	LockAcquiredSound=SoundCue'A_Vehicle_Cicada.SoundCues.A_Vehicle_Cicada_TargetLock'
	LockLostSound=SoundCue'A_Weapon_RocketLauncher.Cue.A_Weapon_RL_SeekLost_Cue'

	WeaponProjectiles(0)=class'EM_XX.Elite_Rocket_ProJ'
	WeaponProjectiles(1)=class'EM_XX.Elite_Rocket_ProJ'
	LoadedRocketClass=class'Elite_Rocket_Loaded'
	SeekingRocketClass=class'Elite_Rocket_Seeking'
	GrenadeClass=class'Elite_Rocket_Grenade'

   FireOffset=(X=20,Y=10,Z=-10)  //FireOffset=(X=0,Y=0,Z=0)  //   	FireOffset=(X=20,Y=12,Z=-5)

	MaxDesireability=0.78
	AIRating=+0.78
	CurrentRating=+0.78
	bInstantHit=false
	bSplashJump=true
	bRecommendSplashDamage=true
	bSniping=false
	ShouldFireOnRelease(0)=0
	ShouldFireOnRelease(1)=1
	InventoryGroup=8
	GroupWeight=0.5

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

	AltFireQueueTimes(0)=0.2
	AltFireQueueTimes(1)=0.2
	AltFireQueueTimes(2)=0.2
	AltFireQueueTimes(3)=0.2
	AltFireQueueTimes(4)=0.2
	AltFireQueueTimes(5)=0.2
//	AltFireQueueTimes(6)=0.2
//	AltFireQueueTimes(7)=0.2
//	AltFireQueueTimes(8)=0.2
//	AltFireQueueTimes(9)=0.2
	AltFireLaunchTimes(0)= 0.2
	AltFireLaunchTimes(1)= 0.2
	AltFireLaunchTimes(2)= 0.2
	AltFireLaunchTimes(3)= 0.2
	AltFireLaunchTimes(4)= 0.2
	AltFireLaunchTimes(5)= 0.2
//	AltFireLaunchTimes(6)= 0.2
//	AltFireLaunchTimes(7)= 0.2
//	AltFireLaunchTimes(8)= 0.2
//	AltFireLaunchTimes(9)= 0.2
	AltFireEndTimes(0)=0.2
	AltFireEndTimes(1)=0.2
	AltFireEndTimes(2)=0.2
	AltFireEndTimes(3)=0.2
	AltFireEndTimes(4)=0.2
	AltFireEndTimes(5)=0.2
//	AltFireEndTimes(6)=0.2
//	AltFireEndTimes(7)=0.2
//	AltFireEndTimes(8)=0.2
//	AltFireEndTimes(9)=0.2

	MaxLoadCount=6
	SpreadDist=600
	FiringStatesArray(1)=WeaponLoadAmmo
	WeaponFireTypes(0)=EWFT_Projectile
	WeaponFireTypes(1)=EWFT_Projectile

	WaitToFirePct=0.01  //0.85
	GracePeriod=0.01  //0.96

	MuzzleFlashSocket=MuzzleFlashSocketA
	MuzzleFlashSocketList(0)=MuzzleFlashSocketA
	MuzzleFlashSocketList(1)=MuzzleFlashSocketA
	MuzzleFlashSocketList(2)=MuzzleFlashSocketA

	MuzzleFlashPSCTemplate=WP_RocketLauncher.Effects.P_WP_RockerLauncher_Muzzle_Flash
	MuzzleFlashDuration=0.33
	MuzzleFlashLightClass=class'UTGame.UTRocketMuzzleFlashLight'

	ConsoleLockAim=0.992
	LockRange=10000
	LockAim=0.997
	LockChecktime=0.1
	LockAcquireTime=1.1
	LockTolerance=2.0  //0.2

   RocketRecoil=1000

	IconX=460
	IconY=34
	IconWidth=51
	IconHeight=38

	GrenadeSpreadDist=300

	JumpDamping=0.75

	LockerRotation=(pitch=0,yaw=0,roll=-16384)
	IconCoordinates=(U=131,V=379,UL=129,VL=50)
	CrossHairCoordinates=(U=128,V=64,UL=64,VL=64)
	DualIconCoordinates=(U=131,V=379,UL=129,VL=50)
	QuickPickGroup=2
	QuickPickWeight=0.9

	LoadedIconCoords[0]=(U=0,V=384,UL=63,VL=63)
	LoadedIconCoords[1]=(U=63,V=384,UL=63,VL=63)
	LoadedIconCoords[2]=(U=126,V=384,UL=63,VL=63)

	LeftIdleAnim=WeaponIdle
	WeaponDualEqipAnim=WeaponEquip
   WeaponFireAnim(0)="WeaponFire"
   WeaponFireAnim(1)="WeaponFire"

	DualEquiptime=1.0
   bLoaded=true

   Priority=900.8
	ShotCost(0)=1
	ShotCost(1)=1
	AimingHelpRadius[0]=20.0
	AimingHelpRadius[1]=20.0
	AimError=525

   ItemName="Elite Rocket Launcher"             // Weapon Switch Name
   PickupMessage="Elite Rocket Launcher"
   Name="Elite Rocket Launcher"           // Menu Name
}
