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

class Elite_Link extends UTWeap_LinkGun
	dependson(MutEM_XX);

enum LDualMode
{
	LDM_SingleWeapon,
	LDM_DualEquipping,
	LDM_Dual,
	LDM_Max
};

var() int LucyRecoil;

/** Name of the animation to play when reloading */
var name WeaponReloadAnim;
var name ArmReloadAnim;
var SoundCue WeaponReloadSnd;
var AnimSet LeftArmAnimSet;

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

/** if true, we are a dual link gun */
var repnotify LDualMode	DualMode;

var UIRoot.TextureCoordinates DualIconCoordinates;

var MaterialInstanceConstant LeftWeaponMaterialInstance;

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

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

/** 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 link gun*/
var bool bLastFiredLeft;

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

var name WeaponDualEqipAnim;
var name ArmDualEquipAnim;

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

var bool bFullDualCoolDown;

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

var name LeftIdleAnim;

simulated function PostBeginPlay()
{
	super.PostBeginPlay();

   if ( class'MutEM_XX'.default.Config_LinkGun.bDoubles )
   {
   BecomeDual();
   }

   if ( class'MutEM_XX'.default.Config_LinkGun.bAmmoRegeneration )
   {
	if ( Role == ROLE_Authority )
		SetTimer(class'MutEM_XX'.default.Config_LinkGun.fPriFireInterval * 2, true, 'AmmoRegen');
	}

	FireInterval[0]=class'MutEM_XX'.default.Config_LinkGun.fPriFireInterval;
   ShotCost[0]=class'MutEM_XX'.default.Config_LinkGun.iShotCost;

	MinimumDamage=class'MutEM_XX'.default.Config_LinkGun.iSecDamage;
	BeamAmmoUsePerSecond=class'MutEM_XX'.default.Config_LinkGun.iBeamAmmoSec;
   WeaponLinkDistance=class'MutEM_XX'.default.Config_LinkGun.iWeaponLinkDistance;
	LinkFlexibility=class'MutEM_XX'.default.Config_LinkGun.fLinkFlexibility;

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

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

	MomentumTransfer=class'MutEM_XX'.default.Config_LinkGun.iMomentum;
   WeaponRange=class'MutEM_XX'.default.Config_LinkGun.iBeamRange;
	LucyRecoil=class'MutEM_XX'.default.Config_LinkGun.iLucyRecoil;
}

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

/**
 * Setup the overlay skins
 */
simulated function SetSkin(Material NewMaterial)
{
	local int i,Cnt;
//	local UTPawn P;
	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);
				}
			}
	}
}

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.00);
			OverlayLeftMesh.SetOwnerNoSee(LeftMesh.bOwnerNoSee);
			OverlayLeftMesh.SetDepthPriorityGroup(SDPG_Foreground);
			OverlayLeftMesh.SetSkeletalMesh(LeftMesh.SkeletalMesh);
			OverlayLeftMesh.AnimSets = LeftMesh.AnimSets;
			OverlayLeftMesh.SetParentAnimComponent(LeftMesh);
			OverlayLeftMesh.SetFOV(LeftMesh.FOV);
		}
		else
		{
			WarnInternal("Could not create Weapon Overlay mesh for" @ self @ LeftMesh);
		}
	}
}

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

	Super.ChangeVisibility(bIsVisible);

	if (DualMode != LDM_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 != LDM_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);
		}
	}
}

/**
 * On a remote client, watch for a change in bDualMode and if it changes, signal this has become a dual
 * weapon.
 */
simulated event ReplicatedEvent(name VarName)
{
	if (VarName == 'DualMode')
	{
	   BecomeDual();
	}
	else
	{
		Super.ReplicatedEvent(VarName);
	}
}

