//=============================================================================
// KFWeap_Bow_CompoundBow
//=============================================================================
// A Bow that can alternate between Sharp and Cryo arrows.
//=============================================================================
// Killing Floor 2
// Copyright (C) 2019 Tripwire Interactive LLC
//	- Tulio Beloqui (Saber Interactive)
//=============================================================================

class KFWeap_Bow_CompoundBow extends KFWeapon;

/** Charge Level Props **/
var float MaxChargeTime;
var float ValueIncreaseTime;
var float StateMaxChargeTime;
var float StateValueIncreaseTime;

var transient float ChargeTime;
var transient float MaxChargeLevel;
var transient bool bIsFullyCharged;


/** Flag to check if we are still firing in the CompoundBowCharge state in order to check for interrupts when we are making the reload animation  */
var transient bool bHasArrowBeenFired;
/** Name to check from where we come from at active state begin play in order to prevent it to go from active to ironsights if a reload is pending  */
//var transient Name sPreviousStateName;


/** The FireMode to start fire after the Reload is complete
**  Used to keep charging the CompoundBow while reloading */
var byte StartFireModeAfterReload;

/** True if we are reloading after running out of ammo **/
var bool bReloadingFromEmptyMag;

/** The increase of the damage applied in each charge level **/
var float DmgIncreasePerCharge;

/** Array for holding the speeds applied to the projectile based on the charge level. See GetChargeLevel() **/
var	array<float> ArrowSpeedPerCharge;

/** How much to increase the wait time to force a reload, this value will be added to FireInterval **/
var() float		ForceReloadTime;

/** The partcile FX to display for the Cryo Projectile **/
var ParticleSystem CryoProjectileEffectOn;
var ParticleSystem CryoProjectileEffectOff;
var transient KFParticleSystemComponent CryoProjectilePSC;

/** The Sound FX to play for the Cryo Projectile **/
var() AkEvent CryoProjectileSoundEffectOn;
var() AkEvent CryoProjectileSoundEffectOff;

/** Anims for Iron, Idle and ShootLoop transitions **/
var(Animations) const editconst name IdleToIronSightAnim;
var(Animations) const editconst name IronSightToIdleAnim;
var(Animations) const editconst name IronSightShootToShootAnim;
var(Animations) const editconst name ShootToIronSightShootAnim;

const ArrowSocketName = 'RW_Weapon';

/** Returns a value between 0 and ArrowSpeedPerCharge size - 1. **/
simulated function int GetChargeLevel()
{
	local float Level;
	Level = Min(ChargeTime / StateValueIncreaseTime, MaxChargeLevel);
	return Min (Level, ArrowSpeedPerCharge.Length - 1);
}

/** Returns trader filter index based on weapon type (copied from Crossbow) */
static simulated event EFilterTypeUI GetTraderFilter()
{
    return FT_Projectile;
}

simulated function ConsumeAmmo (byte FireModeNum)
{
	super.ConsumeAmmo (FireModeNum);

	if (Role == ROLE_Authority || bAllowClientAmmoTracking)
	{
		if (FireModeNum == DEFAULT_FIREMODE || FireModeNum == ALTFIRE_FIREMODE)
		{
			bReloadingFromEmptyMag = (SpareAmmoCount[GetAmmoType (FireModeNum)] == 0);
		}
	}
}

/** Return true if this weapon should play the fire last animation for this shoot animation */
simulated function bool ShouldPlayFireLast(byte FireModeNum)
{
    if( SpareAmmoCount[GetAmmoType(FireModeNum)] == 0 )
    {
        return true;
    }
	
    return false;
}

