1
0
This commit is contained in:
2022-09-01 18:58:51 +03:00
parent 670ad3af13
commit 3e3e8af04f
119 changed files with 5648 additions and 371 deletions

View File

@ -0,0 +1,77 @@
//=============================================================================
// KFBarmwichBonfireVolume
//=============================================================================
// Barmwich volume used for bonfires. Triggers seasonal progression.
//=============================================================================
// Killing Floor 2
// Copyright (C) 2022 Tripwire Interactive LLC
//=============================================================================
class KFBarmwichBonfireVolume extends KFPhysicsDamageByPawnVolume
placeable;
/** Objective index for the event this is tied to */
var() int ObjectiveIndex;
/** Index of the event this is tied to */
var() int EventIndex;
var array<Actor> AffectedActors;
var transient bool bIsDataValid;
simulated event PostBeginPlay()
{
Super.PostBeginPlay();
bIsDataValid = IsObjectiveDataValid();
}
function CausePainTo(Actor Other)
{
Super.CausePainTo(Other);
if (bIsDataValid && KFPawn_Monster(Other) != none && KFPawn_Monster(Other).IsAliveAndWell())
{
if (AffectedActors.Find(Other) == INDEX_NONE)
{
AffectedActors.AddItem(Other);
NotifyProgression();
}
}
}
function NotifyProgression()
{
local KFPlayerController KFPC;
if (!bIsDataValid)
{
return;
}
foreach WorldInfo.AllControllers(class'KFPlayerController', KFPC)
{
KFPC.ClientOnTryCompleteObjective(ObjectiveIndex, EventIndex);
}
}
function ClearAllActors()
{
AffectedActors.Remove(0, AffectedActors.Length);
}
function ClearActor(Actor Other)
{
AffectedActors.RemoveItem(Other);
}
simulated function bool IsObjectiveDataValid()
{
return ObjectiveIndex >= 0 && ObjectiveIndex < 5 && EventIndex > SEI_None && EventIndex < SEI_MAX;
}
DefaultProperties
{
bIsDataValid = false;
}

View File

@ -43,7 +43,7 @@ defaultproperties
//KDeathUpKick=120
//KDeathVel=10
StumblePower=12
StumblePower=48 //12
GunHitPower=12
OverrideImpactEffect=ParticleSystem'WEP_HRG_BlastBrawlers_EMIT.FX_BlastBrawlers_Impact'

View File

@ -0,0 +1,87 @@
//=============================================================================
// KFDT_Ballistic_G36C
//=============================================================================
// Class Description
//=============================================================================
// Killing Floor 2
// Copyright (C) 2022 Tripwire Interactive LLC
//
//=============================================================================
class KFDT_Ballistic_G36C extends KFDT_Ballistic_AssaultRifle
abstract
hidedropdown;
/** G36C has still to play a metal effect if impacting metal. (and we demoted to impact on Flesh) */
var ParticleSystem MetalImpactEffect;
var AkEvent MetalImpactSound;
static function PlayImpactHitEffects( KFPawn P, vector HitLocation, vector HitDirection, byte HitZoneIndex, optional Pawn HitInstigator )
{
local KFSkinTypeEffects SkinType, OriginalSkinType, FleshSkinType;
local int i;
if ( P.CharacterArch != None && default.EffectGroup < FXG_Max )
{
// Search if affected target has Flesh skin type
for (i = 0; i < P.CharacterArch.ImpactSkins.Length ; ++i)
{
if (P.CharacterArch.ImpactSkins[i].Name == 'Flesh'
|| P.CharacterArch.ImpactSkins[i].Name == 'Tough_Flesh')
{
FleshSkinType = P.CharacterArch.ImpactSkins[i];
break;
}
}
SkinType = P.GetHitZoneSkinTypeEffects( HitZoneIndex );
OriginalSkinType = SkinType;
// If we don't hit flesh or shield, try to demote to Flesh
if (SkinType != none && SkinType.Name != 'Flesh' && SkinType.Name != 'Tough_Flesh' && SkinType.Name != 'ShieldEffects')
{
// We default to none as we don't want bullet to ricochet if any
SkinType = none;
// Demote to flesh skin hit
if (FleshSkinType != none)
{
SkinType = FleshSkinType;
}
}
// If we hit metal we have to make sure we play it's Metal impact effect (this effect doesn't contain bullet ricochet) (don't play sound though!)
if (OriginalSkinType != none && (OriginalSkinType.Name == 'Metal' || OriginalSkinType.Name == 'Machine'))
{
OriginalSkinType.PlayImpactParticleEffect(P, HitLocation, HitDirection, HitZoneIndex, default.EffectGroup, default.MetalImpactEffect);
OriginalSkinType.PlayTakeHitSound(P, HitLocation, HitInstigator, default.EffectGroup, default.MetalImpactSound);
}
if (SkinType != none)
{
SkinType.PlayImpactParticleEffect(P, HitLocation, HitDirection, HitZoneIndex, default.EffectGroup);
SkinType.PlayTakeHitSound(P, HitLocation, HitInstigator, default.EffectGroup);
}
}
}
defaultproperties
{
KDamageImpulse=900
KDeathUpKick=-300
KDeathVel=100
DamageModifierAP=0.8f
ArmorDamageModifier=15.0f
StumblePower=15
GunHitPower=15
WeaponDef=class'KFWeapDef_G36C'
//Perk
ModifierPerkList(0)=class'KFPerk_Swat'
MetalImpactEffect=ParticleSystem'FX_Impacts_EMIT.FX_Wep_Impact_MetalArmor_E'
MetalImpactSound=AkEvent'WW_Skin_Impacts.Play_Slashing_Metal_3P'
}

View File

