1
0
This commit is contained in:
2021-09-03 00:46:08 +03:00
parent 9a5bfed23e
commit 9ed2045549
101 changed files with 5216 additions and 199 deletions

View File

@ -0,0 +1,27 @@
//=============================================================================
// KFDT_Ballistic_HRG_Boomy
//=============================================================================
//
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFDT_Ballistic_HRG_Boomy extends KFDT_Ballistic_Submachinegun
abstract
hidedropdown;
defaultproperties
{
KDamageImpulse=900
KDeathUpKick=-300
KDeathVel=100
StumblePower=35
GunHitPower=25
WeaponDef=class'KFWeapDef_HRG_Boomy'
//Perk
ModifierPerkList(0)=class'KFPerk_Demolitionist'
}

View File

@ -0,0 +1,29 @@
//=============================================================================
// KFDT_Ballistic_HRG_Energy_Primary
//=============================================================================
// HRG Energy Gun Damage Type
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFDT_Ballistic_HRG_Energy_Primary extends KFDT_Ballistic_Handgun
abstract
hidedropdown;
defaultproperties
{
KDamageImpulse=900
KDeathUpKick=-300
KDeathVel=100
StumblePower=15
GunHitPower=175
WeaponDef=class'KFWeapDef_HRG_Energy'
//Perk
ModifierPerkList(0)=class'KFPerk_Gunslinger'
EffectGroup=FXG_Energy_Yellow
}

View File

@ -0,0 +1,28 @@
//=============================================================================
// KFDT_Ballistic_HRG_Energy_Secondary
//=============================================================================
//
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFDT_Ballistic_HRG_Energy_Secondary extends KFDT_Ballistic_Handgun
abstract
hidedropdown;
defaultproperties
{
StumblePower=100
KnockdownPower=20
GunHitPower=250
EMPPower=60
WeaponDef=class'KFWeapDef_HRG_Energy'
//Perk
ModifierPerkList(2)=class'KFPerk_Gunslinger'
EffectGroup=FXG_Energy_Magenta
}

View File

@ -0,0 +1,59 @@
//=============================================================================
// KFDT_Ballistic_ParasiteImplanter
//=============================================================================
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFDT_Ballistic_ParasiteImplanter extends KFDT_Ballistic_Rifle
abstract
hidedropdown;
/** Allows the damage type to customize exactly which hit zones it can dismember */
static simulated function bool CanDismemberHitZone( name InHitZoneName )
{
if( super.CanDismemberHitZone( InHitZoneName ) )
{
return true;
}
switch ( InHitZoneName )
{
case 'lupperarm':
case 'rupperarm':
return true;
}
return false;
}
/** Called when damage is dealt to apply additional damage type (e.g. Damage Over Time) */
static function ApplySecondaryDamage( KFPawn Victim, int DamageTaken, optional Controller InstigatedBy )
{
local class<KFDamageType> ToxicDT;
ToxicDT = class'KFDT_Ballistic_Assault_Medic'.static.GetMedicToxicDmgType( DamageTaken, InstigatedBy );
if ( ToxicDT != None )
{
Victim.ApplyDamageOverTime(DamageTaken, InstigatedBy, ToxicDT);
}
}
defaultproperties
{
KDamageImpulse=2000
KDeathUpKick=400
KDeathVel=250
KnockdownPower=25
//StunPower=20 //25
StumblePower=80
GunHitPower=160
//MeleeHitPower=0
WeaponDef=class'KFWeapDef_ParasiteImplanter'
ModifierPerkList(0)=class'KFPerk_FieldMedic'
ModifierPerkList(1)=class'KFPerk_Sharpshooter'
}

View File

@ -0,0 +1,36 @@
//=============================================================================
// KFDT_Ballistic_ParasiteImplanterAlt
//=============================================================================
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFDT_Ballistic_ParasiteImplanterAlt extends KFDT_Toxic
abstract
hidedropdown;
/** Called when damage is dealt to apply additional damage type (e.g. Damage Over Time) */
static function ApplySecondaryDamage( KFPawn Victim, int DamageTaken, optional Controller InstigatedBy )
{
local class<KFDamageType> ToxicDT;
ToxicDT = class'KFDT_Ballistic_Assault_Medic'.static.GetMedicToxicDmgType( DamageTaken, InstigatedBy );
if ( ToxicDT != None )
{
Victim.ApplyDamageOverTime(DamageTaken, InstigatedBy, ToxicDT);
}
}
defaultproperties
{
KnockdownPower=30
StumblePower=200
GunHitPower=100
PoisonPower=0 //80
WeaponDef=class'KFWeapDef_ParasiteImplanter'
ModifierPerkList(0)=class'KFPerk_FieldMedic'
ModifierPerkList(1)=class'KFPerk_Sharpshooter'
}

View File

@ -0,0 +1,136 @@
//=============================================================================
// KFDT_Bludgeon_BladedPistol
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFDT_Bludgeon_BladedPistol extends KFDT_Slashing
abstract
hidedropdown;
/** Allows the damage type to customize exactly which hit zones it can dismember */
static simulated function bool CanDismemberHitZone( name InHitZoneName )
{
return true;
}
/** Allows the damage type to map a hit zone to a different bone for dismemberment purposes */
static simulated function GetBoneToDismember(KFPawn_Monster InPawn, vector HitDirection, name InHitZoneName, out name OutBoneName)
{
local EPawnOctant SlashDir;
local KFCharacterInfo_Monster MonsterInfo;
MonsterInfo = InPawn.GetCharacterMonsterInfo();
if ( MonsterInfo == none )
{
return;
}
SlashDir = GetLastSlashDirection(InPawn, HitDirection);
if( SlashDir == DIR_Forward || SlashDir == DIR_Backward )
{
if( InHitZoneName == 'chest' || InHitZoneName == 'head' )
{
if( MonsterInfo.SpecialMeleeDismemberment.bAllowVerticalSplit )
{
// Randomly pick the left or right shoulder bone and split the guy in half vertically
OutBoneName = Rand(2) == 0
? MonsterInfo.SpecialMeleeDismemberment.LeftShoulderBoneName
: MonsterInfo.SpecialMeleeDismemberment.RightShoulderBoneName;
}
}
}
else if( SlashDir == DIR_Left || SlashDir == DIR_Right )
{
if( InHitZoneName == 'chest' || InHitZoneName == 'abdomen' || InHitZoneName == 'stomach' )
{
if( MonsterInfo.SpecialMeleeDismemberment.bAllowHorizontalSplit )
{
// Split the guy in half horizontally
OutBoneName = MonsterInfo.SpecialMeleeDismemberment.SpineBoneName;
}
}
}
else if( SlashDir == DIR_ForwardLeft || SlashDir == DIR_BackwardRight )
{
if( InHitZoneName == 'chest' )
{
if( MonsterInfo.SpecialMeleeDismemberment.bAllowVerticalSplit )
{
OutBoneName = MonsterInfo.SpecialMeleeDismemberment.RightShoulderBoneName;
}
}
else if( InHitZoneName == 'head' )
{
if( MonsterInfo.SpecialMeleeDismemberment.bAllowVerticalSplit )
{
// Use a random chance to decide whether to dismember the head or the shoulder constraints
if( Rand(2) == 0 )
{
// ... and choose one of the shoulder constraints at random
OutBoneName = MonsterInfo.SpecialMeleeDismemberment.RightShoulderBoneName;
}
}
}
}
else if( SlashDir == DIR_ForwardRight || SlashDir == DIR_BackwardLeft )
{
if( InHitZoneName == 'chest' )
{
if( MonsterInfo.SpecialMeleeDismemberment.bAllowVerticalSplit )
{
OutBoneName = MonsterInfo.SpecialMeleeDismemberment.LeftShoulderBoneName;
}
}
else if( InHitZoneName == 'head' )
{
if( MonsterInfo.SpecialMeleeDismemberment.bAllowVerticalSplit )
{
// Use a random chance to decide whether to dismember the head or the shoulder constraints
if( Rand(2) == 0 )
{
OutBoneName = MonsterInfo.SpecialMeleeDismemberment.LeftShoulderBoneName;
}
}
}
}
}
/** Allows the damage type to modify the impulse when a specified hit zone is dismembered */
static simulated function ModifyDismembermentHitImpulse(KFPawn_Monster InPawn, name InHitZoneName, vector HitDirection,
out vector OutImpulseDir, out vector OutParentImpulseDir,
out float OutImpulseScale, out float OutParentImpulseScale)
{
local EPawnOctant SlashDir;
SlashDir = GetLastSlashDirection(InPawn, HitDirection);
// Apply upward impulse on decapitation from a clean horizontal slash
if( InHitZoneName == 'head' &&
( SlashDir == DIR_Left || SlashDir == DIR_Right ) )
{
OutImpulseDir += 10*vect(0,0,1);
OutImpulseDir = Normal(OutImpulseDir);
OutParentImpulseScale = 0.f;
}
// Do not apply any impulse on split in half from a vertical slash
else if( (InHitZoneName == 'head' || InHitZoneName == 'chest' ) &&
( SlashDir == DIR_Forward || SlashDir == DIR_Backward) )
{
OutImpulseScale = 0.f;
OutParentImpulseScale = 0.f;
}
}
DefaultProperties
{
StumblePower=200
MeleeHitPower=100
WeaponDef=class'KFWeapDef_BladedPistol'
ModifierPerkList(0)=class'KFPerk_Berserker'
ModifierPerkList(1)=class'KFPerk_Gunslinger'
}

View File

@ -0,0 +1,15 @@
//=============================================================================
// KFDT_Bludgeon_HRG_Boomy
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFDT_Bludgeon_HRG_Boomy extends KFDT_Bludgeon_RifleButt
abstract
hidedropdown;
DefaultProperties
{
WeaponDef=class'KFWeapDef_HRG_Boomy'
}

View File

@ -0,0 +1,16 @@
//=============================================================================
// KFDT_Bludgeon_HRG_Energy
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFDT_Bludgeon_HRG_Energy extends KFDT_Bludgeon_RifleButt
abstract
hidedropdown;
DefaultProperties
{
//defaults
WeaponDef=class'KFWeapDef_HRG_Energy'
}

View File

@ -0,0 +1,16 @@
//=============================================================================
// KFDT_Bludgeon_ParasiteImplanter
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFDT_Bludgeon_ParasiteImplanter extends KFDT_Bludgeon_RifleButt
abstract
hidedropdown;
DefaultProperties
{
//defaults
WeaponDef=class'KFWeapDef_ParasiteImplanter'
}

View File

@ -0,0 +1,30 @@
//=============================================================================
// KFDT_Explosive_GravityImploderWave
//=============================================================================
// Explosive damage type for the Gravity Imploder shockwave
//=============================================================================
// Killing Floor 2
// Copyright (C) 2020 Tripwire Interactive LLC
//=============================================================================
class KFDT_Explosive_HRG_Boomy extends KFDT_Explosive
abstract
hidedropdown;
defaultproperties
{
bShouldSpawnPersistentBlood=true
// physics impact
RadialDamageImpulse=3000 //5000 //20000
GibImpulseScale=0.15
KDeathUpKick=1000
KDeathVel=300
KnockdownPower=7
StumblePower=20
//Perk
ModifierPerkList(0)=class'KFPerk_Demolitionist'
WeaponDef=class'KFWeapDef_HRG_Boomy'
}

View File

@ -0,0 +1,16 @@
//=============================================================================
// KFDT_Healing_ParasiteSeed
//=============================================================================
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFDT_Healing_ParasiteSeed extends KFDT_Healing
abstract
hidedropdown;
defaultproperties
{
bNoPain=true
}

View File

@ -0,0 +1,190 @@
//=============================================================================
// KFDT_Slashing_EvisceratorProj
//=============================================================================
// Damage type for projectiles fired from the Eviscerator
//=============================================================================
// Killing Floor 2
// Copyright (C) 2015 Tripwire Interactive LLC
// John "Ramm-Jaeger" Gibson
//=============================================================================
class KFDT_Slashing_BladedPistol extends KFDT_Slashing
abstract
hidedropdown;
`define COSINE_0_DEGREES 1
`define COSINE_20_DEGREES 0.94
`define COSINE_70_DEGREES 0.34
`define COSINE_90_DEGREES 0
/** Allows the damage type to customize exactly which hit zones it can dismember */
static simulated function bool CanDismemberHitZone( name InHitZoneName )
{
return true;
}
/** @return The slast type from the HitFxInfo. This returns a 8-way slash info. */
static simulated function EPawnOctant GetLastSlashDirection(KFPawn_Monster InPawn, vector HitDirection)
{
local vector SlashPlaneNormal;
local rotator InstigatorRotation;
local vector InstigatorFaceDir, InstigatorRightDir;
local float UpDotSlash, RightDotSlash, UpThresholdValue;
if( InPawn != none )
{
HitDirection = Normal(HitDirection);
InstigatorRotation = InPawn.GetBaseAimRotation();
InstigatorFaceDir = GetRotatorAxis(InstigatorRotation, 0);
InstigatorRightDir = GetRotatorAxis(InstigatorRotation, 1);
// Cross the face direction of the instigator with the hit direction to find
// the normal to the "slashing" plane
SlashPlaneNormal = Normal(InstigatorFaceDir Cross HitDirection);
// Dot the slash plane normal with the world up direction to figure out
// the quadrant for the normal of the slash plane
UpDotSlash = vect(0,0,1) Dot SlashPlaneNormal;
UpThresholdValue = Abs(UpDotSlash);
// Dot the slash plane normal with the instigator right to figure out
// the direction of the slash
RightDotSlash = InstigatorRightDir Dot SlashPlaneNormal;
// Threshhold against the preset values to find out the type of slash. The sign (+ or -) of the
// dot products are used to further classify the direction of the slash
if( UpThresholdValue <= `COSINE_0_DEGREES && UpThresholdValue >= `COSINE_20_DEGREES )
{
if( UpDotSlash > 0 )
return DIR_Right;
else
return DIR_Left;
}
else if( UpThresholdValue <= `COSINE_20_DEGREES && UpThresholdValue >= `COSINE_70_DEGREES )
{
if( UpDotSlash < 0 && RightDotSlash > 0 )
return DIR_ForwardLeft;
else if( UpDotSlash > 0 && RightDotSlash > 0 )
return DIR_ForwardRight;
else if( UpDotSlash > 0 && RightDotSlash < 0 )
return DIR_BackwardRight;
else if( UpDotSlash < 0 && RightDotSlash < 0 )
return DIR_BackwardLeft;
}
else if( UpThresholdValue <= `COSINE_70_DEGREES && UpThresholdValue >= `COSINE_90_DEGREES )
{
if( RightDotSlash > 0 )
return DIR_Forward;
else
return DIR_Backward;
}
}
return DIR_None;
}
/** Allows the damage type to map a hit zone to a different bone for dismemberment purposes */
static simulated function GetBoneToDismember(KFPawn_Monster InPawn, vector HitDirection, name InHitZoneName, out name OutBoneName)
{
local EPawnOctant SlashDir;
local KFCharacterInfo_Monster MonsterInfo;
MonsterInfo = InPawn.GetCharacterMonsterInfo();
if ( MonsterInfo == none )
{
return;
}
SlashDir = GetLastSlashDirection(InPawn, HitDirection);
if( SlashDir == DIR_Forward || SlashDir == DIR_Backward )
{
if( InHitZoneName == 'chest' || InHitZoneName == 'head' )
{
if( MonsterInfo.SpecialMeleeDismemberment.bAllowVerticalSplit )
{
// Randomly pick the left or right shoulder bone and split the guy in half vertically
OutBoneName = Rand(2) == 0
? MonsterInfo.SpecialMeleeDismemberment.LeftShoulderBoneName
: MonsterInfo.SpecialMeleeDismemberment.RightShoulderBoneName;
}
}
}
else if( SlashDir == DIR_Left || SlashDir == DIR_Right )
{
if( InHitZoneName == 'chest' || InHitZoneName == 'abdomen' || InHitZoneName == 'stomach')
{
if( MonsterInfo.SpecialMeleeDismemberment.bAllowHorizontalSplit )
{
// Split the guy in half horizontally
OutBoneName = MonsterInfo.SpecialMeleeDismemberment.SpineBoneName;
}
}
}
else if( SlashDir == DIR_ForwardLeft || SlashDir == DIR_BackwardRight )
{
if( InHitZoneName == 'chest' )
{
if( MonsterInfo.SpecialMeleeDismemberment.bAllowVerticalSplit )
{
OutBoneName = MonsterInfo.SpecialMeleeDismemberment.RightShoulderBoneName;
}
}
else if( InHitZoneName == 'head' )
{
if( MonsterInfo.SpecialMeleeDismemberment.bAllowVerticalSplit )
{
// Use a random chance to decide whether to dismember the head or the shoulder constraints
if( Rand(2) == 0 )
{
// ... and choose one of the shoulder constraints at random
OutBoneName = MonsterInfo.SpecialMeleeDismemberment.RightShoulderBoneName;
}
}
}
}
else if( SlashDir == DIR_ForwardRight || SlashDir == DIR_BackwardLeft )
{
if( InHitZoneName == 'chest' )
{
if( MonsterInfo.SpecialMeleeDismemberment.bAllowVerticalSplit )
{
OutBoneName = MonsterInfo.SpecialMeleeDismemberment.LeftShoulderBoneName;
}
}
else if( InHitZoneName == 'head' )
{
if( MonsterInfo.SpecialMeleeDismemberment.bAllowVerticalSplit )
{
// Use a random chance to decide whether to dismember the head or the shoulder constraints
if( Rand(2) == 0 )
{
OutBoneName = MonsterInfo.SpecialMeleeDismemberment.LeftShoulderBoneName;
}
}
}
}
}
defaultproperties
{
EffectGroup=FXG_Sawblade
KDamageImpulse=1000
KDeathUpKick=800
KDeathVel=135
// Instigator damage can happen on owning client when projectile hits before Instigator is replicated and
// (Other != Instigator) == FALSE. This problem is specific to the eviscerator projectile since it's a
// replicated CSHD weapon, but it might make sense to have bNoInstigatorDamage=true on more weapons.
bNoInstigatorDamage=true
//StunPower=0
StumblePower=100
GunHitPower=100
//MeleeHitPower=100
WeaponDef=class'KFWeapDef_BladedPistol'
ModifierPerkList(0)=class'KFPerk_Berserker'
ModifierPerkList(1)=class'KFPerk_Gunslinger'
}

