1
0
This commit is contained in:
GenZmeY 2022-11-28 00:46:28 +03:00
parent 23d1ca3a9a
commit 2c6c4ddc5c
35 changed files with 3324 additions and 0 deletions

View File

@ -0,0 +1,36 @@
//=============================================================================
// KFDT_Ballistic_HRG_Locust
//=============================================================================
// HRG Locust bullet impact
//=============================================================================
// Killing Floor 2
// Copyright (C) 2022 Tripwire Interactive LLC
//=============================================================================
class KFDT_Toxic_HRG_Locust extends KFDT_Bleeding
abstract
hidedropdown;
// Damage dealt when zeds touch each other and spread the afflictions
var int SpreadOnTouchDamage;
static function int GetSpreadOnTouchDamage()
{
return default.SpreadOnTouchDamage;
}
defaultproperties
{
DoT_Type=DOT_Bleeding
DoT_Duration=3.0
DoT_Interval=0.5
DoT_DamageScale=0.5
BleedPower = 20
PoisonPower = 25
ModifierPerkList(0)=class'KFPerk_Survivalist'
WeaponDef=class'KFWeapDef_HRG_Locust'
SpreadOnTouchDamage=30
}

View File

@ -0,0 +1,27 @@
class KFGFXSpecialEventObjectivesContainer_Fall2022 extends KFGFxSpecialEventObjectivesContainer;
function Initialize(KFGFxObject_Menu NewParentMenu)
{
super.Initialize(NewParentMenu);
}
DefaultProperties
{
ObjectiveIconURLs[0] = "Halloween2022_UI.UI_Objectives_Halloween2022_CreaturesInDarkness" // Kill 15 Bosses on any map or mode
ObjectiveIconURLs[1] = "Spring_UI.UI_Objectives_Spring_Weekly" // Complete the Weekly on BarmwichTown
ObjectiveIconURLs[2] = "Halloween2022_UI.UI_Objetives_Halloween2022_ElementalMedallions" // Open the Weapon Room
ObjectiveIconURLs[3] = "Halloween2022_UI.UI_Objectives_Halloween2022_ZedOnFire" // Make 50 Zeds to pass through the bonfires of Barmwitch Town
ObjectiveIconURLs[4] = "Halloween2022_UI.UI_Objetives_Halloween2022_LongNightofWitches" // Complete wave 15 on Endless Hard or higher difficulty on Barmwitch Town
//defaults
AllCompleteRewardIconURL="CHR_PlagueDoctorUniform_Item_TEX.potionbackpack.plaguedoctorbackpack_precious_large"
ChanceDropIconURLs[0]="CHR_CosmeticSet14_Item_TEX.Tickets.CyberPunk_ticket"
ChanceDropIconURLs[1]="CHR_CosmeticSet14_Item_TEX.Tickets.CyberPunk_ticket_golden"
IconURL="halloween2022_ui.KF2_Halloween_BloodandBonfires_SmallLogo"
UsesProgressList[0] = true
UsesProgressList[1] = false
UsesProgressList[2] = false
UsesProgressList[3] = true
UsesProgressList[4] = false
}

View File

@ -0,0 +1,49 @@
//=============================================================================
// KFGFxWidget_VIP
//=============================================================================
// HUD Widget that displays VIP messages to the player
//=============================================================================
// Killing Floor 2
// Copyright (C) 2022 Tripwire Interactive LLC
//
//=============================================================================
class KFGFxWidget_VIP extends GFxObject;
function SetVIP()
{
SetString("VIPSetLocalised", Class'KFCommon_LocalizedStrings'.default.VIPString);
SetString("VIPObjectiveSetLocalised", Class'KFCommon_LocalizedStrings'.default.VIPObjectiveBString);
SetString("VIPPlayerSet", Class'KFCommon_LocalizedStrings'.default.VIPObjectiveCString);
SetBool("VIPPlayerNameSetVisibility", true);
SetBool("VIPHideHealthBar", true);
}
function SetNOVIP(string VIPPlayerName, int VIPCurrentHealth, int VIPMaxHealth)
{
SetString("VIPSetLocalised", Class'KFCommon_LocalizedStrings'.default.VIPString);
SetString("VIPObjectiveSetLocalised", Class'KFCommon_LocalizedStrings'.default.VIPObjectiveAString);
SetString("VIPPlayerSet", VIPPlayerName);
SetBool("VIPPlayerNameSetVisibility", true);
UpdateHealth(VIPCurrentHealth, VIPMaxHealth);
}
function UpdateVIPVisibility(bool visible)
{
if (visible)
{
SetBool("VIPSetVisibility", true);
}
else
{
SetBool("VIPSetVisibility", false);
}
}
function UpdateHealth(int VIPCurrentHealth, int VIPMaxHealth)
{
SetFloat("VIPHealthBarPercentage", VIPMaxHealth != 0 ? (float(VIPCurrentHealth) / VIPMaxHealth) : 0.0f);
}

View File

