691 lines
19 KiB
Ucode
691 lines
19 KiB
Ucode
//=============================================================================
|
|
// KFWeap_Pistol_DualBladed
|
|
//=============================================================================
|
|
//=============================================================================
|
|
// Killing Floor 2
|
|
// Copyright (C) 2021 Tripwire Interactive LLC
|
|
//=============================================================================
|
|
|
|
class KFWeap_Pistol_DualBladed extends KFWeap_DualBase;
|
|
|
|
/*
|
|
*
|
|
* BROUGHT FROM MELEE WEAPON TO SUPPORT PARRYING
|
|
*
|
|
*/
|
|
|
|
/** These override the base firemodes of the same ID (for readability) */
|
|
const BLOCK_FIREMODE = 1; // ALTFIRE_FIREMODE
|
|
|
|
/*********************************************************************************************
|
|
* @name Defensive Abilities
|
|
*********************************************************************************************/
|
|
|
|
struct native BlockEffectInfo
|
|
{
|
|
var class<DamageType> DmgType;
|
|
|
|
/** If != None, overrides the class default FX */
|
|
var AkEvent BlockSound;
|
|
var AkEvent ParrySound;
|
|
var ParticleSystem BlockParticleSys;
|
|
var ParticleSystem ParryParticleSys;
|
|
};
|
|
|
|
var array<BlockEffectInfo> BlockTypes;
|
|
|
|
/** Damage while blocking will be mitigated by this percentage */
|
|
var() float BlockDamageMitigation;
|
|
|
|
/** Parry damage will be mitigated by this percentage */
|
|
var() float ParryDamageMitigationPercent;
|
|
/** Hit reaction strength to bypass pawn's ParryStumbleResist */
|
|
var() byte ParryStrength;
|
|
|
|
/** If true, owning pawn moves at a slower (iron sight) walking speed */
|
|
var bool bMoveAtWalkingSpeed;
|
|
|
|
/** Time between block hit reaction anims */
|
|
var() protected float BlockHitAnimCooldownTime;
|
|
|
|
/** The last time we played a block hit reaction anim */
|
|
var transient protected float LastBlockHitAnimTime;
|
|
|
|
/** Animations played on successful block */
|
|
var array<name> MeleeBlockHitAnims;
|
|
|
|
/*********************************************************************************************
|
|
* @name Effects
|
|
********************************************************************************************* */
|
|
/** Block / Parry */
|
|
var AkBaseSoundObject BlockSound;
|
|
var AKBaseSoundObject ParrySound;
|
|
var ParticleSystem BlockParticleSystem;
|
|
var ParticleSystem ParryParticleSystem;
|
|
var name BlockEffectsSocketName;
|
|
|
|
/** Defensive stance animation names */
|
|
const MeleeBlockStartAnim = 'Brace_in';
|
|
const MeleeBlockLoopAnim = 'Brace_loop';
|
|
const MeleeBlockEndAnim = 'Brace_out';
|
|
|
|
var array<name> BonesToLockOnEmpty_Override;
|
|
|
|
simulated function NotifyAttackParried();
|
|
simulated function NotifyAttackBlocked();
|
|
|
|
// Global declarations for blocking state
|
|
simulated function BlockLoopTimer();
|
|
simulated function ParryCheckTimer();
|
|
|
|
/** Called on the server when successfully block/parry an attack */
|
|
unreliable client function ClientPlayBlockEffects(optional byte BlockTypeIndex=255)
|
|
{
|
|
local AkBaseSoundObject Sound;
|
|
local ParticleSystem PSTemplate;
|
|
|
|
GetBlockEffects(BlockTypeIndex, Sound, PSTemplate);
|
|
PlayLocalBlockEffects(Sound, PSTemplate);
|
|
}
|
|
|
|
/** Called on the server when successfully block/parry an attack */
|
|
reliable client function ClientPlayParryEffects(optional byte BlockTypeIndex=255)
|
|
{
|
|
local AkBaseSoundObject Sound;
|
|
local ParticleSystem PSTemplate;
|
|
local KFPerk InstigatorPerk;
|
|
|
|
InstigatorPerk = GetPerk();
|
|
if( InstigatorPerk != none )
|
|
{
|
|
InstigatorPerk.SetSuccessfullParry();
|
|
}
|
|
|
|
GetParryEffects(BlockTypeIndex, Sound, PSTemplate);
|
|
PlayLocalBlockEffects(Sound, PSTemplate);
|
|
}
|
|
|
|
simulated state MeleeBlocking
|
|
{
|
|
ignores ForceReload, ShouldAutoReload;
|
|
|
|
simulated function bool AllowIronSights() { return false; }
|
|
|
|
simulated function byte GetWeaponStateId()
|
|
{
|
|
return WEP_MeleeBlock;
|
|
}
|
|
|
|
simulated function BeginState(name PreviousStateName)
|
|
{
|
|
local float ParryDuration;
|
|
|
|
ParryDuration = PlayBlockStart();
|
|
|
|
// Set the duration of the window to parry incoming attacks
|
|
if ( ParryDuration > 0.f )
|
|
{
|
|
SetTimer( ParryDuration, false, nameof(ParryCheckTimer) );
|
|
}
|
|
|
|
NotifyBeginState();
|
|
}
|
|
|
|
simulated function EndState(Name NextStateName)
|
|
{
|
|
if ( Instigator.IsLocallyControlled() )
|
|
{
|
|
PlayAnimation(MeleeBlockEndAnim);
|
|
}
|
|
|
|
//SetSlowMovement(false);
|
|
NotifyEndState();
|
|
}
|
|
|
|
/** Return to active state if we're done blocking */
|
|
simulated function EndFire(byte FireModeNum)
|
|
{
|
|
Global.EndFire(FireModeNum);
|
|
|
|
// Wait until parry is finished, then check PendingFire to stop blocking
|
|
if ( !StillFiring(CurrentFireMode) && !IsTimerActive(nameof(ParryCheckTimer)) )
|
|
{
|
|
GotoState('BlockingCooldown');
|
|
}
|
|
}
|
|
|
|
/** After the parry window is finished, check PendingFire to see if we're still blocking */
|
|
simulated function ParryCheckTimer()
|
|
{
|
|
// Check PendingFire to stop blocking
|
|
if ( !StillFiring(CurrentFireMode) )
|
|
{
|
|
GotoState('BlockingCooldown');
|
|
}
|
|
}
|
|
|
|
/** Grab/Grapple attacks can be parried */
|
|
function bool IsGrappleBlocked(Pawn InstigatedBy)
|
|
{
|
|
local float FacingDot;
|
|
local vector Dir2d;
|
|
|
|
// zero Z to give us a 2d dot product
|
|
Dir2d = Normal2d(InstigatedBy.Location - Instigator.Location);
|
|
FacingDot = vector(Instigator.Rotation) dot (Dir2d);
|
|
|
|
// Cos(85)
|
|
if ( FacingDot > 0.087f )
|
|
{
|
|
if ( IsTimerActive(nameof(ParryCheckTimer)) )
|
|
{
|
|
KFPawn(InstigatedBy).NotifyAttackParried(Instigator, 255);
|
|
ClientPlayParryEffects();
|
|
NotifyAttackParried();
|
|
}
|
|
else
|
|
{
|
|
ClientPlayBlockEffects();
|
|
NotifyAttackBlocked();
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/** While holding a melee weapon reduce some incoming damage */
|
|
function AdjustDamage(out int InDamage, class<DamageType> DamageType, Actor DamageCauser)
|
|
{
|
|
local float FacingDot;
|
|
local vector Dir2d;
|
|
local KFPerk InstigatorPerk;
|
|
local byte BlockTypeIndex;
|
|
|
|
// don't apply block/parry effects for teammates
|
|
if (Instigator.IsSameTeam(DamageCauser.Instigator))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// zero Z to give us a 2d dot product
|
|
Dir2d = Normal2d(DamageCauser.Location - Instigator.Location);
|
|
FacingDot = vector(Instigator.Rotation) dot (Dir2d);
|
|
|
|
// Cos(85)
|
|
if ( FacingDot > 0.087f && CanBlockDamageType(DamageType, BlockTypeIndex) )
|
|
{
|
|
InstigatorPerk = GetPerk();
|
|
|
|
if ( IsTimerActive(nameof(ParryCheckTimer)) )
|
|
{
|
|
InDamage *= GetUpgradedParryDamageMitigation(CurrentWeaponUpgradeIndex);
|
|
// Notify attacking pawn for effects / animations
|
|
if ( KFPawn(DamageCauser) != None )
|
|
{
|
|
KFPawn(DamageCauser).NotifyAttackParried(Instigator, ParryStrength);
|
|
}
|
|
|
|
// @NOTE: This is now always true per discussion with AndrewL on KFII-29686. Since we always
|
|
// do the damage mitigation, we should always play the effect regardless of whether the
|
|
// zed was stumbled or knocked down. -MattF
|
|
ClientPlayParryEffects(BlockTypeIndex);
|
|
|
|
NotifyAttackParried();
|
|
|
|
if( InstigatorPerk != none )
|
|
{
|
|
InstigatorPerk.SetSuccessfullParry();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
InDamage *= GetUpgradedBlockDamageMitigation(CurrentWeaponUpgradeIndex);
|
|
ClientPlayBlockEffects(BlockTypeIndex);
|
|
|
|
NotifyAttackBlocked();
|
|
|
|
if( InstigatorPerk != none )
|
|
{
|
|
InstigatorPerk.SetSuccessfullBlock();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
simulated function BlockLoopTimer()
|
|
{
|
|
if( Instigator.IsLocallyControlled() )
|
|
{
|
|
PlayAnimation(MeleeBlockLoopAnim, , true);
|
|
}
|
|
}
|
|
|
|
/** State override for Block_Hit animations */
|
|
unreliable client function ClientPlayBlockEffects(optional byte BlockTypeIndex=255)
|
|
{
|
|
local int AnimIdx;
|
|
local float Duration;
|
|
local KFPerk InstigatorPerk;
|
|
|
|
Global.ClientPlayBlockEffects(BlockTypeIndex);
|
|
|
|
InstigatorPerk = GetPerk();
|
|
if( InstigatorPerk != none )
|
|
{
|
|
InstigatorPerk.SetSuccessfullBlock();
|
|
}
|
|
|
|
if( MeleeBlockHitAnims.Length > 0 && `TimeSince(LastBlockHitAnimTime) > BlockHitAnimCooldownTime && !IsTimerActive(nameof(ParryCheckTimer)) )
|
|
{
|
|
AnimIdx = Rand(MeleeBlockHitAnims.Length);
|
|
Duration = MySkelMesh.GetAnimLength(MeleeBlockHitAnims[AnimIdx]);
|
|
|
|
if ( Duration > 0 )
|
|
{
|
|
LastBlockHitAnimTime = WorldInfo.TimeSeconds;
|
|
PlayAnimation(MeleeBlockHitAnims[AnimIdx]);
|
|
SetTimer(Duration, false, nameof(BlockLoopTimer));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
simulated function float PlayBlockStart()
|
|
{
|
|
local float AnimDuration;
|
|
|
|
if( Instigator.IsLocallyControlled() )
|
|
{
|
|
PlayAnimation(MeleeBlockStartAnim);
|
|
}
|
|
|
|
// set when to start playing the looping anim
|
|
AnimDuration = MySkelMesh.GetAnimLength(MeleeBlockStartAnim);
|
|
if ( AnimDuration > 0.f )
|
|
{
|
|
SetTimer(AnimDuration, false, nameof(BlockLoopTimer));
|
|
}
|
|
else
|
|
{
|
|
BlockLoopTimer();
|
|
}
|
|
|
|
// set the parry duration to the same as the block start anim
|
|
return AnimDuration;
|
|
}
|
|
|
|
/** Called on the client when successfully block/parry an attack */
|
|
simulated function PlayLocalBlockEffects(AKBaseSoundObject Sound, ParticleSystem PSTemplate)
|
|
{
|
|
local vector Loc;
|
|
local rotator Rot;
|
|
local ParticleSystemComponent PSC;
|
|
|
|
if ( Sound != None )
|
|
{
|
|
PlaySoundBase(Sound, true);
|
|
}
|
|
|
|
if ( PSTemplate != None )
|
|
{
|
|
if ( MySkelMesh.GetSocketWorldLocationAndRotation(BlockEffectsSocketName, Loc, Rot) )
|
|
{
|
|
PSC = WorldInfo.MyEmitterPool.SpawnEmitter(PSTemplate, Loc, Rot);
|
|
PSC.SetDepthPriorityGroup(SDPG_Foreground);
|
|
}
|
|
else
|
|
{
|
|
`log(self@GetFuncName()@"missing BlockEffects Socket!");
|
|
}
|
|
}
|
|
}
|
|
|
|
/** If true, this damage type can be blocked by the MeleeBlocking state */
|
|
function bool CanBlockDamageType(class<DamageType> DamageType, optional out byte out_Idx)
|
|
{
|
|
local int Idx;
|
|
|
|
// Check if this damage should be ignored completely
|
|
for (Idx = 0; Idx < BlockTypes.length; ++Idx)
|
|
{
|
|
if ( ClassIsChildOf(DamageType, BlockTypes[Idx].DmgType) )
|
|
{
|
|
out_Idx = Idx;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
out_Idx = INDEX_NONE;
|
|
return false;
|
|
}
|
|
|
|
/** Returns sound and particle system overrides using index into BlockTypes array */
|
|
simulated function GetBlockEffects(byte BlockIndex, out AKBaseSoundObject outSound, out ParticleSystem outParticleSys)
|
|
{
|
|
outSound = BlockSound;
|
|
outParticleSys = BlockParticleSystem;
|
|
|
|
if ( BlockIndex != 255 )
|
|
{
|
|
if ( BlockTypes[BlockIndex].BlockSound != None )
|
|
{
|
|
outSound = BlockTypes[BlockIndex].BlockSound;
|
|
}
|
|
if ( BlockTypes[BlockIndex].BlockParticleSys != None )
|
|
{
|
|
outParticleSys = BlockTypes[BlockIndex].BlockParticleSys;
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Returns sound and particle system overrides using index into BlockTypes array */
|
|
simulated function GetParryEffects(byte BlockIndex, out AKBaseSoundObject outSound, out ParticleSystem outParticleSys)
|
|
{
|
|
outSound = ParrySound;
|
|
outParticleSys = ParryParticleSystem;
|
|
|
|
if ( BlockIndex != 255 )
|
|
{
|
|
if ( BlockTypes[BlockIndex].ParrySound != None )
|
|
{
|
|
outSound = BlockTypes[BlockIndex].ParrySound;
|
|
}
|
|
if ( BlockTypes[BlockIndex].ParryParticleSys != None )
|
|
{
|
|
outParticleSys = BlockTypes[BlockIndex].ParryParticleSys;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*********************************************************************************************
|
|
* State BlockingCooldown
|
|
* A short cooldown state to prevent spamming block while still allowing pendingfire to be set
|
|
*********************************************************************************************/
|
|
|
|
// Global declarations for this state
|
|
simulated function BlockCooldownTimer();
|
|
|
|
simulated state BlockingCooldown extends Active
|
|
{
|
|
ignores AllowSprinting;
|
|
|
|
/** Set cooldown duration */
|
|
simulated function BeginState( Name PreviousStateName )
|
|
{
|
|
SetTimer(0.5, false, nameof(BlockCooldownTimer));
|
|
Super.BeginState(PreviousStateName);
|
|
}
|
|
|
|
// prevent going to block/parry state
|
|
simulated function bool HasAmmo( byte FireModeNum, optional int Amount )
|
|
{
|
|
if ( FireModeNum == BLOCK_FIREMODE )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return Global.HasAmmo(FireModeNum, Amount);
|
|
}
|
|
|
|
// prevent HasAmmo (above) from causing an auto reload
|
|
simulated function bool ShouldAutoReload(byte FireModeNum)
|
|
{
|
|
if ( FireModeNum == BLOCK_FIREMODE )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return Global.ShouldAutoReload(FireModeNum);
|
|
}
|
|
|
|
simulated function BlockCooldownTimer()
|
|
{
|
|
GotoState('Active');
|
|
}
|
|
}
|
|
|
|
/*
|
|
*
|
|
* END of parrying code.
|
|
*
|
|
*/
|
|
|
|
|
|
/**
|
|
* Toggle between DEFAULT and ALTFIRE
|
|
*/
|
|
simulated function AltFireMode()
|
|
{
|
|
if (!Instigator.IsLocallyControlled())
|
|
{
|
|
return;
|
|
}
|
|
|
|
// break out of ironsights when starting to block
|
|
if (bUsingSights)
|
|
{
|
|
SetIronSights(false);
|
|
}
|
|
|
|
Super(KFWeapon).StartFire(BLOCK_FIREMODE);
|
|
}
|
|
|
|
/** Called during reload state */
|
|
simulated function bool CanOverrideMagReload(byte FireModeNum)
|
|
{
|
|
if (FireModeNum == BLOCK_FIREMODE)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return super.CanOverrideMagReload(FireModeNum);
|
|
}
|
|
|
|
/*********************************************************************************************
|
|
* Upgrades
|
|
********************************************************************************************/
|
|
|
|
static simulated function float GetUpgradedBlockDamageMitigation(int UpgradeIndex)
|
|
{
|
|
return GetUpgradedStatValue(default.BlockDamageMitigation, EWUS_BlockDmgMitigation, UpgradeIndex);
|
|
}
|
|
|
|
static simulated function float GetUpgradedParryDamageMitigation(int UpgradeIndex)
|
|
{
|
|
return GetUpgradedStatValue(default.ParryDamageMitigationPercent, EWUS_ParryDmgMitigation, UpgradeIndex);
|
|
}
|
|
|
|
simulated function int GetModifiedDamage(byte FireModeNum, optional vector RayDir)
|
|
{
|
|
if (FireModeNum == BASH_FIREMODE)
|
|
{
|
|
return GetUpgradedStatValue(InstantHitDamage[FireModeNum], EWUS_Damage2, CurrentWeaponUpgradeIndex);
|
|
}
|
|
|
|
return super.GetModifiedDamage(FireModeNum, RayDir);
|
|
}
|
|
|
|
/** Check AmmoCount and update anim tree nodes if needed */
|
|
simulated function UpdateOutOfAmmoEffects(float BlendTime)
|
|
{
|
|
if ( WorldInfo.NetMode == NM_DedicatedServer )
|
|
return;
|
|
|
|
if( EmptyMagBlendNode != None )
|
|
{
|
|
// Differentiate Left/Right
|
|
if ( bAllowClientAmmoTracking && AmmoCount[0] <= 1 )
|
|
{
|
|
EmptyMagBlendNode.SetBlendTarget(1, 0);
|
|
if ( AmmoCount[0] == 0 )
|
|
{
|
|
|
|
EmptyMagBlendNode = AnimNodeBlendPerBone(SkeletalMeshComponent(Mesh).FindAnimNode('EmptyMagBlend'));
|
|
BuildEmptyMagNodeWeightList( EmptyMagBlendNode, BonesToLockOnEmpty_Override );
|
|
|
|
EmptyMagBlendNode.SetBlendTarget(1,0);
|
|
|
|
`Log("blending left");
|
|
EmptyMagBlendNode_L.SetBlendTarget(1,0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Unlocks the bolt bone (Called by animnotify) */
|
|
simulated function ANIMNOTIFY_UnLockBolt()
|
|
{
|
|
super.ANIMNOTIFY_UnLockBolt();
|
|
EmptyMagBlendNode_L.SetBlendTarget(0, 0);
|
|
|
|
EmptyMagBlendNode = AnimNodeBlendPerBone(SkeletalMeshComponent(Mesh).FindAnimNode('EmptyMagBlend'));
|
|
BuildEmptyMagNodeWeightList( EmptyMagBlendNode, BonesToLockOnEmpty);
|
|
}
|
|
|
|
/**
|
|
This weapon only supports akimbo anims.
|
|
Overriding bUseAltFireMode that comes from gameplay options by the user
|
|
*/
|
|
simulated event PostInitAnimTree(SkeletalMeshComponent SkelComp)
|
|
{
|
|
super.PostInitAnimTree(SkelComp);
|
|
|
|
bUseAltFireMode = false;
|
|
}
|
|
|
|
defaultproperties
|
|
{
|
|
// Content
|
|
PackageKey="Dual_BladedPistol"
|
|
FirstPersonMeshName="WEP_1P_Dual_BladedPistol_MESH.WEP_1stP_DualBladedPistol_Rig"
|
|
FirstPersonAnimSetNames(0)="WEP_1P_Dual_BladedPistol_ANIM.Wep_1stP_Dual_BladedPistol_ANIM"
|
|
PickupMeshName="WEP_3P_Dual_BladedPistol_MESH.Wep_Dual_BladedPistol_Pickup"
|
|
AttachmentArchetypeName="WEP_Dual_BladedPistol_ARCH.Wep_Dual_BladedPistol_3P"
|
|
MuzzleFlashTemplateName="WEP_Dual_BladedPistol_ARCH.Wep_Dual_BladedPistol_MuzzleFlash"
|
|
|
|
Begin Object Name=FirstPersonMesh
|
|
AnimTreeTemplate=AnimTree'CHR_1P_Arms_ARCH.WEP_1stP_Dual_Animtree_Master'
|
|
End Object
|
|
|
|
FireOffset=(X=30,Y=7,Z=-5)
|
|
LeftFireOffset=(X=30,Y=-7,Z=-5)
|
|
|
|
// Zooming/Position
|
|
IronSightPosition=(X=-3,Y=0,Z=0)
|
|
PlayerViewOffset=(X=-15,Y=0,Z=0)
|
|
|
|
QuickWeaponDownRotation=(Pitch=-8192,Yaw=0,Roll=0)
|
|
|
|
SingleClass=class'KFWeap_Pistol_Bladed'
|
|
|
|
// FOV
|
|
MeshFOV=96
|
|
MeshIronSightFOV=77
|
|
PlayerIronSightFOV=77
|
|
|
|
// Depth of field
|
|
DOF_FG_FocalRadius=40
|
|
DOF_FG_MaxNearBlurSize=3.5
|
|
|
|
// Ammo
|
|
MagazineCapacity[0]=12
|
|
SpareAmmoCapacity[0]=66 //72 //96
|
|
InitialSpareMags[0]=1
|
|
AmmoPickupScale[0]=0.5 //1.0
|
|
bCanBeReloaded=true
|
|
bReloadFromMagazine=true
|
|
|
|
// Recoil
|
|
maxRecoilPitch=330 //400 //250
|
|
minRecoilPitch=300 //350 //200
|
|
maxRecoilYaw=120 //100
|
|
minRecoilYaw=-120 //-100
|
|
RecoilRate=0.07
|
|
RecoilMaxYawLimit=500
|
|
RecoilMinYawLimit=65035
|
|
RecoilMaxPitchLimit=900
|
|
RecoilMinPitchLimit=65035
|
|
RecoilISMaxYawLimit=50
|
|
RecoilISMinYawLimit=65485
|
|
RecoilISMaxPitchLimit=250
|
|
RecoilISMinPitchLimit=65485
|
|
|
|
// DEFAULT_FIREMODE
|
|
FiringStatesArray(DEFAULT_FIREMODE)=WeaponSingleFiring
|
|
WeaponFireTypes(DEFAULT_FIREMODE)=EWFT_Projectile
|
|
WeaponProjectiles(DEFAULT_FIREMODE)=class'KFProj_Blade_BladedPistol'
|
|
PenetrationPower(DEFAULT_FIREMODE)=3.0
|
|
FireInterval(DEFAULT_FIREMODE)=+0.19 //+0.231
|
|
InstantHitDamage(DEFAULT_FIREMODE)=115.0
|
|
InstantHitDamageTypes(DEFAULT_FIREMODE)=class'KFDT_Slashing_BladedPistol'
|
|
Spread(DEFAULT_FIREMODE)=0.005 //0.015
|
|
|
|
FireModeIconPaths(DEFAULT_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_Sawblade'
|
|
|
|
// MELEE_BLOCK_FIREMODE
|
|
FiringStatesArray(BLOCK_FIREMODE)=MeleeBlocking
|
|
WeaponFireTypes(BLOCK_FIREMODE)=EWFT_Custom
|
|
FireInterval(BLOCK_FIREMODE)=1.f
|
|
AmmoCost(BLOCK_FIREMODE)=0
|
|
|
|
// BASH_FIREMODE
|
|
InstantHitDamageTypes(BASH_FIREMODE)=class'KFDT_Bludgeon_BladedPistol'
|
|
InstantHitDamage(BASH_FIREMODE)=75 //26
|
|
|
|
// Fire Effects
|
|
WeaponFireSnd(DEFAULT_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_BladedPistol.Play_WEP_BladedPistol_Fire_3P', FirstPersonCue=AkEvent'WW_WEP_BladedPistol.Play_WEP_BladedPistol_Fire_1P')
|
|
WeaponDryFireSnd(DEFAULT_FIREMODE)=AkEvent'WW_WEP_BladedPistol.Play_WEP_BladedPistol_Handling_DryFire'
|
|
|
|
WeaponFireSnd(ALTFIRE_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_BladedPistol.Play_WEP_BladedPistol_Fire_3P', FirstPersonCue=AkEvent'WW_WEP_BladedPistol.Play_WEP_BladedPistol_Fire_1P')
|
|
WeaponDryFireSnd(ALTFIRE_FIREMODE)=AkEvent'WW_WEP_BladedPistol.Play_WEP_BladedPistol_Handling_DryFire'
|
|
|
|
// Attachments
|
|
bHasIronSights=true
|
|
bHasFlashlight=true
|
|
|
|
AssociatedPerkClasses(0)=class'KFPerk_Gunslinger'
|
|
AssociatedPerkClasses(1)=class'KFPerk_Berserker'
|
|
|
|
|
|
// Inventory
|
|
InventoryGroup= IG_Primary
|
|
InventorySize=6
|
|
GroupPriority=45
|
|
bCanThrow=true
|
|
bDropOnDeath=true
|
|
WeaponSelectTexture=Texture2D'WEP_UI_Dual_BladedPistol_TEX.UI_WeaponSelect_Dual_BladedPistol'
|
|
bIsBackupWeapon=false
|
|
|
|
BonesToLockOnEmpty=(RW_FrontPivot)
|
|
BonesToLockOnEmpty_L=(LW_FrontPivot)
|
|
BonesToLockOnEmpty_Override=(RW_FrontPivot, LW_FrontPivot)
|
|
|
|
bHasFireLastAnims=true
|
|
|
|
// default MIC param names
|
|
BlockEffectsSocketName=BlockEffect
|
|
// Defensive
|
|
BlockDamageMitigation=0.60f
|
|
ParryDamageMitigationPercent=0.5
|
|
ParryStrength=4
|
|
BlockHitAnimCooldownTime=0.5f
|
|
BlockTypes.Add((DmgType=class'KFDT_Bludgeon'))
|
|
BlockTypes.Add((DmgType=class'KFDT_Slashing'))
|
|
|
|
// Block Sounds
|
|
BlockSound=AkEvent'WW_WEP_Bullet_Impacts.Play_Block_MEL_Crovel'
|
|
ParrySound=AkEvent'WW_WEP_Bullet_Impacts.Play_Parry_Metal'
|
|
|
|
BlockParticleSystem=ParticleSystem'FX_Impacts_EMIT.FX_Block_melee_01'
|
|
ParryParticleSystem=ParticleSystem'FX_Impacts_EMIT.FX_Parry_melee_01'
|
|
MeleeBlockHitAnims=(Block_Hit_V1, Block_Hit_V2, Block_Hit_V3);
|
|
|
|
// Upgrades
|
|
UpgradeFireModes(BLOCK_FIREMODE) = 0
|
|
//Upgrades
|
|
WeaponUpgrades[1]=(Stats=((Stat=EWUS_Damage0, Scale=1.15f), (Stat=EWUS_Damage1, Scale=1.15f), (Stat=EWUS_Damage2, Scale=1.15f), (Stat=EWUS_Weight, Add=1)))
|
|
WeaponUpgrades[2]=(Stats=((Stat=EWUS_Damage0, Scale=1.3f), (Stat=EWUS_Damage1, Scale=1.3f), (Stat=EWUS_Damage2, Scale=1.3f), (Stat=EWUS_Weight, Add=2)))
|
|
}
|
|
|