@ -0,0 +1,82 @@
//=============================================================================
// KFDT_Ballistic_HRG_Dragonbreath
//=============================================================================
// Killing Floor 2
// Copyright (C) 2022 Tripwire Interactive LLC
//=============================================================================
class KFDT_Ballistic_HRG_Dragonbreath extends KFDT_Ballistic_Shotgun
abstract
hidedropdown;
// Damage type to use for the burning damage over time
var class<KFDamageType> BurnDamageType;
/** 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':
case 'chest':
case 'heart':
return true;
}
return false;
}
/** Play damage type specific impact effects when taking damage */
static function PlayImpactHitEffects( KFPawn P, vector HitLocation, vector HitDirection, byte HitZoneIndex, optional Pawn HitInstigator )
{
// Play burn effect when dead
if( P.bPlayedDeath && P.WorldInfo.TimeSeconds > P.TimeOfDeath )
{
default.BurnDamageType.static.PlayImpactHitEffects(P, HitLocation, HitDirection, HitZoneIndex, HitInstigator);
return;
}
super.PlayImpactHitEffects(P, HitLocation, HitDirection, HitZoneIndex, HitInstigator);
}
/** 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 )
{
// Overriden to specific a different damage type to do the burn damage over
// time. We do this so we don't get shotgun pellet impact sounds/fx during
// the DOT burning.
if ( default.BurnDamageType.default.DoT_Type != DOT_None )
{
Victim.ApplyDamageOverTime(DamageTaken, InstigatedBy, default.BurnDamageType);
}
}
defaultproperties
{
GoreDamageGroup=DGT_Shotgun
BloodSpread=0.4
BloodScale=0.6
KDamageImpulse=3500
KDeathUpKick=800
KDeathVel=650
GibImpulseScale=1.0
BurnPower=40
StumblePower=40
GunHitPower=50
WeaponDef=class'KFWeapDef_HRG_Dragonbreath'
BurnDamageType=class'KFDT_Fire_HRG_DragonsBreathDoT'
EffectGroup=FXG_IncendiaryRound
ModifierPerkList(0)=class'KFPerk_Firebug'
}

View File

@ -0,0 +1,18 @@
//=============================================================================
// KFDT_Ballistic_HRG_Locust
//=============================================================================
// HRG Locust bullet impact
//=============================================================================
// Killing Floor 2
// Copyright (C) 2022 Tripwire Interactive LLC
//=============================================================================
class KFDT_Ballistic_HRG_Locust extends KFDamageType
abstract
hidedropdown;
defaultproperties
{
ModifierPerkList(0)=class'KFPerk_Survivalist'
WeaponDef=class'KFWeapDef_HRG_Locust'
}

View File

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

View File

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

View File

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

View File

@ -0,0 +1,40 @@
//=============================================================================
// KFDT_Explosive_HRG_Locust
//=============================================================================
// Explosive damage type for the HRG Locust
//=============================================================================
// Killing Floor 2
// Copyright (C) 2022 Tripwire Interactive LLC
//=============================================================================
class KFDT_Explosive_HRG_Locust extends KFDT_Explosive
abstract
hidedropdown;
// Damage type to use for the damage over time effect
var class<KFDamageType> DoTDamageType;
/** 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)
{
if (Victim.Controller == InstigatedBy)
{
return;
}
if (default.DoTDamageType.default.DoT_Type != DOT_None)
{
Victim.ApplyDamageOverTime(class'KFDT_Toxic_HRG_Locust'.default.SpreadOnTouchDamage, InstigatedBy, default.DoTDamageType);
}
}
defaultproperties
{
//Perk
ModifierPerkList(0)=class'KFPerk_Survivalist'
WeaponDef=class'KFWeapDef_HRG_Locust'
DoTDamageType=class'KFDT_Toxic_HRG_Locust'
bCausesFracture=false
bCanPlayDeadHitEffects=false
}

View File

@ -0,0 +1,39 @@
//=============================================================================
// KFDT_Fire_Ground_HRG_DragonBreath
//=============================================================================
// Damage caused by burning from being hit by a HRG dragon breath ground fire
//=============================================================================
// Killing Floor 2
// Copyright (C) 2022 Tripwire Interactive LLC
//=============================================================================
class KFDT_Fire_Ground_HRG_DragonBreath extends KFDT_Fire_Ground
abstract;
static function int GetKillerDialogID()
{
return 86;//KILL_Fire
}
static function int GetDamagerDialogID()
{
return 102;//DAMZ_Fire
}
static function int GetDamageeDialogID()
{
return 116;//DAMP_Fire
}
defaultproperties
{
WeaponDef=class'KFWeapDef_HRG_Dragonbreath'
DoT_Type=DOT_Fire
DoT_Duration=2.7
DoT_Interval=0.5
DoT_DamageScale=0.7
BurnPower=10
}

View File

@ -0,0 +1,41 @@
//=============================================================================
// KFDT_Fire_HRG_DragonsBreathDoT
//=============================================================================
// Damage caused by burning from being hit by an HRG dragon's breath round
//=============================================================================
// Killing Floor 2
// Copyright (C) 2022 Tripwire Interactive LLC
//
//=============================================================================
class KFDT_Fire_HRG_DragonsBreathDoT extends KFDT_Fire
abstract
hidedropdown;
static function int GetKillerDialogID()
{
return 86;//KILL_Fire
}
static function int GetDamagerDialogID()
{
return 102;//DAMZ_Fire
}
static function int GetDamageeDialogID()
{
return 116;//DAMP_Fire
}
defaultproperties
{
WeaponDef=class'KFWeapDef_HRG_Dragonbreath'
DoT_Type=DOT_Fire
DoT_Duration=2.7 //5.0 //1.0
DoT_Interval=0.5
DoT_DamageScale=0.7 //1.0
BurnPower=10 //1.0 //18.5
}

View File

@ -0,0 +1,23 @@
//=============================================================================
// KFDT_Piercing_ScytheStab
//=============================================================================
// Killing Floor 2
// Copyright (C) 2022 Tripwire Interactive LLC
//=============================================================================
class KFDT_Piercing_ScytheStab extends KFDT_Piercing
abstract
hidedropdown;
defaultproperties
{
KDamageImpulse=200
KDeathUpKick=250
StumblePower=50
MeleeHitPower=100
WeaponDef=class'KFWeapDef_Scythe'
ModifierPerkList(0)=class'KFPerk_Berserker'
}

View File

@ -0,0 +1,140 @@
//=============================================================================
// KFDT_Slashing_ScytheLong
//=============================================================================
// Killing Floor 2
// Copyright (C) 2022 Tripwire Interactive LLC
//=============================================================================
class KFDT_Slashing_ScytheLong 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
{
KDamageImpulse=10000 //1500
KDeathUpKick=2000 //200
KDeathVel=3750 //375
KnockdownPower=0
StunPower=0
StumblePower=100
MeleeHitPower=100
WeaponDef=class'KFWeapDef_Scythe'
ModifierPerkList(0)=class'KFPerk_Berserker'
}

View File

@ -0,0 +1,38 @@
//=============================================================================
// KFDT_Slashing_ScytheLongAlt
//=============================================================================
// Killing Floor 2
// Copyright (C) 2022 Tripwire Interactive LLC
//=============================================================================
class KFDT_Slashing_ScytheLongAlt extends KFDT_Slashing_ZweihanderHeavy
abstract
hidedropdown;
defaultproperties
{
KDamageImpulse=3600 //1600
KDeathUpKick=400 //200
KDeathVel=750 //500
KnockdownPower=50
StunPower=0
StumblePower=200
MeleeHitPower=100
// Obliteration
GoreDamageGroup = DGT_Explosive
RadialDamageImpulse = 8000.f // This controls how much impulse is applied to gibs when exploding
bUseHitLocationForGibImpulses = true // This will make the impulse origin where the victim was hit for directional gibs
bPointImpulseTowardsOrigin = true // This creates an impulse direction aligned along hitlocation and pawn location -- this will push all gibs in the same direction
ImpulseOriginScale = 100.f // Higher means more directional gibbing, lower means more outward (and upward) gibbing
ImpulseOriginLift = 150.f
MaxObliterationGibs = 12 // Maximum number of gibs that can be spawned by obliteration, 0=MAX
bCanGib = true
bCanObliterate = true
ObliterationHealthThreshold = 0
ObliterationDamageThreshold = 100
WeaponDef=class'KFWeapDef_Scythe'
ModifierPerkList(0)=class'KFPerk_Berserker'
}

View File

@ -0,0 +1,140 @@
//=============================================================================
// KFDT_Slashing_ScytheShort
//=============================================================================
// Killing Floor 2
// Copyright (C) 2022 Tripwire Interactive LLC
//=============================================================================
class KFDT_Slashing_ScytheShort 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
{
KDamageImpulse=10000 //1500
KDeathUpKick=2000 //200
KDeathVel=3750 //375
KnockdownPower=0
StunPower=0
StumblePower=50
MeleeHitPower=100
WeaponDef=class'KFWeapDef_Scythe'
ModifierPerkList(0)=class'KFPerk_Berserker'
}

View File

@ -0,0 +1,38 @@
//=============================================================================
// KFDT_Slashing_ScytheShortAlt
//=============================================================================
// Killing Floor 2
// Copyright (C) 2022 Tripwire Interactive LLC
//=============================================================================
class KFDT_Slashing_ScytheShortAlt extends KFDT_Slashing_ZweihanderHeavy
abstract
hidedropdown;
defaultproperties
{
KDamageImpulse=3600 //1600
KDeathUpKick=400 //200
KDeathVel=750 //500
KnockdownPower=0
StunPower=0
StumblePower=150
MeleeHitPower=100
// Obliteration
GoreDamageGroup = DGT_Explosive
RadialDamageImpulse = 8000.f // This controls how much impulse is applied to gibs when exploding
bUseHitLocationForGibImpulses = true // This will make the impulse origin where the victim was hit for directional gibs
bPointImpulseTowardsOrigin = true // This creates an impulse direction aligned along hitlocation and pawn location -- this will push all gibs in the same direction
ImpulseOriginScale = 100.f // Higher means more directional gibbing, lower means more outward (and upward) gibbing
ImpulseOriginLift = 150.f
MaxObliterationGibs = 12 // Maximum number of gibs that can be spawned by obliteration, 0=MAX
bCanGib = true
bCanObliterate = true
ObliterationHealthThreshold = 0
ObliterationDamageThreshold = 100
WeaponDef=class'KFWeapDef_Scythe'
ModifierPerkList(0)=class'KFPerk_Berserker'
}

View File

@ -0,0 +1,33 @@
//=============================================================================
// KFExplosion_HRG_Dragonbreath_GroundFire
//=============================================================================
// Explosion actor class for ground fire
//=============================================================================
// Killing Floor 2
// Copyright (C) 2022 Tripwire Interactive LLC
//=============================================================================
class KFExplosion_HRG_Dragonbreath_GroundFire extends KFExplosionActorLingering;
simulated function SpawnExplosionParticleSystem(ParticleSystem Template)
{
// If the template is none, grab the default
if( !ExplosionTemplate.bAllowPerMaterialFX && Template == none )
{
Template = KFGameExplosion(ExplosionTemplate).ExplosionEffects.DefaultImpactEffect.ParticleTemplate;
}
// Use custom pool
WorldInfo.GroundFireEmitterPool.SpawnEmitter(Template, Location, rotator(ExplosionTemplate.HitNormal), None);
}
DefaultProperties
{
//Interval=0.25f INTERVAL IS OVERRIDDEN BY ITS PROJECTILE
MaxTime=2.0
ExplosionLightPriority=LPP_Low
LoopStartEvent=AkEvent'ww_wep_hrg_megadragonbreath.Play_WEP_HRG_MegaDragonbreath_Flame_LP'
LoopStopEvent=AkEvent'ww_wep_hrg_megadragonbreath.Stop_WEP_HRG_MegaDragonbreath_End_Flame_LP'
}

View File

@ -0,0 +1,43 @@
//=============================================================================
// KFExplosion_HRG_Locust
//=============================================================================
// Explosion actor class for HRG Locust
//=============================================================================
// Killing Floor 2
// Copyright (C) 2022 Tripwire Interactive LLC
//=============================================================================
class KFExplosion_HRG_Locust extends KFExplosionActorLingering;
var private bool bFirstExplosion;
protected simulated function bool DoExplosionDamage(bool bCauseDamage, bool bCauseEffects)
{
local bool bReturnValue;
// Only does explosion damage one time
if (bCauseDamage && bFirstExplosion == false)
{
bCauseDamage = false;
}
bReturnValue = super.DoExplosionDamage(bCauseDamage, bCauseEffects);
bFirstExplosion = false;
return bReturnValue;
}
DefaultProperties
{
Interval=0.5f
MaxTime=3.0
bOnlyDamagePawns=true
bDoFullDamage=false
bFirstExplosion=true
LoopStartEvent=AkEvent'WW_WEP_HRG_Locust.Play_WEP_HRG_Locust_Insects'
LoopStopEvent=AkEvent'WW_WEP_HRG_Locust.Stop_WEP_HRG_Locust_Insect'
}

View File

@ -87,6 +87,7 @@ protected simulated function AffectsPawn(Pawn Victim, float DamageScale)
if( HumanVictim != none && HumanVictim.GetExposureTo(Location) > 0 )
{
OwnerProjectile = KFProj_MedicGrenade(Owner);
if( OwnerProjectile != none )
{
bCanRepairArmor = OwnerProjectile.HealedPawns.Find( HumanVictim ) == INDEX_NONE;

View File

@ -180,7 +180,7 @@ protected simulated function bool DoExplosionDamage(bool bCauseDamage, bool bCau
if( bOnlyDamagePawns )
{
return ExplodePawns();
return ExplodePawns(bCauseDamage);
}
return super(KFExplosionActor).DoExplosionDamage(bCauseDamage, bCauseEffects);

View File

@ -62,7 +62,7 @@ function UpdateHealer(Optional bool bForce)
}
function ShowActiveIndicators( array<string> IconPathStrings )
function ShowActiveIndicators( array<ActiveSkill> ActiveSkills )
{
}

View File

@ -48,6 +48,8 @@ var protected transient bool bWaveStarted;
// When this is true next wave will be last
var protected bool bGunGamePlayerOnLastGun;
var transient array<KFBarmwichBonfireVolume> BonfireVolumes;
/** Whether this game mode should play music from the get-go (lobby) */
static function bool ShouldPlayMusicAtStart()
{
@ -75,6 +77,8 @@ event PostBeginPlay()
TimeBetweenWaves = GetTraderTime();
bGunGamePlayerOnLastGun = false;
UpdateBonfires();
}
/** Set up the spawning */
@ -1144,6 +1148,8 @@ function WaveEnded(EWaveEndCondition WinCondition)
return;
}
ClearAllActorsFromBonfire();
if (WorldInfo.NetMode == NM_DedicatedServer)
{
scripttrace();
@ -1202,28 +1208,9 @@ function WaveEnded(EWaveEndCondition WinCondition)
}
}
if (OutbreakEvent != none && OutbreakEvent.ActiveEvent.bGunGameMode)
if (OutbreakEvent != none)
{
MyKFGRI.GunGameWavesCurrent += 1;
// If we unlocked last weapon we only finish if we completed the boss wave
// If we didn't unlock to last weapon and we just finished last wave (before BOSS), repeat
if (bGunGamePlayerOnLastGun)
{
MyKFGRI.bWaveGunGameIsFinal = true;
if (WaveNum < WaveMax)
{
WaveNum = WaveMax - 1;
}
}
else if (WaveNum >= WaveMax - 1)
{
// Repeat wave before BOSS till forever
WaveNum = WaveMax - 2;
}
MyKFGRI.bNetDirty = true;
OnOutbreakWaveWon();
}
if (WaveNum < WaveMax)
@ -1873,6 +1860,38 @@ function DebugKillZeds()
}
}
function OnOutbreakWaveWon() {}
function UpdateBonfires()
{
local KFBarmwichBonfireVolume BonfireVolume;
foreach AllActors(class'KFBarmwichBonfireVolume', BonfireVolume)
{
BonfireVolumes.AddItem(BonfireVolume);
}
}
function ClearAllActorsFromBonfire()
{
local KFBarmwichBonfireVolume BonfireVolume;
foreach BonfireVolumes(BonfireVolume)
{
BonfireVolume.ClearAllActors();
}
}
function ClearActorFromBonfire(Actor Other)
{
local KFBarmwichBonfireVolume BonfireVolume;
foreach BonfireVolumes(BonfireVolume)
{
BonfireVolume.ClearActor(Other);
}
}
DefaultProperties
{
TimeBetweenWaves=60 //This is going to be a difficulty setting later

View File

@ -607,7 +607,7 @@ function EndOfMatch(bool bVictory)
KFPC.CompletedWeeklySurvival();
}
}
super.EndOfMatch(bVictory);
}
@ -988,7 +988,7 @@ function LoadGunGameWeapons(Controller NewPlayer)
Weapon = KFWeapon(Inv);
if (Weapon != none)
{
Weapon.GunGameRemove();
Weapon.RemoveGun();
}
}
}
@ -1108,37 +1108,43 @@ function ResetGunGame(KFPlayerController_WeeklySurvival KFPC_WS)
function NotifyKilled(Controller Killer, Controller Killed, Pawn KilledPawn, class<DamageType> damageType )
{
local KFPawn_Monster KFPM;
local KFPlayerController_WeeklySurvival KFPC_WS;
local KFPlayerController_WeeklySurvival KFPC_WS_Killer, KFPC_WS_Killed;
super.NotifyKilled(Killer, Killed, KilledPawn, damageType);
if (!OutbreakEvent.ActiveEvent.bGunGameMode)
{
return;
}
// If pawn is monster increase gun game score for that monster
KFPM = KFPawn_Monster(KilledPawn);
KFPC_WS = KFPlayerController_WeeklySurvival(Killer);
KFPM = KFPawn_Monster(KilledPawn);
KFPC_WS_Killer = KFPlayerController_WeeklySurvival(Killer);
KFPC_WS_Killed = KFPlayerController_WeeklySurvival(Killed);
if (KFPM != none && KFPC_WS != none)
{
if (KFPC_WS.Pawn.Health > 0)
if (OutbreakEvent.ActiveEvent.bGunGameMode)
{
// If pawn is monster increase gun game score for that monster
if (KFPM != none && KFPC_WS_Killer != none)
{
KFPC_WS.GunGameData.Score += KFPM.GunGameKilledScore;
UpdateGunGameLevel(KFPC_WS);
if (KFPC_WS_Killer.Pawn.Health > 0)
{
KFPC_WS_Killer.GunGameData.Score += KFPM.GunGameKilledScore;
UpdateGunGameLevel(KFPC_WS_Killer);
}
}
else
{
// If pawn is human reset game score (we can just check Killed exists as Controller
if (KFPC_WS_Killed != none)
{
ResetGunGame(KFPC_WS_Killed);
}
}
}
else
if (OutbreakEvent.ActiveEvent.bVIPGameMode)
{
// If pawn is human reset game score (we can just check Killed exists as Controller)
KFPC_WS = KFPlayerController_WeeklySurvival(Killed);
if (KFPC_WS != none)
if (KFPC_WS_Killed != none && KFPC_WS_Killed.VIPGameData.isVIP)
{
ResetGunGame(KFPC_WS);
// UnregisterPlayer is done on the same frame but this function comes first..
// we queue a petition to end the game if no vip is found
SetTimer(1.5f, false, 'OnVIPDiesEndMatch');
}
}
}
@ -1240,7 +1246,7 @@ function UpdateGunGameLevel(KFPlayerController_WeeklySurvival KFPC_WS)
{
// To prevent audio/vfx lock, while firing when removing the equipped weapon we do a proper gun remove
// This new function manages it's state internally
CurrentWeapon.GunGameRemove();
CurrentWeapon.RemoveGun();
}
if (class'KFPerk_SWAT'.static.Is9mm(CurrentWeapon))
@ -1278,6 +1284,222 @@ function UpdateGunGameLevel(KFPlayerController_WeeklySurvival KFPC_WS)
}
}
///////////////////////////////////////////////////////////////////////////////////
function UnregisterPlayer(PlayerController PC)
{
local KFPlayerController_WeeklySurvival KFPC_WS;
super.UnregisterPlayer(PC);
KFPC_WS = KFPlayerController_WeeklySurvival(PC);
if (OutbreakEvent.ActiveEvent.bVIPGameMode)
{
if (KFPC_WS != none && KFPC_WS.VIPGameData.IsVIP)
{
ChooseVIP(false, KFPC_WS);
}
}
}
function WaveStarted()
{
Super.WaveStarted();
if (OutbreakEvent.ActiveEvent.bVIPGameMode)
{
if (WaveNum <= 1)
{
ChooseVIP(true);
}
}
}
function OnVIPDiesEndMatch()
{
local KFPlayerController KFPC;
foreach WorldInfo.AllControllers(class'KFPlayerController', KFPC)
{
KFPC.SetCameraMode('ThirdPerson');
}
WaveEnded(WEC_TeamWipedOut);
}
function ChooseVIP_SetupVIP()
{
local KFPlayerController_WeeklySurvival KFPC_WS, NewVIP;
local KFGameReplicationInfo KFGRI;
NewVIP = none;
KFGRI = KFGameReplicationInfo(WorldInfo.GRI);
foreach WorldInfo.AllControllers(class'KFPlayerController_WeeklySurvival', KFPC_WS)
{
if (KFPC_WS != none)
{
if (KFPC_WS.VIPGameData.IsVIP)
{
NewVIP = KFPC_WS;
break;
}
}
}
if (NewVIP != none)
{
//`Log("Setup new VIP: " $NewVIP);
if (NewVIP.Pawn != none)
{
//`Log("Finished setup new VIP: " $NewVIP);
NewVIP.GetPerk().PerkSetOwnerHealthAndArmor(false);
if (NewVIP.VIPGameData.PendingHealthReset)
{
NewVIP.VIPGameData.PendingHealthReset = false;
// Change current health directly, Pawn.HealDamage does a lot of other stuff that can block the healing
NewVIP.Pawn.Health = NewVIP.Pawn.HealthMax;
}
// Replicate new data to clients
KFGRI.UpdateVIPPlayer(KFPlayerReplicationInfo(NewVIP.PlayerReplicationInfo));
KFGRI.UpdateVIPMaxHealth(NewVIP.Pawn.HealthMax);
KFGRI.UpdateVIPCurrentHealth(NewVIP.Pawn.Health);
NewVIP.PlayVIPGameChosenSound(3.5f);
ClearTimer('ChooseVIP_SetupVIP');
}
}
}
function ChooseVIP(bool ForceAddHealth, optional KFPlayerController_WeeklySurvival PlayerJustLeft = none)
{
local int RandomNumber;
local KFPlayerController_WeeklySurvival KFPC_WS, CurrentVIP, NewVIP;
local array<KFPlayerController_WeeklySurvival> PotentialVIP;
local KFGameReplicationInfo KFGRI;
//`Log("ChooseVIP!!!!!");
ClearTimer('ChooseVIP_SetupVIP');
KFGRI = KFGameReplicationInfo(WorldInfo.GRI);
foreach WorldInfo.AllControllers(class'KFPlayerController_WeeklySurvival', KFPC_WS)
{
if (KFPC_WS != none)
{
if (KFPC_WS.VIPGameData.IsVIP == false && KFPC_WS.VIPGameData.WasVIP == false)
{
PotentialVIP.AddItem(KFPC_WS);
}
if (KFPC_WS.VIPGameData.IsVIP)
{
CurrentVIP = KFPC_WS;
}
}
}
if (CurrentVIP != none)
{
//`Log("Remove old VIP: " $CurrentVIP);
CurrentVIP.VIPGameData.IsVIP = false;
CurrentVIP.GetPerk().PerkSetOwnerHealthAndArmor(false);
}
// If there's no potential VIP we restart
if (PotentialVIP.Length == 0)
{
foreach WorldInfo.AllControllers(class'KFPlayerController_WeeklySurvival', KFPC_WS)
{
if (KFPC_WS != none)
{
KFPC_WS.VIPGameData.WasVIP = false;
if (PlayerJustLeft == none
|| PlayerJustLeft != KFPC_WS)
{
PotentialVIP.AddItem(KFPC_WS);
}
}
}
}
if (PotentialVIP.Length > 0)
{
RandomNumber = Rand(PotentialVIP.Length);
NewVIP = PotentialVIP[RandomNumber];
NewVIP.VIPGameData.IsVIP = true;
NewVIP.VIPGameData.WasVIP = true;
}
if (NewVIP != none)
{
if (ForceAddHealth || (KFGRI != none && KFGRI.bWaveIsActive == false))
{
NewVIP.VIPGameData.PendingHealthReset = true;
}
// If there's no Pawn we have to wait on a Timer function
if (NewVIP.Pawn != none)
{
ChooseVIP_SetupVIP();
}
else
{
SetTimer(0.25f, true, 'ChooseVIP_SetupVIP');
}
ClearTimer('OnVIPDiesEndMatch');
}
}
function OnOutbreakWaveWon()
{
Super.OnOutbreakWaveWon();
// GunGame Mode
if (OutbreakEvent.ActiveEvent.bGunGameMode)
{
MyKFGRI.GunGameWavesCurrent += 1;
// If we unlocked last weapon we only finish if we completed the boss wave
// If we didn't unlock to last weapon and we just finished last wave (before BOSS), repeat
if (bGunGamePlayerOnLastGun)
{
MyKFGRI.bWaveGunGameIsFinal = true;
if (WaveNum < WaveMax)
{
WaveNum = WaveMax - 1;
}
}
else if (WaveNum >= WaveMax - 1)
{
// Repeat wave before BOSS till forever
WaveNum = WaveMax - 2;
}
MyKFGRI.bNetDirty = true;
}
// VIP Mode
if (OutbreakEvent.ActiveEvent.bVIPGameMode)
{
ChooseVIP(true);
}
}
defaultproperties
{
//Overrides

View File

@ -198,19 +198,32 @@ simulated function bool CanActivateObjectiveByWeekly()
{
if (Role == Role_Authority)
{
if (KFGameInfo(WorldInfo.Game).OutbreakEvent != none
&& KFGameInfo(WorldInfo.Game).OutbreakEvent.ActiveEvent.bGunGameMode)
if (KFGameInfo(WorldInfo.Game).OutbreakEvent != none)
{
return false;
if (KFGameInfo(WorldInfo.Game).OutbreakEvent.ActiveEvent.bGunGameMode)
{
return false;
}
if (KFGameInfo(WorldInfo.Game).OutbreakEvent.ActiveEvent.bVIPGameMode)
{
return false;
}
}
}
else
{
if (KFGameReplicationInfo(WorldInfo.GRI) != none
&& KFGameReplicationInfo(WorldInfo.GRI).bIsWeeklyMode
&& KFGameReplicationInfo(WorldInfo.GRI).CurrentWeeklyIndex == 16)
if (KFGameReplicationInfo(WorldInfo.GRI) != none && KFGameReplicationInfo(WorldInfo.GRI).bIsWeeklyMode)
{
return false;
if (KFGameReplicationInfo(WorldInfo.GRI).CurrentWeeklyIndex == 16)
{
return false;
}
if (KFGameReplicationInfo(WorldInfo.GRI).CurrentWeeklyIndex == 17)
{
return false;
}
}
}

View File

@ -920,7 +920,6 @@ defaultproperties
bSpawnWeaponListAffectsSecondaryWeapons=true,
OverrideItemPickupModifier= 0.5f, //1.0f, //2.0f, // 0.f,
OverrideAmmoPickupModifier= 1.0f, //2.0f, //3.0f, // 0.01f,
bOnlyArmorItemPickup=true,
TraderTimeModifier=1.0f, // 0.1f,
TimeBetweenWaves=30.f,
bDisableAddDosh=true,
@ -1190,6 +1189,37 @@ defaultproperties
)}
// VIP
SetEvents[17]={(
EventDifficulty=2,
GameLength=GL_Normal,
bVIPGameMode=true,
VIPTargetting=(class'KFGameContent.KFPawn_ZedScrake'
, class'KFGameContent.KFPawn_ZedFleshpound'
, class'KFGameContent.KFPawn_ZedFleshpoundMini'
, class'KFGameContent.KFPawn_ZedGorefast'
, class'KFGameContent.KFPawn_ZedGorefastDualBlade'
, class'KFGameContent.KFPawn_ZedClot_Cyst'
, class'KFGameContent.KFPawn_ZedClot_Slasher'
, class'KFGameContent.KFPawn_ZedClot_Alpha'
, class'KFGameContent.KFPawn_ZedClot_AlphaKing'
, class'KFGameContent.KFPawn_ZedBloat'
, class'KFGameContent.KFPawn_ZedHusk'
, class'KFGameContent.KFPawn_ZedSiren'
, class'KFGameContent.KFPawn_ZedCrawler'
, class'KFGameContent.KFPawn_ZedCrawlerKing'
, class'KFGameContent.KFPawn_ZedStalker'
, class'KFGameContent.KFPawn_ZedDAR_EMP'
, class'KFGameContent.KFPawn_ZedDAR_Laser'
, class'KFGameContent.KFPawn_ZedDAR_Rocket'
, class'KFGameContent.KFPawn_ZedMatriarch'
, class'KFGameContent.KFPawn_ZedPatriarch'
, class'KFGameContent.KFPawn_ZedBloatKing'
, class'KFGameContent.KFPawn_ZedBloatKingSubspawn'
, class'KFGameContent.KFPawn_ZedFleshpoundKing'
, class'KFGameContent.KFPawn_ZedHans'),
)}
//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