/**
 * 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 != LDM_Dual)
	{
      if ( class'MutEM_XX'.default.Config_LinkGun.bDoubles )
      {
		   DualMode = LDM_DualEquipping;
		   BecomeDual();			// Handle any animations/effects locally.
		}
	}
	return super.DenyPickupQuery(ItemClass, Pickup);
}

/**
 * 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 == LDM_SingleWeapon) ? default.IconCoordinates : DualIconCoordinates;
	if ( DualMode == LDM_DualEquipping )
	{
//		MaxAmmoCount = 2 * default.MaxAmmoCount;
//		AmmoCount = 2 * AmmoCount;
		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)
		{
			P.bDualWielding = true;
			if (P.CurrentWeaponAttachment != None)
			{
				P.CurrentWeaponAttachment.SetDualWielding(true);
			}
		}

		PlayWeaponAnimation( WeaponDualEqipAnim, DualEquiptime,, LeftMesh );
//		PlayArmAnimation( WeaponDualEqipAnim, DualEquiptime, true,, LeftMesh );
	}
}
simulated function AttachWeaponTo(SkeletalMeshComponent MeshCpnt, optional Name SocketName )
{
	local UTPawn UTP;

	UTP = UTPawn(Instigator);
	if (UTP != None)
	{
		if (DualMode != LDM_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 = LDM_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 != LDM_SingleWeapon)
	{
	    SmallWeaponsOffset.Y = -1.0;
	    PlayerViewOffset.Y = -1.0;
	}

	Super.SetPosition(Holder);

	SmallWeaponsOffset = OldSmallWeaponsOffset;
}

/**
 * Determine which gun to use
 */
simulated function bool UseLeftBarrel()
{
	return ( DualMode == LDM_Dual && (ShotCount % 2 > 0 ) );
}

/**
 * I track each shot so that the 2nd weapon will work.
 */

simulated function TrackShotCount()
{
	ShotCount++;
}

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


/**
 * 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 == LDM_Dual)
	{
		Rate *= 2;
	}

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

	// Start muzzle flash effect
	CauseMuzzleFlash();

	ShakeView();

	TrackShotCount();
	
   // Start Recoil effect - I had to start it somewhere
   ProcessRecoil();
}

/* I'm making the recoil being handled in this function */
simulated function ProcessRecoil()
{
	// Secondary Fire this is Not supposed to happen!
	if (CurrentFireMode == 1)
		return;

		if (Instigator != None)
		{	// Recoil will knock the player back
			Instigator.AddVelocity( Normal(vector(Rotation) * -1 ) * class'MutEM_XX'.default.Config_LinkGun.iLucyRecoil / Instigator.Mass,
				Instigator.Location,
	   InstantHitDamageTypes[0] );
		}
}

/**
 * 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 == LDM_Dual)
	{
		FI *= 0.5;
	}

	return FI;
}

/**
 * Returns the name of the firing animation
 */

simulated function name GetFireAnim(int FireModeNum)
{
	return WeaponFireAnim[FireModeNum];
}

/**
 * Added support for handling the 2nd gun
 */

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

	if ( WeaponPutDownAnim != '' )
	{
		PlayWeaponAnimation( WeaponPutDownAnim, PutDownTime );
//		PlayArmAnimation( WeaponPutDownAnim, PutDownTime );
		if ( DualMode == LDM_Dual )
		{
			PlayWeaponAnimation( WeaponPutDownAnim, PutDownTime,,LeftMesh);
//			PlayArmAnimation( WeaponPutDownAnim, PutDownTime,true,,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 == LDM_Dual )
	   {
		   bForceReturnToActive=true;
      }
	}
	 /**
	 * We poll the PendingFire in RefireCheckTimer() to insure the switch to Burst Firing
	 * respects the current shot timings
	 */

	simulated function RefireCheckTimer()
	{
		// if switching to another weapon, abort firing and put down right away
		if( bWeaponPutDown )
		{
			PutDownWeapon();
			return;
		}

		if (bForceReturnToActive)
		{
			GotoState('Active');
			return;
		}

		if ( PendingFire(1) )
		{

			SendToFiringState(1);
			return;
		}

		super.RefireCheckTimer();
	}

	simulated function EndState(name NextStateName)
	{
		if (CurrentFireMode == 0 )
		{
			ShotCount = 0;
		}
		super.EndState(NextStateName);
	}
}