View File

@ -0,0 +1,29 @@
//=============================================================================
// KFDT_Toxic_ParasiteSeedExplosion
//=============================================================================
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFDT_Toxic_ParasiteSeedExplosion extends KFDT_Toxic_MedicGrenade
abstract
hidedropdown;
defaultproperties
{
DoT_Type=DOT_Toxic
DoT_Duration=6.5 //3.0
DoT_Interval=0.5
DoT_DamageScale=0.1
KnockdownPower=30
StumblePower=200
GunHitPower=100
PoisonPower=80.f
ModifierPerkList(0)=class'KFPerk_FieldMedic'
ModifierPerkList(1)=class'KFPerk_SharpShooter'
WeaponDef=class'KFWeapDef_ParasiteImplanter'
}

View File

@ -0,0 +1,97 @@
//=============================================================================
// KFExplosion_ParasiteSeed
//=============================================================================
// Used by projectiles and kismet to spawn an explosion
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFExplosion_ParasiteSeed extends KFExplosion_MedicGrenade;
var transient bool FirstExplosion;
/**
* Deal damage or heal players
*/
protected simulated function AffectsPawn(Pawn Victim, float DamageScale)
{
local KFPawn_Human HumanVictim;
local KFPawn_Monster MonsterVictim;
local KFProj_MedicGrenade OwnerProjectile;
local bool bCanRepairArmor;
local Box BBox;
local vector BBoxCenter;
local Actor HitActor;
local bool bDamageBlocked;
if( Victim != none && Victim.IsAliveAndWell() )
{
MonsterVictim = KFPawn_Monster(Victim);
if( MonsterVictim != none )
{
if(!FirstExplosion || bWasFadedOut|| bDeleteMe || bPendingDelete )
{
return;
}
Victim.GetComponentsBoundingBox(BBox);
BBoxCenter = (BBox.Min + BBox.Max) * 0.5f;
HitActor = TraceExplosive(BBoxCenter, Location + vect(0, 0, 20));
bDamageBlocked = (HitActor != None && HitActor != Victim);
if(bDamageBlocked && HitActor.IsA('KFDoorActor'))
{
bDamageBlocked = false;
}
if( !bDamageBlocked )
{
Victim.TakeRadiusDamage(InstigatorController, ExplosionTemplate.Damage * DamageScale, ExplosionTemplate.DamageRadius,
ExplosionTemplate.MyDamageType, ExplosionTemplate.MomentumTransferScale, Location, bDoFullDamage,
(Owner != None) ? Owner : self, ExplosionTemplate.DamageFalloffExponent);
}
}
else
{
HumanVictim = KFPawn_Human(Victim);
if( HumanVictim != none && HumanVictim.GetExposureTo(Location) > 0 )
{
OwnerProjectile = KFProj_MedicGrenade(Owner);
if( OwnerProjectile != none )
{
bCanRepairArmor = OwnerProjectile.HealedPawns.Find( HumanVictim ) == INDEX_NONE;
}
HumanVictim.HealDamage(HealingAmount, InstigatorController, HealingDamageType, bCanRepairArmor);
if( bCanRepairArmor )
{
OwnerProjectile.HealedPawns.AddItem( HumanVictim );
}
}
}
}
}
simulated function DelayedExplosionDamage()
{
FirstExplosion=false;
super.DelayedExplosionDamage();
}
DefaultProperties
{
FirstExplosion = true;
HealingDamageType=class'KFDT_Healing_ParasiteSeed'
HealingAmount=5 //10
Interval=0.5 //1
MaxTime=5.5 //6.5 //8
bExplodeMoreThanOnce=false
bDoFullDamage=false //true
bSkipLineCheckForPawns=true
LoopingParticleEffect=ParticleSystem'WEP_3P_Medic_Grenade_EMIT.FX_Medic_Grenade_Explosion'
LoopStartEvent=AkEvent'WW_WEP_Medic_GrenadeLauncher.Play_WEP_Medic_GrenadeLauncher_Grenade_Smoke_Loop'
LoopStopEvent=AkEvent'WW_WEP_Medic_GrenadeLauncher.Stop_WEP_Medic_GrenadeLauncher_Grenade_Smoke_Loop'
}

View File

@ -0,0 +1,26 @@
//=============================================================================
// KFExplosion_ParasiteSeedHuman
//=============================================================================
// Explosion created when hitting a human
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFExplosion_ParasiteSeedHuman extends KFExplosion_MedicGrenade;
DefaultProperties
{
HealingDamageType=class'KFDT_Healing_ParasiteSeed'
HealingAmount=30 //10
Interval=1.0 //1
MaxTime=0.5 //6.5 //8
bExplodeMoreThanOnce=false
bDoFullDamage=false //true
bSkipLineCheckForPawns=true
LoopingParticleEffect=ParticleSystem'WEP_3P_Medic_Grenade_EMIT.FX_Medic_Grenade_Explosion'
LoopStartEvent=AkEvent'WW_WEP_Medic_GrenadeLauncher.Play_WEP_Medic_GrenadeLauncher_Grenade_Smoke_Loop'
LoopStopEvent=AkEvent'WW_WEP_Medic_GrenadeLauncher.Stop_WEP_Medic_GrenadeLauncher_Grenade_Smoke_Loop'
}

View File

@ -235,16 +235,26 @@ protected function ScoreMonsterKill( Controller Killer, Controller Monster, KFPa
if(OutbreakEvent.ActiveEvent.bHealAfterKill)
{
if( MonsterPawn != none && MonsterPawn.DamageHistory.Length > 0 )
{
HealAfterKilling( MonsterPawn, Killer );
if( MonsterPawn != none && MonsterPawn.DamageHistory.Length > 0 )
{
if(OutbreakEvent.ActiveEvent.bHealWithHeadshot)
{
if (MonsterPawn.LastHitZoneIndex == HZI_HEAD)
{
HealAfterKilling( MonsterPawn, Killer, false );
}
}
else
{
HealAfterKilling( MonsterPawn, Killer );
}
}
}
}
/** Heal players after a Zed was killed, based in more heal to the player that was the killer and less heal to the players that damaged the Zed */
function HealAfterKilling(KFPawn_Monster MonsterPawn , Controller Killer)
function HealAfterKilling(KFPawn_Monster MonsterPawn , Controller Killer, optional bool bGivePowerUp = true)
{
local int i;
local int j;
@ -302,7 +312,7 @@ function HealAfterKilling(KFPawn_Monster MonsterPawn , Controller Killer)
{
PawnHuman.HealDamageForce(MonsterPawn.HealByKill, KFPC, class'KFDT_Healing', false, false );
if( KFPawn_ZedFleshpound(MonsterPawn) != none || KFPawn_ZedScrake(MonsterPawn) != none )
if( bGivePowerUp && ( KFPawn_ZedFleshpound(MonsterPawn) != none || KFPawn_ZedScrake(MonsterPawn) != none ))
{
KFPC.ReceivePowerUp(class'KFPowerUp_HellishRage_NoCostHeal');
}
@ -322,6 +332,11 @@ function HealAfterKilling(KFPawn_Monster MonsterPawn , Controller Killer)
function StartMatch()
{
super.StartMatch();
if (OutbreakEvent.ActiveEvent.bForceWWLMusic)
{
ForceWWLMusicTrack();
}
}
function CreateDifficultyInfo(string Options)

View File

@ -64,6 +64,7 @@ simulated function NotifyWaveStart()
DefaultProperties
{
bIsWeeklyMode=True
BrokenTraderItemPickups={(
(WeaponClasses={(
class'KFGame.KFWeapDef_9mmDual',

View File

@ -518,6 +518,118 @@ defaultproperties
)}
//Wild West
SetEvents[12]={(
EventDifficulty=2,
GameLength=GL_Normal,
PerksAvailableList=(class'KFPerk_Gunslinger', class'KFPerk_Sharpshooter'),
TraderWeaponList=KFGFxObject_TraderItems'GP_Trader_ARCH.WildWestWeeklyTraderList',
bWildWestSkillConditionsActive=true,
//bModifyZedTimeOnANearZedKill=true,
DoshOnKillGlobalModifier=1.4,
PickupResetTime=PRS_Wave,
OverrideItemPickupModifier=0,
OverrideAmmoPickupModifier=1,
WaveAmmoPickupModifiers={(
0.125, 0.175, 0.35, 0.525, 0.7, 0.875, 0.75, 0.99, 0.99
)},
SpawnRateMultiplier=0.75,
WaveAICountScale=(0.75, 0.7, 0.7, 0.65, 0.65, 0.6),
bHealAfterKill = true,
bHealWithHeadshot = true,
bForceWWLMusic = true,
ZedsToAdjust={(
(ClassToAdjust=class'KFGameContent.KFPawn_ZedCrawler', HealByKill=1, HealByAssistance=0),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedCrawlerKing', HealByKill=5, HealByAssistance=0),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedClot_Cyst', HealByKill=1, HealByAssistance=0),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedClot_Alpha', HealByKill=1, HealByAssistance=0),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedClot_AlphaKing', HealByKill=10, HealByAssistance=0),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedClot_Slasher', HealByKill=1, HealByAssistance=0),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedSiren', HealByKill=10, HealByAssistance=0),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedStalker', HealByKill=2, HealByAssistance=0),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedGorefast', HealByKill=5, HealByAssistance=0),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedGorefastDualBlade', HealByKill=5, HealByAssistance=0),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedBloat', HealByKill=10, HealByAssistance=0),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedHusk', HealByKill=10, HealByAssistance=0),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedDAR_EMP', HealByKill=5, HealByAssistance=0),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedDAR_Laser', HealByKill=5, HealByAssistance=0),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedDAR_Rocket', HealByKill=5, HealByAssistance=0),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedScrake', HealByKill=20, HealByAssistance=0),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedFleshpound', HealByKill=20, HealByAssistance=0, HealthScale=0.8, DamageDealtScale=0.7),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedFleshpoundMini', HealByKill=15, HealByAssistance=0, HealthScale=0.8, DamageDealtScale=0.7),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedBloatKingSubspawn', HealByKill=2, HealByAssistance=0),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedMatriarch',HealthScale=0.8,DamageDealtScale=0.7),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedPatriarch',HealthScale=0.8,DamageDealtScale=0.7),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedHans',HealthScale=0.8,DamageDealtScale=0.7),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedFleshpoundKing',HealthScale=0.8,DamageDealtScale=0.7),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedBloatKing',HealthScale=0.8,DamageDealtScale=0.7)
)},
SpawnReplacementList={(
(SpawnEntry=AT_FleshPound,NewClass=(class'KFGameContent.KFPawn_ZedScrake'),PercentChance=0.5),
(SpawnEntry=AT_FleshpoundMini,NewClass=(class'KFGameContent.KFPawn_ZedGorefastDualBlade'),PercentChance=0.5)
)}
)}
//Infernal Eternal
SetEvents[13]={(
EventDifficulty=3,
GameLength=GL_Normal,
SpawnRateMultiplier=3,
WaveAICountScale=(1.3, 1.3, 1.3, 1.3, 1.3, 1.3),
OverrideAmmoPickupModifier=1, // 1.2
WaveAmmoPickupModifiers={(
0.125, 0.15, 0.3, 0.45, 0.6, 0.75, 0.9, 0.99, 0.99
)},
bUseOverrideAmmoRespawnTime=true,
OverrideAmmoRespawnTime={(
PlayersMod[0]=25.000000,
PlayersMod[1]=12.000000,
PlayersMod[2]=8.000000,
PlayersMod[3]=5.000000,
PlayersMod[4]=4.000000,
PlayersMod[5]=3.000000,
ModCap=1.000000
)},
ZedsToAdjust={(
(ClassToAdjust=class'KFGameContent.KFPawn_ZedMatriarch',HealthScale=2.0,DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedPatriarch',HealthScale=2.0,DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedHans',HealthScale=2.0,DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedFleshpoundKing',HealthScale=2.0,DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedBloatKing',HealthScale=2.0,DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedClot_Cyst',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedClot_Alpha',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedClot_AlphaKing',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedClot_Slasher',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedSiren',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedStalker',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedCrawler',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedCrawlerKing',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedGorefast',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedGorefastDualBlade',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedBloat',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedHusk',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedDAR_EMP',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedDAR_Laser',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedDAR_Rocket',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedScrake',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedFleshpound',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedFleshpoundMini',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
(ClassToAdjust=class'KFGameContent.KFPawn_ZedBloatKingSubspawn',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2)
)},
SpawnReplacementList={(
(SpawnEntry=AT_Clot,NewClass=(class'KFGameContent.KFPawn_ZedClot_Alpha'),PercentChance=0.15),
(SpawnEntry=AT_AlphaClot,NewClass=(class'KFGameContent.KFPawn_ZedClot_AlphaKing'),PercentChance=0.15),
(SpawnEntry=AT_GoreFast,NewClass=(class'KFGameContent.KFPawn_ZedGorefastDualBlade'),PercentChance=0.15),
(SpawnEntry=AT_Crawler,NewClass=(class'KFGameContent.KFPawn_ZedCrawlerKing'),PercentChance=0.15),
(SpawnEntry=AT_Bloat,NewClass=(class'KFGameContent.KFPawn_ZedScrake'),PercentChance=0.05),
(SpawnEntry=AT_FleshpoundMini,NewClass=(class'KFGameContent.KFPawn_ZedFleshpound'),PercentChance=0.05)
)}
)}
//Test events from here down. These don't end up in the regular rotation.
// The override ID starts from one higher than the last SetEvents entry above.
// Ex: Big head = 7, Horde = 8

View File

@ -98,4 +98,6 @@ DefaultProperties
`if(`notdefined(ShippingPC))
DebugRadarTexture=Texture2D'UI_ZEDRadar_TEX.MapIcon_Clot';
`endif
ZEDCowboyHatAttachName=Hat_Attach
}

View File

@ -88,4 +88,6 @@ DefaultProperties
`if(`notdefined(ShippingPC))
DebugRadarTexture=Texture2D'UI_ZEDRadar_TEX.MapIcon_Slasher';
`endif
ZEDCowboyHatAttachName=Hat_Attach
}

View File

@ -464,4 +464,6 @@ defaultproperties
// ---------------------------------------------
// Spawning
MinSpawnSquadSizeType=EST_Crawler
ZEDCowboyHatAttachName=Hat_Attach
}

View File