@ -440,7 +440,7 @@ function AdjustDamage(out int InDamage, out vector Momentum, Controller Instigat
}
}
function HandleAfflictionsOnHit(Controller DamageInstigator, vector HitDir, class<DamageType> DamageType, Actor DamageCauser)
function HandleAfflictionsOnHit(Controller DamageInstigator, vector HitDir, class<KFDamageType> DamageType, Actor DamageCauser)
{
if (ShieldHealthPctByte == 0)
{

View File

@ -39,6 +39,7 @@ state WaveState
local TraceHitInfo HitInfo;
local float Radius;
local float DamageHead;
local name HitBoneName;
if(bWaveActive)
{
@ -54,9 +55,17 @@ state WaveState
if(DamageHead > 0)
{
//`Log("Take: "$Victim);
//HitInfo.BoneName = 'head';
HitBoneName = Victim.HeadBoneName;
if(HitBoneName != `NAME_NONE)
{
HitInfo.BoneName = HitBoneName;
}
//`Log("HitInfo.BoneName: "$HitInfo.BoneName);
Victim.TakeDamage(DamageHead * UpgradeDamageMod, InstigatorController, Victim.Location, Normal(Victim.Location - Instigator.Location), MyDamageType, HitInfo, (Owner != None) ? Owner : self);
//Monster.PlayDismemberment(0, MyDamageType, WaveImpactMomentum);
if (Victim.Health <= 0)
{

View File

@ -0,0 +1,25 @@
//=============================================================================
// KFProj_HRG_DragonBreath_Splash
//=============================================================================
// Projectile class for hrg dragonbreath gun splash. Handles a few overrides.
//=============================================================================
// Killing Floor 2
// Copyright (C) 2022 Tripwire Interactive LLC
//=============================================================================
class KFProj_HRG_DragonBreath_Splash extends KFProj_FlareGunSplash;
defaultproperties
{
PostExplosionLifetime=2.5
ExplosionActorClass=class'KFExplosion_HRG_Dragonbreath_GroundFire'
Begin Object Name=ExploTemplate0
Damage=8
DamageRadius=150.0
MyDamageType=class'KFDT_Fire_Ground_HRG_DragonBreath'
ExplosionEffects=KFImpactEffectInfo'WEP_Flamethrower_ARCH.GroundFire_Impacts'
End Object
AssociatedPerkClass=none
}

View File

@ -0,0 +1,171 @@
//=============================================================================
// KFProj_HRG_Locust
//=============================================================================
// HRG Locust projectile
//=============================================================================
// Killing Floor 2
// Copyright (C) 2022 Tripwire Interactive LLC
//
//=============================================================================
class KFProj_HRG_Locust extends KFProj_BallisticExplosive
hidedropdown;
/** Our intended target actor */
var private KFPawn LockedTarget;
/** How much 'stickyness' when seeking toward our target. Determines how accurate rocket is */
var const float SeekStrength;
replication
{
if( bNetInitial )
LockedTarget;
}
function SetLockedTarget( KFPawn NewTarget )
{
LockedTarget = NewTarget;
}
simulated function bool AllowNuke()
{
return false;
}
simulated function bool AllowDemolitionistConcussive()
{
return false;
}
simulated function bool AllowDemolitionistExplosionChangeRadius()
{
return false;
}
simulated event Tick( float DeltaTime )
{
local vector TargetImpactPos, DirToTarget;
super.Tick( DeltaTime );
// Skip the first frame, then start seeking
if( !bHasExploded
&& LockedTarget != none
&& Physics == PHYS_Projectile
&& Velocity != vect(0,0,0)
&& LockedTarget.IsAliveAndWell()
&& `TimeSince(CreationTime) > 0.03f )
{
// Grab our desired relative impact location from the weapon class
TargetImpactPos = class'KFWeap_HRG_Locust'.static.GetLockedTargetLoc( LockedTarget );
// Seek towards target
Speed = VSize( Velocity );
DirToTarget = Normal( TargetImpactPos - Location );
Velocity = Normal( Velocity + (DirToTarget * (SeekStrength * DeltaTime)) ) * Speed;
// Aim rotation towards velocity every frame
SetRotation( rotator(Velocity) );
}
}
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 *= KFPawn(OwnerPawn).GetPerk().GetAoERadiusModifier();
}
}
}
}
defaultproperties
{
Physics=PHYS_Projectile
Speed=4000 //6000
MaxSpeed=4000 //6000
TossZ=0
GravityScale=1.0
MomentumTransfer=0.0f
Damage=10
DamageRadius=0
SeekStrength=928000.0f // 128000.0f
bWarnAIWhenFired=true
ProjFlightTemplate=ParticleSystem'WEP_HRG_Locust_EMIT.FX_HRG_Locust_Projectile'
ProjFlightTemplateZedTime=ParticleSystem'WEP_HRG_Locust_EMIT.FX_HRG_Locust_Projectile_ZED_TIME'
ProjDisintegrateTemplate=ParticleSystem'WEP_HRG_Locust_EMIT.FX_Flying_Bugs_dispersion'
AmbientSoundPlayEvent=AkEvent'WW_WEP_Seeker_6.Play_WEP_Seeker_6_Projectile'
AmbientSoundStopEvent=AkEvent'WW_WEP_Seeker_6.Stop_WEP_Seeker_6_Projectile'
ExplosionActorClass=class'KFExplosion_HRG_Locust'
AltExploEffects=KFImpactEffectInfo'WEP_HRG_Locust_ARCH.FX_HRG_Locust_Explosion_Concussive_force'
// Grenade explosion light
Begin Object Class=PointLightComponent Name=ExplosionPointLight
LightColor=(R=252,G=218,B=171,A=255)
Brightness=4.f
Radius=2000.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=80
DamageRadius=300
DamageFalloffExponent=0.5f
DamageDelay=0.f
//Impulse applied to Zeds
MomentumTransferScale=1
// Damage Effects
MyDamageType=class'KFDT_Explosive_HRG_Locust'
KnockDownStrength=0
FractureMeshRadius=0.0
FracturePartVel=0.0
ExplosionEffects=KFImpactEffectInfo'WEP_HRG_Locust_ARCH.FX_HRG_Locust_Explosion_Concussive_force'
ExplosionSound=AkEvent'WW_WEP_Seeker_6.Play_WEP_Seeker_6_Explosion'
// Dynamic Light
ExploLight=ExplosionPointLight
ExploLightStartFadeOutTime=0.0
ExploLightFadeOutTime=0.2
// Camera Shake
CamShake=CameraShake'FX_CameraShake_Arch.Misc_Explosions.Light_Explosion_Rumble'
CamShakeInnerRadius=0
CamShakeOuterRadius=500
CamShakeFalloff=3.f
bOrientCameraShakeTowardsEpicenter=true
bIgnoreInstigator=true
End Object
ExplosionTemplate=ExploTemplate0
bCanDisintegrate=false
}

View File

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

View File

@ -0,0 +1,85 @@
//=============================================================================
// KFProj_Pellet_HRG_Dragonbreath
//=============================================================================
//=============================================================================
// Killing Floor 2
// Copyright (C) 2022 Tripwire Interactive LLC
//=============================================================================
class KFProj_Pellet_HRG_Dragonbreath extends KFProj_Bullet_Pellet
hidedropdown;
/** Last hit normal from Touch() or HitWall() */
var vector LastHitNormal;
var float GroundFireChance;
simulated function ProcessTouch(Actor Other, Vector HitLocation, Vector HitNormal)
{
LastHitNormal = HitNormal;
Super.ProcessTouch(Other, HitLocation, HitNormal);
}
/**
* Explode this Projectile
*/
simulated function TriggerExplosion(Vector HitLocation, Vector HitNormal, Actor HitActor)
{
LastHitNormal = HitNormal;
Super.TriggerExplosion(HitLocation, HitNormal, HitActor);
}
simulated protected function StopSimulating()
{
local vector FlameSpawnVel;
if (Role == ROLE_Authority && Physics == PHYS_Falling && FRand() < GroundFireChance)
{
//SpawnGroundFire();
FlameSpawnVel = 0.25f * CalculateResidualFlameVelocity(LastHitNormal, Normal(Velocity), VSize(Velocity));
SpawnResidualFlame(class'KFProj_HRG_DragonBreath_Splash', Location + (LastHitNormal * 10.f), FlameSpawnVel);
}
super.StopSimulating();
}
defaultproperties
{
GroundFireChance=1.f
Physics=PHYS_Falling
MaxSpeed=7000.0
Speed=7000.0
TerminalVelocity=7000.0
bWarnAIWhenFired=true
DamageRadius=0
GravityScale=0.35
TossZ=0
Begin Object Class=PointLightComponent Name=PointLight0
LightColor=(R=252,G=218,B=171,A=255)
Brightness=0.5f
Radius=500.f
FalloffExponent=10.f
CastShadows=False
CastStaticShadows=FALSE
CastDynamicShadows=False
bCastPerObjectShadows=false
bEnabled=true
LightingChannels=(Indoor=TRUE,Outdoor=TRUE,bInitialized=TRUE)
End Object
ProjFlightLight=PointLight0
ImpactEffects=KFImpactEffectInfo'WEP_DragonsBreath_ARCH.DragonsBreath_bullet_impact'
ProjFlightTemplate=ParticleSystem'WEP_DragonsBreath_EMIT.Tracer.FX_DragonsBreath_Tracer'
ProjFlightTemplateZedTime=ParticleSystem'WEP_DragonsBreath_EMIT.Tracer.FX_DragonsBreath_Tracer_ZEDTime'
AmbientSoundPlayEvent=AkEvent'WW_WEP_SA_DragonsBreath.Play_SA_DragonsBreath_Projectile_Loop'
AmbientSoundStopEvent=AkEvent'WW_WEP_SA_DragonsBreath.Stop_SA_DragonsBreath_Projectile_Loop'
}

View File

@ -0,0 +1,128 @@
//=============================================================================
// KFSeasonalEventStats_Fall2022
//=============================================================================
// Tracks event-specific challenges/accomplishments for Fall 2022
//=============================================================================
// Killing Floor 2
// Copyright (C) 2021 Tripwire Interactive LLC
//=============================================================================
class KFSeasonalEventStats_Fall2022 extends KFSeasonalEventStats;
var transient private const int BossKillsRequired, ZedsInBonfiresRequired, 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 BarmwichTown
bObjectiveIsValidForMap[2] = 0; // Open the Weapon Room
bObjectiveIsValidForMap[3] = 0; // Make 50 Zeds to pass through the bonfires of Barmwitch Town
bObjectiveIsValidForMap[4] = 0; // Complete wave 15 on Endless Hard or higher difficulty on Barmwitch Town
if (CapsMapName == "KF-BARMWICHTOWN")
{
bObjectiveIsValidForMap[1] = 1;
bObjectiveIsValidForMap[2] = 1;
bObjectiveIsValidForMap[3] = 1;
bObjectiveIsValidForMap[4] = 1;
}
SetSeasonalEventStatsMax(BossKillsRequired, 0, 0, ZedsInBonfiresRequired, EndlessWaveRequired);
}
private event GrantEventItems()
{
if (Outer.IsEventObjectiveComplete(0) &&
Outer.IsEventObjectiveComplete(1) &&
Outer.IsEventObjectiveComplete(2) &&
Outer.IsEventObjectiveComplete(3) &&
Outer.IsEventObjectiveComplete(4))
{
GrantEventItem(9424);
}
}
// 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 WeaponRoomIdx, BonfireIdx;
WeaponRoomIdx = 2;
BonfireIdx = 3;
if(EventIndex == SEI_Fall)
{
if (ObjectiveIndex == WeaponRoomIdx)
{
if (bObjectiveIsValidForMap[ObjectiveIndex] != 0)
{
FinishedObjective(SEI_Fall, ObjectiveIndex);
}
}
else if (ObjectiveIndex == BonfireIdx)
{
if (bObjectiveIsValidForMap[ObjectiveIndex] != 0)
{
IncrementSeasonalEventStat(ObjectiveIndex, 1);
if (Outer.GetSeasonalEventStatValue(ObjectiveIndex) >= ZedsInBonfiresRequired)
{
FinishedObjective(SEI_Fall, ObjectiveIndex);
}
}
}
}
}
defaultproperties
{
BossKillsRequired=15
EndlessWaveRequired=15
ZedsInBonfiresRequired=50
}

View File

@ -0,0 +1,83 @@
//=============================================================================
// KFWeapAttach_HRG_Dragonbreath
//=============================================================================
//
//=============================================================================
// Killing Floor 2
// Copyright (C) 2022 Tripwire Interactive LLC
//=============================================================================
class KFWeapAttach_HRG_Dragonbreath extends KFWeaponAttachment;
`define HRGDRAGONBREATH_MIC_BARREL_INDEX 0
var transient float BarrelHeatPerProjectile;
var transient float MaxBarrelHeat;
var transient float BarrelCooldownRate;
var transient float CurrentBarrelHeat;
var transient float LastBarrelHeat;
var transient int NumPelletsDefault;
var transient int NumPelletsAlt;
simulated event PreBeginPlay()
{
Super.PreBeginPlay();
BarrelHeatPerProjectile = class'KFWeap_HRG_Dragonbreath'.default.BarrelHeatPerProjectile;
MaxBarrelHeat = class'KFWeap_HRG_Dragonbreath'.default.MaxBarrelHeat;
BarrelCooldownRate = class'KFWeap_HRG_Dragonbreath'.default.BarrelCooldownRate;
NumPelletsDefault = class'KFWeap_HRG_Dragonbreath'.default.NumPellets[0];
NumPelletsAlt = class'KFWeap_HRG_Dragonbreath'.default.NumPellets[1];
}
simulated event PostBeginPlay()
{
Super.PostBeginPlay();
// Force start with "Glow_Intensity" of 0.0f
LastBarrelHeat = MaxBarrelHeat;
ChangeBarrelMaterial();
}
simulated function ChangeBarrelMaterial()
{
if( CurrentBarrelHeat != LastBarrelHeat )
{
if ( WeaponMIC == None && WeapMesh != None )
{
WeaponMIC = WeapMesh.CreateAndSetMaterialInstanceConstant(`HRGDRAGONBREATH_MIC_BARREL_INDEX);
}
WeaponMIC.SetScalarParameterValue('Barrel_intensity', CurrentBarrelHeat);
}
}
simulated function Tick(float Delta)
{
Super.Tick(Delta);
CurrentBarrelHeat = fmax(CurrentBarrelHeat - BarrelCooldownRate * Delta, 0.0f);
ChangeBarrelMaterial();
}
/** Override to update emissive in weapon's barrel after firing */
simulated function PlayWeaponFireAnim()
{
local float BarrelHeatPerShot;
local KFPawn OwnerPawn;
Super.PlayWeaponFireAnim();
OwnerPawn = KFPawn(Owner);
BarrelHeatPerShot = BarrelHeatPerProjectile * (OwnerPawn.FiringMode == 0 ? NumPelletsDefault : NumPelletsAlt);
CurrentBarrelHeat = fmin(CurrentBarrelHeat + BarrelHeatPerShot, MaxBarrelHeat);
}
defaultproperties
{
CurrentBarrelHeat=0.0f
LastBarrelHeat=0.0f
NumPelletsDefault=0
NumPelletsAlt=0
}

View File

@ -0,0 +1,144 @@
//=============================================================================
// KFWeapAttach_Scythe
//=============================================================================
//
//=============================================================================
// Killing Floor 2
// Copyright (C) 2022 Tripwire Interactive LLC
//=============================================================================
class KFWeapAttach_Scythe extends KFWeaponAttachment;
var const float UnfoldBlendingDuration;
var const float UnfoldedAnimRateModifier;
const FoldAnim = 'Clean_NoBlood';
var AnimTree CustomAnimTree;
var AnimNodeBlendPerBone FoldBlendNode;
var transient bool bIsFolded;
event PreBeginPlay()
{
Super.PreBeginPlay();
// Override the animtree. Doing this here (before AttachTo) instead of in defaultprops
// avoids an undesired call to our owning Pawn's PostInitAnimTree
if ( CustomAnimTree != None )
{
WeapMesh.SetAnimTreeTemplate(CustomAnimTree);
WeapAnimNode = AnimNodeSequence(WeapMesh.FindAnimNode('WeaponSeq'));
FoldBlendNode = AnimNodeBlendPerBone(WeapMesh.FindAnimNode('FoldBlendNode'));
// The special event might have arrived before the attachment is created, but it's updated in the owner, so copy the state here...
if (KFPawn(Owner) != none && FoldBlendNode != none)
{
bIsFolded = KFPawn(Owner).WeaponSpecialAction == 0;
FoldBlendNode.SetBlendTarget(bIsFolded ? 1.0f : 0.0f, 0.f);
}
}
}
simulated function ChangeMode()
{
bIsFolded = !bIsFolded;
// FoldControl = SkelControlSingleBone( WeapMesh.FindSkelControl('FoldControl') );
if( FoldBlendNode != none )
{
FoldBlendNode.SetBlendTarget( bIsFolded ? 1.0f : 0.0f, 0.0f );
}
}
/** Called from the pawn when our first person weapon changes states */
simulated function UpdateThirdPersonWeaponAction(EWeaponState NewWeaponState, KFPawn P, byte ThirdPersonAnimRateByte )
{
Super.UpdateThirdPersonWeaponAction(NewWeaponState, P, ThirdPersonAnimRate);
if (NewWeaponState == WEP_Cleaning)
{
if (WeapAnimNode != none)
{
if (WeapAnimNode.AnimSeq == none)
{
WeapAnimNode.SetAnim(FoldAnim);
}
WeapAnimNode.PlayAnim();
}
}
}
simulated function ANIMNOTIFY_ShellEject()
{
ChangeMode();
}
/**
* Plays a split (upper and lower body) animation on the owning pawn
* Network: All but dedicated
*
* @param P Owning pawn to play animation on
* @param AnimName Anim to play
* @param bPlaySynchronizedWeaponAnim If true, try to play the same animation on the weapon mesh
*/
simulated function float PlayCharacterMeshAnim(KFPawn P, name AnimName, optional bool bPlaySynchedWeaponAnim, optional bool bLooping)
{
local float AnimRate;
local float Duration;
local EAnimSlotStance Stance;
local string AnimStr;
// skip weapon anims while in a special move
if( P.IsDoingSpecialMove() && !P.SpecialMoves[P.SpecialMove].bAllowThirdPersonWeaponAnims )
{
return 0.f;
}
Stance = (!P.bIsCrouched) ? EAS_UpperBody : EAS_CH_UpperBody;
AnimRate = ThirdPersonAnimRate;
AnimStr = Caps(string(AnimName));
if (!bIsFolded && (InStr(AnimStr, "ATK") != INDEX_NONE || InStr(AnimName, "COMB") != INDEX_NONE))
{
AnimRate *= UnfoldedAnimRateModifier;
}
Duration = P.PlayBodyAnim(AnimName, Stance, AnimRate, DefaultBlendInTime, DefaultBlendOutTime, bLooping);
if ( Duration > 0 && bPlaySynchedWeaponAnim )
{
PlayWeaponMeshAnim(AnimName, P.BodyStanceNodes[Stance], bLooping);
}
`log(GetFuncName()@"called on:"$P@"Anim:"$AnimName@"Duration:"$Duration, bDebug);
return Duration;
}
/** Special event added for weap attachments. Free for use */
function OnSpecialEvent(int Arg)
{
bIsFolded = Arg == 0;
// FoldControl = SkelControlSingleBone( WeapMesh.FindSkelControl('FoldControl') );
if( FoldBlendNode != none )
{
FoldBlendNode.SetBlendTarget( bIsFolded ? 1.0f : 0.0f, 0.0f );
}
}
defaultproperties
{
CustomAnimTree=AnimTree'WEP_Scythe_ARCH.3P_Scythe_Animtree'
bIsFolded=true;
UnfoldBlendingDuration=0.25f
UnfoldedAnimRateModifier=0.7f;
// Weapon SkeletalMesh
Begin Object Name=SkeletalMeshComponent0
bForceRefPose=0
End Object
}

View File

@ -0,0 +1,159 @@
//=============================================================================
// KFWeap_AssaultRifle_G36C
//=============================================================================
// Class Description
//=============================================================================
// Killing Floor 2
// Copyright (C) 2022 Tripwire Interactive LLC
//=============================================================================
class KFWeap_AssaultRifle_G36C extends KFWeap_SMGBase;
simulated function ZoomIn(bool bAnimateTransition, float ZoomTimeToGo)
{
super.ZoomIn(bAnimateTransition, ZoomTimeToGo);
if (LaserSight != none)
{
LaserSight.ChangeVisibility(false);
}
}
simulated function ZoomOut( bool bAnimateTransition, float ZoomTimeToGo )
{
super.ZoomOut( bAnimateTransition, ZoomTimeToGo );
if (LaserSight != none)
{
LaserSight.ChangeVisibility(true);
}
}
defaultproperties
{
bHasFireLastAnims=true
BonesToLockOnEmpty=(RW_Bolt, RW_Charging_Handle)
// Shooting Animations
FireSightedAnims[0]=Shoot_Iron
FireSightedAnims[1]=Shoot_Iron2
FireSightedAnims[2]=Shoot_Iron3
// FOV
MeshFOV=70
MeshIronSightFOV=20
PlayerIronSightFOV=70
// Depth of field
DOF_FG_FocalRadius=150
DOF_FG_MaxNearBlurSize=3
// Zooming/Position
IronSightPosition=(X=40,Y=0.1,Z=-4.57)
PlayerViewOffset=(X=14,Y=11,Z=-5)
// Content
PackageKey="G36C"
FirstPersonMeshName="WEP_1P_G36C_MESH.Wep_1stP_G36C_Rig"
FirstPersonAnimSetNames(0)="WEP_1P_G36C_ANIM.Wep_1stP_G36C_Anim"
PickupMeshName="WEP_3P_G36C_MESH.Wep_G36C_Pickup"
AttachmentArchetypeName="WEP_G36C_ARCH.Wep_G36C_3P"
MuzzleFlashTemplateName="WEP_G36C_ARCH.Wep_G36C_MuzzleFlash"
LaserSightTemplate=KFLaserSightAttachment'FX_LaserSight_ARCH.LaserSight_WithAttachment_1P'
// Ammo
MagazineCapacity[0]=30
SpareAmmoCapacity[0]=450
InitialSpareMags[0]=3
bCanBeReloaded=true
bReloadFromMagazine=true
// Recoil
maxRecoilPitch=90
minRecoilPitch=80
maxRecoilYaw=80
minRecoilYaw=-80
RecoilRate=0.085
RecoilMaxYawLimit=500
RecoilMinYawLimit=65035
RecoilMaxPitchLimit=900
RecoilMinPitchLimit=65035
RecoilISMaxYawLimit=100
RecoilISMinYawLimit=65460
RecoilISMaxPitchLimit=350
RecoilISMinPitchLimit=65460
IronSightMeshFOVCompensationScale=4.0
// Old Recoil Data
// maxRecoilPitch=80
// minRecoilPitch=65
// maxRecoilYaw=60
// minRecoilYaw=-60
// RecoilRate=0.063
// RecoilMaxYawLimit=400
// RecoilMinYawLimit=65135
// RecoilMaxPitchLimit=800
// RecoilMinPitchLimit=65035
// RecoilISMaxYawLimit=150
// RecoilISMinYawLimit=65385
// RecoilISMaxPitchLimit=350
// RecoilISMinPitchLimit=65435
// IronSightMeshFOVCompensationScale=1.5
// Inventory
InventorySize=7
GroupPriority=100
WeaponSelectTexture=Texture2D'wep_ui_g36c_tex.UI_WeaponSelect_G36C'
// DEFAULT_FIREMODE
FireModeIconPaths(DEFAULT_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_BulletAuto'
FiringStatesArray(DEFAULT_FIREMODE)=WeaponFiring
WeaponFireTypes(DEFAULT_FIREMODE)=EWFT_InstantHit
WeaponProjectiles(DEFAULT_FIREMODE)=class'KFProj_Bullet_AssaultRifle'
InstantHitDamageTypes(DEFAULT_FIREMODE)=class'KFDT_Ballistic_G36C'
PenetrationPower(DEFAULT_FIREMODE)=4.0
FireInterval(DEFAULT_FIREMODE)=+0.08 // 750 RPM
Spread(DEFAULT_FIREMODE)=0.005
InstantHitDamage(DEFAULT_FIREMODE)=45.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_InstantHit
WeaponProjectiles(ALTFIRE_FIREMODE)=class'KFProj_Bullet_AssaultRifle'
InstantHitDamageTypes(ALTFIRE_FIREMODE)=class'KFDT_Ballistic_G36C'
PenetrationPower(ALTFIRE_FIREMODE)=4.0
FireInterval(ALTFIRE_FIREMODE)=+0.08 // 750 RPM
InstantHitDamage(ALTFIRE_FIREMODE)=45.0
Spread(ALTFIRE_FIREMODE)=0.005
// BASH_FIREMODE
InstantHitDamageTypes(BASH_FIREMODE)=class'KFDT_Bludgeon_G36C'
InstantHitDamage(BASH_FIREMODE)=26
// Fire Effects
WeaponFireSnd(DEFAULT_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_G36C.Play_WEP_G36C_3P_Shoot_LP', FirstPersonCue=AkEvent'WW_WEP_G36C.Play_WEP_G36C_1P_Shoot_LP')
WeaponFireSnd(ALTFIRE_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_G36C.Play_WEP_G36C_3P_Shoot_Single', FirstPersonCue=AkEvent'WW_WEP_G36C.Play_WEP_G36C_1P_Shoot_Single')
WeaponDryFireSnd(DEFAULT_FIREMODE)=AkEvent'WW_WEP_SA_AK12.Play_WEP_SA_AK12_Handling_DryFire' //@TODO: Replace me
WeaponDryFireSnd(ALTFIRE_FIREMODE)=AkEvent'WW_WEP_SA_AK12.Play_WEP_SA_AK12_Handling_DryFire' //@TODO: Replace me
// WeaponDryFireSnd(DEFAULT_FIREMODE)=AkEvent'WW_WEP_G36C.Play_WEP_G36C_Dry_Fire'
// WeaponDryFireSnd(ALTFIRE_FIREMODE)=AkEvent'WW_WEP_G36C.Play_WEP_G36C_Dry_Fire'
// Advanced (High RPM) Fire Effects
bLoopingFireAnim(DEFAULT_FIREMODE)=true
bLoopingFireSnd(DEFAULT_FIREMODE)=true
WeaponFireLoopEndSnd(DEFAULT_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_G36C.Play_WEP_G36C_3P_End_LP', FirstPersonCue=AkEvent'WW_WEP_G36C.Play_WEP_G36C_1P_End_LP')
SingleFireSoundIndex=ALTFIRE_FIREMODE
// Attachments
bHasIronSights=true
bHasFlashlight=false
bHasLaserSight=true
AssociatedPerkClasses(0)=class'KFPerk_Swat'
// Weapon Upgrade stat boosts
WeaponUpgrades[1]=(Stats=((Stat=EWUS_Damage0, Scale=1.15f), (Stat=EWUS_Damage1, Scale=1.15f), (Stat=EWUS_Weight, Add=1)))
}

View File

@ -998,7 +998,7 @@ defaultproperties
// Zooming/Position
PlayerViewOffset = (X = 3.0, Y = 10, Z = -1)
IronSightPosition = (X = 0, Y = 0, Z = 0)
IronSightPosition = (X = 0, Y = 0.037, Z = 0.11)
// Ammo
MagazineCapacity[0] = 50

View File

@ -73,7 +73,7 @@ defaultproperties
DOF_FG_MaxNearBlurSize=2.5
// Zooming/Position
IronSightPosition=(X=10,Y=0,Z=0) //x20
IronSightPosition=(X=10,Y=-0.015,Z=0.09) //x20
PlayerViewOffset=(X=30.0,Y=10,Z=-2.5) //x18 y9 z0
// Content

View File

@ -176,7 +176,7 @@ simulated function GetTurretSpawnLocationAndDir(out vector SpawnLocation, out ve
}
/** Detonates the oldest turret */
simulated function Detonate()
simulated function Detonate(optional bool bKeepTurret = false)
{
local int i;
local array<Actor> TurretsCopy;
@ -187,10 +187,15 @@ simulated function Detonate()
TurretsCopy = KFPC.DeployedTurrets;
for (i = 0; i < TurretsCopy.Length; i++)
{
if (bKeepTurret && i == 0)
{
continue;
}
KFPawn_AutoTurret(TurretsCopy[i]).SetTurretState(ETS_Detonate);
}
KFPC.DeployedTurrets.Remove(0, KFPC.DeployedTurrets.Length);
KFPC.DeployedTurrets.Remove(bKeepTurret ? 1 : 0, KFPC.DeployedTurrets.Length);
SetReadyToUse(true);
@ -231,7 +236,17 @@ function SetOriginalValuesFromPickup( KFWeapon PickedUpWeapon )
if (PickedUpWeapon.KFPlayer != none && PickedUpWeapon.KFPlayer != KFPC)
{
KFPC.DeployedTurrets = PickedUpWeapon.KFPlayer.DeployedTurrets;
for (i = 0; i < PickedUpWeapon.KFPlayer.DeployedTurrets.Length; i++)
{
KFPC.DeployedTurrets.AddItem(PickedUpWeapon.KFPlayer.DeployedTurrets[i]);
}
PickedUpWeapon.KFPlayer.DeployedTurrets.Remove(0, PickedUpWeapon.KFPlayer.DeployedTurrets.Length);
}
if (KFPC.DeployedTurrets.Length > 1)
{
Detonate(true);
}
PickedUpWeapon.KFPlayer = none;

View File

@ -184,7 +184,7 @@ defaultproperties
PlayerIronSightFOV=80
// Zooming/Position
IronSightPosition=(X=3,Y=0,Z=0)
IronSightPosition=(X=3,Y=-0.032,Z=-0.03)
PlayerViewOffset=(X=5.0,Y=9,Z=-3)
// Depth of field

View File

@ -396,8 +396,13 @@ simulated protected function PrepareExplosion()
KFPC = KFPlayerController(Instigator.Controller);
if (KFPC != none)
{
`Log("RADIUS BEFORE: " $ExplosionTemplate.DamageRadius);
InstigatorPerk = KFPC.GetPerk();
ExplosionTemplate.DamageRadius *= InstigatorPerk.GetAoERadiusModifier();
`Log("RADIUS BEFORE: " $ExplosionTemplate.DamageRadius);
}
}
@ -448,6 +453,9 @@ simulated function SpawnExplosionFromTemplate(KFGameExplosion Template)
ExploActor.Explode(Template, vector(SpawnRot));
}
// Reset damage radius
ExplosionTemplate.DamageRadius = StartingDamageRadius;
}
simulated function CustomFire()

View File

@ -138,6 +138,8 @@ simulated function CustomFire()
// tell remote clients that we fired, to trigger effects in third person
IncrementFlashCount();
ExplosionTemplate.DamageRadius = StartingDamageRadius;
if ( bDebug )
{
DrawDebugCone(SpawnLoc, vector(SpawnRot), ExplosionTemplate.DamageRadius, ExplosionTemplate.DirectionalExplosionAngleDeg * DegToRad,

View File

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

View File

@ -366,8 +366,8 @@ defaultproperties
//WeaponUpgrades[1]=(IncrementDamage=1.4f,IncrementWeight=1, IncrementHealFullRecharge=.8)
//WeaponUpgrades[2]=(IncrementDamage=1.8f,IncrementWeight=2, IncrementHealFullRecharge=.6)
WeaponUpgrades[1]=(Stats=((Stat=EWUS_Damage0, Scale=1.15f), (Stat=EWUS_Weight, Add=1), (Stat=EWUS_HealFullRecharge, Scale=0.9f)))
WeaponUpgrades[2]=(Stats=((Stat=EWUS_Damage0, Scale=1.3f), (Stat=EWUS_Weight, Add=2), (Stat=EWUS_HealFullRecharge, Scale=0.8f)))
WeaponUpgrades[1]=(Stats=((Stat=EWUS_Damage0, Scale=1.15f), (Stat=EWUS_Weight, Add=1)))
WeaponUpgrades[2]=(Stats=((Stat=EWUS_Damage0, Scale=1.3f), (Stat=EWUS_Weight, Add=2)))
// From original KFWeap_RifleBase base class
AimCorrectionSize=40.f

View File

@ -0,0 +1,286 @@
//=============================================================================
// KFWeap_HRG_Dragonbreath
//=============================================================================
// Killing Floor 2
// Copyright (C) 2022 Tripwire Interactive LLC
//=============================================================================
class KFWeap_HRG_Dragonbreath extends KFWeap_ShotgunBase;
/** How much to scale recoil when firing in double barrel fire. */
var(Recoil) float QuadFireRecoilModifier;
/** Shoot animation to play when shooting both barrels from the hip */
var(Animations) const editconst name FireQuadAnim;
/** How much momentum to apply when fired in double barrel */
var(Recoil) float DoubleBarrelKickMomentum;
/** How much to reduce shoot momentum when falling */
var(Recoil) float FallingMomentumReduction;
var(Spread) const float SpreadWidthDegrees;
var(Spread) const float SpreadWidthDegreesAlt;
var transient float StartingPelletPosition;
var transient float StartingPelletPositionAlt;
var const float BarrelHeatPerProjectile;
var const float MaxBarrelHeat;
var const float BarrelCooldownRate;
var transient float CurrentBarrelHeat;
var transient float LastBarrelHeat;
simulated event PreBeginPlay()
{
Super.PreBeginPlay();
Spread[DEFAULT_FIREMODE] = SpreadWidthDegrees * DegToRad / NumPellets[DEFAULT_FIREMODE];
Spread[ALTFIRE_FIREMODE] = SpreadWidthDegreesAlt * DegToRad / NumPellets[ALTFIRE_FIREMODE];
StartingPelletPosition = -SpreadWidthDegrees * DegToRad / 2.0f;
StartingPelletPositionAlt = -SpreadWidthDegreesAlt * DegToRad / 2.0f;
}
simulated event PostBeginPlay()
{
Super.PostBeginPlay();
// Force start with "Glow_Intensity" of 0.0f
LastBarrelHeat = MaxBarrelHeat;
ChangeBarrelMaterial();
}
simulated function AltFireMode()
{
if ( !Instigator.IsLocallyControlled() )
{
return;
}
StartFire(ALTFIRE_FIREMODE);
}
/** Returns number of projectiles to fire from SpawnProjectile */
simulated function byte GetNumProjectilesToFire(byte FireModeNum)
{
return NumPellets[CurrentFireMode];
}
/** Handle one-hand fire anims */
simulated function name GetWeaponFireAnim(byte FireModeNum)
{
if (bUsingSights)
{
return FireSightedAnims[FireModeNum];
}
else
{
if (FireModeNum == ALTFIRE_FIREMODE)
{
return FireQuadAnim;
}
else
{
return FireAnim;
}
}
}
simulated function KFProjectile SpawnAllProjectiles(class<KFProjectile> KFProjClass, vector RealStartLoc, vector AimDir)
{
local int ProjectilesToFire, i;
local float InitialOffset;
ProjectilesToFire = GetNumProjectilesToFire(CurrentFireMode);
if (CurrentFireMode == GRENADE_FIREMODE || ProjectilesToFire <= 1)
{
return SpawnProjectile(KFProjClass, RealStartLoc, AimDir);
}
InitialOffset = CurrentFireMode == DEFAULT_FIREMODE ? StartingPelletPosition : StartingPelletPositionAlt;
for (i = 0; i < ProjectilesToFire; i++)
{
SpawnProjectile(KFProjClass, RealStartLoc, CalculateSpread(InitialOffset, Spread[CurrentFireMode], i, CurrentFireMode == ALTFIRE_FIREMODE));
CurrentBarrelHeat = fmin(CurrentBarrelHeat + BarrelHeatPerProjectile, MaxBarrelHeat);
}
ChangeBarrelMaterial();
return None;
}
simulated function vector CalculateSpread(float InitialOffset, float CurrentSpread, byte PelletNum, bool bHorizontal)
{
local Vector X, Y, Z, POVLoc;
local Quat R;
local rotator POVRot;
if (Instigator != None && Instigator.Controller != none)
{
Instigator.Controller.GetPlayerViewPoint(POVLoc, POVRot);
}
GetAxes(POVRot, X, Y, Z);
R = QuatFromAxisAndAngle(bHorizontal ? Z : Y, InitialOffset + CurrentSpread * PelletNum);
return QuatRotateVector(R, vector(POVRot));
}
simulated function ChangeBarrelMaterial()
{
local int i;
if( CurrentBarrelHeat != LastBarrelHeat )
{
for( i = 0; i < WeaponMICs.Length; ++i )
{
if( WeaponMICs[i] != none )
{
WeaponMICs[i].SetScalarParameterValue('Barrel_intensity', CurrentBarrelHeat);
LastBarrelHeat = CurrentBarrelHeat;
}
}
}
}
simulated function Tick(float Delta)
{
Super.Tick(Delta);
CurrentBarrelHeat = fmax(CurrentBarrelHeat - BarrelCooldownRate * Delta, 0.0f);
ChangeBarrelMaterial();
}
defaultproperties
{
// Inventory
InventorySize=7
GroupPriority=110
WeaponSelectTexture=Texture2D'WEP_UI_Quad_Barrel_TEX.UI_WeaponSelect_QuadBarrel'
// FOV
MeshFOV=60
MeshIronSightFOV=52
PlayerIronSightFOV=70
// Depth of field
DOF_FG_FocalRadius=65
DOF_FG_MaxNearBlurSize=3
// Zooming/Position
PlayerViewOffset=(X=15.0,Y=8.0,Z=-4.5)
IronSightPosition=(X=3,Y=0,Z=0)
// Content
PackageKey="HRG_MegaDragonsbreath"
FirstPersonMeshName="wep_1p_hrg_megadragonsbreath_mesh.Wep_1stP_HRG_MegaDragonsbreath_Rig"
FirstPersonAnimSetNames(0)="wep_1p_hrg_megadragonsbreath_anim.Wep_1stP_HRG_MegaDragonsbreath_Anim"
PickupMeshName="wep_3p_hrg_megadragonsbreath_mesh.Wep_3rdP_HRG_MegaDragonsbreath_Pickup"
AttachmentArchetypeName="wep_hrg_megadragonsbreath_arch.Wep_HRG_MegaDragonsbreath_3P"
MuzzleFlashTemplateName="wep_hrg_megadragonsbreath_arch.Wep_HRG_MegaDragonsbreath_MuzzleFlash"
// Animations
FireAnim=Shoot_Single
FireQuadAnim=Shoot_Double
FireSightedAnims[0]=Shoot_Iron_Single
FireSightedAnims[1]=Shoot_Iron_Double
bHasFireLastAnims=false
// DEFAULT_FIREMODE
FireModeIconPaths(DEFAULT_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_ShotgunSingle'
FiringStatesArray(DEFAULT_FIREMODE)=WeaponSingleFiring
WeaponFireTypes(DEFAULT_FIREMODE)=EWFT_Projectile
WeaponProjectiles(DEFAULT_FIREMODE)=class'KFProj_Pellet_HRG_Dragonbreath'
InstantHitDamage(DEFAULT_FIREMODE)=28.0 //36
InstantHitDamageTypes(DEFAULT_FIREMODE)=class'KFDT_Ballistic_HRG_Dragonbreath'
PenetrationPower(DEFAULT_FIREMODE)=4.0
FireInterval(DEFAULT_FIREMODE)=0.25 // 240 RPM
FireOffset=(X=25,Y=3.5,Z=-4)
NumPellets(DEFAULT_FIREMODE)=8
Spread(DEFAULT_FIREMODE)=0
ForceReloadTimeOnEmpty=0.3
// ALT_FIREMODE
FireModeIconPaths(ALTFIRE_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_ShotgunAuto'
FiringStatesArray(ALTFIRE_FIREMODE)= WeaponSingleFiring
WeaponFireTypes(ALTFIRE_FIREMODE)=EWFT_Projectile
WeaponProjectiles(ALTFIRE_FIREMODE)=class'KFProj_Pellet_HRG_Dragonbreath'
InstantHitDamage(ALTFIRE_FIREMODE)=28.0
InstantHitDamageTypes(ALTFIRE_FIREMODE)=class'KFDT_Ballistic_HRG_Dragonbreath'
PenetrationPower(ALTFIRE_FIREMODE)=4.0
FireInterval(ALTFIRE_FIREMODE)=0.25 // 240 RPM
NumPellets(ALTFIRE_FIREMODE)=8
Spread(ALTFIRE_FIREMODE)=0
AmmoCost(ALTFIRE_FIREMODE)=1
DoubleBarrelKickMomentum=1000
FallingMomentumReduction=0.5
// BASH_FIREMODE
InstantHitDamageTypes(BASH_FIREMODE)=class'KFDT_Bludgeon_HRG_Dragonbreath'
InstantHitDamage(BASH_FIREMODE)=27
// Fire Effects
WeaponFireSnd(DEFAULT_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_Quad_Shotgun.Play_Quad_Shotgun_Fire_3P_Single', FirstPersonCue=AkEvent'WW_WEP_Quad_Shotgun.Play_Quad_Shotgun_Fire_1P_Single') //@TODO: Replace
WeaponFireSnd(ALTFIRE_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_Quad_Shotgun.Play_Quad_Shotgun_Fire_3P_AltFire', FirstPersonCue=AkEvent'WW_WEP_Quad_Shotgun.Play_Quad_Shotgun_Fire_1P_AltFire') //@TODO: Replace
WeaponDryFireSnd(DEFAULT_FIREMODE)=AkEvent'WW_WEP_Quad_Shotgun.Play_Quad_Shotgun_DryFire' //@TODO: Replace
WeaponDryFireSnd(ALTFIRE_FIREMODE)=AkEvent'WW_WEP_Quad_Shotgun.Play_Quad_Shotgun_DryFire' //@TODO: Replace
// Attachments
bHasIronSights=true
bHasFlashlight=false
// Ammo
MagazineCapacity[0]=4
SpareAmmoCapacity[0]=48 //72
InitialSpareMags[0]=3 //8
AmmoPickupScale[0]=2.0 //3.0
bCanBeReloaded=true
bReloadFromMagazine=true
bNoMagazine=true
// Recoil
maxRecoilPitch=1200 //900
minRecoilPitch=775
maxRecoilYaw=800 //500
minRecoilYaw=-500
RecoilRate=0.085
RecoilBlendOutRatio=1.1
RecoilMaxYawLimit=500
RecoilMinYawLimit=65035
RecoilMaxPitchLimit=1500
RecoilMinPitchLimit=64785
RecoilISMaxYawLimit=50
RecoilISMinYawLimit=65485
RecoilISMaxPitchLimit=500
RecoilISMinPitchLimit=65485
RecoilViewRotationScale=0.8
FallingRecoilModifier=1.5
HippedRecoilModifier=1.1 //1.25
QuadFireRecoilModifier=2.0
AssociatedPerkClasses(0)=class'KFPerk_Firebug'
WeaponFireWaveForm=ForceFeedbackWaveform'FX_ForceFeedback_ARCH.Gunfire.Heavy_Recoil_SingleShot'
// Weapon Upgrade stat boosts
//WeaponUpgrades[1]=(IncrementDamage=1.15f,IncrementWeight=1)
WeaponUpgrades[1]=(Stats=((Stat=EWUS_Damage0, Scale=1.15f), (Stat=EWUS_Damage1, Scale=1.15f), (Stat=EWUS_Weight, Add=1)))
SpreadWidthDegrees=7.0f
SpreadWidthDegreesAlt=15.0f
StartingPelletPosition=0.0f
StartingPelletPositionAlt=0.0f
MaxBarrelHeat=5.0f
BarrelHeatPerProjectile=0.089f
BarrelCooldownRate=0.45f
CurrentBarrelHeat=0.0f
LastBarrelHeat=0.0f
NumBloodMapMaterials=3
}

View File

@ -746,7 +746,7 @@ defaultproperties
PlayerIronSightFOV=80
// Zooming/Position
IronSightPosition=(X=3,Y=0,Z=0)
IronSightPosition=(X=3,Y=-0.032,Z=-0.03)
PlayerViewOffset=(X=5.0,Y=9,Z=-3)
// Depth of field

View File

@ -0,0 +1,684 @@
//=============================================================================
// KFWeap_HRG_Locust
//=============================================================================
// A mosquito rocket launcher
//=============================================================================
// Killing Floor 2
// Copyright (C) 2022 Tripwire Interactive LLC
//
//=============================================================================
class KFWeap_HRG_Locust extends KFWeap_GrenadeLauncher_Base;
const MAX_LOCKED_TARGETS = 6;
/** Constains all currently locked-on targets */
var protected array<Pawn> LockedTargets;
/** How much to scale recoil when firing in multi-rocket mode */
var float BurstFireRecoilModifier;
/** The last time a target was acquired */
var protected float LastTargetLockTime;
/** The last time a target validation check was performed */
var protected float LastTargetValidationCheckTime;
/** How much time after a lock on occurs before another is allowed */
var const float TimeBetweenLockOns;
/** How much time should pass between target validation checks */
var const float TargetValidationCheckInterval;
/** Minimum distance a target can be from the crosshair to be considered for lock on */
var const float MinTargetDistFromCrosshairSQ;
/** Dot product FOV that targets need to stay within to maintain a target lock */
var const float MaxLockMaintainFOVDotThreshold;
/** Sound Effects to play when Locking */
var AkBaseSoundObject LockAcquiredSoundFirstPerson;
var AkBaseSoundObject LockLostSoundFirstPerson;
/** Icon textures for lock on drawing */
var const Texture2D LockedOnIcon;
var LinearColor LockedIconColor;
/** Ironsights Audio */
var AkComponent IronsightsComponent;
var AkEvent IronsightsZoomInSound;
var AkEvent IronsightsZoomOutSound;
/** Reduction for the amount of damage dealt to the weapon owner (including damage by the explosion) */
var() float SelfDamageReductionValue;
/**
* Toggle between DEFAULT and ALTFIRE
*/
simulated function AltFireMode()
{
super.AltFireMode();
LockedTargets.Length = 0;
}
/*********************************************************************************************
* @name Target Locking And Validation
**********************************************************************************************/
/** We need to update our locked targets every frame and make sure they're within view and not dead */
simulated event Tick( float DeltaTime )
{
local Pawn RecentlyLocked, StaticLockedTargets[6];
local bool bUpdateServerTargets;
local int i;
super.Tick( DeltaTime );
if( bUsingSights && bUseAltFireMode
&& Instigator != none
&& Instigator.IsLocallyControlled() )
{
if( `TimeSince(LastTargetLockTime) > TimeBetweenLockOns
&& LockedTargets.Length < AmmoCount[GetAmmoType(0)]
&& LockedTargets.Length < MAX_LOCKED_TARGETS)
{
bUpdateServerTargets = FindTargets( RecentlyLocked );
}
if( LockedTargets.Length > 0 )
{
bUpdateServerTargets = bUpdateServerTargets || ValidateTargets( RecentlyLocked );
}
// If we are a client, synchronize our targets with the server
if( bUpdateServerTargets && Role < ROLE_Authority )
{
for( i = 0; i < MAX_LOCKED_TARGETS; ++i )
{
if( i < LockedTargets.Length )
{
StaticLockedTargets[i] = LockedTargets[i];
}
else
{
StaticLockedTargets[i] = none;
}
}
ServerSyncLockedTargets( StaticLockedTargets );
}
}
}
/**
* Given an potential target TA determine if we can lock on to it. By default only allow locking on
* to pawns.
*/
simulated function bool CanLockOnTo(Actor TA)
{
Local KFPawn PawnTarget;
PawnTarget = KFPawn(TA);
// Make sure the pawn is legit, isn't dead, and isn't already at full health
if ((TA == None) || !TA.bProjTarget || TA.bDeleteMe || (PawnTarget == None) ||
(TA == Instigator) || (PawnTarget.Health <= 0) ||
!HasAmmo(DEFAULT_FIREMODE))
{
return false;
}
// Make sure and only lock onto players on the same team
return !WorldInfo.GRI.OnSameTeam(Instigator, TA);
}
/** Finds a new lock on target, adds it to the target array and returns TRUE if the array was updated */
simulated function bool FindTargets( out Pawn RecentlyLocked )
{
local Pawn P, BestTargetLock;
local byte TeamNum;
local vector AimStart, AimDir, TargetLoc, Projection, DirToPawn, LinePoint;
local Actor HitActor;
local float PointDistSQ, Score, BestScore, TargetSizeSQ;
TeamNum = Instigator.GetTeamNum();
AimStart = GetSafeStartTraceLocation();
AimDir = vector( GetAdjustedAim(AimStart) );
BestScore = 0.f;
//Don't add targets if we're already burst firing
if (IsInState('WeaponBurstFiring'))
{
return false;
}
foreach WorldInfo.AllPawns( class'Pawn', P )
{
if (!CanLockOnTo(P))
{
continue;
}
// Want alive pawns and ones we already don't have locked
if( P != none && P.IsAliveAndWell() && P.GetTeamNum() != TeamNum && LockedTargets.Find(P) == INDEX_NONE )
{
TargetLoc = GetLockedTargetLoc( P );
Projection = TargetLoc - AimStart;
DirToPawn = Normal( Projection );
// Filter out pawns too far from center
if( AimDir dot DirToPawn < 0.5f )
{
continue;
}
// Check to make sure target isn't too far from center
PointDistToLine( TargetLoc, AimDir, AimStart, LinePoint );
PointDistSQ = VSizeSQ( LinePoint - P.Location );
TargetSizeSQ = P.GetCollisionRadius() * 2.f;
TargetSizeSQ *= TargetSizeSQ;
if( PointDistSQ > (TargetSizeSQ + MinTargetDistFromCrosshairSQ) )
{
continue;
}
// Make sure it's not obstructed
HitActor = class'KFAIController'.static.ActorBlockTest(self, TargetLoc, AimStart,, true, true);
if( HitActor != none && HitActor != P )
{
continue;
}
// Distance from target has much more impact on target selection score
Score = VSizeSQ( Projection ) + PointDistSQ;
if( BestScore == 0.f || Score < BestScore )
{
BestTargetLock = P;
BestScore = Score;
}
}
}
if( BestTargetLock != none )
{
LastTargetLockTime = WorldInfo.TimeSeconds;
LockedTargets.AddItem( BestTargetLock );
RecentlyLocked = BestTargetLock;
// Plays sound/FX when locking on to a new target
PlayTargetLockOnEffects();
return true;
}
RecentlyLocked = none;
return false;
}
/** Checks to ensure all of our current locked targets are valid */
simulated function bool ValidateTargets( optional Pawn RecentlyLocked )
{
local int i;
local bool bShouldRemoveTarget, bAlteredTargets;
local vector AimStart, AimDir, TargetLoc;
local Actor HitActor;
if( `TimeSince(LastTargetValidationCheckTime) < TargetValidationCheckInterval )
{
return false;
}
LastTargetValidationCheckTime = WorldInfo.TimeSeconds;
AimStart = GetSafeStartTraceLocation();
AimDir = vector( GetAdjustedAim(AimStart) );
bAlteredTargets = false;
for( i = 0; i < LockedTargets.Length; ++i )
{
// For speed don't bother checking a target we just locked
if( RecentlyLocked != none && RecentlyLocked == LockedTargets[i] )
{
continue;
}
bShouldRemoveTarget = false;
if( LockedTargets[i] == none
|| !LockedTargets[i].IsAliveAndWell() )
{
bShouldRemoveTarget = true;
}
else
{
TargetLoc = GetLockedTargetLoc( LockedTargets[i] );
if( AimDir dot Normal(LockedTargets[i].Location - AimStart) >= MaxLockMaintainFOVDotThreshold )
{
HitActor = class'KFAIController'.static.ActorBlockTest( self, TargetLoc, AimStart,, true, true );
if( HitActor != none && HitActor != LockedTargets[i] )
{
bShouldRemoveTarget = true;
}
}
else
{
bShouldRemoveTarget = true;
}
}
// A target was invalidated, remove it from the list
if( bShouldRemoveTarget )
{
LockedTargets.Remove( i, 1 );
--i;
bAlteredTargets = true;
continue;
}
}
// Plays sound/FX when losing a target lock, but only if we didn't play a lock on this frame
if( bAlteredTargets && RecentlyLocked == none )
{
PlayTargetLostEffects();
}
return bAlteredTargets;
}
/** Synchronizes our locked targets with the server */
reliable server function ServerSyncLockedTargets( Pawn TargetPawns[MAX_LOCKED_TARGETS] )
{
local int i;
LockedTargets.Length = 0;
for( i = 0; i < MAX_LOCKED_TARGETS; ++i )
{
if (TargetPawns[i] != none)
{
LockedTargets.AddItem(TargetPawns[i]);
}
}
}
/** Adjusts our destination target impact location */
static simulated function vector GetLockedTargetLoc( Pawn P )
{
// Go for the chest, but just in case we don't have something with a chest bone we'll use collision and eyeheight settings
if( P.Mesh.SkeletalMesh != none && P.Mesh.bAnimTreeInitialised )
{
if( P.Mesh.MatchRefBone('Spine2') != INDEX_NONE )
{
return P.Mesh.GetBoneLocation( 'Spine2' );
}
else if( P.Mesh.MatchRefBone('Spine1') != INDEX_NONE )
{
return P.Mesh.GetBoneLocation( 'Spine1' );
}
return P.Mesh.GetPosition() + ((P.CylinderComponent.CollisionHeight + (P.BaseEyeHeight * 0.5f)) * vect(0,0,1)) ;
}
// General chest area, fallback
return P.Location + ( vect(0,0,1) * P.BaseEyeHeight * 0.75f );
}
simulated function ZoomIn(bool bAnimateTransition, float ZoomTimeToGo)
{
super.ZoomIn(bAnimateTransition, ZoomTimeToGo);
if (IronsightsZoomInSound != none && Instigator != none && Instigator.IsLocallyControlled())
{
IronsightsComponent.PlayEvent(IronsightsZoomInSound, false);
}
}
/** Clear all locked targets when zooming out, both server and client */
simulated function ZoomOut( bool bAnimateTransition, float ZoomTimeToGo )
{
super.ZoomOut( bAnimateTransition, ZoomTimeToGo );
if (IronsightsZoomOutSound != none && Instigator != none && Instigator.IsLocallyControlled())
{
IronsightsComponent.PlayEvent(IronsightsZoomOutSound, false);
}
// Play a target lost effect if we're clearing targets on the way out
if( Instigator.IsLocallyControlled() && LockedTargets.Length > 0 )
{
PlayTargetLostEffects();
}
LockedTargets.Length = 0;
}
/** Play FX or sounds when locking on to a new target */
simulated function PlayTargetLockOnEffects()
{
if( Instigator != none && Instigator.IsHumanControlled() )
{
PlaySoundBase( LockAcquiredSoundFirstPerson, true );
}
}
/** Play FX or sounds when losing a target lock */
simulated function PlayTargetLostEffects()
{
if( Instigator != none && Instigator.IsHumanControlled() )
{
PlaySoundBase( LockLostSoundFirstPerson, true );
}
}
/*********************************************************************************************
* @name Projectile Spawning
**********************************************************************************************/
/** Spawn projectile is called once for each rocket fired. In burst mode it will cycle through targets until it runs out */
simulated function KFProjectile SpawnProjectile( class<KFProjectile> KFProjClass, vector RealStartLoc, vector AimDir )
{
local KFProj_HRG_Locust LocustProj;
if( CurrentFireMode == GRENADE_FIREMODE )
{
return super.SpawnProjectile( KFProjClass, RealStartLoc, AimDir );
}
// We need to set our target if we are firing from a locked on position
if( bUsingSights
&& CurrentFireMode == ALTFIRE_FIREMODE
&& LockedTargets.Length > 0 )
{
// We'll aim our rocket at a target here otherwise we will spawn a dumbfire rocket at the end of the function
if( LockedTargets.Length > 0 )
{
// Spawn our projectile and set its target
LocustProj = KFProj_HRG_Locust( super.SpawnProjectile(KFProjClass, RealStartLoc, AimDir) );
if( LocustProj != none )
{
//Seek to new target, then remove from list. Always use first target in the list for new fire.
LocustProj.SetLockedTarget( KFPawn(LockedTargets[0]) );
LockedTargets.Remove(0, 1);
return LocustProj;
}
}
return None;
}
return super.SpawnProjectile( KFProjClass, RealStartLoc, AimDir );
}
/*********************************************************************************************
* @name Targeting HUD -- Partially adapted from KFWeap_Rifle_RailGun
**********************************************************************************************/
/** Handle drawing our custom lock on HUD */
simulated function DrawHUD( HUD H, Canvas C )
{
local int i;
if( !bUsingSights || LockedTargets.Length == 0 )
{
return;
}
// Draw target locked icons
C.EnableStencilTest( true );
for( i = 0; i < LockedTargets.Length; ++i )
{
if( LockedTargets[i] != none )
{
DrawTargetingIcon( C, i );
}
}
C.EnableStencilTest( false );
}
/** Draws a targeting icon for each one of our locked targets */
simulated function DrawTargetingIcon( Canvas Canvas, int Index )
{
local vector WorldPos, ScreenPos;
local float IconSize, IconScale;
// Project world pos to canvas
WorldPos = GetLockedTargetLoc( LockedTargets[Index] );
ScreenPos = Canvas.Project( WorldPos );//WorldToCanvas(Canvas, WorldPos);
// calculate scale based on resolution and distance
IconScale = fMin( float(Canvas.SizeX) / 1024.f, 1.f );
// Scale down up to 40 meters away, with a clamp at 20% size
IconScale *= fClamp( 1.f - VSize(WorldPos - Instigator.Location) / 4000.f, 0.2f, 1.f );
// Apply size scale
IconSize = 200.f * IconScale;
ScreenPos.X -= IconSize / 2.f;
ScreenPos.Y -= IconSize / 2.f;
// Off-screen check
if( ScreenPos.X < 0 || ScreenPos.X > Canvas.SizeX || ScreenPos.Y < 0 || ScreenPos.Y > Canvas.SizeY )
{
return;
}
Canvas.SetPos( ScreenPos.X, ScreenPos.Y );
// Draw the icon
Canvas.DrawTile( LockedOnIcon, IconSize, IconSize, 0, 0, LockedOnIcon.SizeX, LockedOnIcon.SizeY, LockedIconColor );
}
/*********************************************************************************************
* State WeaponSingleFiring
* Fire must be released between every shot.
*********************************************************************************************/
simulated state WeaponSingleFiring
{
simulated function BeginState( Name PrevStateName )
{
LockedTargets.Length = 0;
super.BeginState( PrevStateName );
}
}
/*********************************************************************************************
* State WeaponBurstFiring
* Fires a burst of bullets. Fire must be released between every shot.
*********************************************************************************************/
simulated state WeaponBurstFiring
{
simulated function int GetBurstAmount()
{
// Clamp our bursts to either the number of targets or how much ammo we have remaining
return Clamp( LockedTargets.Length, 1, AmmoCount[GetAmmoType(CurrentFireMode)] );
}
/** Overridden to apply scaled recoil when in multi-rocket mode */
simulated function ModifyRecoil( out float CurrentRecoilModifier )
{
super.ModifyRecoil( CurrentRecoilModifier );
CurrentRecoilModifier *= BurstFireRecoilModifier;
}
simulated function bool ShouldRefire()
{
return LockedTargets.Length > 0;
}
simulated function FireAmmunition()
{
super.FireAmmunition();
if (Role < ROLE_Authority)
{
LockedTargets.Remove(0, 1);
}
}
simulated event EndState( Name NextStateName )
{
LockedTargets.Length = 0;
super.EndState( NextStateName );
}
}
/**
Reduce the damage received and apply it to the shield
*/
function AdjustDamage(out int InDamage, class<DamageType> DamageType, Actor DamageCauser)
{
super.AdjustDamage(InDamage, DamageType, DamageCauser);
if (Instigator != none && DamageCauser.Instigator == Instigator)
{
InDamage *= SelfDamageReductionValue;
}
}
defaultproperties
{
ForceReloadTime=0.4f
// Inventory
InventoryGroup=IG_Primary
GroupPriority=100
InventorySize=6
WeaponSelectTexture=Texture2D'wep_ui_hrg_locust_tex.UI_WeaponSelect_HRG_Locust'
// FOV
MeshFOV=86
MeshIronSightFOV=65
PlayerIronSightFOV=70
PlayerSprintFOV=95
// Depth of field
DOF_FG_FocalRadius=50
DOF_FG_MaxNearBlurSize=2.5
// Zooming/Position
PlayerViewOffset=(X=20.0,Y=5,Z=-5)
FastZoomOutTime=0.2
// Content
PackageKey="HRG_Locust"
FirstPersonMeshName="wep_1p_hrg_locust_mesh.Wep_1stP_HRG_Locust_Rig"
FirstPersonAnimSetNames(0)="WEP_1P_HRG_Locust_ANIM.Wep_1stP_HRG_Locust_Anim"
PickupMeshName="wep_3p_hrg_locust_mesh.Wep_3rdP_HRG_Locust_Pickup"
AttachmentArchetypeName="wep_hrg_locust_arch.Wep_HRG_Locust_3P"
MuzzleFlashTemplateName="wep_hrg_locust_arch.Wep_HRG_Locust_MuzzleFlash"
// Target Locking
MinTargetDistFromCrosshairSQ=2500.0f // 0.5 meters
TimeBetweenLockOns=0.06f
TargetValidationCheckInterval=0.1f
MaxLockMaintainFOVDotThreshold=0.36f
// LockOn Visuals
LockedOnIcon=Texture2D'Wep_Scope_TEX.Wep_1stP_Yellow_Red_Target'
LockedIconColor=(R=1.f, G=0.f, B=0.f, A=0.5f)
// Lock On/Lost Sounds
LockAcquiredSoundFirstPerson=AkEvent'WW_WEP_SA_Railgun.Play_Railgun_Scope_Locked'
LockLostSoundFirstPerson=AkEvent'WW_WEP_SA_Railgun.Play_Railgun_Scope_Lost'
// Zooming/Position
IronSightPosition=(X=0,Y=-0.065,Z=-0.31)
// Ammo
MagazineCapacity[0]=6
SpareAmmoCapacity[0]=84
InitialSpareMags[0]=3
AmmoPickupScale[0]=2.0
bCanBeReloaded=true
bReloadFromMagazine=true
// Recoil
maxRecoilPitch=400
minRecoilPitch=275
maxRecoilYaw=200
minRecoilYaw=-200
RecoilRate=0.085
RecoilBlendOutRatio=0.35
RecoilMaxYawLimit=500
RecoilMinYawLimit=65035
RecoilMaxPitchLimit=1500
RecoilMinPitchLimit=64785
RecoilISMaxYawLimit=50
RecoilISMinYawLimit=65485
RecoilISMaxPitchLimit=500
RecoilISMinPitchLimit=65485
RecoilViewRotationScale=0.8
FallingRecoilModifier=1.5
HippedRecoilModifier=1.25
BurstFireRecoilModifier=0.15f // Reduce recoil between rockets when in burst mode
// DEFAULT_FIREMODE
FireModeIconPaths(DEFAULT_FIREMODE)=Texture2D'UI_FireModes_TEX.UI_FireModeSelect_Rocket'
FiringStatesArray(DEFAULT_FIREMODE)=WeaponFiring
WeaponFireTypes(DEFAULT_FIREMODE)=EWFT_Projectile
WeaponProjectiles(DEFAULT_FIREMODE)=class'KFProj_HRG_Locust'
FireInterval(DEFAULT_FIREMODE)=+0.35
InstantHitDamage(DEFAULT_FIREMODE)=1 //140 // 120.0 //100.00
InstantHitDamageTypes(DEFAULT_FIREMODE)=class'KFDT_Ballistic_HRG_Locust'
Spread(DEFAULT_FIREMODE)=0.025
FireOffset=(X=20,Y=4.0,Z=-3)
// ALT_FIREMODE
FireModeIconPaths(ALTFIRE_FIREMODE)= Texture2D'UI_SecondaryAmmo_TEX.UI_FireModeSelect_AutoTarget'
FiringStatesArray(ALTFIRE_FIREMODE)=WeaponBurstFiring
WeaponFireTypes(ALTFIRE_FIREMODE)=EWFT_Projectile
WeaponProjectiles(ALTFIRE_FIREMODE)=class'KFProj_HRG_Locust'
FireInterval(ALTFIRE_FIREMODE)=+0.3 //0.1
InstantHitDamage(ALTFIRE_FIREMODE)=1 //140 // 120.0 //100.00
InstantHitDamageTypes(ALTFIRE_FIREMODE)=class'KFDT_Ballistic_HRG_Locust'
Spread(ALTFIRE_FIREMODE)=0.025
AmmoCost(ALTFIRE_FIREMODE)=1
// BASH_FIREMODE
InstantHitDamageTypes(BASH_FIREMODE)=class'KFDT_Bludgeon_HRG_Locust'
InstantHitDamage(BASH_FIREMODE)=29
// Fire Effects
WeaponFireSnd(DEFAULT_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_Seeker_6.Play_WEP_Seeker_6_Fire_3P', FirstPersonCue=AkEvent'WW_WEP_Seeker_6.Play_WEP_Seeker_6_Fire_1P')
WeaponFireSnd(ALTFIRE_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_Seeker_6.Play_WEP_Seeker_6_Fire_3P', FirstPersonCue=AkEvent'WW_WEP_Seeker_6.Play_WEP_Seeker_6_Fire_1P')
WeaponDryFireSnd(DEFAULT_FIREMODE)=AkEvent'WW_WEP_SA_RPG7.Play_WEP_SA_RPG7_DryFire'
WeaponDryFireSnd(ALTFIRE_FIREMODE)=AkEvent'WW_WEP_SA_RPG7.Play_WEP_SA_RPG7_DryFire'
// Animation
bHasFireLastAnims=true
IdleFidgetAnims=(Guncheck_v1, Guncheck_v2)
//BonesToLockOnEmpty=(RW_Grenade1)
// Attachments
bHasIronSights=true
bHasFlashlight=false
AssociatedPerkClasses(0)=class'KFPerk_Survivalist'
WeaponFireWaveForm=ForceFeedbackWaveform'FX_ForceFeedback_ARCH.Gunfire.Heavy_Recoil_SingleShot'
// Audio
Begin Object Class=AkComponent name=IronsightsComponent0
bForceOcclusionUpdateInterval=true
OcclusionUpdateInterval=0.f // never update occlusion for footsteps
bStopWhenOwnerDestroyed=true
End Object
IronsightsComponent=IronsightsComponent0
Components.Add(IronsightsComponent0)
IronsightsZoomInSound=AkEvent'WW_WEP_Seeker_6.Play_Seeker_6_Iron_In'
IronsightsZoomOutSound=AkEvent'WW_WEP_Seeker_6.Play_Seeker_6_Iron_In_Out'
// Weapon Upgrade stat boosts
//WeaponUpgrades[1]=(IncrementDamage=1.125f,IncrementWeight=1)
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)))
SelfDamageReductionValue = 0f;
}

View File

@ -842,8 +842,8 @@ defaultproperties
ValueIncreaseTime=0.2
//FOR LERPING DAMANGE
MaxDamageByCharge=300 //250 //200 //120
MinDamageByCharge=30 //25 //30
MaxDamageByCharge=350 //300 //250 //200 //120
MinDamageByCharge=35 //30 //25 //30
// FOV
Meshfov=80
MeshIronSightFOV=65 //52
@ -895,7 +895,7 @@ defaultproperties
HippedRecoilModifier=1.5
// Inventory
InventorySize=8
InventorySize=7 //8
GroupPriority=80 //75
WeaponSelectTexture=Texture2D'WEP_UI_Mine_Reconstructor_TEX.UI_WeaponSelect_HMTechMineReconstructor' //@TODO: Replace me

View File

@ -492,7 +492,7 @@ defaultproperties
// Zooming/Position
PlayerViewOffset=(X=-15,Y=12,Z=-6)
IronSightPosition=(X=-3,Y=0,Z=0)
IronSightPosition=(X=-3,Y=0.145,Z=0)
// Content
PackageKey="Blunderbuss"

View File

@ -121,7 +121,7 @@ defaultproperties
// Zooming/Position [FFERRANDO NEEDS TO BE UPDATED TO G18]
PlayerViewOffset=(X=-15,Y=12,Z=-6)
IronSightPosition=(X=0,Y=0,Z=0) //(X=-3,Y=-0.38,Z=-0.2)
IronSightPosition=(X=0,Y=-0.12,Z=-0.1) //(X=-3,Y=-0.38,Z=-0.2)
// Content [FFERRANDO NEEDS TO BE UPDATED TO G18]
PackageKey="G18C"

View File

@ -91,7 +91,7 @@ defaultproperties
// Zooming/Position
PlayerViewOffset=(X=20.0,Y=11.0,Z=-2) //(X=15.0,Y=11.5,Z=-4)
IronSightPosition=(X=30.0,Y=0,Z=0)
IronSightPosition=(X=30.0,Y=-0.035,Z=-0.07)
// AI warning system
bWarnAIWhenAiming=true

View File

@ -57,7 +57,7 @@ defaultproperties
// Zooming/Position
PlayerViewOffset=(X=15.0,Y=11.5,Z=-4)
IronSightPosition=(X=0.0,Y=0,Z=0)
IronSightPosition=(X=0.0,Y=-0.016,Z=-0.016)
// AI warning system
bWarnAIWhenAiming=true

View File

@ -509,7 +509,7 @@ defaultproperties
// Zooming/Position
PlayerViewOffset=(X=3.0,Y=7,Z=-2)
IronSightPosition=(X=-0.25,Y=0,Z=0) // any further back along X and the scope clips through the camera during firing
IronSightPosition=(X=-0.25,Y=0.005,Z=-0.005) // any further back along X and the scope clips through the camera during firing
// AI warning system
bWarnAIWhenAiming=true

View File

@ -137,7 +137,7 @@ simulated function bool FindTargets( out Pawn RecentlyLocked )
local byte TeamNum;
local vector AimStart, AimDir, TargetLoc, Projection, DirToPawn, LinePoint;
local Actor HitActor;
local float PointDistSQ, Score, BestScore;
local float PointDistSQ, Score, BestScore, TargetSizeSQ;
TeamNum = Instigator.GetTeamNum();
AimStart = GetSafeStartTraceLocation();
@ -172,7 +172,11 @@ simulated function bool FindTargets( out Pawn RecentlyLocked )
// Check to make sure target isn't too far from center
PointDistToLine( TargetLoc, AimDir, AimStart, LinePoint );
PointDistSQ = VSizeSQ( LinePoint - P.Location );
if( PointDistSQ > MinTargetDistFromCrosshairSQ )
TargetSizeSQ = P.GetCollisionRadius() * 2.f;
TargetSizeSQ *= TargetSizeSQ;
if( PointDistSQ > (TargetSizeSQ + MinTargetDistFromCrosshairSQ) )
{
continue;
}

View File

@ -23,7 +23,7 @@ defaultproperties
PlayerIronSightFOV=75
// Zooming/Position
IronSightPosition=(X=15.f,Y=0.f,Z=0.0f)
IronSightPosition=(X=15.f,Y=0.03f,Z=0.1f)
PlayerViewOffset=(X=20.f,Y=9.5f,Z=-3.0f)
// Content

View File

@ -38,7 +38,7 @@ defaultproperties
PlayerIronSightFOV=70
// Zooming/Position
IronSightPosition=(X=8,Y=0,Z=0)
IronSightPosition=(X=8,Y=0.01,Z=-0.04)
PlayerViewOffset=(X=22,Y=10,Z=-4.5)
// Content

View File

@ -72,7 +72,7 @@ defaultproperties
// Zooming/Position
PlayerViewOffset=(X=14.0,Y=6.5,Z=-3.5)
IronSightPosition=(X=12.0,Y=0,Z=0)
IronSightPosition=(X=12.0,Y=-0.03,Z=-0.07)
// Content
PackageKey="Medic_Shotgun"