simulated function PlayWeaponEquip()
{
	local name Anim;
	local SoundCue EquipSound;

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

	if ( Anim != '' )
	{
		PlayWeaponAnimation( Anim, GetEquipTime() );
//		PlayArmAnimation( Anim, GetEquipTime() );
		if ( DualMode == LDM_Dual )
		{
			PlayWeaponAnimation( Anim, GetEquipTime(),,LeftMesh);
//			PlayArmAnimation( Anim, GetEquipTime(),true,,LeftMesh);
		}
	}

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

}

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 != LDM_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 != LDM_Dual);
	}

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

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

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

////////////////////////
//  Muzzle Flash Support
////////////////////////

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

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

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

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

	// Weapon SkeletalMesh
	Begin Object Name=FirstPersonMesh
		SkeletalMesh=SkeletalMesh'WP_LinkGun.Mesh.SK_WP_Linkgun_1P'
		AnimSets(0)=AnimSet'WP_LinkGun.Anims.K_WP_LinkGun_1P_Base'
		Animations=MeshSequenceA
		Scale=0.9
		FOV=60.0
	   Materials(0)=Material'EM_XX_Content.Lucifer_Final'
	End Object
	
	// Pickup staticmesh
	Begin Object Name=PickupMesh
		SkeletalMesh=SkeletalMesh'EM_XX_Content.Mesh.Lucifer_3P'
	   Materials(0)=Material'EM_XX_Content.Lucifer_Final'
	End Object

//   PlayerViewOffset=(X=0.0,Y=0.0,Z=0.0)
//   SmallWeaponsOffset=(X=16.0,Y=6.0,Z=-6.0)

   WeaponProjectiles(0)=Class'EM_XX.Elite_Link_ProJ'
	FireInterval(0)=+0.12
	FireInterval(1)=+0.35
	InstantHitDamage(1)=1000
	InstantHitDamageTypes(1)=class'EM_XX.Elite_Link_Beam_DMG'
	MomentumTransfer=5000.0
	BeamAmmoUsePerSecond=20
	MinimumDamage=1.0
   MuzzleFlashPSCTemplate=ParticleSystem'WP_LinkGun.Effects.P_WP_LinkGun_Beam_Impact_Red'
	MuzzleFlashAltPSCTemplate=ParticleSystem'WP_LinkGun.Effects.P_FX_LinkGun_MF_Beam_Red'
   MuzzleFlashLightClass=class'EM_XX.Elite_Link_Muz'
   MuzzleFlashColor=(R=255,G=0,B=0,A=255)
   BeamTemplate[1]=ParticleSystem'VH_DarkWalker.Effects.P_VH_DarkWalker_MainGun_Beam'
	TeamMuzzleFlashTemplates[0]=ParticleSystem'WP_LinkGun.Effects.P_FX_LinkGun_MF_Beam_Red'
	TeamMuzzleFlashTemplates[1]=ParticleSystem'WP_LinkGun.Effects.P_FX_LinkGun_MF_Beam_Red'
	TeamMuzzleFlashTemplates[2]=ParticleSystem'WP_LinkGun.Effects.P_FX_LinkGun_MF_Beam_Red'
   EquipTime=0.2
   PutDownTime=0.2
   LucyRecoil=10000
   LinkFlexibility=0
   Priority=1000.4
	WeaponRange=60000.000000
   DualMode=LDM_DualEquipping
   DualEquiptime=0.200000

   WeaponReloadAnim="weaponequipempty"
   ArmReloadAnim="WeaponEquipFirst"
   LeftArmAnimSet=AnimSet'WP_LinkGun.Anims.K_WP_LinkGun_1P_Base'
   DualIconCoordinates=(U=453.000000,V=467.000000,UL=147.000000,VL=41.000000)

   WeaponDualEqipAnim="WeaponEquip"
   ArmDualEquipAnim="WeaponEquip"
   LeftIdleAnim="WeaponIdle"

   PoweredUpEffect=PoweredUpComponent

   AmmoCount=50
   LockerAmmoCount=50
   MaxAmmoCount=420

   AttachmentClass=Class'EM_XX.Elite_Link_Attach'

   Mesh=FirstPersonMesh
   bExportMenuData=True
   ItemName="Elite Link Guns"
   PickupMessage="Elite Link Guns"

   DroppedPickupMesh=PickupMesh
   PickupFactoryMesh=PickupMesh
   Name="Elite_Link"
}