@ -431,4 +431,6 @@ defaultproperties
StartSprintingSound=AkEvent'WW_ZED_Evil_DAR.Play_ZED_EvilDAR_SFX_Thruster_Start'
SprintLoopingSound=AkEvent'WW_ZED_Evil_DAR.Play_ZED_EvilDAR_SFX_Thruster_LP'
StopSprintingSound=AkEvent'WW_ZED_Evil_DAR.Play_ZED_EvilDAR_SFX_Thruster_Stop'
ZEDCowboyHatAttachName=Hat_Attach
}

View File

@ -605,4 +605,6 @@ End Object
MinSpawnSquadSizeType=EST_Large
OnDeathAchievementID=KFACHID_ItsOnlyAFleshWound
ZEDCowboyHatAttachName=Hat_Attach
}

View File

@ -72,4 +72,6 @@ defaultproperties
IncapSettings(AF_Freeze)= (Vulnerability=(0.95), Cooldown=10.5, Duration=1.0)
IncapSettings(AF_Snare)= (Vulnerability=(1.0, 2.0, 1.0, 1.0, 2.0), Cooldown=8.5, Duration=5.0)
IncapSettings(AF_Bleed)= (Vulnerability=(0.75))
ZEDCowboyHatAttachName=HEAD_Attach
}

View File

@ -657,4 +657,6 @@ DefaultProperties
// ---------------------------------------------
// Spawning
MinSpawnSquadSizeType=EST_Medium
ZEDCowboyHatAttachName=Hat_Attach
}

View File

@ -2012,4 +2012,6 @@ defaultproperties
// Gun tracking
bUseServerSideGunTracking=true
GunTargetBoneName=Spine2
ZEDCowboyHatAttachName=Hat_Attach
}

View File

@ -391,4 +391,6 @@ defaultproperties
MinSpawnSquadSizeType=EST_Large
OnDeathAchievementID=KFACHID_HackAndSlash
ZEDCowboyHatAttachName=Hat_Attach
}

View File

@ -250,4 +250,6 @@ defaultproperties
`endif
OnDeathAchievementID=KFACHID_DeadSilence
ZEDCowboyHatAttachName=Hat_Attach
}

View File

@ -0,0 +1,79 @@
//=============================================================================
// KFProj_Blade_BladedPistol
//=============================================================================
// Blade class for the BladedPistol
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFProj_Blade_BladedPistol extends KFProj_RicochetStickBullet
hidedropdown;
// Make sure that last location always exists.
simulated event PostBeginPlay()
{
Super.PostBeginPlay();
LastLocation = Location;
}
simulated function bool ShouldProcessBulletTouch()
{
return BouncesLeft > 0 && GravityScale == default.GravityScale;
}
defaultproperties
{
MaxSpeed=4000.0 //2500.0
Speed=4000.0 //2500.0
GravityScale=0.8 //0.75
DamageRadius=0
bWarnAIWhenFired=true
BouncesLeft=2
DampingFactor=0.8 //0.95
RicochetEffects=KFImpactEffectInfo'WEP_BladedPistol_ARCH.BladedImpacts'
LifeSpan=8
LifeSpanAfterStick=180
Begin Object Name=CollisionCylinder
CollisionRadius=6
CollisionHeight=2
End Object
// Additional zero-extent line traces
//ExtraLineCollisionOffsets.Add((Y=-8))
//ExtraLineCollisionOffsets.Add((Y=8))
ExtraLineCollisionOffsets.Add((Y=-16))
ExtraLineCollisionOffsets.Add((Y=16))
ExtraLineCollisionOffsets.Add((Z=-6))
ExtraLineCollisionOffsets.Add((Z=6))
// Since we're still using an extent cylinder, we need a line at 0
ExtraLineCollisionOffsets.Add(())
bAmbientSoundZedTimeOnly=false
bNoReplicationToInstigator=false
bUseClientSideHitDetection=true
bUpdateSimulatedPosition=true
bRotationFollowsVelocity=false
bNetTemporary=False
ProjFlightTemplate=ParticleSystem'WEP_BladedPistol_EMIT.FX_bladed_projectile_01'
ProjFlightTemplateZedTime=ParticleSystem'WEP_BladedPistol_EMIT.FX_bladed_projectile_01'
ImpactEffects=KFImpactEffectInfo'WEP_BladedPistol_ARCH.BladedEmbedFX'
AmbientSoundPlayEvent=AkEvent'WW_WEP_BladedPistol.Play_WEP_BladedPistol_Projectile_Loop'
AmbientSoundStopEvent=AkEvent'WW_WEP_BladedPistol.Stop_WEP_BladedPistol_Projectile_Loop'
PickupRadius=250 //200
WeaponClassName=KFWeap_Pistol_Bladed
ProjPickupTemplate=ParticleSystem'WEP_BladedPistol_EMIT.FX_bladed_pickup_01'
AmmoPickupSound=AkEvent'WW_WEP_BladedPistol.Play_WEP_BladedPistol_Projectile_Pickup'
TouchTimeThreshhold=0.15
}

View File

@ -0,0 +1,79 @@
//=============================================================================
// KFProj_Bullet_HRG_Boomy
//=============================================================================
// Class Description
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFProj_Bullet_HRG_Boomy extends KFProj_BallisticExplosive
hidedropdown;
simulated protected function PrepareExplosionTemplate()
{
super.PrepareExplosionTemplate();
/** Since bIgnoreInstigator is transient, its value must be defined here */
ExplosionTemplate.bIgnoreInstigator = true;
}
defaultproperties
{
MaxSpeed=22500.0
Speed=22500.0
DamageRadius=0
ProjDisintegrateTemplate=ParticleSystem'ZED_Siren_EMIT.FX_Siren_grenade_disable_01'
// ProjFlightTemplate=ParticleSystem'WEP_HRG_Boomy_EMIT.FX_Boomy_Tracer_ZEDTime'
ProjFlightTemplateZedTime=ParticleSystem'WEP_HRG_Boomy_EMIT.FX_Boomy_Tracer_ZEDTime'
// Grenade explosion light
Begin Object Class=PointLightComponent Name=ExplosionPointLight
LightColor=(R=252,G=218,B=171,A=255)
Brightness=0.5f
Radius=400.f
FalloffExponent=10.f
CastShadows=False
CastStaticShadows=FALSE
CastDynamicShadows=False
bCastPerObjectShadows=false
bEnabled=FALSE
LightingChannels=(Indoor=TRUE,Outdoor=TRUE,bInitialized=TRUE)
End Object
// explosion
Begin Object Class=KFGameExplosion Name=ExploTemplate0
Damage=35 //30
DamageRadius=150 //120
DamageFalloffExponent=1.f
DamageDelay=0.f
MomentumTransferScale=10000
// Damage Effects
MyDamageType=class'KFDT_Explosive_HRG_Boomy'
KnockDownStrength=150
FractureMeshRadius=200.0
FracturePartVel=500.0
ExplosionSound=AkEvent'ww_wep_hrg_boomy.Play_WEP_HRG_Boomy_ProjExplosion'
ExplosionEffects=KFImpactEffectInfo'WEP_HRG_Boomy_ARCH.WEB_HRG_Boomy_Impacts'
// Dynamic Light
ExploLight=ExplosionPointLight
ExploLightStartFadeOutTime=0.0
ExploLightFadeOutTime=0.3
bIgnoreInstigator=true
// Camera Shake
CamShake=CameraShake'FX_CameraShake_Arch.Misc_Explosions.Light_Explosion_Rumble'
CamShakeInnerRadius=0
CamShakeOuterRadius=300
CamShakeFalloff=1.5f
bOrientCameraShakeTowardsEpicenter=true
End Object
ExplosionTemplate=ExploTemplate0
}

View File

@ -0,0 +1,23 @@
//=============================================================================
// KFProj_Bullet_HRG_Energy
//=============================================================================
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFProj_Bullet_HRG_Energy extends KFProj_Bullet
hidedropdown;
defaultproperties
{
MaxSpeed=15000.0
Speed=15000.0
DamageRadius=0
ProjFlightTemplateZedTime=ParticleSystem'WEP_HRG_Energy_EMIT.FX_Energy_Tracer_Instant'
ImpactEffects = KFImpactEffectInfo'WEP_HRG_Energy_ARCH.Wep_HRG_Energy_Impact'
}

View File

@ -0,0 +1,21 @@
//=============================================================================
// KFProj_Bullet_HRG_Energy_Secondary
//=============================================================================
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFProj_Bullet_HRG_Energy_Secondary extends KFProj_Bullet;
defaultproperties
{
MaxSpeed=7500.0
Speed=7500.0
DamageRadius=0
ProjFlightTemplateZedTime=ParticleSystem'WEP_HRG_Energy_EMIT.FX_Energy_Alt_Tracer_Instant'
ImpactEffects = KFImpactEffectInfo'WEP_HRG_Energy_ARCH.Wep_HRG_Energy_Impact_Alt'
}

View File

@ -0,0 +1,22 @@
//=============================================================================
// KFProj_Bullet_ParasiteImplanter
//=============================================================================
// Bullet class for the Parasite Implanter
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFProj_Bullet_ParasiteImplanter extends KFProj_Bullet
hidedropdown;
defaultproperties
{
MaxSpeed=24000.0
Speed=24000.0
DamageRadius=0
ProjFlightTemplate=ParticleSystem'WEP_1P_L85A2_EMIT.FX_L85A2_Tracer_ZEDTime'
}

View File

@ -0,0 +1,382 @@
//=============================================================================
// KFProj_Bullet_ParasiteImplanterAlt
//=============================================================================
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFProj_Bullet_ParasiteImplanterAlt extends KFProjectile;
var float FuseTime;
/** This is the effect indicator that is played for the current user **/
var(Projectile) ParticleSystem ProjIndicatorTemplate;
var ParticleSystemComponent ProjIndicatorEffects;
var bool IndicatorActive;
var transient bool bShouldEnableIndicator;
var Class<GameExplosionActor> HumanExplosionActorClass;
var KFGameExplosion HumanExplosionTemplate;
var private AKEvent SeedTimerOutEvent;
simulated function TryActivateIndicator()
{
if(!IndicatorActive && Instigator != None)
{
IndicatorActive = true;
if(WorldInfo.NetMode == NM_Standalone || Instigator.Role == Role_AutonomousProxy ||
(Instigator.Role == ROLE_Authority && WorldInfo.NetMode == NM_ListenServer && Instigator.IsLocallyControlled() ))
{
if( ProjIndicatorTemplate != None )
{
ProjIndicatorEffects = WorldInfo.MyEmitterPool.SpawnEmitterCustomLifetime(ProjIndicatorTemplate);
}
if(ProjIndicatorEffects != None)
{
ProjIndicatorEffects.SetAbsolute(false, false, false);
ProjIndicatorEffects.SetLODLevel(WorldInfo.bDropDetail ? 1 : 0);
ProjIndicatorEffects.bUpdateComponentInTick = true;
AttachComponent(ProjIndicatorEffects);
}
}
}
}
/**
* Set the initial velocity and cook time
*/
simulated event PostBeginPlay()
{
Super.PostBeginPlay();
if (Role == ROLE_Authority)
{
SetTimer(FuseTime, false, 'Timer_Detonate');
}
AdjustCanDisintigrate();
}
/**
* Explode after a certain amount of time
*/
function Timer_Detonate()
{
Detonate();
}
/** Called when the owning instigator controller has left a game */
simulated function OnInstigatorControllerLeft()
{
if( WorldInfo.NetMode != NM_Client )
{
SetTimer( 1.f + Rand(5) + fRand(), false, nameOf(Timer_Detonate) );
}
}
/**
* Trace down and get the location to spawn the explosion effects and decal
*/
simulated function GetExplodeEffectLocation(out vector HitLocation, out vector HitRotation, out Actor HitActor)
{
local vector EffectStartTrace, EffectEndTrace;
local TraceHitInfo HitInfo;
EffectStartTrace = Location + vect(0,0,1) * 4.f;
EffectEndTrace = EffectStartTrace - vect(0,0,1) * 32.f;
// Find where to put the decal
HitActor = Trace(HitLocation, HitRotation, EffectEndTrace, EffectStartTrace, false,, HitInfo, TRACEFLAG_Bullet);
// If the locations are zero (probably because this exploded in the air) set defaults
if (IsZero(HitLocation))
{
HitLocation = Location;
}
if (IsZero(HitRotation))
{
HitRotation = vect(0,0,1);
}
}
/** Used to check current status of StuckTo actor (to figure out if we should fall) */
simulated event Tick(float DeltaTime)
{
super.Tick(DeltaTime);
StickHelper.Tick(DeltaTime);
if (!IsZero(Velocity))
{
SetRelativeRotation(rotator(Velocity));
}
if (bShouldEnableIndicator)
{
TryActivateIndicator();
}
}
simulated function Explode(vector HitLocation, vector HitNormal)
{
StickHelper.UnPin();
super.Explode(HitLocation, HitNormal);
}
simulated function SyncOriginalLocation()
{
local Actor HitActor;
local vector HitLocation, HitNormal;
local TraceHitInfo HitInfo;
if (Role < ROLE_Authority && Instigator != none && Instigator.IsLocallyControlled())
{
HitActor = Trace(HitLocation, HitNormal, OriginalLocation, Location,,, HitInfo, TRACEFLAG_Bullet);
if (HitActor != none)
{
StickHelper.TryStick(HitNormal, HitLocation, HitActor);
}
}
}
simulated protected function StopSimulating()
{
super.StopSimulating();
if (ProjIndicatorEffects!=None)
{
ProjIndicatorEffects.DeactivateSystem();
}
}
/** Causes charge to explode */
function Detonate()
{
local KFPawn_Monster KFPM;
//@Todo: Some VFX?
if (StuckToActor != none)
{
KFPM = KFPawn_Monster(StuckToActor);
if (KFPM != none)
{
KFPM.ParasiteSeeds.RemoveItem(self);
}
}
StickHelper.UnPin();
ShutDown();
}
simulated function OnActorSticked(Actor TargetActor)
{
local KFPawn_Monster KFPM;
KFPM = KFPawn_Monster(TargetActor);
if (KFPM != none)
{
if (Role == ROLE_Authority)
{
KFPM.AddParasiteSeed(self);
PlaySoundBase(SeedTimerOutEvent, false, false);
}
if (WorldInfo.NetMode == NM_Client || WorldInfo.NetMode == NM_StandAlone)
{
bShouldEnableIndicator = true;
}
}
}
simulated function ExplodeOnHuman(Vector HitLocation, Vector HitNormal, Actor HitActor)
{
local vector NudgedHitLocation, ExplosionDirection;
if (HumanExplosionTemplate != None)
{
StopSimulating();
// using a hit location slightly away from the impact point is nice for certain things
NudgedHitLocation = HitLocation + (HitNormal * 32.f);
ExplosionActor = Spawn(HumanExplosionActorClass, self,, NudgedHitLocation, rotator(HitNormal));
if (ExplosionActor != None)
{
ExplosionActor.Instigator = Instigator;
ExplosionActor.InstigatorController = InstigatorController;
PrepareExplosionTemplate();
// If the locations are zero (probably because this exploded in the air) set defaults
if( IsZero(HitLocation) )
{
HitLocation = Location;
}
if( IsZero(HitNormal) )
{
HitNormal = vect(0,0,1);
}
// these are needed for the decal tracing later in GameExplosionActor.Explode()
HumanExplosionTemplate.HitLocation = HitLocation;// NudgedHitLocation
HumanExplosionTemplate.HitNormal = HitNormal;
// If desired, attach to mover if we hit one
if(bAttachExplosionToHitMover && InterpActor(HitActor) != None)
{
ExplosionActor.Attachee = HitActor;
HumanExplosionTemplate.bAttachExplosionEmitterToAttachee = TRUE;
ExplosionActor.SetBase(HitActor);
}
// directional?
if (HumanExplosionTemplate.bDirectionalExplosion)
{
ExplosionDirection = GetExplosionDirection(HitNormal);
//DrawDebugLine(ExplosionActor.Location, ExplosionActor.Location+ExplosionDirection*64, 255, 255, 0, TRUE);
}
// @todo: make this function responsible for setting explosion instance parameters, and take instance parameters
// out of GearExplosion (e.g. Attachee)
PrepareExplosionActor(ExplosionActor);
ExplosionActor.Explode(HumanExplosionTemplate, ExplosionDirection); // go bewm
}
// done with it
if (!bPendingDelete && !bDeleteMe)
{
// defer destruction so any replication of explosion stuff can happen if necessary
DeferredDestroy(PostExplosionLifetime);
}
}
}
simulated function ProcessTouch(Actor Other, Vector HitLocation, Vector HitNormal)
{
if (KFPawn_Human(Other) != none && Other != Instigator)
{
ExplodeOnHuman(HitLocation, HitNormal, Other);
}
else
{
super.ProcessTouch(Other, HitLocation, HitNormal);
}
}
defaultproperties
{
ProjFlightTemplate=ParticleSystem'WEP_ParasiteImplanter_EMIT.FX_Seed_Projectile'
ProjIndicatorTemplate=ParticleSystem'WEP_ParasiteImplanter_EMIT.FX_Seed_Projectile_Indicator'
bWarnAIWhenFired=true
MaxSpeed=15000.0 //10000.0 //4000.0
Speed=15000.0 //10000.0 //4000.0
TerminalVelocity=15000.0 //10000.0 //4000.0
Physics=PHYS_Falling
TossZ=0 //150
GravityScale=0 //0.01 //0.7
GlassShatterType=FMGS_ShatterAll
bCollideComplex=true
bIgnoreFoliageTouch=true
bBlockedByInstigator=false
bAlwaysReplicateExplosion=true
FuseTime=6.0 //4.0
bNetTemporary=false
NetPriority=5
NetUpdateFrequency=200
bNoReplicationToInstigator=false
bUseClientSideHitDetection=true
bUpdateSimulatedPosition=true
bSyncToOriginalLocation=true
bSyncToThirdPersonMuzzleLocation=true
PinBoneIdx=INDEX_None
bCanBeDamaged=true
bCanDisintegrate=true
ExplosionActorClass=class'KFExplosion_ParasiteSeed'
HumanExplosionActorClass=class'KFExplosion_ParasiteSeedHuman'
// explosion
Begin Object Class=KFGameExplosion Name=ExploTemplate0
Damage=400 //250
DamageRadius=450
DamageFalloffExponent=0.5f //1.f
DamageDelay=0.f
MyDamageType=class'KFDT_Toxic_ParasiteSeedExplosion'
// Damage Effects
KnockDownStrength=0
KnockDownRadius=0
FractureMeshRadius=0
FracturePartVel=0
// ExplosionEffects=KFImpactEffectInfo'FX_Impacts_ARCH.Explosions.MedicGrenade_Explosion'
ExplosionSound=AkEvent'WW_WEP_Medic_GrenadeLauncher.Play_WEP_Medic_GrenadeLauncher_Grenade_Explosion'
MomentumTransferScale=0
// Camera Shake
CamShake=none
CamShakeInnerRadius=0
CamShakeOuterRadius=0
CamShakeFalloff=1.5f
bOrientCameraShakeTowardsEpicenter=true
End Object
ExplosionTemplate=ExploTemplate0
Begin Object Class=KFGameExplosion Name=ExploTemplate1
Damage=1 //250
DamageRadius=100 //450
DamageFalloffExponent=0.5f //1.f
DamageDelay=0.f
// Damage Effects
KnockDownStrength=0
KnockDownRadius=0
FractureMeshRadius=0
FracturePartVel=0
// ExplosionEffects=KFImpactEffectInfo'FX_Impacts_ARCH.Explosions.MedicGrenade_Explosion'
ExplosionSound=AkEvent'WW_WEP_Medic_GrenadeLauncher.Play_WEP_Medic_GrenadeLauncher_Grenade_Explosion'
MomentumTransferScale=0
// Camera Shake
CamShake=none
CamShakeInnerRadius=0
CamShakeOuterRadius=0
CamShakeFalloff=1.5f
bOrientCameraShakeTowardsEpicenter=true
End Object
HumanExplosionTemplate=ExploTemplate1
bCanStick=true
bCanPin=true
Begin Object Class=KFProjectileStickHelper_ParasiteImplanter Name=StickHelper0
End Object
StickHelper=StickHelper0
ProjDisintegrateTemplate=ParticleSystem'ZED_Siren_EMIT.FX_Siren_grenade_disable_01'
bShouldEnableIndicator=false;
ImpactEffects = KFImpactEffectInfo'WEP_ParasiteImplanter_ARCH.Wep_Parasite_Impact_Alt'
SeedTimerOutEvent = AkEvent'WW_WEP_ParasiteImplanter.Play_WEP_ParasiteImplanter_Seed_Timer_Out';
}

View File

@ -905,8 +905,8 @@ defaultproperties
MaxDamageRadiusPerPercentage=340
MinDamageRadiusPerPercentage=160
MaxDamagePerPercentage=300 //270//180
MinDamagePerPercentage=30//90
MaxDamagePerPercentage=350 //300
MinDamagePerPercentage=35 //30
MaxCollisionRadius=20
MinCollisionRadius=10

View File

@ -249,6 +249,29 @@ function vector CalculateResidualFlameVelocity( vector HitNormal, vector HitVelD
return SpawnDir * ResidualFlameForceMultiplier;
}
simulated protected function PrepareExplosionTemplate()
{
local Weapon OwnerWeapon;
local Pawn OwnerPawn;
local KFPerk_Survivalist Perk;
super(KFProjectile).PrepareExplosionTemplate();
OwnerWeapon = Weapon(Owner);
if (OwnerWeapon != none)
{
OwnerPawn = Pawn(OwnerWeapon.Owner);
if (OwnerPawn != none)
{
Perk = KFPerk_Survivalist(KFPawn(OwnerPawn).GetPerk());
if (Perk != none)
{
ExplosionTemplate.DamageRadius *= Perk.GetAoERadiusModifier();
}
}
}
}
defaultproperties
{
ProjFlightTemplate=ParticleSystem'WEP_Thermite_EMIT.FX_Harpoon_Projectile'

View File

@ -0,0 +1,205 @@
//=============================================================================
// KFProjectileStickHelper_ParasiteImplanter
//=============================================================================
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFProjectileStickHelper_ParasiteImplanter extends KFProjectileStickHelper;
simulated function TryStick(vector HitNormal, optional vector HitLocation, optional Actor HitActor)
{
if( WorldInfo.NetMode != NM_DedicatedServer )
{
`ImpactEffectManager.PlayImpactEffects(HitLocation, Instigator,, KFProj_Bullet_ParasiteImplanterAlt(Outer).ImpactEffects);
}
super.TryStick(HitNormal, HitLocation, HitActor);
}
/** Stops movement of projectile and calculates orientation to surface */
simulated function Stick(Actor HitActor, vector HitLocation, vector HitNormal, const out TraceHitInfo HitInfo)
{
local int BoneIdx;
local KFPawn_Monster HitMonster;
local array<ImpactInfo> HitZoneImpactList;
local vector StartTrace, EndTrace, Direction, ClosestBoneLocation;
local name BoneName;
BoneName = HitInfo.BoneName;
HitMonster = KFPawn_Monster(HitActor);
if (HitMonster != none)
{
// get injury hit zone
StartTrace = HitLocation;
Direction = Normal(Velocity);
EndTrace = StartTrace + Direction * (HitMonster.CylinderComponent.CollisionRadius * 6.0);
TraceProjHitZones(HitMonster, EndTrace, StartTrace, HitZoneImpactList);
if (BoneName == '')
{
// get the best bone to attach to
ClosestBoneLocation = HitMonster.Mesh.GetClosestCollidingBoneLocation(HitLocation, true, false);
BoneName = HitMonster.Mesh.FindClosestBone(ClosestBoneLocation, ClosestBoneLocation);
}
// Deleted damage to monster code, we don't want to do damage on sticking
// Bringed damage back
if (KFWeapon(Owner) != none)
{
HitZoneImpactList[0].RayDir = Normal(EndTrace - StartTrace); // add a raydir here since TraceProjHitZones doesn't fill this out (so certain afflictions apply)
KFWeapon(Owner).HandleProjectileImpact(WeaponFireMode, HitZoneImpactList[0], PenetrationPower);
}
}
else if (KFPawn_Human(HitActor) != none)
{
// When it hits a human, use explosion.
KFProj_Bullet_ParasiteImplanterAlt(Outer).ExplodeOnHuman(HitLocation, HitNormal, HitActor);
return;
}
if (!IsZero(HitLocation))
{
SetLocation(HitLocation);
}
SetStickOrientation(HitNormal);
BoneIdx = INDEX_NONE;
if (BoneName != '')
{
BoneIdx = GetBoneIndexFromActor(HitActor, BoneName);
}
StickToActor(HitActor, HitInfo.HitComponent, BoneIdx, true);
if (Role < ROLE_Authority)
{
Outer.ServerStick(HitActor, BoneIdx, StuckToLocation, StuckToRotation);
}
if (WorldInfo.NetMode != NM_DedicatedServer && StickAkEvent != none)
{
PlaySoundBase(StickAkEvent);
}
}
/** Changes the base of the charge to the stick actor and sets its relative loc/rot */
simulated function StickToActor(Actor StickTo, PrimitiveComponent HitComp, int BoneIdx, optional bool bCalculateRelativeLocRot)
{
local SkeletalMeshComponent SkelMeshComp;
local Name BoneName;
local vector RelStuckToLocation;
local rotator RelStuckToRotation;
local KFPawn StickToPawn;
local KFProj_Bullet_ParasiteImplanterAlt ParasiteProj;
StickToPawn = KFPawn(StickTo);
if (bCanPin && (StickToPawn == none || StickToPawn.bCanBePinned))
{
// if StickTo pawn is dead, pin it and keep flying
if (Role == ROLE_Authority)
{
if (StickToPawn != none && !StickToPawn.IsAliveAndWell())
{
if (PinPawn == none)
{
Pin(StickTo, BoneIdx);
}
return;
}
}
if (WorldInfo.NetMode != NM_DedicatedServer && PinPawn != none)
{
if (StickToPawn == none)
{
// Pin pinned pawn to StickTo actor
//PinPawn.Mesh.RetardRBLinearVelocity(vector(Rotation), 0.75);
PinPawn.Mesh.SetRBPosition(Location, PinBoneName);
PinConstraint = Spawn(class'RB_ConstraintActorSpawnable',,,Location);
PinConstraint.InitConstraint(PinPawn, none, PinBoneName, '');
}
PinPawn = none;
}
}
else if (StickToPawn != none && !StickToPawn.IsAliveAndWell())
{
return;
}
SetPhysics(PHYS_None);
PrevStuckToActor = StuckToActor;
StuckToActor = StickTo;
StuckToBoneIdx = BoneIdx;
// if we found a skel mesh, set our base to it and set relative loc/rot
if (BoneIdx != INDEX_NONE)
{
SkelMeshComp = SkeletalMeshComponent(HitComp);
BoneName = SkelMeshComp.GetBoneName(BoneIdx);
if (bCalculateRelativeLocRot)
{
StuckToLocation = Location;
StuckToRotation = Rotation;
}
SkelMeshComp.TransformToBoneSpace(BoneName, StuckToLocation, StuckToRotation, RelStuckToLocation, RelStuckToRotation);
SetBase(StickTo,, SkelMeshComp, BoneName);
SetRelativeLocation(RelStuckToLocation);
SetRelativeRotation(RelStuckToRotation);
}
// otherwise, just set our base
else
{
if (bCalculateRelativeLocRot)
{
// set replicated loc/rot
StuckToLocation = Location;
StuckToRotation = Rotation;
}
else
{
// set loc/rot to replicated loc/rot
SetLocation(StuckToLocation);
SetRotation(StuckToRotation);
}
SetBase(StickTo);
}
ParasiteProj = KFProj_Bullet_ParasiteImplanterAlt(Outer);
ParasiteProj.OnActorSticked(StickTo);
}
/** Resets physics/collision vars to defaults */
simulated function UnStick()
{
// local KFPawn_Monster KFPM;
GravityScale=0.5f;
/*
KFPM = KFPawn_Monster(StuckToActor);
if (KFPM != none && KFPM.Health > 0)
{
KFPM.ParasiteSeeds.Remove(0, KFPM.ParasiteSeeds.Length - (KFPM.MaxNumSeeds-1));
}
*/
super.UnStick();
}

