1
0
KF2-Dev-Scripts/KFGameContent/Classes/KFWeap_Bow_CompoundBow.uc

819 lines
22 KiB
Ucode
Raw Normal View History

2020-12-13 15:01:13 +00:00
//=============================================================================
// 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
2021-06-02 20:06:18 +00:00
SpareAmmoCapacity[0]=35 //30
InitialSpareMags[0]=11 //10
AmmoPickupScale[0]=4.0 //3.0
2020-12-13 15:01:13 +00:00
// 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'
}