@ -0,0 +1,29 @@
//=============================================================================
// KFWeaponDefintion
//=============================================================================
// A lightweight container for basic weapon properties that can be safely
// accessed without a weapon actor (UI, remote clients).
//=============================================================================
// Killing Floor 2
// Copyright (C) 2022 Tripwire Interactive LLC
//=============================================================================
class KFWeapDef_G36C extends KFWeaponDefinition
abstract;
DefaultProperties
{
WeaponClassPath="KFGameContent.KFWeap_AssaultRifle_G36C"
BuyPrice=1600
AmmoPricePerMag=36
ImagePath="wep_ui_g36c_tex.UI_WeaponSelect_G36C"
EffectiveRange=70
UpgradePrice[0]=1500
UpgradeSellPrice[0]=1125
SharedUnlockId=SCU_G36C
}

View File

@ -0,0 +1,24 @@
//=============================================================================
// KFWeapDef_Dragonbreath
// This is the Doomstick
//=============================================================================
// Killing Floor 2
// Copyright (C) 2017 Tripwire Interactive LLC
//=============================================================================
class KFWeapDef_HRG_Dragonbreath extends KFWeaponDefinition
abstract;
DefaultProperties
{
WeaponClassPath="KFGameContent.KFWeap_HRG_Dragonbreath"
BuyPrice=1400
AmmoPricePerMag=25
ImagePath="WEP_UI_HRG_MegaDragonsbreath_TEX.UI_WeaponSelect_HRG_MegaDragonsbreath"
EffectiveRange=25
UpgradePrice[0]=1500
UpgradeSellPrice[0]=1125
}

View File

@ -0,0 +1,28 @@
//=============================================================================
// KFWeapDef_HRG_Locust
//=============================================================================
// A lightweight container for basic weapon properties that can be safely
// accessed without a weapon actor (UI, remote clients).
//=============================================================================
// Killing Floor 2
// Copyright (C) 2022 Tripwire Interactive LLC
//=============================================================================
class KFWeapDef_HRG_Locust extends KFWeaponDefinition
abstract;
DefaultProperties
{
WeaponClassPath="KFGameContent.KFWeap_HRG_Locust"
BuyPrice=900
AmmoPricePerMag=40
ImagePath="wep_ui_hrg_locust_tex.UI_WeaponSelect_HRG_Locust"
EffectiveRange=100
UpgradePrice[0]=700
UpgradePrice[1]=1500
UpgradeSellPrice[0]=525
UpgradeSellPrice[1]=1650
}

View File

@ -0,0 +1,26 @@
//=============================================================================
// KFWeapDef_Scythe
//=============================================================================
//=============================================================================
// Killing Floor 2
// Copyright (C) 2022 Tripwire Interactive LLC
//=============================================================================
class KFWeapDef_Scythe extends KFWeaponDefinition
abstract;
DefaultProperties
{
WeaponClassPath="KFGameContent.KFWeap_Edged_Scythe"
BuyPrice=1500
ImagePath="WEP_UI_Scythe_TEX.UI_WeaponSelect_Scythe"
EffectiveRange=5
UpgradePrice[0]=1500
UpgradeSellPrice[0]=1125
SharedUnlockId=SCU_Scythe
}

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

@ -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(DamageTaken, 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,23 @@
//=============================================================================
// KFDT_Piercing_ScytheStabFolded
//=============================================================================
// Killing Floor 2
// Copyright (C) 2022 Tripwire Interactive LLC
//=============================================================================
class KFDT_Piercing_ScytheStabFolded 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,22 @@
//=============================================================================
// KFExplosion_HRG_Locust
//=============================================================================
// Explosion actor class for HRG Locust
//=============================================================================
// Killing Floor 2
// Copyright (C) 2022 Tripwire Interactive LLC
//=============================================================================
class KFExplosion_HRG_Locust extends KFExplosionActorLingering;
DefaultProperties
{
Interval=0.5f
MaxTime=3.0
bOnlyDamagePawns=true
bDoFullDamage=false
LoopStartEvent=AkEvent'WW_WEP_HRG_Locust.Play_WEP_HRG_Locust_Insects'
LoopStopEvent=AkEvent'WW_WEP_HRG_Locust.Stop_WEP_HRG_Locust_Insect'
}

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=60
DamageRadius=200
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

@ -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,174 @@
//=============================================================================
// 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);
}
}
simulated function AttachLaserSight()
{
if( WorldInfo.NetMode == NM_DedicatedServer )
{
return;
}
super.AttachLaserSight();
if (LaserSight != none)
{
LaserSight.bForceDotToMatch = 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=50
minRecoilPitch=40
maxRecoilYaw=70
minRecoilYaw=-70
RecoilRate=0.085
RecoilMaxYawLimit=500
RecoilMinYawLimit=65035
RecoilMaxPitchLimit=900
RecoilMinPitchLimit=65035
RecoilISMaxYawLimit=100
RecoilISMinYawLimit=65460
RecoilISMaxPitchLimit=350
RecoilISMinPitchLimit=65460
IronSightMeshFOVCompensationScale=6.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

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

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_HRG_MegaDragonsbreath_TEX.UI_WeaponSelect_HRG_MegaDragonsbreath'
// 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]=60 //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

@ -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;
}