View File

@ -0,0 +1,117 @@
//=============================================================================
// KFSeasonalEventStats_Fall2021
//=============================================================================
// Tracks event-specific challenges/accomplishments for Fall 2021
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFSeasonalEventStats_Fall2021 extends KFSeasonalEventStats;
var transient private const int BossKillsRequired, EndlessWaveRequired;
private event Initialize(string MapName)
{
local string CapsMapName;
CapsMapName = Caps(MapName);
bObjectiveIsValidForMap[0] = 1; // Kill 15 Bosses on any map or mode
bObjectiveIsValidForMap[1] = 0; // Complete the Weekly on Netherhold
bObjectiveIsValidForMap[2] = 0; // Find the nether heart
bObjectiveIsValidForMap[3] = 0; // Unlock the chapel and the dining hall doors
bObjectiveIsValidForMap[4] = 0; // Complete wave 15 on Endless Hard or higher difficulty on Netherhold
if (CapsMapName == "KF-NETHERHOLD")
{
bObjectiveIsValidForMap[1] = 1;
bObjectiveIsValidForMap[2] = 1;
bObjectiveIsValidForMap[3] = 1;
bObjectiveIsValidForMap[4] = 1;
}
SetSeasonalEventStatsMax(BossKillsRequired, 0, 0, 0, 0);
}
private event GrantEventItems()
{
if (Outer.IsEventObjectiveComplete(0) &&
Outer.IsEventObjectiveComplete(1) &&
Outer.IsEventObjectiveComplete(2) &&
Outer.IsEventObjectiveComplete(3) &&
Outer.IsEventObjectiveComplete(4))
{
// TODO: Uncomment me and set the proper item ID
GrantEventItem(8990);
}
}
// Kill 15 Bosses on any map or mode
simulated function OnBossDied()
{
local int ObjIdx;
ObjIdx = 0;
// Boss kills in any map
if (bObjectiveIsValidForMap[ObjIdx] != 0)
{
IncrementSeasonalEventStat(ObjIdx, 1);
if (Outer.GetSeasonalEventStatValue(ObjIdx) >= BossKillsRequired)
{
FinishedObjective(SEI_Fall, ObjIdx);
}
}
}
// Complete the Weekly on Netherhold
simulated event OnGameWon(class<GameInfo> GameClass, int Difficulty, int GameLength, bool bCoOp)
{
local int ObjIdx;
ObjIdx = 1;
if (bObjectiveIsValidForMap[ObjIdx] != 0)
{
if (GameClass == class'KFGameInfo_WeeklySurvival')
{
FinishedObjective(SEI_Fall, ObjIdx);
}
}
}
// Complete wave 15 on Endless Hard or higher difficulty on Netherhold
simulated event OnWaveCompleted(class<GameInfo> GameClass, int Difficulty, int WaveNum)
{
local int ObjIdx;
ObjIdx = 4;
if (bObjectiveIsValidForMap[ObjIdx] != 0)
{
if (WaveNum >= EndlessWaveRequired && GameClass == class'KFGameInfo_Endless' && Difficulty >= `DIFFICULTY_HARD)
{
FinishedObjective(SEI_Fall, ObjIdx);
}
}
}
simulated function OnTryCompleteObjective(int ObjectiveIndex, int EventIndex)
{
local int NetherHeartIdx, ChapelIdx;
NetherHeartIdx = 2;
ChapelIdx = 3;
if(EventIndex == SEI_Fall)
{
if (ObjectiveIndex == NetherHeartIdx || ObjectiveIndex == ChapelIdx)
{
if (bObjectiveIsValidForMap[ObjectiveIndex] != 0)
{
FinishedObjective(SEI_Fall, ObjectiveIndex);
}
}
}
}
defaultproperties
{
BossKillsRequired=15
EndlessWaveRequired=15
}

View File

@ -9,18 +9,21 @@
class KFWeapAttach_FAMAS extends KFWeaponAttachment;
const SecondaryFireAnim = 'Shoot_Secondary';
const SecondaryFireIronAnim = 'Shoot_Secondary_Iron';
const SecondaryFireAnimLast = 'Shoot_Secondary_Last';
const SecondaryFireIronAnimLast = 'Shoot_Secondary_Iron_Last';
const SecondaryFireBodyAnim = 'ADD_Shoot_Secondary';
const SecondaryFireBodyAnimCH = 'ADD_Shoot_Secondary_CH';
const SecondaryFireBodyAnimIron = 'ADD_Shoot_Secondary_Iron';
const SecondaryReloadAnimEmpty = 'Reload_Secondary_Empty';
const SecondaryReloadAnimHalf = 'Reload_Secondary_Half';
const SecondaryReloadAnimEliteEmpty = 'Reload_Secondary_Elite_Empty';
const SecondaryReloadAnimEliteHalf = 'Reload_Secondary_Elite_Half';
const ShotgunMuzzleSocket = 'ShotgunMuzzleFlash';
const SecondaryFireAnim = 'Shoot_Secondary';
const SecondaryFireAnimCrouch = 'Shoot_Secondary_CH';
const SecondaryFireIronAnim = 'Shoot_Secondary_Iron';
const SecondaryFireBodyAnim = 'ADD_Shoot_Secondary';
const SecondaryFireBodyAnimCH = 'ADD_Shoot_Secondary_CH';
const SecondaryFireBodyAnimIron = 'ADD_Shoot_Secondary_Iron';
const SecondaryReloadAnimEmpty = 'Reload_Secondary_Empty';
const SecondaryReloadAnimEmptyCrouch = 'Reload_Secondary_Empty_CH';
const SecondaryReloadAnimHalf = 'Reload_Secondary_Half';
const SecondaryReloadAnimHalfCrouch = 'Reload_Secondary_Half_CH';
const SecondaryReloadAnimEliteEmpty = 'Reload_Secondary_Elite_Empty';
const SecondaryReloadAnimEliteEmptyCrouch = 'Reload_Secondary_Elite_Empty_CH';
const SecondaryReloadAnimEliteHalf = 'Reload_Secondary_Elite_Half';
const SecondaryReloadAnimEliteHalfCrouch = 'Reload_Secondary_Elite_Half_CH';
const ShotgunMuzzleSocket = 'ShotgunMuzzleFlash';
var protected transient KFMuzzleFlash ShotgunMuzzleFlash;
@ -30,18 +33,25 @@ simulated function PlayReloadMagazineAnim(EWeaponState NewWeaponState, KFPawn P)
{
local name AnimName;
if(NewWeaponState == WEP_ReloadSecondary || NewWeaponState == WEP_ReloadSecondary_Elite)
switch (NewWeaponState)
{
switch (NewWeaponState)
{
case WEP_ReloadSecondary:
AnimName = (P.MyKFWeapon.AmmoCount[1] == 0) ? SecondaryReloadAnimEmpty : SecondaryReloadAnimHalf;
break;
case WEP_ReloadSecondary_Elite:
AnimName = (P.MyKFWeapon.AmmoCount[1] == 0) ? SecondaryReloadAnimEliteEmpty : SecondaryReloadAnimEliteHalf;
break;
}
case WEP_ReloadSecondary:
AnimName = (P.bIsCrouched) ? SecondaryReloadAnimHalfCrouch : SecondaryReloadAnimHalf;
break;
case WEP_ReloadSecondaryEmpty:
AnimName = (P.bIsCrouched) ? SecondaryReloadAnimEmptyCrouch : SecondaryReloadAnimEmpty;
break;
case WEP_ReloadSecondary_Elite:
AnimName = (P.bIsCrouched) ? SecondaryReloadAnimEliteHalfCrouch : SecondaryReloadAnimEliteHalf;
break;
case WEP_ReloadSecondaryEmpty_Elite:
AnimName = (P.bIsCrouched) ? SecondaryReloadAnimEliteEmptyCrouch : SecondaryReloadAnimEliteEmpty;
break;
}
if (AnimName != '')
{
PlayCharacterMeshAnim(P, AnimName, true);
}
else
@ -103,21 +113,19 @@ simulated function PlayFireAnim(KFPawn P)
}
else if (OwnerPawn.FiringMode == 1) // ALT FIRE MODE (Shotgun)
{
// Anim = (P.MyKFWeapon.AmmoCount[1] == 0) ? SecondaryFireIronAnimLast : SecondaryFireIronAnim;
Anim = SecondaryFireIronAnim;
}
}
else // Normal anims
{
if (Pawn(Owner).FiringMode == 0) // DEFAULT FIRE MODE (Rifle)
if (OwnerPawn.FiringMode == 0) // DEFAULT FIRE MODE (Rifle)
{
Anim = WeaponFireAnim;
}
else if (Pawn(Owner).FiringMode == 1) // ALT FIRE MODE (Shotgun)
else if (OwnerPawn.FiringMode == 1) // ALT FIRE MODE (Shotgun)
{
// Anim = (P.MyKFWeapon.AmmoCount[1] == 0) ? SecondaryFireAnimLast : SecondaryFireAnim;
Anim = SecondaryFireAnim;
Anim = OwnerPawn.bIsCrouched ? SecondaryFireAnimCrouch : SecondaryFireAnim;
}
}

View File

@ -0,0 +1,106 @@
//=============================================================================
// KFWeapAttach_HRG_Energy
//=============================================================================
//
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFWeapAttach_HRG_Energy extends KFWeaponAttachment;
`define HRG_ENERGY_MIC_LED_INDEX_1 0
`define HRG_ENERGY_MIC_SCREEN_INDEX 1
`define HRG_ENERGY_MIC_LED_INDEX_2 2
var MaterialInstanceConstant WeaponMIC_2;
var MaterialInstanceConstant WeaponMICScreen;
simulated function SetWeaponAltFireMode (bool bUsingAltFireMode)
{
super.SetWeaponAltFireMode(bUsingAltFireMode);
UpdateMaterial(bUsingAltFireMode ? 1 : 0);
}
simulated function UpdateMaterial(byte FireMode)
{
local LinearColor MatColor;
if (WeapMesh == none)
{
return;
}
MatColor = FireMode == 0 ? class'KFWeap_HRG_Energy'.default.DefaultFireMaterialColor : class'KFWeap_HRG_Energy'.default.AltFireMaterialColor;
if ( WeaponMIC == none )
{
WeaponMIC = WeapMesh.CreateAndSetMaterialInstanceConstant(`HRG_ENERGY_MIC_LED_INDEX_1);
}
if ( WeaponMIC_2 == none )
{
WeaponMIC_2 = WeapMesh.CreateAndSetMaterialInstanceConstant(`HRG_ENERGY_MIC_LED_INDEX_2);
}
if (WeaponMICScreen == none)
{
WeaponMICScreen = WeapMesh.CreateAndSetMaterialInstanceConstant(`HRG_ENERGY_MIC_SCREEN_INDEX);
}
WeaponMIC.SetVectorParameterValue('Vector_GlowColor', MatColor);
WeaponMIC_2.SetVectorParameterValue('Vector_GlowColor', MatColor);
WeaponMICScreen.SetVectorParameterValue('Color_override', MatColor);
}
/** Plays fire animation on weapon mesh */
simulated function PlayWeaponFireAnim()
{
local float Duration, AnimRateModifier;
local name Animation;
local KFPawn_Human KFPH;
KFPH = KFPawn_Human(Instigator);
AnimRateModifier = (KFPH != none && KFPH.bUsingAltFireMode) ? class'KFWeap_HRG_Energy'.default.SecondaryFireAnimRateModifier : 1.0f;
if ( Instigator.bIsWalking )
{
Duration = WeapMesh.GetAnimLength( WeaponIronFireAnim );
Animation = WeaponIronFireAnim;
}
else
{
Duration = WeapMesh.GetAnimLength( WeaponFireAnim );
Animation = WeaponFireAnim;
WeapMesh.PlayAnim( WeaponFireAnim, Duration / ThirdPersonAnimRate,, true );
}
WeapMesh.PlayAnim( Animation, Duration / ThirdPersonAnimRate * AnimRateModifier,, true );
}
/** Play a 3rd person reload animation */
simulated function PlayReloadMagazineAnim(EWeaponState NewWeaponState, KFPawn P)
{
local name AnimName;
switch (NewWeaponState)
{
case WEP_Reload:
case WEP_ReloadEmpty:
AnimName = (!P.bIsCrouched) ? ReloadHalfAnim : CH_ReloadHalfAnim;
break;
case WEP_Reload_Elite:
case WEP_ReloadEmpty_Elite:
AnimName = (!P.bIsCrouched) ? ReloadHalfEliteAnim : CH_ReloadHalfEliteAnim;
break;
}
PlayCharacterMeshAnim(P, AnimName, true);
}
defaultproperties
{
}

View File

@ -0,0 +1,108 @@
//=============================================================================
// KFWeapAttach_FAMAS
//=============================================================================
//
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFWeapAttach_ParasiteImplanter extends KFWeaponAttachment;
`define PARASITEIMPLANTER_MIC_INDEX 0
const SecondaryFireAnim = 'Shoot_Secondary';
const SecondaryFireAnimCrouch = 'Shoot_Secondary_CH';
const SecondaryFireIronAnim = 'Shoot_Secondary_Iron';
const SecondaryFireBodyAnim = 'ADD_Shoot_Secondary';
const SecondaryFireBodyAnimCH = 'ADD_Shoot_Secondary_CH';
const SecondaryFireBodyAnimIron = 'ADD_Shoot_Secondary_Iron';
/** Material colors applied to different fire modes */
var LinearColor NoAmmoMaterialColor;
var LinearColor AmmoReadyMaterialColor;
/** Plays fire animation on weapon mesh */
simulated function PlayWeaponFireAnim()
{
local float Duration;
local name Anim;
if ( Instigator.bIsWalking )
{
if (Instigator.FiringMode == 0) // DEFAULT FIRE MODE
{
Anim = WeaponIronFireAnim;
}
else if (Instigator.FiringMode == 1)
{
Anim = SecondaryFireIronAnim;
}
}
else
{
if (Instigator.FiringMode == 0) // ALT FIRE MODE
{
Anim = WeaponFireAnim;
}
else if (Instigator.FiringMode == 1)
{
Anim = Instigator.bIsCrouched ? SecondaryFireAnimCrouch : SecondaryFireAnim;
}
}
Duration = WeapMesh.GetAnimLength( Anim );
WeapMesh.PlayAnim( Anim, Duration / ThirdPersonAnimRate,, true );
}
/** Plays fire animation on pawn */
simulated function PlayPawnFireAnim( KFPawn P, EAnimSlotStance AnimType )
{
if (P.FiringMode == 0)
{
super.PlayPawnFireAnim(P, AnimType);
}
else if (P.FiringMode == 1)
{
if ( P.bIsCrouched )
{
P.PlayBodyAnim(SecondaryFireBodyAnimCH, AnimType, ThirdPersonAnimRate, ShootBlendInTime, ShootBlendOutTime);
}
else if ( P.bIsWalking )
{
P.PlayBodyAnim(SecondaryFireBodyAnimIron, AnimType, ThirdPersonAnimRate, ShootBlendInTime, ShootBlendOutTime);
}
else
{
P.PlayBodyAnim(SecondaryFireBodyAnim, AnimType, ThirdPersonAnimRate, ShootBlendInTime, ShootBlendOutTime);
}
}
}
/** Special event added for weap attachments. Free for use */
function OnSpecialEvent(int Arg)
{
if (Arg <= 2)
{
UpdateMaterial(Arg == 2);
}
}
simulated function UpdateMaterial(bool HasEnoughAmmo)
{
local LinearColor Value;
Value = HasEnoughAmmo ? AmmoReadyMaterialColor : NoAmmoMaterialColor;
if ( WeaponMIC == None && WeapMesh != None )
{
WeaponMIC = WeapMesh.CreateAndSetMaterialInstanceConstant(`PARASITEIMPLANTER_MIC_INDEX);
}
WeaponMIC.SetVectorParameterValue('Vector_GlowColor', Value);
}
defaultproperties
{
NoAmmoMaterialColor=(R=0.0f,G=0.0f,B=0.0f)
AmmoReadyMaterialColor=(R=0.08f,G=1.0f,B=0.08f)
}

View File

@ -387,7 +387,14 @@ simulated state AltReloading extends Reloading
Perk = GetPerk();
bTacticalReload = (Perk != None && Perk.GetUsingTactialReload(self));
return (bTacticalReload ? WEP_ReloadSecondary_Elite : WEP_ReloadSecondary);
if (AmmoCount[ALTFIRE_FIREMODE] == 0)
{
return (bTacticalReload ? WEP_ReloadSecondaryEmpty_Elite : WEP_ReloadSecondaryEmpty);
}
else
{
return (bTacticalReload ? WEP_ReloadSecondary_Elite : WEP_ReloadSecondary);
}
}
simulated event BeginState(Name PreviousStateName)

View File

@ -661,8 +661,8 @@ defaultproperties
HealFullRechargeSeconds=12
// Heavy Attack Explosion Ammo
MagazineCapacity[0]=3
SpareAmmoCapacity[0]=12
MagazineCapacity[0]=2 //3
SpareAmmoCapacity[0]=10 //12
InitialSpareMags[0]=1
bCanBeReloaded=true
bReloadFromMagazine=true
@ -687,7 +687,7 @@ defaultproperties
// Heavy Attack
FireModeIconPaths(HEAVY_ATK_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_BluntMelee'
InstantHitDamage(HEAVY_ATK_FIREMODE)=130
InstantHitDamage(HEAVY_ATK_FIREMODE)=140 //130
InstantHitDamageTypes(HEAVY_ATK_FIREMODE) = class'KFDT_Bludgeon_MedicBatHeavy'
// Heavy Attack Explosion
@ -729,12 +729,12 @@ defaultproperties
// Explosion
ExplosionActorClass = class'KFExplosionActorReplicated'
Begin Object Class=KFGameExplosion Name=HeavyAttackHealingExplosion
Damage=200
Damage=225 //200
DamageRadius=500
DamageFalloffExponent=0.f
DamageDelay=0.f
MyDamageType=class'KFDT_Toxic_MedicBatGas'
HealingAmount=30
HealingAmount=20 //30
// Damage Effects
KnockDownStrength=0

View File

@ -373,7 +373,21 @@ simulated function float GetReloadRateScale()
simulated function bool HasAnyAmmo()
{
return AmmoCount[0] != 0 && SpareAmmoCount[0] != 0;
return AmmoCount[0] > 0 || SpareAmmoCount[0] > 0;
}
simulated function int GetMeleeDamage(byte FireModeNum, optional vector RayDir)
{
local int Damage;
Damage = GetModifiedDamage(FireModeNum, RayDir);
// decode damage scale (see GetDamageScaleByAngle) from the RayDir
if ( !IsZero(RayDir) )
{
Damage = Round(float(Damage) * FMin(VSize(RayDir), 1.f));
}
return Damage;
}
defaultproperties

View File

@ -0,0 +1,192 @@
//=============================================================================
// KFWeap_HRG_Boomy
//=============================================================================
//
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFWeap_HRG_Boomy extends KFWeap_SMGBase;
/**
* Overriden to use instant hit vfx.
* Basically, calculate the hit location so vfx can play
*/
simulated function Projectile ProjectileFire()
{
local vector StartTrace, EndTrace, RealStartLoc, AimDir;
local ImpactInfo TestImpact;
local vector DirA, DirB;
local Quat Q;
local class<KFProjectile> MyProjectileClass;
MyProjectileClass = GetKFProjectileClass();
// This is where we would start an instant trace. (what CalcWeaponFire uses)
StartTrace = GetSafeStartTraceLocation();
AimDir = Vector(GetAdjustedAim( StartTrace ));
// this is the location where the projectile is spawned.
RealStartLoc = GetPhysicalFireStartLoc(AimDir);
// if projectile is spawned at different location of crosshair,
// then simulate an instant trace where crosshair is aiming at, Get hit info.
EndTrace = StartTrace + AimDir * GetTraceRange();
TestImpact = CalcWeaponFire( StartTrace, EndTrace );
// Set flash location to trigger client side effects. Bypass Weapon.SetFlashLocation since
// that function is not marked as simulated and we want instant client feedback.
// ProjectileFire/IncrementFlashCount has the right idea:
// 1) Call IncrementFlashCount on Server & Local
// 2) Replicate FlashCount if ( !bNetOwner )
// 3) Call WeaponFired() once on local player
if( Instigator != None )
{
Instigator.SetFlashLocation( Self, CurrentFireMode, TestImpact.HitLocation );
}
if( Role == ROLE_Authority || (MyProjectileClass.default.bUseClientSideHitDetection
&& MyProjectileClass.default.bNoReplicationToInstigator && Instigator != none
&& Instigator.IsLocallyControlled()) )
{
if( StartTrace != RealStartLoc )
{
// Store the original aim direction without correction
DirB = AimDir;
// Then we realign projectile aim direction to match where the crosshair did hit.
AimDir = Normal(TestImpact.HitLocation - RealStartLoc);
// Store the desired corrected aim direction
DirA = AimDir;
// Clamp the maximum aim adjustment for the AimDir so you don't get wierd
// cases where the projectiles velocity is going WAY off of where you
// are aiming. This can happen if you are really close to what you are
// shooting - Ramm
if ( (DirA dot DirB) < MaxAimAdjust_Cos )
{
Q = QuatFromAxisAndAngle(Normal(DirB cross DirA), MaxAimAdjust_Angle);
AimDir = QuatRotateVector(Q,DirB);
}
}
return SpawnAllProjectiles(MyProjectileClass, RealStartLoc, AimDir);
}
return None;
}
defaultproperties
{
bHasFireLastAnims=true
BonesToLockOnEmpty=(RW_Charging_Handle)
// Shooting Animations
FireSightedAnims[0]=Shoot_Iron
FireSightedAnims[1]=Shoot_Iron2
FireSightedAnims[2]=Shoot_Iron3
// FOV
MeshFOV=75
MeshIronSightFOV=52
PlayerIronSightFOV=70
// Depth of field
DOF_FG_FocalRadius=85
DOF_FG_MaxNearBlurSize=2.5
// Content
PackageKey="HRG_Boomy"
FirstPersonMeshName="WEP_1P_HRG_Boomy_MESH.Wep_1stP_HRG_Boomy_Rig"
FirstPersonAnimSetNames(0)="WEP_1P_HRG_Boomy_ANIM.WEP_1stP_HRG_Boomy_Anim"
PickupMeshName="WEP_3P_HRG_Boomy_MESH.Wep_3rdP_HRG_Boomy_Pickup"
AttachmentArchetypeName="WEP_HRG_Boomy_ARCH.Wep_HRG_Boomy_3P"
MuzzleFlashTemplateName="WEP_HRG_Boomy_ARCH.Wep_HRG_Boomy_MuzzleFlash"
// Zooming/Position
PlayerViewOffset=(X=5.0,Y=9,Z=-5)
IronSightPosition=(X=5,Y=0,Z=0)
// Ammo
MagazineCapacity[0]=24
SpareAmmoCapacity[0]=192
InitialSpareMags[0]=1
bCanBeReloaded=true
bReloadFromMagazine=true
// Recoil
maxRecoilPitch=325 //325 //130 //165
minRecoilPitch=300 //275 //115 //130
maxRecoilYaw=140 //150 //115 //130
minRecoilYaw=-140 //-150 //-115 //130
RecoilRate=0.085
RecoilMaxYawLimit=500
RecoilMinYawLimit=65035
RecoilMaxPitchLimit=900
RecoilMinPitchLimit=65035
RecoilISMaxYawLimit=75
RecoilISMinYawLimit=65460
RecoilISMaxPitchLimit=375
RecoilISMinPitchLimit=65460
RecoilViewRotationScale=0.25
IronSightMeshFOVCompensationScale=1.5
HippedRecoilModifier=1.5
// Inventory / Grouping
InventorySize=7
GroupPriority=50
WeaponSelectTexture=Texture2D'WEP_UI_HRG_Boomy_TEX.UI_WeaponSelect_HRG_Boomy'
AssociatedPerkClasses(0)=class'KFPerk_Demolitionist'
// DEFAULT_FIREMODE
FireModeIconPaths(DEFAULT_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_BulletAuto'
FiringStatesArray(DEFAULT_FIREMODE)=WeaponFiring
WeaponFireTypes(DEFAULT_FIREMODE)=EWFT_Projectile
WeaponProjectiles(DEFAULT_FIREMODE)=class'KFProj_Bullet_HRG_Boomy'
InstantHitDamageTypes(DEFAULT_FIREMODE)=class'KFDT_Ballistic_HRG_Boomy'
FireInterval(DEFAULT_FIREMODE)=+0.1667 // 360 RPM
Spread(DEFAULT_FIREMODE)=0.01 //0.025
InstantHitDamage(DEFAULT_FIREMODE)=25.0
FireOffset=(X=30,Y=4.5,Z=-5)
// ALT_FIREMODE
FireModeIconPaths(ALTFIRE_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_BulletSingle'
FiringStatesArray(ALTFIRE_FIREMODE)=WeaponSingleFiring
WeaponFireTypes(ALTFIRE_FIREMODE)=EWFT_Projectile
WeaponProjectiles(ALTFIRE_FIREMODE)=class'KFProj_Bullet_HRG_Boomy'
InstantHitDamageTypes(ALTFIRE_FIREMODE)=class'KFDT_Ballistic_HRG_Boomy'
FireInterval(ALTFIRE_FIREMODE)=+0.1667 // 360 RPM
InstantHitDamage(ALTFIRE_FIREMODE)=25.0
Spread(ALTFIRE_FIREMODE)=0.01 //0.025
// BASH_FIREMODE
InstantHitDamageTypes(BASH_FIREMODE)=class'KFDT_Bludgeon_HRG_Boomy'
InstantHitDamage(BASH_FIREMODE)=26
// Fire Effects
WeaponFireSnd(DEFAULT_FIREMODE)=(DefaultCue=AkEvent'ww_wep_hrg_boomy.Play_WEP_HRG_Boomy_3P_ShootLoop', FirstPersonCue=AkEvent'ww_wep_hrg_boomy.Play_WEP_HRG_Boomy_1P_ShootLoop')
WeaponFireSnd(ALTFIRE_FIREMODE)=(DefaultCue=AkEvent'ww_wep_hrg_boomy.Play_WEP_HRG_Boomy_3P_Shoot', FirstPersonCue=AkEvent'ww_wep_hrg_boomy.Play_WEP_HRG_Boomy_1P_Shoot')
WeaponFireLoopEndSnd(DEFAULT_FIREMODE)=(DefaultCue=AkEvent'ww_wep_hrg_boomy.Play_WEP_HRG_Boomy_3P_ShootLoopEnd', FirstPersonCue=AkEvent'ww_wep_hrg_boomy.Play_WEP_HRG_Boomy_1P_ShootLoopEnd')
WeaponDryFireSnd(DEFAULT_FIREMODE)=AkEvent'WW_WEP_SA_L85A2.Play_WEP_SA_L85A2_Handling_DryFire'
WeaponDryFireSnd(ALTFIRE_FIREMODE)=AkEvent'WW_WEP_SA_L85A2.Play_WEP_SA_L85A2_Handling_DryFire'
// Advanced (High RPM) Fire Effects
bLoopingFireAnim(DEFAULT_FIREMODE)=true
bLoopingFireSnd(DEFAULT_FIREMODE)=true
SingleFireSoundIndex=ALTFIRE_FIREMODE
// Attachments
bHasIronSights=true
bHasFlashlight=false
WeaponUpgrades[1]=(Stats=((Stat=EWUS_Damage0, Scale=1.15f), (Stat=EWUS_Damage1, 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_Weight, Add=2)))
WeaponUpgrades[3]=(Stats=((Stat=EWUS_Damage0, Scale=1.45f), (Stat=EWUS_Damage1, Scale=1.45f), (Stat=EWUS_Weight, Add=3)))
}

View File

@ -0,0 +1,510 @@
//=============================================================================
// KFWeap_HRG_Energy
//=============================================================================
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFWeap_HRG_Energy extends KFWeap_PistolBase;
`define HRG_ENERGY_MIC_LED_INDEX_1 0
`define HRG_ENERGY_MIC_SCREEN_INDEX 1
`define HRG_ENERGY_MIC_LED_INDEX_2 2
/*********************************************************************************************
@name Optics UI
********************************************************************************************* */
var class<KFGFxWorld_MedicOptics> OpticsUIClass;
var KFGFxWorld_MedicOptics OpticsUI;
/** The last updated value for our ammo - Used to know when to update our optics ammo */
var byte StoredPrimaryAmmo;
var byte StoredSecondaryAmmo;
var transient float AltFireMaxShots;
/** Modifier applied to the alt fire animation */
var float SecondaryFireAnimRateModifier;
/** Material colors applied to different fire modes */
var LinearColor DefaultFireMaterialColor;
var LinearColor AltFireMaterialColor;
/** How much recoil the altfire should do */
var protected const float AltFireRecoilScale;
simulated event PreBeginPlay()
{
super.PreBeginPlay();
AltFireMaxShots = MagazineCapacity[DEFAULT_FIREMODE] / AmmoCost[ALTFIRE_FIREMODE];
}
simulated function Activate()
{
super.Activate();
UpdateMaterial(bUseAltFireMode ? ALTFIRE_FIREMODE : DEFAULT_FIREMODE);
}
simulated function UpdateMaterial(byte FireMode)
{
local LinearColor MatColor;
MatColor = FireMode == DEFAULT_FIREMODE ? DefaultFireMaterialColor : AltFireMaterialColor;
if( WeaponMICs.Length > `HRG_ENERGY_MIC_LED_INDEX_1 )
{
WeaponMICs[`HRG_ENERGY_MIC_LED_INDEX_1].SetVectorParameterValue('Vector_GlowColor', MatColor);
}
if (WeaponMICs.Length > `HRG_ENERGY_MIC_SCREEN_INDEX)
{
WeaponMICs[`HRG_ENERGY_MIC_SCREEN_INDEX].SetVectorParameterValue('Color_override', MatColor);
}
if( WeaponMICs.Length > `HRG_ENERGY_MIC_LED_INDEX_2 )
{
WeaponMICs[`HRG_ENERGY_MIC_LED_INDEX_2].SetVectorParameterValue('Vector_GlowColor', MatColor);
}
}
/**
* Check target locking - server-side only
* HealAmmo Regen client and server
*/
simulated event Tick( FLOAT DeltaTime )
{
if (Instigator != none && Instigator.weapon == self)
{
UpdateOpticsUI();
}
Super.Tick(DeltaTime);
}
/*********************************************************************************************
@name Optics UI
********************************************************************************************* */
/** Get our optics movie from the inventory once our InvManager is created */
reliable client function ClientWeaponSet(bool bOptionalSet, optional bool bDoNotActivate)
{
local KFInventoryManager KFIM;
super.ClientWeaponSet(bOptionalSet, bDoNotActivate);
if (OpticsUI == none)
{
KFIM = KFInventoryManager(InvManager);
if (KFIM != none)
{
//Create the screen's UI piece
OpticsUI = KFGFxWorld_MedicOptics(KFIM.GetOpticsUIMovie(OpticsUIClass));
}
}
}
function ItemRemovedFromInvManager()
{
local KFInventoryManager KFIM;
local KFWeap_MedicBase KFW;
Super.ItemRemovedFromInvManager();
if (OpticsUI != none)
{
KFIM = KFInventoryManager(InvManager);
if (KFIM != none)
{
// @todo future implementation will have optics in base weapon class
foreach KFIM.InventoryActors(class'KFWeap_MedicBase', KFW)
{
// This is not a MedicBase, no need to check against itself
if(KFW.OpticsUI.Class == OpticsUI.class)
{
// A different weapon is still using this optics class
return;
}
}
//Create the screen's UI piece
KFIM.RemoveOpticsUIMovie(OpticsUI.class);
OpticsUI.Close();
OpticsUI = none;
}
}
}
/** Unpause our optics movie and reinitialize our ammo when we equip the weapon */
simulated function AttachWeaponTo(SkeletalMeshComponent MeshCpnt, optional Name SocketName)
{
super.AttachWeaponTo(MeshCpnt, SocketName);
if (OpticsUI != none)
{
OpticsUI.SetPause(false);
OpticsUI.ClearLockOn();
UpdateOpticsUI(true);
OpticsUI.SetShotPercentCost( AmmoCost[ALTFIRE_FIREMODE]);
}
}
/** Pause the optics movie once we unequip the weapon so it's not playing in the background */
simulated function DetachWeapon()
{
local Pawn OwnerPawn;
super.DetachWeapon();
OwnerPawn = Pawn(Owner);
if( OwnerPawn != none && OwnerPawn.Weapon == self )
{
if (OpticsUI != none)
{
OpticsUI.SetPause();
}
}
}
/**
* Update our displayed ammo count if it's changed
*/
simulated function UpdateOpticsUI(optional bool bForceUpdate)
{
if (OpticsUI != none && OpticsUI.OpticsContainer != none)
{
if (AmmoCount[DEFAULT_FIREMODE] != StoredPrimaryAmmo || bForceUpdate)
{
StoredPrimaryAmmo = AmmoCount[DEFAULT_FIREMODE];
OpticsUI.SetPrimaryAmmo(StoredPrimaryAmmo);
if(AmmoCount[DEFAULT_FIREMODE] < AmmoCost[ALTFIRE_FIREMODE])
{
OpticsUI.SetHealerCharge(0);
}
else
{
OpticsUI.SetHealerCharge((AmmoCount[DEFAULT_FIREMODE] / AmmoCost[ALTFIRE_FIREMODE]) / AltFireMaxShots * 100);
}
}
if(OpticsUI.MinPercentPerShot != AmmoCost[ALTFIRE_FIREMODE])
{
OpticsUI.SetShotPercentCost( AmmoCost[ALTFIRE_FIREMODE] );
}
}
}
/** Healing charge doesn't count as ammo for purposes of inventory management (e.g. switching) */
simulated function bool HasAnyAmmo()
{
return HasSpareAmmo() || HasAmmo(DEFAULT_FIREMODE) || HasSpareAmmo(ALTFIRE_FIREMODE) || HasAmmo(ALTFIRE_FIREMODE);
}
simulated function StartFire(byte FireModeNum)
{
if (FireModeNum == DEFAULT_FIREMODE && bUseAltFireMode)
{
if (AmmoCount[FireModeNum] < AmmoCost[ALTFIRE_FIREMODE] && SpareAmmoCount[FireModeNum] > 0)
{
BeginFire(RELOAD_FIREMODE);
return;
}
}
super.StartFire(FireModeNum);
}
simulated function AltFireMode()
{
if ( !Instigator.IsLocallyControlled() )
{
return;
}
if ( !bUseAltFireMode && SpareAmmoCount[0] + AmmoCount[0] < AmmoCost[1] )
{
return;
}
super.AltFireMode();
UpdateMaterial(bUseAltFireMode ? ALTFIRE_FIREMODE : DEFAULT_FIREMODE);
NotifyAltFireUsage();
}
/** Overriden to use WeaponAnimSeqNode */
simulated function PlayWeaponAnimation(name Sequence, float fDesiredDuration, optional bool bLoop, optional SkeletalMeshComponent SkelMesh)
{
local float DesiredRate;
if ( Mesh != none && Instigator != none && WorldInfo.NetMode != NM_DedicatedServer )
{
if ( WeaponAnimSeqNode != None )
{
if (WeaponAnimSeqNode.AnimSeq == None || WeaponAnimSeqNode.AnimSeq.SequenceName != Sequence)
{
WeaponAnimSeqNode.SetAnim(Sequence);
}
if(fDesiredDuration > 0.0 && WeaponAnimSeqNode.AnimSeq.RateScale > 0.0)
{
DesiredRate = WeaponAnimSeqNode.AnimSeq.SequenceLength / (fDesiredDuration * WeaponAnimSeqNode.AnimSeq.RateScale);
WeaponAnimSeqNode.PlayAnim(bLoop, DesiredRate);
}
else
{
WeaponAnimSeqNode.PlayAnim(bLoop, DefaultAnimSpeed);
}
}
}
}
/**
* PlayFireEffects Is the root function that handles all of the effects associated with
* a weapon. This function creates the 1st person effects. It should only be called
* on a locally controlled player.
*/
simulated function PlayFireEffects( byte FireModeNum, optional vector HitLocation )
{
local name WeaponFireAnimName;
local KFPerk CurrentPerk;
local float TempTweenTime, AdjustedAnimLength;
// If we have stopped the looping fire sound to play single fire sounds for zed time
// start the looping sound back up again when the time is back above zed time speed
if( FireModeNum < bLoopingFireSnd.Length && bLoopingFireSnd[FireModeNum] && !bPlayingLoopingFireSnd )
{
StartLoopingFireSound(FireModeNum);
}
PlayFiringSound(CurrentFireMode);
if( Instigator != none )
{
// Tell our pawn about any changes in animation speed
UpdateWeaponAttachmentAnimRate( GetThirdPersonAnimRate() );
if( Instigator.IsLocallyControlled() )
{
if( Instigator.IsFirstPerson() )
{
if ( !bPlayingLoopingFireAnim )
{
WeaponFireAnimName = GetWeaponFireAnim(FireModeNum);
if ( WeaponFireAnimName != '' )
{
AdjustedAnimLength = MySkelMesh.GetAnimLength(WeaponFireAnimName);
TempTweenTime = FireTweenTime;
if (FireModeNum == ALTFIRE_FIREMODE)
{
AdjustedAnimLength *= SecondaryFireAnimRateModifier;
}
CurrentPerk = GetPerk();
if( CurrentPerk != none )
{
CurrentPerk.ModifyRateOfFire( AdjustedAnimLength, self );
// We need to unlock the slide if we fire from zero ammo while uber ammo is active
if( EmptyMagBlendNode != none
&& BonesToLockOnEmpty.Length > 0
&& AmmoCount[GetAmmoType(FireModeNum)] == 0
&& CurrentPerk.GetIsUberAmmoActive(self) )
{
EmptyMagBlendNode.SetBlendTarget( 0, 0 );
TempTweenTime = 0.f;
}
}
PlayAnimation(WeaponFireAnimName, AdjustedAnimLength,, TempTweenTime);
}
}
// Start muzzle flash effect
CauseMuzzleFlash(FireModeNum);
}
HandleRecoil();
ShakeView();
if (AmmoCount[0] == 0 && ForceReloadTimeOnEmpty > 0)
{
SetTimer(ForceReloadTimeOnEmpty, false, nameof(ForceReload));
}
}
}
}
simulated function ModifyRecoil( out float CurrentRecoilModifier )
{
if( CurrentFireMode == ALTFIRE_FIREMODE )
{
CurrentRecoilModifier *= AltFireRecoilScale;
}
super.ModifyRecoil( CurrentRecoilModifier );
}
simulated function NotifyAltFireUsage()
{
local KFPawn_Human KFPH;
// Notify 3P to change material.
KFPH = KFPawn_Human(Instigator);
if (KFPH != none)
{
KFPH.SetUsingAltFireMode(bUseAltFireMode, true);
KFPH.bNetDirty = true;
}
}
simulated state WeaponEquipping
{
simulated function BeginState(Name PreviousStateName)
{
super.BeginState(PreviousStateName);
// NotifyAltFireUsage();
if (WorldInfo.NetMode == NM_Client || WorldInfo.NetMode == NM_Standalone)
{
SetTimer(1.0f, false, nameof(NotifyAltFireUsage));
}
}
}
/** Returns animation to play based on reload type and status */
simulated function name GetReloadAnimName( bool bTacticalReload )
{
return bTacticalReload ? ReloadNonEmptyMagEliteAnim : ReloadNonEmptyMagAnim;
}
simulated function ConsumeAmmo( byte FireModeNum )
{
super.ConsumeAmmo(FireModeNum);
if( bUseAltFireMode && SpareAmmoCount[0] + AmmoCount[0] < AmmoCost[1] )
{
bUseAltFireMode = false;
UpdateMaterial(DEFAULT_FIREMODE);
NotifyAltFireUsage();
}
}
defaultproperties
{
// Inventory
InventoryGroup=IG_Secondary
InventorySize=4
GroupPriority=125
bCanThrow=true
bDropOnDeath=true
WeaponSelectTexture=Texture2D'WEP_UI_HRG_Energy_TEX.UI_WeaponSelect_HRG_Energy'
SecondaryAmmoTexture=Texture2D'UI_SecondaryAmmo_TEX.MedicDarts'
AssociatedPerkClasses(0)=class'KFPerk_Gunslinger'
// Shooting Animations
FireSightedAnims[0]=Shoot_Iron
FireSightedAnims[1]=Shoot_Iron2
FireSightedAnims[2]=Shoot_Iron3
// FOV
MeshFOV=86
MeshIronSightFOV=77
PlayerIronSightFOV=77
// Depth of field
DOF_FG_FocalRadius=40
DOF_FG_MaxNearBlurSize=3.5
// Zooming/Position
PlayerViewOffset=(X=29.0,Y=13,Z=-4)
//Content
PackageKey="HRG_Energy"
FirstPersonMeshName="WEP_1P_HRG_Energy_MESH.Wep_1stP_HRG_Energy_Rig"
FirstPersonAnimSetNames(0)="WEP_1P_HRG_Energy_ANIM.WEP_1P_HRG_Energy_ANIM"
PickupMeshName="wep_3p_HRG_Energy_mesh.Wep_HRG_Energy_Pickup"
AttachmentArchetypeName="WEP_HRG_Energy_ARCH.Wep_HRG_Energy_3P"
MuzzleFlashTemplateName="WEP_HRG_Energy_ARCH.Wep_HRG_Energy_MuzzleFlash"
OpticsUIClass=class'KFGFxWorld_MedicOptics'
// Zooming/Position
IronSightPosition=(X=15,Y=0,Z=0)
// Ammo
MagazineCapacity[0]=15
SpareAmmoCapacity[0]=135
InitialSpareMags[0]=2
bCanBeReloaded=true
bReloadFromMagazine=true
MagazineCapacity[1]=0
bCanRefillSecondaryAmmo=false
// Recoil
maxRecoilPitch=475 //250
minRecoilPitch=425 //200
maxRecoilYaw=130 //100
minRecoilYaw=-130 //-100
RecoilRate=0.07
RecoilMaxYawLimit=500
RecoilMinYawLimit=65035
RecoilMaxPitchLimit=900
RecoilMinPitchLimit=65035
RecoilISMaxYawLimit=50
RecoilISMinYawLimit=65485
RecoilISMaxPitchLimit=250
RecoilISMinPitchLimit=65485
AltFireRecoilScale=2.0f
// DEFAULT_FIREMODE
FireModeIconPaths(DEFAULT_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_BulletSingle'
FiringStatesArray(DEFAULT_FIREMODE)=WeaponSingleFiring
WeaponFireTypes(DEFAULT_FIREMODE)=EWFT_InstantHit
WeaponProjectiles(DEFAULT_FIREMODE)=class'KFProj_Bullet_HRG_Energy'
FireInterval(DEFAULT_FIREMODE)=+0.175 //342 RPM
PenetrationPower(DEFAULT_FIREMODE)=1.0
InstantHitDamage(DEFAULT_FIREMODE)=90.0 //125.0
InstantHitDamageTypes(DEFAULT_FIREMODE)=class'KFDT_Ballistic_HRG_Energy_Primary'
Spread(DEFAULT_FIREMODE)=0.015
FireOffset=(X=20,Y=4.0,Z=-3)
// ALTFIRE_FIREMODE
FireModeIconPaths(ALTFIRE_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_Electricity'
FiringStatesArray(ALTFIRE_FIREMODE)=WeaponFiring
WeaponFireTypes(ALTFIRE_FIREMODE)=EWFT_InstantHit
FireInterval(ALTFIRE_FIREMODE)=+0.705 //85 RPM
WeaponProjectiles(ALTFIRE_FIREMODE)=class'KFProj_Bullet_HRG_Energy_Secondary'
InstantHitDamageTypes(ALTFIRE_FIREMODE)=class'KFDT_Ballistic_HRG_Energy_Secondary'
InstantHitMomentum(ALTFIRE_FIREMODE)=1.0
PenetrationPower(ALTFIRE_FIREMODE)=3.0
InstantHitDamage(ALTFIRE_FIREMODE)=300.0 //475.0
PenetrationDamageReductionCurve(ALTFIRE_FIREMODE)=(Points=((InVal=0.f,OutVal=0.f),(InVal=1.f, OutVal=1.f)))
AmmoCost(ALTFIRE_FIREMODE)=3
// BASH_FIREMODE
InstantHitDamageTypes(BASH_FIREMODE)=class'KFDT_Bludgeon_HRG_Energy'
InstantHitDamage(BASH_FIREMODE)=26
// Fire Effects
WeaponFireSnd(DEFAULT_FIREMODE)=(DefaultCue=AkEvent'ww_wep_hrg_energy.Play_WEP_HRG_Energy_3P_Shoot', FirstPersonCue=AkEvent'ww_wep_hrg_energy.Play_WEP_HRG_Energy_1P_Shoot')
WeaponFireSnd(ALTFIRE_FIREMODE)=(DefaultCue=AkEvent'ww_wep_hrg_energy.Play_WEP_HRG_Energy_3P_ShootAlt', FirstPersonCue=AkEvent'ww_wep_hrg_energy.Play_WEP_HRG_Energy_1P_ShootAlt')
WeaponDryFireSnd(DEFAULT_FIREMODE)=AkEvent'WW_WEP_SA_MedicPistol.Play_SA_MedicPistol_Handling_DryFire'
WeaponDryFireSnd(ALTFIRE_FIREMODE)=AkEvent'WW_WEP_SA_MedicDart.Play_WEP_SA_Medic_Dart_DryFire'
// Attachments
bHasIronSights=true
bHasFlashlight=false
WeaponUpgrades[1]=(Stats=((Stat=EWUS_Damage0, Scale=1.15f), (Stat=EWUS_Damage1, Scale=1.15f), (Stat=EWUS_Weight, Add=1)))
SecondaryFireAnimRateModifier = 2.0f;
DefaultFireMaterialColor=(R=0.90f,G=0.26f,B=0.0f)
AltFireMaterialColor=(R=0.7f,G=0.04f,B=0.9f)
NumBloodMapMaterials=3
// bForceHandleImpacts=true;
}

View File

@ -842,8 +842,8 @@ defaultproperties
ValueIncreaseTime=0.2
//FOR LERPING DAMANGE
MaxDamageByCharge=250 //200 //120
MinDamageByCharge=25 //30
MaxDamageByCharge=300 //250 //200 //120
MinDamageByCharge=30 //25 //30
// FOV
Meshfov=80
MeshIronSightFOV=65 //52
@ -870,8 +870,8 @@ defaultproperties
// Ammo
MagazineCapacity[0]=12 //24
SpareAmmoCapacity[0]=108 //96 //120
InitialSpareMags[0]=2 //1
SpareAmmoCapacity[0]=132 //108
InitialSpareMags[0]=3 //2
AmmoPickupScale[0]=1.5 //1 //0.75
bCanBeReloaded=true
bReloadFromMagazine=true
@ -905,7 +905,7 @@ defaultproperties
FiringStatesArray(DEFAULT_FIREMODE)=MineReconstructorCharge
WeaponFireTypes(DEFAULT_FIREMODE)=EWFT_Projectile
WeaponProjectiles(DEFAULT_FIREMODE)=class'KFProj_Mine_Reconstructor'
FireInterval(DEFAULT_FIREMODE)=+0.33 //180 RPMs
FireInterval(DEFAULT_FIREMODE)=+0.223 //+0.33
InstantHitDamage(DEFAULT_FIREMODE)=120
PenetrationPower(DEFAULT_FIREMODE)=0.0;
InstantHitDamageTypes(DEFAULT_FIREMODE)=class'KFDT_Toxic_MineReconstructorImpact'
@ -914,7 +914,7 @@ defaultproperties
// ALT_FIREMODE
FiringStatesArray(ALTFIRE_FIREMODE)=WeaponSingleFiring
WeaponFireTypes(ALTFIRE_FIREMODE)=EWFT_Custom
FireInterval(ALTFIRE_FIREMODE)=+0.25
FireInterval(ALTFIRE_FIREMODE)=+0.15 //+0.25
AmmoCost(ALTFIRE_FIREMODE)=0
// BASH_FIREMODE

View File

@ -0,0 +1,228 @@
//=============================================================================
// KFWeap_Pistol_Bladed
//=============================================================================
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFWeap_Pistol_Bladed extends KFWeap_MeleeBase;
/** Returns trader filter index based on weapon type */
static simulated event EFilterTypeUI GetTraderFilter()
{
return FT_Pistol;
}
/** Override melee SetIronSights (which sends to heavy attack) so that this weapon ironsights normally*/
simulated function SetIronSights(bool bNewIronSights)
{
super(KFWeapon).SetIronSights(bNewIronSights);
}
/** Override melee ShouldOwnerWalk which doesn't account for walking when in ironsights */
simulated function bool ShouldOwnerWalk()
{
return super(KFWeapon).ShouldOwnerWalk();
}
/** Override to drop the player out of ironsights first */
simulated function AltFireMode()
{
if (!Instigator.IsLocallyControlled())
{
return;
}
// break out of ironsights when starting to block
if (bUsingSights)
{
SetIronSights(false);
}
StartFire(BLOCK_FIREMODE);
}
simulated state MeleeBlocking
{
simulated function bool AllowIronSights() { return false; }
}
/** Called during reload state */
simulated function bool CanOverrideMagReload(byte FireModeNum)
{
if (FireModeNum == BLOCK_FIREMODE)
{
return true;
}
return super.CanOverrideMagReload(FireModeNum);
}
simulated function StartFire(byte FireModeNum)
{
if( FireModeNum == DEFAULT_FIREMODE )
{
if ( ShouldAutoReload(FireModeNum) )
{
BeginFire(RELOAD_FIREMODE);
return;
}
}
super.StartFire(FireModeNum);
}
/*********************************************************************************************
* @name Firing / Projectile
********************************************************************************************* */
/**
* 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 );
}
defaultproperties
{
// MeleeBase
bMeleeWeapon=false
// FOV
MeshFOV=96
MeshIronSightFOV=77
PlayerIronSightFOV=77
// Depth of field
DOF_FG_FocalRadius=40
DOF_FG_MaxNearBlurSize=3.5
// Zooming/Position
PlayerViewOffset=(X=-15,Y=12,Z=-6)
IronSightPosition=(X=0,Y=0,Z=1.0) //(X=-3,Y=-0.38,Z=-0.2)
// Content
PackageKey="BladedPistol"
FirstPersonMeshName="WEP_1P_BladedPistol_MESH.WEP_1stP_BladedPistol_Rig"
FirstPersonAnimSetNames(0)="WEP_1P_BladedPistol_ANIM.WEP_1stP_BladedPistol_Anim"
PickupMeshName="WEP_3P_BladedPistol_MESH.Wep_BladedPistol_Pickup"
AttachmentArchetypeName="WEP_BladedPistol_ARCH.Wep_BladedPistol_3P"
MuzzleFlashTemplateName="WEP_BladedPistol_ARCH.Wep_BladedPistol_MuzzleFlash"
// Ammo
MagazineCapacity[0]=6
SpareAmmoCapacity[0]=72 //96
InitialSpareMags[0]=2
AmmoPickupScale[0]=1.0 //2.0
bCanBeReloaded=true
bReloadFromMagazine=true
// Recoil
maxRecoilPitch=330 //400 //250
minRecoilPitch=300 //350 //200
maxRecoilYaw=90 //120 //100
minRecoilYaw=-90 //-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.25 //+0.3
InstantHitDamage(DEFAULT_FIREMODE)=115.0
InstantHitDamageTypes(DEFAULT_FIREMODE)=class'KFDT_Slashing_BladedPistol'
Spread(DEFAULT_FIREMODE)=0.005 //0.015
AmmoCost(DEFAULT_FIREMODE)=1
FireOffset=(X=30,Y=5,Z=-4)
FireModeIconPaths(DEFAULT_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_Sawblade'
// ALT_FIREMODE
// FiringStatesArray(ALTFIRE_FIREMODE)=WeaponSingleFiring
// WeaponFireTypes(ALTFIRE_FIREMODE)=EWFT_None
// BASH_FIREMODE
InstantHitDamageTypes(BASH_FIREMODE)=class'KFDT_Bludgeon_BladedPistol'
InstantHitDamage(BASH_FIREMODE)=75 //26
FiringStatesArray(BASH_FIREMODE)=MeleeAttackBasic
WeaponFireTypes(BASH_FIREMODE)=EWFT_Custom
InstantHitMomentum(BASH_FIREMODE)=10000.f
// 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'
// RELOAD_FIREMODE
FiringStatesArray(RELOAD_FIREMODE)="Reloading"
WeaponFireTypes(RELOAD_FIREMODE)=EWFT_InstantHit
// Attachments
bHasIronSights=true
bHasFlashlight=true
AssociatedPerkClasses(0)=class'KFPerk_Gunslinger'
AssociatedPerkClasses(1)=class'KFPerk_Berserker'
// Inventory
InventoryGroup=IG_Secondary
InventorySize=3
GroupPriority=25
bCanThrow=true
bDropOnDeath=true
WeaponSelectTexture=Texture2D'WEP_UI_BladedPistol_TEX.UI_WeaponSelect_BladedPistol'
bIsBackupWeapon=false
DualClass=class'KFWeap_Pistol_DualBladed'
// Custom animations
FireSightedAnims=(Shoot_Iron)
IdleFidgetAnims=(Guncheck_v1, Guncheck_v2, Guncheck_v3)
bHasFireLastAnims=true
BonesToLockOnEmpty=(RW_FrontPivot)
// 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
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)))
}

View File

@ -0,0 +1,679 @@
//=============================================================================
// 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);
}
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]=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)))
}

View File

@ -0,0 +1,428 @@
//=============================================================================
// KFWeap_Rifle_ParasiteImplanter
//=============================================================================
// Weapon code for parasite implanter.
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFWeap_Rifle_ParasiteImplanter extends KFWeap_ScopedBase;
`define PARASITE_MIC_LED_INDEX 0
var float LastFireInterval;
/** How many seed ammo to recharge per second */
var float SeedFullRechargeSeconds;
/** How many ammo to recharge per second. */
var transient float SeedRechargePerSecond;
var transient float SeedIncrement;
var repnotify byte SeedAmmo;
const SecondaryFireAnim = 'Shoot_Secondary';
const SecondaryFireIronAnim = 'Shoot_Secondary_Iron';
/** Material colors applied to different fire modes */
var LinearColor NoAmmoMaterialColor;
var LinearColor AmmoReadyMaterialColor;
/** How much recoil the altfire should do */
var protected const float AltFireRecoilScale;
replication
{
if (bNetDirty && Role == ROLE_Authority)
SeedAmmo;
}
simulated event ReplicatedEvent(name VarName)
{
if (VarName == nameof(SeedAmmo))
{
if (AmmoCount[ALTFIRE_FIREMODE] < AmmoCost[ALTFIRE_FIREMODE] && SeedAmmo >= AmmoCost[ALTFIRE_FIREMODE])
{
UpdateMaterial(true);
}
else if (AmmoCount[ALTFIRE_FIREMODE] >= AmmoCost[ALTFIRE_FIREMODE] && SeedAmmo < AmmoCost[ALTFIRE_FIREMODE])
{
UpdateMaterial(false);
}
AmmoCount[ALTFIRE_FIREMODE] = SeedAmmo;
}
else
{
Super.ReplicatedEvent(VarName);
}
}
/*********************************************************************************************
* @name Trader
*********************************************************************************************/
/** Returns trader filter index based on weapon type */
static simulated event EFilterTypeUI GetTraderFilter()
{
if( default.FiringStatesArray[DEFAULT_FIREMODE] == 'WeaponFiring' || default.FiringStatesArray[DEFAULT_FIREMODE] == 'WeaponBurstFiring' )
{
return FT_Assault;
}
else // if( FiringStatesArray[DEFAULT_FIREMODE] == 'WeaponSingleFiring')
{
return FT_Rifle;
}
}
simulated event PreBeginPlay()
{
super.PreBeginPlay();
StartSeedRecharge();
}
function StartSeedRecharge()
{
// local KFPerk InstigatorPerk;
local float UsedSeedRechargeTime;
// begin ammo recharge on server
if( Role == ROLE_Authority )
{
UsedSeedRechargeTime = SeedFullRechargeSeconds;
SeedRechargePerSecond = MagazineCapacity[ALTFIRE_FIREMODE] / UsedSeedRechargeTime;
SeedIncrement = 0;
}
}
function RechargeSeed(float DeltaTime)
{
if ( Role == ROLE_Authority )
{
SeedIncrement += SeedRechargePerSecond * DeltaTime;
if( SeedIncrement >= 1.0 && AmmoCount[ALTFIRE_FIREMODE] < MagazineCapacity[ALTFIRE_FIREMODE] )
{
AmmoCount[ALTFIRE_FIREMODE]++;
SeedIncrement -= 1.0;
SeedAmmo = AmmoCount[ALTFIRE_FIREMODE];
}
}
}
/** Overridden to call StartHealRecharge on server */
function GivenTo( Pawn thisPawn, optional bool bDoNotActivate )
{
super.GivenTo( thisPawn, bDoNotActivate );
if( Role == ROLE_Authority && !thisPawn.IsLocallyControlled() )
{
StartSeedRecharge();
}
}
/*********************************************************************************************
@name Actor
********************************************************************************************* */
simulated event Tick( FLOAT DeltaTime )
{
local bool bWasLowAmmo;
bWasLowAmmo = AmmoCount[ALTFIRE_FIREMODE] < AmmoCost[ALTFIRE_FIREMODE];
if( AmmoCount[ALTFIRE_FIREMODE] < MagazineCapacity[ALTFIRE_FIREMODE] )
{
RechargeSeed(DeltaTime);
}
if (WorldInfo.NetMode != NM_DedicatedServer)
{
if (bWasLowAmmo && AmmoCount[ALTFIRE_FIREMODE] >= AmmoCost[ALTFIRE_FIREMODE])
{
UpdateMaterial(true);
}
}
else
{
if (bWasLowAmmo && AmmoCount[ALTFIRE_FIREMODE] >= AmmoCost[ALTFIRE_FIREMODE])
{
NotifyAltAmmoReady(true);
}
}
Super.Tick(DeltaTime);
}
/*********************************************************************************************
* Trader
********************************************************************************************/
/** Allows weapon to set its own trader stats (can set number of stats, names and values of stats) */
static simulated event SetTraderWeaponStats( out array<STraderItemWeaponStats> WeaponStats )
{
super.SetTraderWeaponStats( WeaponStats );
WeaponStats.Length = WeaponStats.Length + 1;
WeaponStats[WeaponStats.Length-1].StatType = TWS_RechargeTime;
WeaponStats[WeaponStats.Length-1].StatValue = default.SeedFullRechargeSeconds;
}
/** Seeds doesn't count as ammo for purposes of inventory management (e.g. switching) */
simulated function bool HasAnyAmmo()
{
return HasSpareAmmo() || HasAmmo(DEFAULT_FIREMODE);
}
simulated function ConsumeAmmo( byte FireModeNum )
{
local bool bWasHighAmmo;
if( FireModeNum != ALTFIRE_FIREMODE )
{
Super.ConsumeAmmo(FireModeNum);
return;
}
`if(`notdefined(ShippingPC))
if( bInfiniteAmmo )
{
return;
}
`endif
bWasHighAmmo = AmmoCount[ALTFIRE_FIREMODE] >= AmmoCost[ALTFIRE_FIREMODE];
// If AmmoCount is being replicated, don't allow the client to modify it here
if (Role == ROLE_Authority)
{
// Don't consume ammo if magazine size is 0 (infinite ammo with no reload)
if (MagazineCapacity[1] > 0 && AmmoCount[1] > 0)
{
// Reduce ammo amount by heal ammo cost
AmmoCount[1] = Max(AmmoCount[1] - AmmoCost[1], 0);
}
}
if (WorldInfo.NetMode != NM_DedicatedServer)
{
if (bWasHighAmmo && AmmoCount[ALTFIRE_FIREMODE] < AmmoCost[ALTFIRE_FIREMODE])
{
UpdateMaterial(false);
}
}
else if (bWasHighAmmo && AmmoCount[ALTFIRE_FIREMODE] < AmmoCost[ALTFIRE_FIREMODE])
{
NotifyAltAmmoReady(false);
}
}
/** Instead of switch fire mode use as immediate alt fire */
simulated function AltFireMode()
{
if ( !Instigator.IsLocallyControlled() )
{
return;
}
StartFire(ALTFIRE_FIREMODE);
}
simulated function float GetFireInterval(byte FireModeNum)
{
if (FireModeNum == DEFAULT_FIREMODE && AmmoCount[FireModeNum] == 0)
{
return LastFireInterval;
}
return super.GetFireInterval(FireModeNum);
}
simulated function name GetWeaponFireAnim(byte FireModeNum)
{
if (FireModeNum == ALTFIRE_FIREMODE)
{
return bUsingSights ? SecondaryFireIronAnim : SecondaryFireAnim;
}
return super.GetWeaponFireAnim(FireModeNum);
}
simulated function UpdateMaterial(bool HasEnoughAmmo)
{
local LinearColor MatColor;
if (WorldInfo.NetMode != NM_DedicatedServer)
{
MatColor = HasEnoughAmmo ? AmmoReadyMaterialColor : NoAmmoMaterialColor;
if( WeaponMICs.Length >= `PARASITE_MIC_LED_INDEX )
{
WeaponMICs[`PARASITE_MIC_LED_INDEX].SetVectorParameterValue('Vector_GlowColor', MatColor);
}
}
}
/**
Should replicate to 3P to show the alt fire ready
*/
simulated function NotifyAltAmmoReady(bool bActive)
{
local KFPawn KFP;
if (WorldInfo.NetMode != NM_Client)
{
KFP = KFPawn(Instigator);
KFP.OnWeaponSpecialAction(bActive ? 2 : 1);
}
}
simulated function ModifyRecoil( out float CurrentRecoilModifier )
{
if( CurrentFireMode == ALTFIRE_FIREMODE )
{
CurrentRecoilModifier *= AltFireRecoilScale;
}
super.ModifyRecoil( CurrentRecoilModifier );
}
simulated function bool ShouldAutoReload(byte FireModeNum)
{
if (FireModeNum == ALTFIRE_FIREMODE)
return false;
return super.ShouldAutoReload(FireModeNum);
}
defaultproperties
{
SeedFullRechargeSeconds=14 //10
// Inventory / Grouping
InventorySize=7
GroupPriority=100
WeaponSelectTexture=Texture2D'wep_ui_parasiteimplanter_tex.UI_WeaponSelect_ParasiteImplanter'
AssociatedPerkClasses(0)=class'KFPerk_FieldMedic'
AssociatedPerkClasses(1)=class'KFPerk_SharpShooter'
// FOV
MeshFOV=70 //65
MeshIronSightFOV=27 //25 //45
PlayerIronSightFOV=70 //65
// Depth of field
DOF_BlendInSpeed=3.0
DOF_FG_FocalRadius=0 //50
DOF_FG_MaxNearBlurSize=3.5
// Content
PackageKey="ParasiteImplanter"
FirstPersonMeshName="WEP_1P_ParasiteImplanter_MESH.Wep_1stP_ParasiteImplanter_Rig"
FirstPersonAnimSetNames(0)="WEP_1P_ParasiteImplanter_ANIM.Wep_1stP_ParasiteImplanter_Anim"
PickupMeshName="WEP_3P_ParasiteImplanter_MESH.Wep_3rdP_ParasiteImplanter_Pickup"
AttachmentArchetypeName="WEP_ParasiteImplanter_ARCH.Wep_ParasiteImplanter_3P"
MuzzleFlashTemplateName="WEP_ParasiteImplanter_ARCH.Wep_ParasiteImplanter_MuzzleFlash"
// Ammo
MagazineCapacity[0]=6
SpareAmmoCapacity[0]=78
InitialSpareMags[0]=3
bCanBeReloaded=true
bReloadFromMagazine=true
MagazineCapacity[1]=100
SeedAmmo=100
bCanRefillSecondaryAmmo=false
// Zooming/Position
PlayerViewOffset=(X=3.0,Y=8,Z=-1.8)
//IronSightPosition=(X=0,Y=-0.07,Z=1.03)
IronSightPosition=(X=0,Y=-0.115,Z=1.0425)
// AI warning system
bWarnAIWhenAiming=true
AimWarningDelay=(X=0.4f, Y=0.8f)
AimWarningCooldown=0.0f
// Recoil
maxRecoilPitch=575 //700
minRecoilPitch=425 //600
maxRecoilYaw=135
minRecoilYaw=-135
RecoilRate=0.08
RecoilMaxYawLimit=500
RecoilMinYawLimit=65035
RecoilMaxPitchLimit=1250
RecoilMinPitchLimit=64785
RecoilISMaxYawLimit=50
RecoilISMinYawLimit=65485
RecoilISMaxPitchLimit=500
RecoilISMinPitchLimit=65485
RecoilViewRotationScale=0.6
IronSightMeshFOVCompensationScale=1.5
AltFireRecoilScale=0.2f
// Scope Render
// 2D scene capture
Begin Object Name=SceneCapture2DComponent0
//TextureTarget=TextureRenderTarget2D'Wep_Mat_Lib.WEP_ScopeLense_Target'
FieldOfView=12.5 //23.0 // "1.5X" = 35.0(our real world FOV determinant)/1.5
End Object
ScopedSensitivityMod=8.0 //16.0
ScopeLenseMICTemplate=MaterialInstanceConstant'WEP_1P_ParasiteImplanter_MAT.Wep_1stP_Parasite_Lens_MIC'
ScopeMICIndex = 2
// DEFAULT_FIREMODE
FireModeIconPaths(DEFAULT_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_BulletSingle'
FiringStatesArray(DEFAULT_FIREMODE)=WeaponSingleFiring
WeaponFireTypes(DEFAULT_FIREMODE)=EWFT_InstantHit
WeaponProjectiles(DEFAULT_FIREMODE)=class'KFProj_Bullet_ParasiteImplanter'
InstantHitDamage(DEFAULT_FIREMODE)=275 //250
InstantHitDamageTypes(DEFAULT_FIREMODE)=class'KFDT_Ballistic_ParasiteImplanter'
FireInterval(DEFAULT_FIREMODE)=+1.0 //60 RPM
Spread(DEFAULT_FIREMODE)=0.005
PenetrationPower(DEFAULT_FIREMODE)=3
FireOffset=(X=25,Y=3.0,Z=-2.5)
LastFireInterval=0.3
// ALT_FIREMODE
FiringStatesArray(ALTFIRE_FIREMODE)=WeaponSingleFiring
WeaponFireTypes(ALTFIRE_FIREMODE)=EWFT_Projectile
FireInterval(ALTFIRE_FIREMODE)=+0.5 //+1.0 //+0.175
InstantHitDamage(ALTFIRE_FIREMODE)=1.0
Spread(ALTFIRE_FIREMODE)=0.005
AmmoCost(ALTFIRE_FIREMODE)=50
WeaponProjectiles(ALTFIRE_FIREMODE)=class'KFProj_Bullet_ParasiteImplanterAlt'
InstantHitDamageTypes(ALTFIRE_FIREMODE)=class'KFDT_Ballistic_ParasiteImplanterAlt'
SecondaryAmmoTexture=Texture2D'ui_firemodes_tex.UI_FireModeSelect_Electricity'
// BASH_FIREMODE
InstantHitDamageTypes(BASH_FIREMODE)=class'KFDT_Bludgeon_ParasiteImplanter'
InstantHitDamage(BASH_FIREMODE)=26
// Custom animations
FireSightedAnims=(Shoot_Iron)
BonesToLockOnEmpty=(RW_Hammer)
bHasFireLastAnims=true
// Fire Effects
WeaponFireSnd(DEFAULT_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_ParasiteImplanter.Play_WEP_ParasiteImplanter_3P_Rifle', FirstPersonCue=AkEvent'WW_WEP_ParasiteImplanter.Play_WEP_ParasiteImplanter_1P_Rifle')
WeaponDryFireSnd(DEFAULT_FIREMODE)=AkEvent'WW_WEP_ParasiteImplanter.Play_WEP_ParasiteImplanter_Dry_Fire_Rifle'
WeaponFireSnd(ALTFIRE_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_ParasiteImplanter.Play_WEP_ParasiteImplanter_3P_Altfire', FirstPersonCue=AkEvent'WW_WEP_ParasiteImplanter.Play_WEP_ParasiteImplanter_1P_Altfire')
WeaponDryFireSnd(ALTFIRE_FIREMODE)=AkEvent'WW_WEP_ParasiteImplanter.Play_WEP_ParasiteImplanter_Dry_Fire_Altfire'
EjectedShellForegroundDuration=1.5f
// Attachments
bHasIronSights=true
bHasFlashlight=false
WeaponFireWaveForm=ForceFeedbackWaveform'FX_ForceFeedback_ARCH.Gunfire.Medium_Recoil'
WeaponUpgrades[1]=(Stats=((Stat=EWUS_Damage0, Scale=1.15f), (Stat=EWUS_Weight, Add=1)))
// From original KFWeap_RifleBase base class
AimCorrectionSize=40.f
NoAmmoMaterialColor=(R=0.0f,G=0.0f,B=0.0f)
AmmoReadyMaterialColor=(R=0.08f,G=1.0f,B=0.08f)
NumBloodMapMaterials=2
}