//============================================================================= // KFWeap_Edged_AbominationAxe //============================================================================= //============================================================================= // Killing Floor 2 // Copyright (C) 2022 Tripwire Interactive LLC //============================================================================= class KFWeap_Edged_Scythe extends KFWeap_MeleeBase; var const array HitboxChainFolded; var const array HitboxChainUnfolded; var const int MaxHitRangeFolded; var const int MaxHitRangeUnfolded; var const int FoldedDamage; var const int FoldedDamageAlt; var const int UnfoldedDamage; var const int UnfoldedDamageAlt; var const class FoldedDT; var const class FoldedDTAlt; var const class UnfoldedDT; var const class UnfoldedDTAlt; var const float UnfoldBlendingDuration; var const float FoldedAttackAnimRate; var const vector PlayerViewOffsetUnfolded; var transient vector OriginalPlayerViewOffset; var transient bool bIsFolded; var AnimNodeBlendPerBone FoldBlendNode; var const ParticleSystem BloodParticles; const BloodParticlesSocket = 'BlockEffect'; var ParticleSystem FoldedTrailParticleSystem; var ParticleSystem UnfoldedTrailParticleSystem; simulated event PreBeginPlay() { Super.PreBeginPlay(); OriginalPlayerViewOffset = PlayerViewOffset; } event PostBeginPlay() { Super.PostBeginPlay(); ChangeMode(true, false); SetFoldedBladeBlendTarget(1.0f, 0.0f); } ///////////////////////////////////////////////////////////////////////////// /** The SkeletalMeshComponents Animations are being instanced from AnimTreeTemplate * before PostInitAnimTree. Be sure to never set the Mesh's animations directly through * the package */ simulated event PostInitAnimTree(SkeletalMeshComponent SkelComp) { Super.PostInitAnimTree(SkelComp); FoldBlendNode = AnimNodeBlendPerBone(SkelComp.FindAnimNode('FoldBlendNode')); SetFoldedBladeBlendTarget(1.0f, 0.0f); } ///////////////////////////////////////////////////////////////////////////// /** Returns true if weapon can potentially be reloaded */ simulated function bool CanReload(optional byte FireModeNum) { return true; } simulated state WeaponUpkeep { simulated function BeginState(name PreviousStateName) { local name AnimName; local float Duration; AnimName = CleanNonBloodyAnim; Duration = MySkelMesh.GetAnimLength(AnimName); if ( Duration > 0.f ) { if ( Instigator.IsFirstPerson() ) { PlayAnimation(AnimName); SetTimer(Duration, FALSE, nameof(SwapComplete)); } } else { `warn("Duration is zero!!!"@AnimName); SetTimer(0.001, FALSE, nameof(SwapComplete)); } NotifyBeginState(); } simulated function BeginFire(byte FireModeNum) { } simulated event EndState(Name NextStateName) { ClearTimer(nameof(SwapComplete)); Super.EndState(NextStateName); NotifyEndState(); } simulated function SwapComplete() { if (Role == ROLE_Authority) { GotoState('Active'); } else { GotoState('Active'); ServerSwapComplete(); } } } server reliable function ServerSwapComplete() { GotoState('Active'); } simulated function ChangeMode(bool IsFolded, bool bApplyBlend = true) { if (MeleeAttackHelper == none) return; if (IsFolded) { MeleeAttackHelper.SetMeleeRange(MaxHitRangeFolded); MeleeAttackHelper.SetHitBoxChain(HitboxChainFolded); InstantHitDamage[DEFAULT_FIREMODE] = FoldedDamage; InstantHitDamage[HEAVY_ATK_FIREMODE] = FoldedDamageAlt; InstantHitDamageTypes[DEFAULT_FIREMODE] = FoldedDT; InstantHitDamageTypes[HEAVY_ATK_FIREMODE] = FoldedDTAlt; PlayerViewOffset = OriginalPlayerViewOffset; InstantHitDamageTypes[BASH_FIREMODE]=class'KFDT_Piercing_ScytheStabFolded'; InstantHitMomentum[BASH_FIREMODE]=100000.f; InstantHitDamage[BASH_FIREMODE]=40; } else { MeleeAttackHelper.SetMeleeRange(MaxHitRangeUnfolded); MeleeAttackHelper.SetHitBoxChain(HitboxChainUnfolded); InstantHitDamage[DEFAULT_FIREMODE] = UnfoldedDamage; InstantHitDamage[HEAVY_ATK_FIREMODE] = UnfoldedDamageAlt; InstantHitDamageTypes[DEFAULT_FIREMODE] = UnfoldedDT; InstantHitDamageTypes[HEAVY_ATK_FIREMODE] = UnfoldedDTAlt; PlayerViewOffset = PlayerViewOffsetUnfolded; InstantHitDamageTypes[BASH_FIREMODE]=class'KFDT_Piercing_ScytheStab'; InstantHitMomentum[BASH_FIREMODE]=100000.f; InstantHitDamage[BASH_FIREMODE]=60; } NotifyServerMode(bIsFolded); if (bApplyBlend) { SetFoldedBladeBlendTarget(bIsFolded ? 1.0f : 0.0f, UnfoldBlendingDuration); } } simulated function SetFoldedBladeBlendTarget(float Value, float BlendTime) { if ( FoldBlendNode != None ) { FoldBlendNode.SetBlendTarget(Value, BlendTime); } } simulated function StartFire(byte FireModeNum) { if (StartFireDisabled && FireModeNum == BLOCK_FIREMODE) { StartFireDisabled = false; return; } if (FireModeNum == DEFAULT_FIREMODE || FireModeNum == HEAVY_ATK_FIREMODE) { DistortTrailParticle = bIsFolded ? FoldedTrailParticleSystem : UnfoldedTrailParticleSystem; } else if (FireModeNum == BASH_FIREMODE) { DistortTrailParticle = none; } super.StartFire(FireModeNum); } static simulated function float CalculateTraderWeaponStatDamage() { // How is this calculated for this weapon? return default.UnfoldedDamage; } simulated function PlayAnimation(name Sequence, optional float fDesiredDuration, optional bool bLoop, optional float BlendInTime=0.1, optional float BlendOutTime=0.0) { local string NewAnimName; if (Sequence == 'Idle' || Sequence == 'Guncheck_V1' || Sequence == 'Guncheck_V2' || Sequence == 'Guncheck_V3') { NewAnimName = string(Sequence); NewAnimName $= ((bIsFolded) ? "_Folded" : "_Unfolded"); Super.PlayAnimation(name(NewAnimName), fDesiredDuration, bLoop, BlendInTime, BlendOutTime); } else { Super.PlayAnimation(Sequence, fDesiredDuration, bLoop, BlendInTime, BlendOutTime); } } simulated function ModifyMeleeAttackSpeed(out float InSpeed, optional int FireMode = DEFAULT_FIREMODE, optional int UpgradeIndex = INDEX_NONE, optional KFPerk CurrentPerk) { Super.ModifyMeleeAttackSpeed(InSpeed, FireMode, UpgradeIndex, CurrentPerk); if (bIsFolded) { InSpeed *= FoldedAttackAnimRate; } } /** * Overriden to apply fold/unfold logic */ simulated function ANIMNOTIFY_LockBolt() { bIsFolded = !bIsFolded; ChangeMode(bIsFolded); } /** Unused */ simulated function ANIMNOTIFY_UnLockBolt() { } /** Play blood VFX as we only use one anim. */ simulated function ANIMNOTIFY_CleanBlood() { if (!bIsBloody) { return; } if (WorldInfo.NetMode != NM_DedicatedServer && BloodParticles != none) { WorldInfo.MyEmitterPool.SpawnEmitterMeshAttachment(BloodParticles, MySkelMesh, BloodParticlesSocket, true); } Super.ANIMNOTIFY_CleanBlood(); } simulated state WeaponEquipping { /** Initialize the weapon as being active and ready to go. */ simulated event BeginState(Name PreviousStateName) { Super.BeginState(PreviousStateName); if (WorldInfo.NetMode != NM_Client) { NotifyInitialState(bIsFolded); } } } /** Should replicate to 3P to show the shield effects */ simulated function NotifyInitialState(bool bFolded) { local KFPawn KFP; if (WorldInfo.NetMode != NM_Client) { `Log("NotifyInitialState: " $bFolded); KFP = KFPawn(Instigator); KFP.OnWeaponSpecialAction(bFolded ? 0 : 1); } } reliable server function NotifyServerMode(bool bFolded) { bIsFolded = bFolded; } defaultproperties { // Zooming/Position PlayerViewOffset=(X=10,Y=0,Z=-10) // (X=2,Y=0,Z=0) PlayerViewOffsetUnfolded=(X=12,Y=0,Z=-7) // Content PackageKey="Scythe" FirstPersonMeshName="WEP_1P_Scythe_MESH.Wep_1stP_Scythe_Rig" FirstPersonAnimSetNames(0)="WEP_1P_Scythe_ANIM.Wep_1st_Scythe_Anim" FirstPersonAnimTree="WEP_1P_Scythe_ANIM.1P_Scythe_Animtree" PickupMeshName="wep_3p_scythe_mesh.Wep_3rdP_Scythe_Pickup" AttachmentArchetypeName="WEP_Scythe_ARCH.Wep_Scythe_3P" // Short Range Mode Params MaxHitRangeFolded=220 FoldedDamage = 70 FoldedDamageAlt = 120 FoldedDT=class'KFDT_Slashing_ScytheShort' FoldedDTAlt=class'KFDT_Slashing_ScytheShortAlt' HitboxChainFolded = {( (BoneOffset=(X=+3,Z=190)), (BoneOffset=(X=-3,Z=170)), (BoneOffset=(X=+3,Z=150)), (BoneOffset=(X=-3,Z=130)), (BoneOffset=(X=+3,Z=110)), (BoneOffset=(X=-3,Z=90)), (BoneOffset=(X=+3,Z=70)), (BoneOffset=(X=-3,Z=50)), (BoneOffset=(X=+3,Z=30)), (BoneOffset=(Z=10)) )} // Long Range Mode Params MaxHitRangeUnfolded=300 UnfoldedDamage=140 UnfoldedDamageAlt=190 UnfoldedDT=class'KFDT_Slashing_ScytheLong' UnfoldedDTAlt=class'KFDT_Slashing_ScytheLongAlt' HitboxChainUnfolded = {( (BoneOffset=(X=-3,Z=290)), (BoneOffset=(X=-3,Z=270)), (BoneOffset=(X=-3,Z=250)), (BoneOffset=(X=+3,Z=230)), (BoneOffset=(X=-3,Z=210)), (BoneOffset=(X=+3,Z=190)), (BoneOffset=(X=-3,Z=170)), (BoneOffset=(X=+3,Z=150)), (BoneOffset=(X=-3,Z=130)), (BoneOffset=(X=+3,Z=110)), (BoneOffset=(X=-3,Z=90)), (BoneOffset=(X=+3,Z=70)), (BoneOffset=(X=-3,Z=50)), (BoneOffset=(X=+3,Z=30)), (BoneOffset=(Z=10)) )} Begin Object Name=MeleeHelper_0 WorldImpactEffects=KFImpactEffectInfo'FX_Impacts_ARCH.Bladed_melee_impact' MeleeImpactCamShakeScale=0.04f //0.5 // modified combo sequences ChainSequence_F=(DIR_ForwardRight, DIR_ForwardLeft, DIR_ForwardRight, DIR_ForwardLeft) ChainSequence_B=(DIR_BackwardLeft, DIR_BackwardRight, DIR_BackwardLeft, DIR_ForwardRight, DIR_Left, DIR_Right, DIR_Left) ChainSequence_L=(DIR_Right, DIR_Left) ChainSequence_R=(DIR_Left, DIR_Right, DIR_ForwardLeft, DIR_ForwardRight, DIR_Left, DIR_Right) End Object InstantHitDamageTypes(DEFAULT_FIREMODE)=class'KFDT_Slashing_ScytheShort' InstantHitMomentum(DEFAULT_FIREMODE)=30000.f InstantHitDamageTypes(HEAVY_ATK_FIREMODE)=class'KFDT_Slashing_ScytheShortAlt' FiringStatesArray(HEAVY_ATK_FIREMODE)=MeleeHeavyAttacking InstantHitMomentum(HEAVY_ATK_FIREMODE)=30000.f // Defined in ChangeMode function //InstantHitDamageTypes(BASH_FIREMODE)=class'KFDT_Piercing_ScytheStab' //InstantHitMomentum(BASH_FIREMODE)=100000.f //InstantHitDamage(BASH_FIREMODE)=50 // Inventory GroupPriority=50 InventorySize=7 WeaponSelectTexture=Texture2D'WEP_UI_Scythe_TEX.UI_WeaponSelect_Scythe' AssociatedPerkClasses(0)=class'KFPerk_Berserker' // Block Sounds BlockSound=AkEvent'WW_WEP_Bullet_Impacts.Play_Block_MEL_Katana' ParrySound=AkEvent'WW_WEP_Bullet_Impacts.Play_Parry_Metal' ParryDamageMitigationPercent=0.4 BlockDamageMitigation=0.5 ParryStrength=5 bIsFolded=true BonesToLockOnEmpty.Empty() UnfoldBlendingDuration=0.05f FoldedAttackAnimRate=0.65f // IdleFidgetAnims=(Guncheck_v1, Guncheck_v2, Guncheck_v3) // Weapon Upgrade stat boosts WeaponUpgrades[1]=(Stats=((Stat=EWUS_Damage0, Scale=1.15f), (Stat=EWUS_Damage1, Scale=1.15f), (Stat=EWUS_Weight, Add=1))) DistortTrailParticle = none WhiteTrailParticle = none // BlueTrailParticle = none // RedTrailParticle = none FoldedTrailParticleSystem=ParticleSystem'WEP_Scythe_EMIT.FX_Scythe_Custom_R_01' UnfoldedTrailParticleSystem=ParticleSystem'WEP_Scythe_EMIT.FX_Scythe_Custom_Unfold_01'; BloodParticles = ParticleSystem'WEP_1P_KATANA_EMIT.FX_katana_blood_flick_01' }