/** Returns animation to play based on reload type and status */
simulated function name GetReloadAnimName (bool bTacticalReload)
{
    if( AmmoCount[GetAmmoType(CurrentFireMode)] > 0 )
	{
		// Disable half-reloads for now.  This can happen if server gets out
		// of sync, but choosing the wrong animation will just make it worse!
		`warn("Compound Bow reloading with non-empty mag");
	}

	if (bReloadingFromEmptyMag)
	{
		return bTacticalReload ? ReloadEmptyMagEliteAnim : ReloadEmptyMagAnim;
	}

	return bTacticalReload ? ReloadNonEmptyMagEliteAnim : ReloadNonEmptyMagAnim;
}

simulated function SetIronSights (bool bNewIronSights)
{
	local KFPawn_Human P;

	Super.SetIronSights(bNewIronSights);

	P = KFPawn_Human(Instigator);

	if (P != none && P.IsLocallyControlled())
	{
		P.SetIronSights(bNewIronSights, true);
		KFPawn(Instigator).bNetDirty = true;
	}
}

simulated function AltFireMode ()
{
	local KFPawn_Human P;

	super.AltFireMode ();
	
	// LocalPlayer Only
	if ( !Instigator.IsLocallyControlled()  )
	{
		return;
	}

	if( WorldInfo.NetMode == NM_DedicatedServer )
	{
		return;
	}
	
	if (bUseAltFireMode)
	{
		CryoProjectilePSC.DeactivateSystem();
		CryoProjectilePSC.SetTemplate(CryoProjectileEffectOn);
		CryoProjectilePSC.ActivateSystem();
		WeaponPlayFireSound (CryoProjectileSoundEffectOn, CryoProjectileSoundEffectOn);
	}
	else
	{
		CryoProjectilePSC.DeactivateSystem();
		CryoProjectilePSC.SetTemplate(CryoProjectileEffectOff);
		CryoProjectilePSC.ActivateSystem();
		WeaponPlayFireSound (CryoProjectileSoundEffectOff, CryoProjectileSoundEffectOff);
	}
	
	P = KFPawn_Human (Instigator);
	if (P != none)
	{
		P.SetUsingAltFireMode (bUseAltFireMode, true);
		P.bNetDirty = true;
	}
}

simulated function AttachWeaponTo (SkeletalMeshComponent MeshCpnt, optional Name SocketName)
{
	super.AttachWeaponTo (MeshCpnt, SocketName);

	if (CryoProjectilePSC == none)
	{
		CryoProjectilePSC = new(self) class'KFParticleSystemComponent';
		CryoProjectilePSC.SetDepthPriorityGroup(SDPG_Foreground);
		CryoProjectilePSC.SetTickGroup(TG_PostUpdateWork);
		CryoProjectilePSC.SetFOV(MySkelMesh.FOV);
		
		MySkelMesh.AttachComponentToSocket (CryoProjectilePSC, ArrowSocketName);
	}

	if (bUseAltFireMode)
	{
		CryoProjectilePSC.SetTemplate(CryoProjectileEffectOn);
		CryoProjectilePSC.ActivateSystem();
		WeaponPlayFireSound (CryoProjectileSoundEffectOn, CryoProjectileSoundEffectOn);
	}
}

/**
 * Detach weapon from skeletal mesh
 */
simulated function DetachWeapon()
{
	if (CryoProjectilePSC != none)
	{
		CryoProjectilePSC.DeactivateSystem ();
		MySkelMesh.DetachComponent (CryoProjectilePSC);
		CryoProjectilePSC = none;
	}
	
    super.DetachWeapon();
}

/**
 * Adjust the FOV for the first person weapon and arms.
 */
simulated event SetFOV( float NewFOV )
{
	super.SetFOV(NewFOV);

	if (CryoProjectilePSC != none)
	{
		CryoProjectilePSC.SetFOV(NewFOV);
	}
}

/**
* Apply the rate of fire modifier to the reload animation as well (for Marksman Perk Skill)
**/
simulated function float GetReloadRateScale ()
{
	local KFPerk CurrentPerk;
	local float AnimRate;
	
	CurrentPerk = GetPerk();
	AnimRate = super.GetReloadRateScale ();
	
	if (CurrentPerk != none)
	{
		CurrentPerk.ModifyRateOfFire( AnimRate, self );
	}

	return AnimRate;
}

/**
 * Starts playing looping FireAnim and FireSnd
 * Adjust the fire rate (for Sharpshooter Perk skill, Marksman)
 */
simulated function StartLoopingFireEffects(byte FireModeNum, optional bool bForceAnim)
{
	local KFPerk CurrentPerk;
	local float AdjustedAnimLength;
	local name WeaponFireAnimName;

	if ( bForceAnim || (FireModeNum < bLoopingFireAnim.Length && bLoopingFireAnim[FireModeNum]) )
	{
		// If available, try to play loop start anim
		WeaponFireAnimName = GetLoopStartFireAnim(FireModeNum);
		if ( WeaponFireAnimName != '' )
		{
			AdjustedAnimLength = MySkelMesh.GetAnimLength(WeaponFireAnimName);
			CurrentPerk = GetPerk();

			if (CurrentPerk != none)
			{
				CurrentPerk.ModifyRateOfFire( AdjustedAnimLength, self );
			}

			PlayAnimation(WeaponFireAnimName, AdjustedAnimLength, FALSE, FireTweenTime, 0.f);
		}
		// Otherwise go straight to the looping animation
		else
		{
			WeaponFireAnimName = GetLoopingFireAnim(FireModeNum);
			PlayAnimation(WeaponFireAnimName, MySkelMesh.GetAnimLength(WeaponFireAnimName), TRUE, FireTweenTime);
		}

		bPlayingLoopingFireAnim = true;
	}

	StartLoopingFireSound(FireModeNum);
}

/**
 * Stops playing looping FireAnim and FireSnd
 * Adjust the fire rate (for Sharpshooter Perk skill, Marksman)
 */
simulated function StopLoopingFireEffects(byte FireModeNum)
{
	local KFPerk CurrentPerk;
	local float AdjustedAnimLength;
	local name LoopEndFireAnim;

	if ( bPlayingLoopingFireAnim )
	{
		LoopEndFireAnim = GetLoopEndFireAnim(FireModeNum);	
		if ( LoopEndFireAnim != '' )
		{
			AdjustedAnimLength = MySkelMesh.GetAnimLength(LoopEndFireAnim);
			CurrentPerk = GetPerk();
			
			if (CurrentPerk != none)
			{
				CurrentPerk.ModifyRateOfFire( AdjustedAnimLength, self );
			}

			PlayAnimation(LoopEndFireAnim, AdjustedAnimLength);
		}
		else
		{
			ClearTimer(nameof(OnAnimEnd));	// needed for loopstart anim to return to idle
		}
		bPlayingLoopingFireAnim = false;
	}

	StopLoopingFireSound( FireModeNum );
}

simulated function CauseMuzzleFlash(byte FireModeNum)
{
	return;
}

/** Charging functionality inspired by HuskCannon fire ball **/
simulated function StartFire(byte FiremodeNum)
{
	/** Do not allow StartFire if we are either:
	*	a)charging (RefireCheckTimer) or
	*	b) we are forcing a Reload after shooting or still in Reloading state.
	**/
	if (FireModeNum == DEFAULT_FIREMODE || FireModeNum == ALTFIRE_FIREMODE || FireModeNum == GRENADE_FIREMODE || FireModeNum == BASH_FIREMODE)
	{
		if (IsTimerActive('RefireCheckTimer') || IsTimerActive(nameOf(ForceReload)) || IsInState('Reloading'))
		{
			if (FireModeNum == DEFAULT_FIREMODE || FireModeNum == ALTFIRE_FIREMODE)
			{
				StartFireModeAfterReload = FireModeNum;
			}

			return;
		}
	}

	super.StartFire(FiremodeNum);
}

simulated function StopFire (byte FireModeNum)
{
	StartFireModeAfterReload = FIREMODE_NONE;
	super.StopFire (FireModeNum);
}

simulated function OnStartFire()
{
	local KFPawn PawnInst;
	PawnInst = KFPawn(Instigator);

	if (PawnInst != none)
	{
		PawnInst.OnStartFire();
	}
}

simulated function float GetForceReloadDelay()
{
	return ForceReloadTime;
}

/** Don't sprint until we've finished our forced reload */
simulated function bool AllowSprinting()
{
	return !IsTimerActive( nameOf(ForceReload) );
}

/** ActiveIronSight and Active States to play Idle to Iron - Iron to Idle animations  **/
simulated state Active
{
	simulated function BeginState(Name PreviousStateName)
	{
		if (IsTimerActive('Timer_StopFireEffects'))
		{
			return;
		}	
		super.BeginState(PreviousStateName);
	}

	simulated function ZoomIn(bool bAnimateTransition, float ZoomTimeToGo)
	{
		if (IsTimerActive('Timer_StopFireEffects'))
		{
			return;
		}
		GotoState('ActiveIronSight');
	}
}

simulated state ActiveIronSight extends Active
{
	simulated function ZoomOut(bool bAnimateTransition, float ZoomTimeToGo)
	{
		ZoomTimeToGo = MySkelMesh.GetAnimLength(IronSightToIdleAnim);

		Global.ZoomOut( true, ZoomTimeToGo );

		PlayAnimation( IronSightToIdleAnim, ZoomTime, false );

		GotoState('Active');
	}

	simulated function BeginState( Name PreviousStateName )
	{
		//bHasArrowBeenFired
		local float ZoomTimeToGo;

		ZoomTimeToGo = MySkelMesh.GetAnimLength(IdleToIronSightAnim);

		Global.ZoomIn( true, ZoomTimeToGo );

		PlayAnimation( IdleToIronSightAnim, ZoomTime, false );
	}
}

simulated state CompoundBowCharge extends WeaponSingleFireAndReload
{
	// No need to replace FireAmmunition, global.FireAmmunition is called instead.
    simulated function FireAmmunition()
    {}

    //Store start fire time so we don't have to timer this
    simulated event BeginState(Name PreviousStateName)
    {
		local KFPerk CurrentPerk;

        super.BeginState(PreviousStateName);

		StateMaxChargeTime = MaxChargeTime;
		StateValueIncreaseTime = ValueIncreaseTime;

		CurrentPerk = GetPerk();
		if (CurrentPerk != none)
		{
			CurrentPerk.ModifyRateOfFire( StateMaxChargeTime, self );
			CurrentPerk.ModifyRateOfFire( StateValueIncreaseTime, self );
		}

		ChargeTime = 0;
		MaxChargeLevel = int(StateMaxChargeTime / StateValueIncreaseTime);
		bIsFullyCharged = false;
		bHasArrowBeenFired = false;
		global.OnStartFire();
    }

	simulated function bool ShouldRefire()
	{
		// ignore how much ammo is left (super/global counts ammo)
		return StillFiring(CurrentFireMode);
	}

    simulated event Tick(float DeltaTime)
    {
		global.Tick(DeltaTime);

		if (bIsFullyCharged)
		{
			return;
		}

		// Don't charge unless we're holding down the button
		if (PendingFire(CurrentFireMode))
		{
			ChargeTime += DeltaTime;
		}
		
		if (ChargeTime >= StateMaxChargeTime)
		{
			bIsFullyCharged = true;
		}
    }

    simulated event EndState(Name NextStateName)
    {
		ClearZedTimeResist();
        ClearPendingFire(CurrentFireMode);
		ClearTimer(nameof(RefireCheckTimer));

		KFPawn(Instigator).bHasStartedFire = false;
		KFPawn(Instigator).bNetDirty = true;

		if (bUsingSights)
    	{
		// do this locally and replicate to avoid sync errors w/ bIronSightOnBringUp
			if ( Instigator.IsLocallyControlled() )
			{
				SetIronSights(false);
			}
    	}
	}

	simulated function PutDownWeapon()
	{
		ChargeTime = 0;
		bIsFullyCharged = false;
		global.PutDownWeapon();
	}
	
	simulated function HandleFinishedFiring ()
	{
		super.FireAmmunition ();
		bHasArrowBeenFired = true;

		if (bPlayingLoopingFireAnim)
		{
			StopLoopingFireEffects(CurrentFireMode);
		}

		if (MuzzleFlash != none)
		{
			SetTimer(MuzzleFlash.MuzzleFlash.Duration, false, 'Timer_StopFireEffects');
		}
		else
		{
			SetTimer(0.3f, false, 'Timer_StopFireEffects');
		}

		NotifyWeaponFinishedFiring(CurrentFireMode);
		
		
		super.HandleFinishedFiring ();

		
	}

	/** override ZoomIn and ZoomOut for Idle to Iron animations **/
	simulated function ZoomIn(bool bAnimateTransition, float ZoomTimeToGo)
	{
		if (bHasArrowBeenFired || !bIsFullyCharged)
		{
			return;
		}
		if (IsTimerActive('Timer_StopFireEffects'))
		{
			return;
		}	
		ZoomTimeToGo = MySkelMesh.GetAnimLength(ShootToIronSightShootAnim);

		Global.ZoomIn( true, ZoomTimeToGo );

		PlayAnimation( ShootToIronSightShootAnim, ZoomTime, false );
	}

	simulated function ZoomOut (bool bAnimateTransition, float ZoomTimeToGo)
	{		
		if (IsTimerActive('Timer_StopFireEffects'))
		{
			return;
		}	
		ZoomTimeToGo = MySkelMesh.GetAnimLength(IronSightShootToShootAnim);

		Global.ZoomOut( true, ZoomTimeToGo );

		PlayAnimation( IronSightShootToShootAnim, ZoomTime, false );
	}
}

simulated function Timer_StopFireEffects()
{
	// Simulate weapon firing effects on the local client
	if (WorldInfo.NetMode == NM_Client)
	{
		Instigator.WeaponStoppedFiring(self, false);
	}

	ClearFlashCount();
	ClearFlashLocation();
}

/** Override Reloading state to give an accurate GetWeaponStateId() for 3rdP **/
simulated state Reloading
{
	simulated function byte GetWeaponStateId ()
	{
		local KFPerk Perk;
		local bool bTacticalReload;

		Perk = GetPerk ();
		bTacticalReload = (Perk != None && Perk.GetUsingTactialReload (self));

		if (bReloadingFromEmptyMag)
		{
			return bTacticalReload ? WEP_ReloadEmpty_Elite : WEP_ReloadEmpty;
		}

		return bTacticalReload ? WEP_Reload_Elite : WEP_Reload;
	}

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

		if (StartFireModeAfterReload != FIREMODE_NONE)
		{
			SetTimer(0.01f, true, 'Timer_StartFireAfterReload');
		}
	}
}

simulated function Timer_StartFireAfterReload()
{
	if (IsTimerActive('Timer_StopFireEffects'))
	{
		return;
	}
	
	ClearTimer('Timer_StartFireAfterReload');
	if (StartFireModeAfterReload != FIREMODE_NONE)
	{
		super.StartFire (StartFireModeAfterReload);
	}
}

simulated function int GetModifiedDamage(byte FireModeNum, optional vector RayDir)
{
	local int ModifiedDamage;

	ModifiedDamage = super.GetModifiedDamage(FireModeNum, RayDir);

	if (FireModeNum == DEFAULT_FIREMODE || FireModeNum == ALTFIRE_FIREMODE)
	{
		ModifiedDamage = ModifiedDamage * (1.f + DmgIncreasePerCharge * GetChargeLevel() );
	}

	return ModifiedDamage;
}

simulated function KFProjectile SpawnProjectile(class<KFProjectile> KFProjClass, vector RealStartLoc, vector AimDir)
{
	local KFProjectile SpawnedProjectile;
    local int Level;
	local float SpeedCharge;

	SpawnedProjectile = Super.SpawnProjectile(KFProjClass, RealStartLoc, AimDir);

	if (SpawnedProjectile != none && (CurrentFireMode == DEFAULT_FIREMODE || CurrentFireMode == ALTFIRE_FIREMODE))
	{
		Level = GetChargeLevel ();
		SpeedCharge = ArrowSpeedPerCharge[Level];

		SpawnedProjectile.MaxSpeed = SpeedCharge;
		SpawnedProjectile.Speed = SpeedCharge;
		SpawnedProjectile.TerminalVelocity = SpeedCharge;

		// give the effect of a shoot without charge for the first and second level:
		if (Level == 0 || level == 1)
		{
			SpawnedProjectile.SetPhysics (PHYS_Falling);
		}

		// Call init once again to update the Projectile's Velocity
		SpawnedProjectile.Init (AimDir);
	}

	return SpawnedProjectile;
}

/**
 * See Pawn.ProcessInstantHit
 * @param DamageReduction: Custom KF parameter to handle penetration damage reduction
 */
simulated function ProcessInstantHitEx(byte FiringMode, ImpactInfo Impact, optional int NumHits, optional out float out_PenetrationVal, optional int ImpactNum )
{
    local KFPerk InstigatorPerk;

    InstigatorPerk = GetPerk();
    if( InstigatorPerk != none )
    {
        InstigatorPerk.UpdatePerkHeadShots( Impact, InstantHitDamageTypes[FiringMode], ImpactNum );
    }

    super.ProcessInstantHitEx( FiringMode, Impact, NumHits, out_PenetrationVal, ImpactNum );
}

simulated function ANIMNOTIFY_LockBolt()
{
	// Consider us empty after every shot so the arrow gets hidden
	EmptyMagBlendNode.SetBlendTarget(1, 0);
}

defaultproperties
{
	// Inventory / Grouping
	InventoryGroup=IG_Primary
	InventorySize=8
	GroupPriority=125

	// Charge props
    MaxChargeTime=0.50664 //ShootLoop_Start[20] Time Length
    ValueIncreaseTime=0.2
	DmgIncreasePerCharge=0.5

	ArrowSpeedPerCharge(0)=4000.0
	ArrowSpeedPerCharge(1)=10000.0
	ArrowSpeedPerCharge(2)=15000.0

	StartFireModeAfterReload=FIREMODE_NONE

    // FOV / Position
    MeshFOV=86
	MeshIronSightFOV=52
    PlayerIronSightFOV=70
	PlayerViewOffset=(X=0,Y=0,Z=0)
	IronSightPosition=(X=0,Y=0,Z=0)

	WeaponSelectTexture=Texture2D'WEP_UI_CompoundBow_TEX.UI_WeaponSelect_Compound_Bow'
   	AssociatedPerkClasses(0)=class'KFPerk_Sharpshooter'

	// AI warning system
	bWarnAIWhenAiming=true
    MaxAIWarningDistSQ=4000000
	AimWarningDelay=(X=0.4f, Y=0.8f)
	AimWarningCooldown=0.0f

	// Content
	PackageKey="CompoundBow"
	FirstPersonMeshName="WEP_1P_CompoundBow_MESH.Wep_1stP_CompoundBow_Rig"
	FirstPersonAnimSetNames(0)="WEP_1P_CompoundBow_ANIM.Wep_1stP_CompoundBow_Anim"
	PickupMeshName="WEP_3P_CompoundBow_MESH.Wep_3rdP_CompoundBow_Pickup"
	AttachmentArchetypeName="WEP_CompoundBow_ARCH.Wep_CompoundBow_3P"
	MuzzleFlashTemplateName="WEP_CompoundBow_ARCH.Wep_CompoundBow_MuzzleFlash"

	// Ammo
	MagazineCapacity[0]=1
	SpareAmmoCapacity[0]=30
	InitialSpareMags[0]=10
	AmmoPickupScale[0]=3.0 // 3 arrows

	// Recoil
	maxRecoilPitch=200
	minRecoilPitch=150
	maxRecoilYaw=100
	minRecoilYaw=-100
	RecoilRate=0.06
	RecoilMaxYawLimit=500
	RecoilMinYawLimit=65035
	RecoilMaxPitchLimit=900
	RecoilMinPitchLimit=64785
	RecoilISMaxYawLimit=50
	RecoilISMinYawLimit=65485
	RecoilISMaxPitchLimit=375
	RecoilISMinPitchLimit=65460

	bCanBeReloaded=true
	bReloadFromMagazine=true

	// Animation
	FireAnim=None
	FireSightedAnims[0]=None
	FireLastAnim=None
	FireLastSightedAnim=None

	bLoopingFireAnim(DEFAULT_FIREMODE)=true
	bLoopingFireAnim(ALTFIRE_FIREMODE)=true

	bHasFireLastAnims=true
	BonesToLockOnEmpty=(RW_Weapon)
	
	IdleToIronSightAnim=Idle_To_Iron
	IronSightToIdleAnim=Iron_To_Idle
	IronSightShootToShootAnim=ShootLoop_Iron_To_ShootLoop
	ShootToIronSightShootAnim=ShootLoop_To_ShootLoop_Iron

	ForceReloadTime=0.1

	// DEFAULT_FIREMODE
	FireModeIconPaths(DEFAULT_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_BulletArrow'
	FiringStatesArray(DEFAULT_FIREMODE)=CompoundBowCharge
	WeaponFireTypes(DEFAULT_FIREMODE)=EWFT_Projectile
	WeaponProjectiles(DEFAULT_FIREMODE)=class'KFProj_Bolt_CompoundBowSharp'
	InstantHitDamage(DEFAULT_FIREMODE)=250.0
	InstantHitDamageTypes(DEFAULT_FIREMODE)=class'KFDT_Piercing_CompoundBowSharpImpact'
	PenetrationPower(DEFAULT_FIREMODE)=5.0
	FireInterval(DEFAULT_FIREMODE)=0.2 // For this weapon, this is not the fire rate, but the time when the auto reload anim kicks in
	Spread(DEFAULT_FIREMODE)=0.007 //0.007
	FireOffset=(X=25,Y=2.0,Z=-4.0)

	// ALT_FIREMODE
	FireModeIconPaths(ALTFIRE_FIREMODE)=Texture2D'wep_ui_cryogun_tex.UI_FireModeSelect_Cryogun'
	FiringStatesArray(ALTFIRE_FIREMODE)=CompoundBowCharge
	WeaponFireTypes(ALTFIRE_FIREMODE)=EWFT_Projectile
	WeaponProjectiles(ALTFIRE_FIREMODE)=class'KFProj_Bolt_CompoundBowCryo'
	InstantHitDamage(ALTFIRE_FIREMODE)=50.0
	InstantHitDamageTypes(ALTFIRE_FIREMODE)=class'KFDT_Piercing_CompoundBowCryoImpact'
	PenetrationPower(ALTFIRE_FIREMODE)=0.0
	FireInterval(ALTFIRE_FIREMODE)=0.2 // For this weapon, this is not the fire rate, but the time when the auto reload anim kicks in
	Spread(ALTFIRE_FIREMODE)=0.007 //0.007

	// Fire Effects
	WeaponFireSnd(DEFAULT_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_SA_CompoundBow.CompoundBow_Fire_3P', FirstPersonCue=AkEvent'WW_WEP_SA_CompoundBow.CompoundBow_Fire_1P')
	WeaponFireSnd(ALTFIRE_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_SA_CompoundBow.CompoundBow_Fire_3P', FirstPersonCue=AkEvent'WW_WEP_SA_CompoundBow.CompoundBow_Fire_1P')

	WeaponDryFireSnd(DEFAULT_FIREMODE)=AkEvent'WW_WEP_SA_Crossbow.Play_WEP_SA_Crossbow_DryFire'
	WeaponDryFireSnd(ALTFIRE_FIREMODE)=AkEvent'WW_WEP_SA_Crossbow.Play_WEP_SA_Crossbow_DryFire'

	// BASH_FIREMODE
	InstantHitDamageTypes(BASH_FIREMODE)=class'KFDT_Pirecing_CompoundBow'
	InstantHitDamage(BASH_FIREMODE)=100

	// Attachments
	bHasIronSights=true
	bHasFlashlight=false

	// Just like the launchers, this weapon has mag size of 1 and force reload which
	// causes significant ammo sync issues.  This fix is far from perfect, but it helps.
	bAllowClientAmmoTracking=true
		
	CryoProjectileEffectOn=ParticleSystem'WEP_CompoundBow_EMIT.FX_Compound_Bow_Cryo_Idle_1P'
	CryoProjectileEffectOff=ParticleSystem'WEP_CompoundBow_EMIT.FX_Compound_Bow_Cryo_ToggleOff'
	
	CryoProjectileSoundEffectOn=AkEvent'WW_WEP_SA_CompoundBow.CompoundBow_Cryo_On'
	CryoProjectileSoundEffectOff=AkEvent'WW_WEP_SA_CompoundBow.CompoundBow_Cryo_Off'
}
