upload
This commit is contained in:
27
KFGameContent/Classes/KFDT_Ballistic_HRG_Boomy.uc
Normal file
27
KFGameContent/Classes/KFDT_Ballistic_HRG_Boomy.uc
Normal file
@ -0,0 +1,27 @@
|
||||
//=============================================================================
|
||||
// KFDT_Ballistic_HRG_Boomy
|
||||
//=============================================================================
|
||||
//
|
||||
//=============================================================================
|
||||
// Killing Floor 2
|
||||
// Copyright (C) 2021 Tripwire Interactive LLC
|
||||
//=============================================================================
|
||||
|
||||
class KFDT_Ballistic_HRG_Boomy extends KFDT_Ballistic_Submachinegun
|
||||
abstract
|
||||
hidedropdown;
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
KDamageImpulse=900
|
||||
KDeathUpKick=-300
|
||||
KDeathVel=100
|
||||
|
||||
StumblePower=35
|
||||
GunHitPower=25
|
||||
|
||||
WeaponDef=class'KFWeapDef_HRG_Boomy'
|
||||
|
||||
//Perk
|
||||
ModifierPerkList(0)=class'KFPerk_Demolitionist'
|
||||
}
|
29
KFGameContent/Classes/KFDT_Ballistic_HRG_Energy_Primary.uc
Normal file
29
KFGameContent/Classes/KFDT_Ballistic_HRG_Energy_Primary.uc
Normal file
@ -0,0 +1,29 @@
|
||||
//=============================================================================
|
||||
// KFDT_Ballistic_HRG_Energy_Primary
|
||||
//=============================================================================
|
||||
// HRG Energy Gun Damage Type
|
||||
//=============================================================================
|
||||
// Killing Floor 2
|
||||
// Copyright (C) 2021 Tripwire Interactive LLC
|
||||
//=============================================================================
|
||||
|
||||
class KFDT_Ballistic_HRG_Energy_Primary extends KFDT_Ballistic_Handgun
|
||||
abstract
|
||||
hidedropdown;
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
KDamageImpulse=900
|
||||
KDeathUpKick=-300
|
||||
KDeathVel=100
|
||||
|
||||
StumblePower=15
|
||||
GunHitPower=175
|
||||
|
||||
WeaponDef=class'KFWeapDef_HRG_Energy'
|
||||
|
||||
//Perk
|
||||
ModifierPerkList(0)=class'KFPerk_Gunslinger'
|
||||
|
||||
EffectGroup=FXG_Energy_Yellow
|
||||
}
|
28
KFGameContent/Classes/KFDT_Ballistic_HRG_Energy_Secondary.uc
Normal file
28
KFGameContent/Classes/KFDT_Ballistic_HRG_Energy_Secondary.uc
Normal file
@ -0,0 +1,28 @@
|
||||
//=============================================================================
|
||||
// KFDT_Ballistic_HRG_Energy_Secondary
|
||||
//=============================================================================
|
||||
//
|
||||
//=============================================================================
|
||||
// Killing Floor 2
|
||||
// Copyright (C) 2021 Tripwire Interactive LLC
|
||||
//=============================================================================
|
||||
|
||||
class KFDT_Ballistic_HRG_Energy_Secondary extends KFDT_Ballistic_Handgun
|
||||
abstract
|
||||
hidedropdown;
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
|
||||
StumblePower=100
|
||||
KnockdownPower=20
|
||||
GunHitPower=250
|
||||
EMPPower=60
|
||||
|
||||
WeaponDef=class'KFWeapDef_HRG_Energy'
|
||||
|
||||
//Perk
|
||||
ModifierPerkList(2)=class'KFPerk_Gunslinger'
|
||||
|
||||
EffectGroup=FXG_Energy_Magenta
|
||||
}
|
59
KFGameContent/Classes/KFDT_Ballistic_ParasiteImplanter.uc
Normal file
59
KFGameContent/Classes/KFDT_Ballistic_ParasiteImplanter.uc
Normal file
@ -0,0 +1,59 @@
|
||||
//=============================================================================
|
||||
// KFDT_Ballistic_ParasiteImplanter
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
// Killing Floor 2
|
||||
// Copyright (C) 2021 Tripwire Interactive LLC
|
||||
//=============================================================================
|
||||
|
||||
class KFDT_Ballistic_ParasiteImplanter extends KFDT_Ballistic_Rifle
|
||||
abstract
|
||||
hidedropdown;
|
||||
|
||||
/** Allows the damage type to customize exactly which hit zones it can dismember */
|
||||
static simulated function bool CanDismemberHitZone( name InHitZoneName )
|
||||
{
|
||||
if( super.CanDismemberHitZone( InHitZoneName ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
switch ( InHitZoneName )
|
||||
{
|
||||
case 'lupperarm':
|
||||
case 'rupperarm':
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Called when damage is dealt to apply additional damage type (e.g. Damage Over Time) */
|
||||
static function ApplySecondaryDamage( KFPawn Victim, int DamageTaken, optional Controller InstigatedBy )
|
||||
{
|
||||
local class<KFDamageType> ToxicDT;
|
||||
|
||||
ToxicDT = class'KFDT_Ballistic_Assault_Medic'.static.GetMedicToxicDmgType( DamageTaken, InstigatedBy );
|
||||
if ( ToxicDT != None )
|
||||
{
|
||||
Victim.ApplyDamageOverTime(DamageTaken, InstigatedBy, ToxicDT);
|
||||
}
|
||||
}
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
KDamageImpulse=2000
|
||||
KDeathUpKick=400
|
||||
KDeathVel=250
|
||||
|
||||
KnockdownPower=25
|
||||
//StunPower=20 //25
|
||||
StumblePower=80
|
||||
GunHitPower=160
|
||||
//MeleeHitPower=0
|
||||
|
||||
WeaponDef=class'KFWeapDef_ParasiteImplanter'
|
||||
|
||||
ModifierPerkList(0)=class'KFPerk_FieldMedic'
|
||||
ModifierPerkList(1)=class'KFPerk_Sharpshooter'
|
||||
}
|
36
KFGameContent/Classes/KFDT_Ballistic_ParasiteImplanterAlt.uc
Normal file
36
KFGameContent/Classes/KFDT_Ballistic_ParasiteImplanterAlt.uc
Normal file
@ -0,0 +1,36 @@
|
||||
//=============================================================================
|
||||
// KFDT_Ballistic_ParasiteImplanterAlt
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
// Killing Floor 2
|
||||
// Copyright (C) 2021 Tripwire Interactive LLC
|
||||
//=============================================================================
|
||||
|
||||
class KFDT_Ballistic_ParasiteImplanterAlt extends KFDT_Toxic
|
||||
abstract
|
||||
hidedropdown;
|
||||
|
||||
/** Called when damage is dealt to apply additional damage type (e.g. Damage Over Time) */
|
||||
static function ApplySecondaryDamage( KFPawn Victim, int DamageTaken, optional Controller InstigatedBy )
|
||||
{
|
||||
local class<KFDamageType> ToxicDT;
|
||||
|
||||
ToxicDT = class'KFDT_Ballistic_Assault_Medic'.static.GetMedicToxicDmgType( DamageTaken, InstigatedBy );
|
||||
if ( ToxicDT != None )
|
||||
{
|
||||
Victim.ApplyDamageOverTime(DamageTaken, InstigatedBy, ToxicDT);
|
||||
}
|
||||
}
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
KnockdownPower=30
|
||||
StumblePower=200
|
||||
GunHitPower=100
|
||||
PoisonPower=0 //80
|
||||
|
||||
WeaponDef=class'KFWeapDef_ParasiteImplanter'
|
||||
|
||||
ModifierPerkList(0)=class'KFPerk_FieldMedic'
|
||||
ModifierPerkList(1)=class'KFPerk_Sharpshooter'
|
||||
}
|
136
KFGameContent/Classes/KFDT_Bludgeon_BladedPistol.uc
Normal file
136
KFGameContent/Classes/KFDT_Bludgeon_BladedPistol.uc
Normal file
@ -0,0 +1,136 @@
|
||||
//=============================================================================
|
||||
// KFDT_Bludgeon_BladedPistol
|
||||
//=============================================================================
|
||||
// Killing Floor 2
|
||||
// Copyright (C) 2021 Tripwire Interactive LLC
|
||||
//=============================================================================
|
||||
|
||||
class KFDT_Bludgeon_BladedPistol extends KFDT_Slashing
|
||||
abstract
|
||||
hidedropdown;
|
||||
|
||||
/** Allows the damage type to customize exactly which hit zones it can dismember */
|
||||
static simulated function bool CanDismemberHitZone( name InHitZoneName )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Allows the damage type to map a hit zone to a different bone for dismemberment purposes */
|
||||
static simulated function GetBoneToDismember(KFPawn_Monster InPawn, vector HitDirection, name InHitZoneName, out name OutBoneName)
|
||||
{
|
||||
local EPawnOctant SlashDir;
|
||||
local KFCharacterInfo_Monster MonsterInfo;
|
||||
|
||||
MonsterInfo = InPawn.GetCharacterMonsterInfo();
|
||||
if ( MonsterInfo == none )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SlashDir = GetLastSlashDirection(InPawn, HitDirection);
|
||||
|
||||
if( SlashDir == DIR_Forward || SlashDir == DIR_Backward )
|
||||
{
|
||||
if( InHitZoneName == 'chest' || InHitZoneName == 'head' )
|
||||
{
|
||||
if( MonsterInfo.SpecialMeleeDismemberment.bAllowVerticalSplit )
|
||||
{
|
||||
// Randomly pick the left or right shoulder bone and split the guy in half vertically
|
||||
OutBoneName = Rand(2) == 0
|
||||
? MonsterInfo.SpecialMeleeDismemberment.LeftShoulderBoneName
|
||||
: MonsterInfo.SpecialMeleeDismemberment.RightShoulderBoneName;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( SlashDir == DIR_Left || SlashDir == DIR_Right )
|
||||
{
|
||||
if( InHitZoneName == 'chest' || InHitZoneName == 'abdomen' || InHitZoneName == 'stomach' )
|
||||
{
|
||||
if( MonsterInfo.SpecialMeleeDismemberment.bAllowHorizontalSplit )
|
||||
{
|
||||
// Split the guy in half horizontally
|
||||
OutBoneName = MonsterInfo.SpecialMeleeDismemberment.SpineBoneName;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( SlashDir == DIR_ForwardLeft || SlashDir == DIR_BackwardRight )
|
||||
{
|
||||
if( InHitZoneName == 'chest' )
|
||||
{
|
||||
if( MonsterInfo.SpecialMeleeDismemberment.bAllowVerticalSplit )
|
||||
{
|
||||
OutBoneName = MonsterInfo.SpecialMeleeDismemberment.RightShoulderBoneName;
|
||||
}
|
||||
}
|
||||
else if( InHitZoneName == 'head' )
|
||||
{
|
||||
if( MonsterInfo.SpecialMeleeDismemberment.bAllowVerticalSplit )
|
||||
{
|
||||
// Use a random chance to decide whether to dismember the head or the shoulder constraints
|
||||
if( Rand(2) == 0 )
|
||||
{
|
||||
// ... and choose one of the shoulder constraints at random
|
||||
OutBoneName = MonsterInfo.SpecialMeleeDismemberment.RightShoulderBoneName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( SlashDir == DIR_ForwardRight || SlashDir == DIR_BackwardLeft )
|
||||
{
|
||||
if( InHitZoneName == 'chest' )
|
||||
{
|
||||
if( MonsterInfo.SpecialMeleeDismemberment.bAllowVerticalSplit )
|
||||
{
|
||||
OutBoneName = MonsterInfo.SpecialMeleeDismemberment.LeftShoulderBoneName;
|
||||
}
|
||||
}
|
||||
else if( InHitZoneName == 'head' )
|
||||
{
|
||||
if( MonsterInfo.SpecialMeleeDismemberment.bAllowVerticalSplit )
|
||||
{
|
||||
// Use a random chance to decide whether to dismember the head or the shoulder constraints
|
||||
if( Rand(2) == 0 )
|
||||
{
|
||||
OutBoneName = MonsterInfo.SpecialMeleeDismemberment.LeftShoulderBoneName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Allows the damage type to modify the impulse when a specified hit zone is dismembered */
|
||||
static simulated function ModifyDismembermentHitImpulse(KFPawn_Monster InPawn, name InHitZoneName, vector HitDirection,
|
||||
out vector OutImpulseDir, out vector OutParentImpulseDir,
|
||||
out float OutImpulseScale, out float OutParentImpulseScale)
|
||||
{
|
||||
local EPawnOctant SlashDir;
|
||||
|
||||
SlashDir = GetLastSlashDirection(InPawn, HitDirection);
|
||||
|
||||
// Apply upward impulse on decapitation from a clean horizontal slash
|
||||
if( InHitZoneName == 'head' &&
|
||||
( SlashDir == DIR_Left || SlashDir == DIR_Right ) )
|
||||
{
|
||||
OutImpulseDir += 10*vect(0,0,1);
|
||||
OutImpulseDir = Normal(OutImpulseDir);
|
||||
OutParentImpulseScale = 0.f;
|
||||
}
|
||||
// Do not apply any impulse on split in half from a vertical slash
|
||||
else if( (InHitZoneName == 'head' || InHitZoneName == 'chest' ) &&
|
||||
( SlashDir == DIR_Forward || SlashDir == DIR_Backward) )
|
||||
{
|
||||
OutImpulseScale = 0.f;
|
||||
OutParentImpulseScale = 0.f;
|
||||
}
|
||||
}
|
||||
|
||||
DefaultProperties
|
||||
{
|
||||
StumblePower=200
|
||||
MeleeHitPower=100
|
||||
|
||||
WeaponDef=class'KFWeapDef_BladedPistol'
|
||||
|
||||
ModifierPerkList(0)=class'KFPerk_Berserker'
|
||||
ModifierPerkList(1)=class'KFPerk_Gunslinger'
|
||||
}
|
15
KFGameContent/Classes/KFDT_Bludgeon_HRG_Boomy.uc
Normal file
15
KFGameContent/Classes/KFDT_Bludgeon_HRG_Boomy.uc
Normal file
@ -0,0 +1,15 @@
|
||||
//=============================================================================
|
||||
// KFDT_Bludgeon_HRG_Boomy
|
||||
//=============================================================================
|
||||
// Killing Floor 2
|
||||
// Copyright (C) 2021 Tripwire Interactive LLC
|
||||
//=============================================================================
|
||||
|
||||
class KFDT_Bludgeon_HRG_Boomy extends KFDT_Bludgeon_RifleButt
|
||||
abstract
|
||||
hidedropdown;
|
||||
|
||||
DefaultProperties
|
||||
{
|
||||
WeaponDef=class'KFWeapDef_HRG_Boomy'
|
||||
}
|
16
KFGameContent/Classes/KFDT_Bludgeon_HRG_Energy.uc
Normal file
16
KFGameContent/Classes/KFDT_Bludgeon_HRG_Energy.uc
Normal file
@ -0,0 +1,16 @@
|
||||
//=============================================================================
|
||||
// KFDT_Bludgeon_HRG_Energy
|
||||
//=============================================================================
|
||||
// Killing Floor 2
|
||||
// Copyright (C) 2021 Tripwire Interactive LLC
|
||||
//=============================================================================
|
||||
|
||||
class KFDT_Bludgeon_HRG_Energy extends KFDT_Bludgeon_RifleButt
|
||||
abstract
|
||||
hidedropdown;
|
||||
|
||||
DefaultProperties
|
||||
{
|
||||
//defaults
|
||||
WeaponDef=class'KFWeapDef_HRG_Energy'
|
||||
}
|
16
KFGameContent/Classes/KFDT_Bludgeon_ParasiteImplanter.uc
Normal file
16
KFGameContent/Classes/KFDT_Bludgeon_ParasiteImplanter.uc
Normal file
@ -0,0 +1,16 @@
|
||||
//=============================================================================
|
||||
// KFDT_Bludgeon_ParasiteImplanter
|
||||
//=============================================================================
|
||||
// Killing Floor 2
|
||||
// Copyright (C) 2021 Tripwire Interactive LLC
|
||||
//=============================================================================
|
||||
|
||||
class KFDT_Bludgeon_ParasiteImplanter extends KFDT_Bludgeon_RifleButt
|
||||
abstract
|
||||
hidedropdown;
|
||||
|
||||
DefaultProperties
|
||||
{
|
||||
//defaults
|
||||
WeaponDef=class'KFWeapDef_ParasiteImplanter'
|
||||
}
|
30
KFGameContent/Classes/KFDT_Explosive_HRG_Boomy.uc
Normal file
30
KFGameContent/Classes/KFDT_Explosive_HRG_Boomy.uc
Normal file
@ -0,0 +1,30 @@
|
||||
//=============================================================================
|
||||
// KFDT_Explosive_GravityImploderWave
|
||||
//=============================================================================
|
||||
// Explosive damage type for the Gravity Imploder shockwave
|
||||
//=============================================================================
|
||||
// Killing Floor 2
|
||||
// Copyright (C) 2020 Tripwire Interactive LLC
|
||||
//=============================================================================
|
||||
|
||||
class KFDT_Explosive_HRG_Boomy extends KFDT_Explosive
|
||||
abstract
|
||||
hidedropdown;
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
bShouldSpawnPersistentBlood=true
|
||||
|
||||
// physics impact
|
||||
RadialDamageImpulse=3000 //5000 //20000
|
||||
GibImpulseScale=0.15
|
||||
KDeathUpKick=1000
|
||||
KDeathVel=300
|
||||
|
||||
KnockdownPower=7
|
||||
StumblePower=20
|
||||
|
||||
//Perk
|
||||
ModifierPerkList(0)=class'KFPerk_Demolitionist'
|
||||
WeaponDef=class'KFWeapDef_HRG_Boomy'
|
||||
}
|
16
KFGameContent/Classes/KFDT_Healing_ParasiteSeed.uc
Normal file
16
KFGameContent/Classes/KFDT_Healing_ParasiteSeed.uc
Normal file
@ -0,0 +1,16 @@
|
||||
//=============================================================================
|
||||
// KFDT_Healing_ParasiteSeed
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
// Killing Floor 2
|
||||
// Copyright (C) 2021 Tripwire Interactive LLC
|
||||
//=============================================================================
|
||||
|
||||
class KFDT_Healing_ParasiteSeed extends KFDT_Healing
|
||||
abstract
|
||||
hidedropdown;
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
bNoPain=true
|
||||
}
|
190
KFGameContent/Classes/KFDT_Slashing_BladedPistol.uc
Normal file
190
KFGameContent/Classes/KFDT_Slashing_BladedPistol.uc
Normal file
@ -0,0 +1,190 @@
|
||||
//=============================================================================
|
||||
// KFDT_Slashing_EvisceratorProj
|
||||
//=============================================================================
|
||||
// Damage type for projectiles fired from the Eviscerator
|
||||
//=============================================================================
|
||||
// Killing Floor 2
|
||||
// Copyright (C) 2015 Tripwire Interactive LLC
|
||||
// John "Ramm-Jaeger" Gibson
|
||||
//=============================================================================
|
||||
|
||||
class KFDT_Slashing_BladedPistol extends KFDT_Slashing
|
||||
abstract
|
||||
hidedropdown;
|
||||
|
||||
`define COSINE_0_DEGREES 1
|
||||
`define COSINE_20_DEGREES 0.94
|
||||
`define COSINE_70_DEGREES 0.34
|
||||
`define COSINE_90_DEGREES 0
|
||||
|
||||
/** Allows the damage type to customize exactly which hit zones it can dismember */
|
||||
static simulated function bool CanDismemberHitZone( name InHitZoneName )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @return The slast type from the HitFxInfo. This returns a 8-way slash info. */
|
||||
static simulated function EPawnOctant GetLastSlashDirection(KFPawn_Monster InPawn, vector HitDirection)
|
||||
{
|
||||
local vector SlashPlaneNormal;
|
||||
local rotator InstigatorRotation;
|
||||
local vector InstigatorFaceDir, InstigatorRightDir;
|
||||
local float UpDotSlash, RightDotSlash, UpThresholdValue;
|
||||
|
||||
if( InPawn != none )
|
||||
{
|
||||
HitDirection = Normal(HitDirection);
|
||||
InstigatorRotation = InPawn.GetBaseAimRotation();
|
||||
InstigatorFaceDir = GetRotatorAxis(InstigatorRotation, 0);
|
||||
InstigatorRightDir = GetRotatorAxis(InstigatorRotation, 1);
|
||||
|
||||
// Cross the face direction of the instigator with the hit direction to find
|
||||
// the normal to the "slashing" plane
|
||||
SlashPlaneNormal = Normal(InstigatorFaceDir Cross HitDirection);
|
||||
|
||||
// Dot the slash plane normal with the world up direction to figure out
|
||||
// the quadrant for the normal of the slash plane
|
||||
UpDotSlash = vect(0,0,1) Dot SlashPlaneNormal;
|
||||
UpThresholdValue = Abs(UpDotSlash);
|
||||
|
||||
// Dot the slash plane normal with the instigator right to figure out
|
||||
// the direction of the slash
|
||||
RightDotSlash = InstigatorRightDir Dot SlashPlaneNormal;
|
||||
|
||||
// Threshhold against the preset values to find out the type of slash. The sign (+ or -) of the
|
||||
// dot products are used to further classify the direction of the slash
|
||||
if( UpThresholdValue <= `COSINE_0_DEGREES && UpThresholdValue >= `COSINE_20_DEGREES )
|
||||
{
|
||||
if( UpDotSlash > 0 )
|
||||
return DIR_Right;
|
||||
else
|
||||
return DIR_Left;
|
||||
}
|
||||
else if( UpThresholdValue <= `COSINE_20_DEGREES && UpThresholdValue >= `COSINE_70_DEGREES )
|
||||
{
|
||||
if( UpDotSlash < 0 && RightDotSlash > 0 )
|
||||
return DIR_ForwardLeft;
|
||||
else if( UpDotSlash > 0 && RightDotSlash > 0 )
|
||||
return DIR_ForwardRight;
|
||||
else if( UpDotSlash > 0 && RightDotSlash < 0 )
|
||||
return DIR_BackwardRight;
|
||||
else if( UpDotSlash < 0 && RightDotSlash < 0 )
|
||||
return DIR_BackwardLeft;
|
||||
}
|
||||
else if( UpThresholdValue <= `COSINE_70_DEGREES && UpThresholdValue >= `COSINE_90_DEGREES )
|
||||
{
|
||||
if( RightDotSlash > 0 )
|
||||
return DIR_Forward;
|
||||
else
|
||||
return DIR_Backward;
|
||||
}
|
||||
}
|
||||
|
||||
return DIR_None;
|
||||
}
|
||||
|
||||
/** Allows the damage type to map a hit zone to a different bone for dismemberment purposes */
|
||||
static simulated function GetBoneToDismember(KFPawn_Monster InPawn, vector HitDirection, name InHitZoneName, out name OutBoneName)
|
||||
{
|
||||
local EPawnOctant SlashDir;
|
||||
local KFCharacterInfo_Monster MonsterInfo;
|
||||
|
||||
MonsterInfo = InPawn.GetCharacterMonsterInfo();
|
||||
if ( MonsterInfo == none )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SlashDir = GetLastSlashDirection(InPawn, HitDirection);
|
||||
|
||||
if( SlashDir == DIR_Forward || SlashDir == DIR_Backward )
|
||||
{
|
||||
if( InHitZoneName == 'chest' || InHitZoneName == 'head' )
|
||||
{
|
||||
if( MonsterInfo.SpecialMeleeDismemberment.bAllowVerticalSplit )
|
||||
{
|
||||
// Randomly pick the left or right shoulder bone and split the guy in half vertically
|
||||
OutBoneName = Rand(2) == 0
|
||||
? MonsterInfo.SpecialMeleeDismemberment.LeftShoulderBoneName
|
||||
: MonsterInfo.SpecialMeleeDismemberment.RightShoulderBoneName;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( SlashDir == DIR_Left || SlashDir == DIR_Right )
|
||||
{
|
||||
if( InHitZoneName == 'chest' || InHitZoneName == 'abdomen' || InHitZoneName == 'stomach')
|
||||
{
|
||||
if( MonsterInfo.SpecialMeleeDismemberment.bAllowHorizontalSplit )
|
||||
{
|
||||
// Split the guy in half horizontally
|
||||
OutBoneName = MonsterInfo.SpecialMeleeDismemberment.SpineBoneName;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( SlashDir == DIR_ForwardLeft || SlashDir == DIR_BackwardRight )
|
||||
{
|
||||
if( InHitZoneName == 'chest' )
|
||||
{
|
||||
if( MonsterInfo.SpecialMeleeDismemberment.bAllowVerticalSplit )
|
||||
{
|
||||
OutBoneName = MonsterInfo.SpecialMeleeDismemberment.RightShoulderBoneName;
|
||||
}
|
||||
}
|
||||
else if( InHitZoneName == 'head' )
|
||||
{
|
||||
if( MonsterInfo.SpecialMeleeDismemberment.bAllowVerticalSplit )
|
||||
{
|
||||
// Use a random chance to decide whether to dismember the head or the shoulder constraints
|
||||
if( Rand(2) == 0 )
|
||||
{
|
||||
// ... and choose one of the shoulder constraints at random
|
||||
OutBoneName = MonsterInfo.SpecialMeleeDismemberment.RightShoulderBoneName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( SlashDir == DIR_ForwardRight || SlashDir == DIR_BackwardLeft )
|
||||
{
|
||||
if( InHitZoneName == 'chest' )
|
||||
{
|
||||
if( MonsterInfo.SpecialMeleeDismemberment.bAllowVerticalSplit )
|
||||
{
|
||||
OutBoneName = MonsterInfo.SpecialMeleeDismemberment.LeftShoulderBoneName;
|
||||
}
|
||||
}
|
||||
else if( InHitZoneName == 'head' )
|
||||
{
|
||||
if( MonsterInfo.SpecialMeleeDismemberment.bAllowVerticalSplit )
|
||||
{
|
||||
// Use a random chance to decide whether to dismember the head or the shoulder constraints
|
||||
if( Rand(2) == 0 )
|
||||
{
|
||||
OutBoneName = MonsterInfo.SpecialMeleeDismemberment.LeftShoulderBoneName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
EffectGroup=FXG_Sawblade
|
||||
KDamageImpulse=1000
|
||||
KDeathUpKick=800
|
||||
KDeathVel=135
|
||||
|
||||
// Instigator damage can happen on owning client when projectile hits before Instigator is replicated and
|
||||
// (Other != Instigator) == FALSE. This problem is specific to the eviscerator projectile since it's a
|
||||
// replicated CSHD weapon, but it might make sense to have bNoInstigatorDamage=true on more weapons.
|
||||
bNoInstigatorDamage=true
|
||||
|
||||
//StunPower=0
|
||||
StumblePower=100
|
||||
GunHitPower=100
|
||||
//MeleeHitPower=100
|
||||
|
||||
WeaponDef=class'KFWeapDef_BladedPistol'
|
||||
|
||||
ModifierPerkList(0)=class'KFPerk_Berserker'
|
||||
ModifierPerkList(1)=class'KFPerk_Gunslinger'
|
||||
}
|
29
KFGameContent/Classes/KFDT_Toxic_ParasiteSeedExplosion.uc
Normal file
29
KFGameContent/Classes/KFDT_Toxic_ParasiteSeedExplosion.uc
Normal file
@ -0,0 +1,29 @@
|
||||
//=============================================================================
|
||||
// KFDT_Toxic_ParasiteSeedExplosion
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
// Killing Floor 2
|
||||
// Copyright (C) 2021 Tripwire Interactive LLC
|
||||
//=============================================================================
|
||||
|
||||
class KFDT_Toxic_ParasiteSeedExplosion extends KFDT_Toxic_MedicGrenade
|
||||
abstract
|
||||
hidedropdown;
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
DoT_Type=DOT_Toxic
|
||||
DoT_Duration=6.5 //3.0
|
||||
DoT_Interval=0.5
|
||||
DoT_DamageScale=0.1
|
||||
|
||||
KnockdownPower=30
|
||||
StumblePower=200
|
||||
GunHitPower=100
|
||||
PoisonPower=80.f
|
||||
|
||||
ModifierPerkList(0)=class'KFPerk_FieldMedic'
|
||||
ModifierPerkList(1)=class'KFPerk_SharpShooter'
|
||||
|
||||
WeaponDef=class'KFWeapDef_ParasiteImplanter'
|
||||
}
|
97
KFGameContent/Classes/KFExplosion_ParasiteSeed.uc
Normal file
97
KFGameContent/Classes/KFExplosion_ParasiteSeed.uc
Normal file
@ -0,0 +1,97 @@
|
||||
//=============================================================================
|
||||
// KFExplosion_ParasiteSeed
|
||||
//=============================================================================
|
||||
// Used by projectiles and kismet to spawn an explosion
|
||||
//=============================================================================
|
||||
// Killing Floor 2
|
||||
// Copyright (C) 2021 Tripwire Interactive LLC
|
||||
//=============================================================================
|
||||
|
||||
class KFExplosion_ParasiteSeed extends KFExplosion_MedicGrenade;
|
||||
|
||||
var transient bool FirstExplosion;
|
||||
|
||||
/**
|
||||
* Deal damage or heal players
|
||||
*/
|
||||
protected simulated function AffectsPawn(Pawn Victim, float DamageScale)
|
||||
{
|
||||
local KFPawn_Human HumanVictim;
|
||||
local KFPawn_Monster MonsterVictim;
|
||||
local KFProj_MedicGrenade OwnerProjectile;
|
||||
local bool bCanRepairArmor;
|
||||
local Box BBox;
|
||||
local vector BBoxCenter;
|
||||
local Actor HitActor;
|
||||
local bool bDamageBlocked;
|
||||
|
||||
if( Victim != none && Victim.IsAliveAndWell() )
|
||||
{
|
||||
MonsterVictim = KFPawn_Monster(Victim);
|
||||
if( MonsterVictim != none )
|
||||
{
|
||||
if(!FirstExplosion || bWasFadedOut|| bDeleteMe || bPendingDelete )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Victim.GetComponentsBoundingBox(BBox);
|
||||
BBoxCenter = (BBox.Min + BBox.Max) * 0.5f;
|
||||
HitActor = TraceExplosive(BBoxCenter, Location + vect(0, 0, 20));
|
||||
bDamageBlocked = (HitActor != None && HitActor != Victim);
|
||||
if(bDamageBlocked && HitActor.IsA('KFDoorActor'))
|
||||
{
|
||||
bDamageBlocked = false;
|
||||
}
|
||||
if( !bDamageBlocked )
|
||||
{
|
||||
Victim.TakeRadiusDamage(InstigatorController, ExplosionTemplate.Damage * DamageScale, ExplosionTemplate.DamageRadius,
|
||||
ExplosionTemplate.MyDamageType, ExplosionTemplate.MomentumTransferScale, Location, bDoFullDamage,
|
||||
(Owner != None) ? Owner : self, ExplosionTemplate.DamageFalloffExponent);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
HumanVictim = KFPawn_Human(Victim);
|
||||
if( HumanVictim != none && HumanVictim.GetExposureTo(Location) > 0 )
|
||||
{
|
||||
OwnerProjectile = KFProj_MedicGrenade(Owner);
|
||||
if( OwnerProjectile != none )
|
||||
{
|
||||
bCanRepairArmor = OwnerProjectile.HealedPawns.Find( HumanVictim ) == INDEX_NONE;
|
||||
}
|
||||
|
||||
HumanVictim.HealDamage(HealingAmount, InstigatorController, HealingDamageType, bCanRepairArmor);
|
||||
|
||||
if( bCanRepairArmor )
|
||||
{
|
||||
OwnerProjectile.HealedPawns.AddItem( HumanVictim );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
simulated function DelayedExplosionDamage()
|
||||
{
|
||||
FirstExplosion=false;
|
||||
super.DelayedExplosionDamage();
|
||||
}
|
||||
|
||||
DefaultProperties
|
||||
{
|
||||
FirstExplosion = true;
|
||||
|
||||
HealingDamageType=class'KFDT_Healing_ParasiteSeed'
|
||||
HealingAmount=5 //10
|
||||
Interval=0.5 //1
|
||||
MaxTime=5.5 //6.5 //8
|
||||
|
||||
bExplodeMoreThanOnce=false
|
||||
bDoFullDamage=false //true
|
||||
bSkipLineCheckForPawns=true
|
||||
|
||||
LoopingParticleEffect=ParticleSystem'WEP_3P_Medic_Grenade_EMIT.FX_Medic_Grenade_Explosion'
|
||||
LoopStartEvent=AkEvent'WW_WEP_Medic_GrenadeLauncher.Play_WEP_Medic_GrenadeLauncher_Grenade_Smoke_Loop'
|
||||
LoopStopEvent=AkEvent'WW_WEP_Medic_GrenadeLauncher.Stop_WEP_Medic_GrenadeLauncher_Grenade_Smoke_Loop'
|
||||
}
|
26
KFGameContent/Classes/KFExplosion_ParasiteSeedHuman.uc
Normal file
26
KFGameContent/Classes/KFExplosion_ParasiteSeedHuman.uc
Normal file
@ -0,0 +1,26 @@
|
||||
//=============================================================================
|
||||
// KFExplosion_ParasiteSeedHuman
|
||||
//=============================================================================
|
||||
// Explosion created when hitting a human
|
||||
//=============================================================================
|
||||
// Killing Floor 2
|
||||
// Copyright (C) 2021 Tripwire Interactive LLC
|
||||
//=============================================================================
|
||||
|
||||
class KFExplosion_ParasiteSeedHuman extends KFExplosion_MedicGrenade;
|
||||
|
||||
DefaultProperties
|
||||
{
|
||||
HealingDamageType=class'KFDT_Healing_ParasiteSeed'
|
||||
HealingAmount=30 //10
|
||||
Interval=1.0 //1
|
||||
MaxTime=0.5 //6.5 //8
|
||||
|
||||
bExplodeMoreThanOnce=false
|
||||
bDoFullDamage=false //true
|
||||
bSkipLineCheckForPawns=true
|
||||
|
||||
LoopingParticleEffect=ParticleSystem'WEP_3P_Medic_Grenade_EMIT.FX_Medic_Grenade_Explosion'
|
||||
LoopStartEvent=AkEvent'WW_WEP_Medic_GrenadeLauncher.Play_WEP_Medic_GrenadeLauncher_Grenade_Smoke_Loop'
|
||||
LoopStopEvent=AkEvent'WW_WEP_Medic_GrenadeLauncher.Stop_WEP_Medic_GrenadeLauncher_Grenade_Smoke_Loop'
|
||||
}
|
@ -235,16 +235,26 @@ protected function ScoreMonsterKill( Controller Killer, Controller Monster, KFPa
|
||||
|
||||
if(OutbreakEvent.ActiveEvent.bHealAfterKill)
|
||||
{
|
||||
if( MonsterPawn != none && MonsterPawn.DamageHistory.Length > 0 )
|
||||
{
|
||||
HealAfterKilling( MonsterPawn, Killer );
|
||||
if( MonsterPawn != none && MonsterPawn.DamageHistory.Length > 0 )
|
||||
{
|
||||
if(OutbreakEvent.ActiveEvent.bHealWithHeadshot)
|
||||
{
|
||||
if (MonsterPawn.LastHitZoneIndex == HZI_HEAD)
|
||||
{
|
||||
HealAfterKilling( MonsterPawn, Killer, false );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
HealAfterKilling( MonsterPawn, Killer );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Heal players after a Zed was killed, based in more heal to the player that was the killer and less heal to the players that damaged the Zed */
|
||||
function HealAfterKilling(KFPawn_Monster MonsterPawn , Controller Killer)
|
||||
function HealAfterKilling(KFPawn_Monster MonsterPawn , Controller Killer, optional bool bGivePowerUp = true)
|
||||
{
|
||||
local int i;
|
||||
local int j;
|
||||
@ -302,7 +312,7 @@ function HealAfterKilling(KFPawn_Monster MonsterPawn , Controller Killer)
|
||||
{
|
||||
PawnHuman.HealDamageForce(MonsterPawn.HealByKill, KFPC, class'KFDT_Healing', false, false );
|
||||
|
||||
if( KFPawn_ZedFleshpound(MonsterPawn) != none || KFPawn_ZedScrake(MonsterPawn) != none )
|
||||
if( bGivePowerUp && ( KFPawn_ZedFleshpound(MonsterPawn) != none || KFPawn_ZedScrake(MonsterPawn) != none ))
|
||||
{
|
||||
KFPC.ReceivePowerUp(class'KFPowerUp_HellishRage_NoCostHeal');
|
||||
}
|
||||
@ -322,6 +332,11 @@ function HealAfterKilling(KFPawn_Monster MonsterPawn , Controller Killer)
|
||||
function StartMatch()
|
||||
{
|
||||
super.StartMatch();
|
||||
|
||||
if (OutbreakEvent.ActiveEvent.bForceWWLMusic)
|
||||
{
|
||||
ForceWWLMusicTrack();
|
||||
}
|
||||
}
|
||||
|
||||
function CreateDifficultyInfo(string Options)
|
||||
|
@ -64,6 +64,7 @@ simulated function NotifyWaveStart()
|
||||
|
||||
DefaultProperties
|
||||
{
|
||||
bIsWeeklyMode=True
|
||||
BrokenTraderItemPickups={(
|
||||
(WeaponClasses={(
|
||||
class'KFGame.KFWeapDef_9mmDual',
|
||||
|
@ -518,6 +518,118 @@ defaultproperties
|
||||
)}
|
||||
|
||||
|
||||
//Wild West
|
||||
SetEvents[12]={(
|
||||
EventDifficulty=2,
|
||||
GameLength=GL_Normal,
|
||||
PerksAvailableList=(class'KFPerk_Gunslinger', class'KFPerk_Sharpshooter'),
|
||||
TraderWeaponList=KFGFxObject_TraderItems'GP_Trader_ARCH.WildWestWeeklyTraderList',
|
||||
bWildWestSkillConditionsActive=true,
|
||||
//bModifyZedTimeOnANearZedKill=true,
|
||||
DoshOnKillGlobalModifier=1.4,
|
||||
PickupResetTime=PRS_Wave,
|
||||
OverrideItemPickupModifier=0,
|
||||
OverrideAmmoPickupModifier=1,
|
||||
WaveAmmoPickupModifiers={(
|
||||
0.125, 0.175, 0.35, 0.525, 0.7, 0.875, 0.75, 0.99, 0.99
|
||||
)},
|
||||
SpawnRateMultiplier=0.75,
|
||||
WaveAICountScale=(0.75, 0.7, 0.7, 0.65, 0.65, 0.6),
|
||||
bHealAfterKill = true,
|
||||
bHealWithHeadshot = true,
|
||||
bForceWWLMusic = true,
|
||||
ZedsToAdjust={(
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedCrawler', HealByKill=1, HealByAssistance=0),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedCrawlerKing', HealByKill=5, HealByAssistance=0),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedClot_Cyst', HealByKill=1, HealByAssistance=0),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedClot_Alpha', HealByKill=1, HealByAssistance=0),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedClot_AlphaKing', HealByKill=10, HealByAssistance=0),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedClot_Slasher', HealByKill=1, HealByAssistance=0),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedSiren', HealByKill=10, HealByAssistance=0),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedStalker', HealByKill=2, HealByAssistance=0),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedGorefast', HealByKill=5, HealByAssistance=0),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedGorefastDualBlade', HealByKill=5, HealByAssistance=0),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedBloat', HealByKill=10, HealByAssistance=0),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedHusk', HealByKill=10, HealByAssistance=0),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedDAR_EMP', HealByKill=5, HealByAssistance=0),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedDAR_Laser', HealByKill=5, HealByAssistance=0),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedDAR_Rocket', HealByKill=5, HealByAssistance=0),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedScrake', HealByKill=20, HealByAssistance=0),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedFleshpound', HealByKill=20, HealByAssistance=0, HealthScale=0.8, DamageDealtScale=0.7),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedFleshpoundMini', HealByKill=15, HealByAssistance=0, HealthScale=0.8, DamageDealtScale=0.7),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedBloatKingSubspawn', HealByKill=2, HealByAssistance=0),
|
||||
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedMatriarch',HealthScale=0.8,DamageDealtScale=0.7),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedPatriarch',HealthScale=0.8,DamageDealtScale=0.7),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedHans',HealthScale=0.8,DamageDealtScale=0.7),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedFleshpoundKing',HealthScale=0.8,DamageDealtScale=0.7),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedBloatKing',HealthScale=0.8,DamageDealtScale=0.7)
|
||||
)},
|
||||
SpawnReplacementList={(
|
||||
(SpawnEntry=AT_FleshPound,NewClass=(class'KFGameContent.KFPawn_ZedScrake'),PercentChance=0.5),
|
||||
(SpawnEntry=AT_FleshpoundMini,NewClass=(class'KFGameContent.KFPawn_ZedGorefastDualBlade'),PercentChance=0.5)
|
||||
)}
|
||||
|
||||
)}
|
||||
|
||||
//Infernal Eternal
|
||||
SetEvents[13]={(
|
||||
EventDifficulty=3,
|
||||
GameLength=GL_Normal,
|
||||
SpawnRateMultiplier=3,
|
||||
WaveAICountScale=(1.3, 1.3, 1.3, 1.3, 1.3, 1.3),
|
||||
OverrideAmmoPickupModifier=1, // 1.2
|
||||
WaveAmmoPickupModifiers={(
|
||||
0.125, 0.15, 0.3, 0.45, 0.6, 0.75, 0.9, 0.99, 0.99
|
||||
)},
|
||||
bUseOverrideAmmoRespawnTime=true,
|
||||
OverrideAmmoRespawnTime={(
|
||||
PlayersMod[0]=25.000000,
|
||||
PlayersMod[1]=12.000000,
|
||||
PlayersMod[2]=8.000000,
|
||||
PlayersMod[3]=5.000000,
|
||||
PlayersMod[4]=4.000000,
|
||||
PlayersMod[5]=3.000000,
|
||||
ModCap=1.000000
|
||||
)},
|
||||
|
||||
ZedsToAdjust={(
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedMatriarch',HealthScale=2.0,DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedPatriarch',HealthScale=2.0,DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedHans',HealthScale=2.0,DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedFleshpoundKing',HealthScale=2.0,DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedBloatKing',HealthScale=2.0,DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
|
||||
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedClot_Cyst',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedClot_Alpha',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedClot_AlphaKing',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedClot_Slasher',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedSiren',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedStalker',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedCrawler',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedCrawlerKing',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedGorefast',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedGorefastDualBlade',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedBloat',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedHusk',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedDAR_EMP',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedDAR_Laser',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedDAR_Rocket',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedScrake',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedFleshpound',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedFleshpoundMini',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2),
|
||||
(ClassToAdjust=class'KFGameContent.KFPawn_ZedBloatKingSubspawn',bStartEnraged=true, DamageDealtScale=1.0, InitialGroundSpeedModifierScale=1.2)
|
||||
)},
|
||||
SpawnReplacementList={(
|
||||
(SpawnEntry=AT_Clot,NewClass=(class'KFGameContent.KFPawn_ZedClot_Alpha'),PercentChance=0.15),
|
||||
(SpawnEntry=AT_AlphaClot,NewClass=(class'KFGameContent.KFPawn_ZedClot_AlphaKing'),PercentChance=0.15),
|
||||
(SpawnEntry=AT_GoreFast,NewClass=(class'KFGameContent.KFPawn_ZedGorefastDualBlade'),PercentChance=0.15),
|
||||
(SpawnEntry=AT_Crawler,NewClass=(class'KFGameContent.KFPawn_ZedCrawlerKing'),PercentChance=0.15),
|
||||
(SpawnEntry=AT_Bloat,NewClass=(class'KFGameContent.KFPawn_ZedScrake'),PercentChance=0.05),
|
||||
(SpawnEntry=AT_FleshpoundMini,NewClass=(class'KFGameContent.KFPawn_ZedFleshpound'),PercentChance=0.05)
|
||||
)}
|
||||
)}
|
||||
|
||||
//Test events from here down. These don't end up in the regular rotation.
|
||||
// The override ID starts from one higher than the last SetEvents entry above.
|
||||
// Ex: Big head = 7, Horde = 8
|
||||
|
@ -98,4 +98,6 @@ DefaultProperties
|
||||
`if(`notdefined(ShippingPC))
|
||||
DebugRadarTexture=Texture2D'UI_ZEDRadar_TEX.MapIcon_Clot';
|
||||
`endif
|
||||
|
||||
ZEDCowboyHatAttachName=Hat_Attach
|
||||
}
|
||||
|
@ -88,4 +88,6 @@ DefaultProperties
|
||||
`if(`notdefined(ShippingPC))
|
||||
DebugRadarTexture=Texture2D'UI_ZEDRadar_TEX.MapIcon_Slasher';
|
||||
`endif
|
||||
|
||||
ZEDCowboyHatAttachName=Hat_Attach
|
||||
}
|
||||
|
@ -464,4 +464,6 @@ defaultproperties
|
||||
// ---------------------------------------------
|
||||
// Spawning
|
||||
MinSpawnSquadSizeType=EST_Crawler
|
||||
|
||||
ZEDCowboyHatAttachName=Hat_Attach
|
||||
}
|
||||
|
@ -431,4 +431,6 @@ defaultproperties
|
||||
StartSprintingSound=AkEvent'WW_ZED_Evil_DAR.Play_ZED_EvilDAR_SFX_Thruster_Start'
|
||||
SprintLoopingSound=AkEvent'WW_ZED_Evil_DAR.Play_ZED_EvilDAR_SFX_Thruster_LP'
|
||||
StopSprintingSound=AkEvent'WW_ZED_Evil_DAR.Play_ZED_EvilDAR_SFX_Thruster_Stop'
|
||||
|
||||
ZEDCowboyHatAttachName=Hat_Attach
|
||||
}
|
||||
|
@ -605,4 +605,6 @@ End Object
|
||||
MinSpawnSquadSizeType=EST_Large
|
||||
|
||||
OnDeathAchievementID=KFACHID_ItsOnlyAFleshWound
|
||||
|
||||
ZEDCowboyHatAttachName=Hat_Attach
|
||||
}
|
@ -72,4 +72,6 @@ defaultproperties
|
||||
IncapSettings(AF_Freeze)= (Vulnerability=(0.95), Cooldown=10.5, Duration=1.0)
|
||||
IncapSettings(AF_Snare)= (Vulnerability=(1.0, 2.0, 1.0, 1.0, 2.0), Cooldown=8.5, Duration=5.0)
|
||||
IncapSettings(AF_Bleed)= (Vulnerability=(0.75))
|
||||
|
||||
ZEDCowboyHatAttachName=HEAD_Attach
|
||||
}
|
@ -657,4 +657,6 @@ DefaultProperties
|
||||
// ---------------------------------------------
|
||||
// Spawning
|
||||
MinSpawnSquadSizeType=EST_Medium
|
||||
|
||||
ZEDCowboyHatAttachName=Hat_Attach
|
||||
}
|
||||
|
@ -2012,4 +2012,6 @@ defaultproperties
|
||||
// Gun tracking
|
||||
bUseServerSideGunTracking=true
|
||||
GunTargetBoneName=Spine2
|
||||
|
||||
ZEDCowboyHatAttachName=Hat_Attach
|
||||
}
|
@ -391,4 +391,6 @@ defaultproperties
|
||||
MinSpawnSquadSizeType=EST_Large
|
||||
|
||||
OnDeathAchievementID=KFACHID_HackAndSlash
|
||||
|
||||
ZEDCowboyHatAttachName=Hat_Attach
|
||||
}
|
||||
|
@ -250,4 +250,6 @@ defaultproperties
|
||||
`endif
|
||||
|
||||
OnDeathAchievementID=KFACHID_DeadSilence
|
||||
|
||||
ZEDCowboyHatAttachName=Hat_Attach
|
||||
}
|
||||
|
79
KFGameContent/Classes/KFProj_Blade_BladedPistol.uc
Normal file
79
KFGameContent/Classes/KFProj_Blade_BladedPistol.uc
Normal file
@ -0,0 +1,79 @@
|
||||
//=============================================================================
|
||||
// KFProj_Blade_BladedPistol
|
||||
//=============================================================================
|
||||
// Blade class for the BladedPistol
|
||||
//=============================================================================
|
||||
// Killing Floor 2
|
||||
// Copyright (C) 2021 Tripwire Interactive LLC
|
||||
//=============================================================================
|
||||
|
||||
class KFProj_Blade_BladedPistol extends KFProj_RicochetStickBullet
|
||||
hidedropdown;
|
||||
|
||||
// Make sure that last location always exists.
|
||||
simulated event PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
|
||||
LastLocation = Location;
|
||||
}
|
||||
|
||||
simulated function bool ShouldProcessBulletTouch()
|
||||
{
|
||||
return BouncesLeft > 0 && GravityScale == default.GravityScale;
|
||||
}
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
MaxSpeed=4000.0 //2500.0
|
||||
Speed=4000.0 //2500.0
|
||||
GravityScale=0.8 //0.75
|
||||
|
||||
DamageRadius=0
|
||||
|
||||
bWarnAIWhenFired=true
|
||||
|
||||
BouncesLeft=2
|
||||
DampingFactor=0.8 //0.95
|
||||
RicochetEffects=KFImpactEffectInfo'WEP_BladedPistol_ARCH.BladedImpacts'
|
||||
LifeSpan=8
|
||||
LifeSpanAfterStick=180
|
||||
|
||||
Begin Object Name=CollisionCylinder
|
||||
CollisionRadius=6
|
||||
CollisionHeight=2
|
||||
End Object
|
||||
|
||||
// Additional zero-extent line traces
|
||||
//ExtraLineCollisionOffsets.Add((Y=-8))
|
||||
//ExtraLineCollisionOffsets.Add((Y=8))
|
||||
ExtraLineCollisionOffsets.Add((Y=-16))
|
||||
ExtraLineCollisionOffsets.Add((Y=16))
|
||||
ExtraLineCollisionOffsets.Add((Z=-6))
|
||||
ExtraLineCollisionOffsets.Add((Z=6))
|
||||
// Since we're still using an extent cylinder, we need a line at 0
|
||||
ExtraLineCollisionOffsets.Add(())
|
||||
|
||||
bAmbientSoundZedTimeOnly=false
|
||||
bNoReplicationToInstigator=false
|
||||
bUseClientSideHitDetection=true
|
||||
bUpdateSimulatedPosition=true
|
||||
bRotationFollowsVelocity=false
|
||||
bNetTemporary=False
|
||||
|
||||
|
||||
ProjFlightTemplate=ParticleSystem'WEP_BladedPistol_EMIT.FX_bladed_projectile_01'
|
||||
ProjFlightTemplateZedTime=ParticleSystem'WEP_BladedPistol_EMIT.FX_bladed_projectile_01'
|
||||
|
||||
ImpactEffects=KFImpactEffectInfo'WEP_BladedPistol_ARCH.BladedEmbedFX'
|
||||
|
||||
AmbientSoundPlayEvent=AkEvent'WW_WEP_BladedPistol.Play_WEP_BladedPistol_Projectile_Loop'
|
||||
AmbientSoundStopEvent=AkEvent'WW_WEP_BladedPistol.Stop_WEP_BladedPistol_Projectile_Loop'
|
||||
|
||||
PickupRadius=250 //200
|
||||
WeaponClassName=KFWeap_Pistol_Bladed
|
||||
ProjPickupTemplate=ParticleSystem'WEP_BladedPistol_EMIT.FX_bladed_pickup_01'
|
||||
AmmoPickupSound=AkEvent'WW_WEP_BladedPistol.Play_WEP_BladedPistol_Projectile_Pickup'
|
||||
|
||||
TouchTimeThreshhold=0.15
|
||||
}
|
79
KFGameContent/Classes/KFProj_Bullet_HRG_Boomy.uc
Normal file
79
KFGameContent/Classes/KFProj_Bullet_HRG_Boomy.uc
Normal file
@ -0,0 +1,79 @@
|
||||
//=============================================================================
|
||||
// KFProj_Bullet_HRG_Boomy
|
||||
//=============================================================================
|
||||
// Class Description
|
||||
//=============================================================================
|
||||
// Killing Floor 2
|
||||
// Copyright (C) 2021 Tripwire Interactive LLC
|
||||
//=============================================================================
|
||||
|
||||
class KFProj_Bullet_HRG_Boomy extends KFProj_BallisticExplosive
|
||||
hidedropdown;
|
||||
|
||||
simulated protected function PrepareExplosionTemplate()
|
||||
{
|
||||
super.PrepareExplosionTemplate();
|
||||
|
||||
/** Since bIgnoreInstigator is transient, its value must be defined here */
|
||||
ExplosionTemplate.bIgnoreInstigator = true;
|
||||
}
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
MaxSpeed=22500.0
|
||||
Speed=22500.0
|
||||
|
||||
DamageRadius=0
|
||||
|
||||
ProjDisintegrateTemplate=ParticleSystem'ZED_Siren_EMIT.FX_Siren_grenade_disable_01'
|
||||
// ProjFlightTemplate=ParticleSystem'WEP_HRG_Boomy_EMIT.FX_Boomy_Tracer_ZEDTime'
|
||||
ProjFlightTemplateZedTime=ParticleSystem'WEP_HRG_Boomy_EMIT.FX_Boomy_Tracer_ZEDTime'
|
||||
|
||||
// Grenade explosion light
|
||||
Begin Object Class=PointLightComponent Name=ExplosionPointLight
|
||||
LightColor=(R=252,G=218,B=171,A=255)
|
||||
Brightness=0.5f
|
||||
Radius=400.f
|
||||
FalloffExponent=10.f
|
||||
CastShadows=False
|
||||
CastStaticShadows=FALSE
|
||||
CastDynamicShadows=False
|
||||
bCastPerObjectShadows=false
|
||||
bEnabled=FALSE
|
||||
LightingChannels=(Indoor=TRUE,Outdoor=TRUE,bInitialized=TRUE)
|
||||
End Object
|
||||
|
||||
// explosion
|
||||
Begin Object Class=KFGameExplosion Name=ExploTemplate0
|
||||
Damage=35 //30
|
||||
DamageRadius=150 //120
|
||||
DamageFalloffExponent=1.f
|
||||
DamageDelay=0.f
|
||||
MomentumTransferScale=10000
|
||||
|
||||
// Damage Effects
|
||||
MyDamageType=class'KFDT_Explosive_HRG_Boomy'
|
||||
KnockDownStrength=150
|
||||
FractureMeshRadius=200.0
|
||||
FracturePartVel=500.0
|
||||
|
||||
ExplosionSound=AkEvent'ww_wep_hrg_boomy.Play_WEP_HRG_Boomy_ProjExplosion'
|
||||
ExplosionEffects=KFImpactEffectInfo'WEP_HRG_Boomy_ARCH.WEB_HRG_Boomy_Impacts'
|
||||
|
||||
// Dynamic Light
|
||||
ExploLight=ExplosionPointLight
|
||||
ExploLightStartFadeOutTime=0.0
|
||||
ExploLightFadeOutTime=0.3
|
||||
|
||||
bIgnoreInstigator=true
|
||||
|
||||
// Camera Shake
|
||||
CamShake=CameraShake'FX_CameraShake_Arch.Misc_Explosions.Light_Explosion_Rumble'
|
||||
CamShakeInnerRadius=0
|
||||
CamShakeOuterRadius=300
|
||||
CamShakeFalloff=1.5f
|
||||
bOrientCameraShakeTowardsEpicenter=true
|
||||
End Object
|
||||
ExplosionTemplate=ExploTemplate0
|
||||
}
|
||||
|
23
KFGameContent/Classes/KFProj_Bullet_HRG_Energy.uc
Normal file
23
KFGameContent/Classes/KFProj_Bullet_HRG_Energy.uc
Normal file
@ -0,0 +1,23 @@
|
||||
//=============================================================================
|
||||
// KFProj_Bullet_HRG_Energy
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
// Killing Floor 2
|
||||
// Copyright (C) 2021 Tripwire Interactive LLC
|
||||
//=============================================================================
|
||||
|
||||
class KFProj_Bullet_HRG_Energy extends KFProj_Bullet
|
||||
hidedropdown;
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
MaxSpeed=15000.0
|
||||
Speed=15000.0
|
||||
|
||||
DamageRadius=0
|
||||
|
||||
ProjFlightTemplateZedTime=ParticleSystem'WEP_HRG_Energy_EMIT.FX_Energy_Tracer_Instant'
|
||||
ImpactEffects = KFImpactEffectInfo'WEP_HRG_Energy_ARCH.Wep_HRG_Energy_Impact'
|
||||
|
||||
}
|
||||
|
21
KFGameContent/Classes/KFProj_Bullet_HRG_Energy_Secondary.uc
Normal file
21
KFGameContent/Classes/KFProj_Bullet_HRG_Energy_Secondary.uc
Normal file
@ -0,0 +1,21 @@
|
||||
//=============================================================================
|
||||
// KFProj_Bullet_HRG_Energy_Secondary
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
// Killing Floor 2
|
||||
// Copyright (C) 2021 Tripwire Interactive LLC
|
||||
//=============================================================================
|
||||
|
||||
class KFProj_Bullet_HRG_Energy_Secondary extends KFProj_Bullet;
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
MaxSpeed=7500.0
|
||||
Speed=7500.0
|
||||
|
||||
DamageRadius=0
|
||||
|
||||
ProjFlightTemplateZedTime=ParticleSystem'WEP_HRG_Energy_EMIT.FX_Energy_Alt_Tracer_Instant'
|
||||
ImpactEffects = KFImpactEffectInfo'WEP_HRG_Energy_ARCH.Wep_HRG_Energy_Impact_Alt'
|
||||
|
||||
}
|
22
KFGameContent/Classes/KFProj_Bullet_ParasiteImplanter.uc
Normal file
22
KFGameContent/Classes/KFProj_Bullet_ParasiteImplanter.uc
Normal file
@ -0,0 +1,22 @@
|
||||
//=============================================================================
|
||||
// KFProj_Bullet_ParasiteImplanter
|
||||
//=============================================================================
|
||||
// Bullet class for the Parasite Implanter
|
||||
//=============================================================================
|
||||
// Killing Floor 2
|
||||
// Copyright (C) 2021 Tripwire Interactive LLC
|
||||
//=============================================================================
|
||||
|
||||
class KFProj_Bullet_ParasiteImplanter extends KFProj_Bullet
|
||||
hidedropdown;
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
MaxSpeed=24000.0
|
||||
Speed=24000.0
|
||||
|
||||
DamageRadius=0
|
||||
|
||||
ProjFlightTemplate=ParticleSystem'WEP_1P_L85A2_EMIT.FX_L85A2_Tracer_ZEDTime'
|
||||
}
|
||||
|
382
KFGameContent/Classes/KFProj_Bullet_ParasiteImplanterAlt.uc
Normal file
382
KFGameContent/Classes/KFProj_Bullet_ParasiteImplanterAlt.uc
Normal file
@ -0,0 +1,382 @@
|
||||
//=============================================================================
|
||||
// KFProj_Bullet_ParasiteImplanterAlt
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
// Killing Floor 2
|
||||
// Copyright (C) 2021 Tripwire Interactive LLC
|
||||
//=============================================================================
|
||||
|
||||
class KFProj_Bullet_ParasiteImplanterAlt extends KFProjectile;
|
||||
|
||||
var float FuseTime;
|
||||
|
||||
/** This is the effect indicator that is played for the current user **/
|
||||
var(Projectile) ParticleSystem ProjIndicatorTemplate;
|
||||
var ParticleSystemComponent ProjIndicatorEffects;
|
||||
|
||||
var bool IndicatorActive;
|
||||
var transient bool bShouldEnableIndicator;
|
||||
|
||||
var Class<GameExplosionActor> HumanExplosionActorClass;
|
||||
var KFGameExplosion HumanExplosionTemplate;
|
||||
|
||||
var private AKEvent SeedTimerOutEvent;
|
||||
|
||||
simulated function TryActivateIndicator()
|
||||
{
|
||||
if(!IndicatorActive && Instigator != None)
|
||||
{
|
||||
IndicatorActive = true;
|
||||
|
||||
if(WorldInfo.NetMode == NM_Standalone || Instigator.Role == Role_AutonomousProxy ||
|
||||
(Instigator.Role == ROLE_Authority && WorldInfo.NetMode == NM_ListenServer && Instigator.IsLocallyControlled() ))
|
||||
{
|
||||
if( ProjIndicatorTemplate != None )
|
||||
{
|
||||
ProjIndicatorEffects = WorldInfo.MyEmitterPool.SpawnEmitterCustomLifetime(ProjIndicatorTemplate);
|
||||
}
|
||||
|
||||
if(ProjIndicatorEffects != None)
|
||||
{
|
||||
ProjIndicatorEffects.SetAbsolute(false, false, false);
|
||||
ProjIndicatorEffects.SetLODLevel(WorldInfo.bDropDetail ? 1 : 0);
|
||||
ProjIndicatorEffects.bUpdateComponentInTick = true;
|
||||
AttachComponent(ProjIndicatorEffects);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the initial velocity and cook time
|
||||
*/
|
||||
simulated event PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
|
||||
if (Role == ROLE_Authority)
|
||||
{
|
||||
SetTimer(FuseTime, false, 'Timer_Detonate');
|
||||
}
|
||||
|
||||
AdjustCanDisintigrate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Explode after a certain amount of time
|
||||
*/
|
||||
function Timer_Detonate()
|
||||
{
|
||||
Detonate();
|
||||
}
|
||||
|
||||
/** Called when the owning instigator controller has left a game */
|
||||
simulated function OnInstigatorControllerLeft()
|
||||
{
|
||||
if( WorldInfo.NetMode != NM_Client )
|
||||
{
|
||||
SetTimer( 1.f + Rand(5) + fRand(), false, nameOf(Timer_Detonate) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trace down and get the location to spawn the explosion effects and decal
|
||||
*/
|
||||
simulated function GetExplodeEffectLocation(out vector HitLocation, out vector HitRotation, out Actor HitActor)
|
||||
{
|
||||
local vector EffectStartTrace, EffectEndTrace;
|
||||
local TraceHitInfo HitInfo;
|
||||
|
||||
EffectStartTrace = Location + vect(0,0,1) * 4.f;
|
||||
EffectEndTrace = EffectStartTrace - vect(0,0,1) * 32.f;
|
||||
|
||||
// Find where to put the decal
|
||||
HitActor = Trace(HitLocation, HitRotation, EffectEndTrace, EffectStartTrace, false,, HitInfo, TRACEFLAG_Bullet);
|
||||
|
||||
// If the locations are zero (probably because this exploded in the air) set defaults
|
||||
if (IsZero(HitLocation))
|
||||
{
|
||||
HitLocation = Location;
|
||||
}
|
||||
|
||||
if (IsZero(HitRotation))
|
||||
{
|
||||
HitRotation = vect(0,0,1);
|
||||
}
|
||||
}
|
||||
|
||||
/** Used to check current status of StuckTo actor (to figure out if we should fall) */
|
||||
simulated event Tick(float DeltaTime)
|
||||
{
|
||||
super.Tick(DeltaTime);
|
||||
|
||||
StickHelper.Tick(DeltaTime);
|
||||
|
||||
if (!IsZero(Velocity))
|
||||
{
|
||||
SetRelativeRotation(rotator(Velocity));
|
||||
}
|
||||
|
||||
if (bShouldEnableIndicator)
|
||||
{
|
||||
TryActivateIndicator();
|
||||
}
|
||||
}
|
||||
|
||||
simulated function Explode(vector HitLocation, vector HitNormal)
|
||||
{
|
||||
StickHelper.UnPin();
|
||||
super.Explode(HitLocation, HitNormal);
|
||||
}
|
||||
|
||||
simulated function SyncOriginalLocation()
|
||||
{
|
||||
local Actor HitActor;
|
||||
local vector HitLocation, HitNormal;
|
||||
local TraceHitInfo HitInfo;
|
||||
|
||||
if (Role < ROLE_Authority && Instigator != none && Instigator.IsLocallyControlled())
|
||||
{
|
||||
HitActor = Trace(HitLocation, HitNormal, OriginalLocation, Location,,, HitInfo, TRACEFLAG_Bullet);
|
||||
if (HitActor != none)
|
||||
{
|
||||
StickHelper.TryStick(HitNormal, HitLocation, HitActor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
simulated protected function StopSimulating()
|
||||
{
|
||||
super.StopSimulating();
|
||||
|
||||
if (ProjIndicatorEffects!=None)
|
||||
{
|
||||
ProjIndicatorEffects.DeactivateSystem();
|
||||
}
|
||||
}
|
||||
|
||||
/** Causes charge to explode */
|
||||
function Detonate()
|
||||
{
|
||||
local KFPawn_Monster KFPM;
|
||||
//@Todo: Some VFX?
|
||||
if (StuckToActor != none)
|
||||
{
|
||||
KFPM = KFPawn_Monster(StuckToActor);
|
||||
if (KFPM != none)
|
||||
{
|
||||
KFPM.ParasiteSeeds.RemoveItem(self);
|
||||
}
|
||||
}
|
||||
|
||||
StickHelper.UnPin();
|
||||
ShutDown();
|
||||
}
|
||||
|
||||
simulated function OnActorSticked(Actor TargetActor)
|
||||
{
|
||||
local KFPawn_Monster KFPM;
|
||||
|
||||
KFPM = KFPawn_Monster(TargetActor);
|
||||
if (KFPM != none)
|
||||
{
|
||||
if (Role == ROLE_Authority)
|
||||
{
|
||||
KFPM.AddParasiteSeed(self);
|
||||
PlaySoundBase(SeedTimerOutEvent, false, false);
|
||||
}
|
||||
|
||||
if (WorldInfo.NetMode == NM_Client || WorldInfo.NetMode == NM_StandAlone)
|
||||
{
|
||||
bShouldEnableIndicator = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
simulated function ExplodeOnHuman(Vector HitLocation, Vector HitNormal, Actor HitActor)
|
||||
{
|
||||
local vector NudgedHitLocation, ExplosionDirection;
|
||||
|
||||
if (HumanExplosionTemplate != None)
|
||||
{
|
||||
StopSimulating();
|
||||
|
||||
// using a hit location slightly away from the impact point is nice for certain things
|
||||
NudgedHitLocation = HitLocation + (HitNormal * 32.f);
|
||||
|
||||
ExplosionActor = Spawn(HumanExplosionActorClass, self,, NudgedHitLocation, rotator(HitNormal));
|
||||
if (ExplosionActor != None)
|
||||
{
|
||||
ExplosionActor.Instigator = Instigator;
|
||||
ExplosionActor.InstigatorController = InstigatorController;
|
||||
|
||||
PrepareExplosionTemplate();
|
||||
|
||||
// If the locations are zero (probably because this exploded in the air) set defaults
|
||||
if( IsZero(HitLocation) )
|
||||
{
|
||||
HitLocation = Location;
|
||||
}
|
||||
|
||||
if( IsZero(HitNormal) )
|
||||
{
|
||||
HitNormal = vect(0,0,1);
|
||||
}
|
||||
|
||||
// these are needed for the decal tracing later in GameExplosionActor.Explode()
|
||||
HumanExplosionTemplate.HitLocation = HitLocation;// NudgedHitLocation
|
||||
HumanExplosionTemplate.HitNormal = HitNormal;
|
||||
|
||||
// If desired, attach to mover if we hit one
|
||||
if(bAttachExplosionToHitMover && InterpActor(HitActor) != None)
|
||||
{
|
||||
ExplosionActor.Attachee = HitActor;
|
||||
HumanExplosionTemplate.bAttachExplosionEmitterToAttachee = TRUE;
|
||||
ExplosionActor.SetBase(HitActor);
|
||||
}
|
||||
|
||||
// directional?
|
||||
if (HumanExplosionTemplate.bDirectionalExplosion)
|
||||
{
|
||||
ExplosionDirection = GetExplosionDirection(HitNormal);
|
||||
//DrawDebugLine(ExplosionActor.Location, ExplosionActor.Location+ExplosionDirection*64, 255, 255, 0, TRUE);
|
||||
}
|
||||
|
||||
// @todo: make this function responsible for setting explosion instance parameters, and take instance parameters
|
||||
// out of GearExplosion (e.g. Attachee)
|
||||
PrepareExplosionActor(ExplosionActor);
|
||||
|
||||
ExplosionActor.Explode(HumanExplosionTemplate, ExplosionDirection); // go bewm
|
||||
}
|
||||
|
||||
// done with it
|
||||
if (!bPendingDelete && !bDeleteMe)
|
||||
{
|
||||
// defer destruction so any replication of explosion stuff can happen if necessary
|
||||
DeferredDestroy(PostExplosionLifetime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
simulated function ProcessTouch(Actor Other, Vector HitLocation, Vector HitNormal)
|
||||
{
|
||||
if (KFPawn_Human(Other) != none && Other != Instigator)
|
||||
{
|
||||
ExplodeOnHuman(HitLocation, HitNormal, Other);
|
||||
}
|
||||
else
|
||||
{
|
||||
super.ProcessTouch(Other, HitLocation, HitNormal);
|
||||
}
|
||||
}
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
ProjFlightTemplate=ParticleSystem'WEP_ParasiteImplanter_EMIT.FX_Seed_Projectile'
|
||||
ProjIndicatorTemplate=ParticleSystem'WEP_ParasiteImplanter_EMIT.FX_Seed_Projectile_Indicator'
|
||||
|
||||
bWarnAIWhenFired=true
|
||||
|
||||
MaxSpeed=15000.0 //10000.0 //4000.0
|
||||
Speed=15000.0 //10000.0 //4000.0
|
||||
TerminalVelocity=15000.0 //10000.0 //4000.0
|
||||
|
||||
Physics=PHYS_Falling
|
||||
|
||||
TossZ=0 //150
|
||||
GravityScale=0 //0.01 //0.7
|
||||
|
||||
GlassShatterType=FMGS_ShatterAll
|
||||
|
||||
bCollideComplex=true
|
||||
|
||||
bIgnoreFoliageTouch=true
|
||||
|
||||
bBlockedByInstigator=false
|
||||
bAlwaysReplicateExplosion=true
|
||||
|
||||
FuseTime=6.0 //4.0
|
||||
|
||||
bNetTemporary=false
|
||||
NetPriority=5
|
||||
NetUpdateFrequency=200
|
||||
|
||||
bNoReplicationToInstigator=false
|
||||
bUseClientSideHitDetection=true
|
||||
bUpdateSimulatedPosition=true
|
||||
bSyncToOriginalLocation=true
|
||||
bSyncToThirdPersonMuzzleLocation=true
|
||||
|
||||
PinBoneIdx=INDEX_None
|
||||
|
||||
bCanBeDamaged=true
|
||||
bCanDisintegrate=true
|
||||
ExplosionActorClass=class'KFExplosion_ParasiteSeed'
|
||||
HumanExplosionActorClass=class'KFExplosion_ParasiteSeedHuman'
|
||||
|
||||
// explosion
|
||||
Begin Object Class=KFGameExplosion Name=ExploTemplate0
|
||||
Damage=400 //250
|
||||
DamageRadius=450
|
||||
DamageFalloffExponent=0.5f //1.f
|
||||
DamageDelay=0.f
|
||||
MyDamageType=class'KFDT_Toxic_ParasiteSeedExplosion'
|
||||
|
||||
// Damage Effects
|
||||
KnockDownStrength=0
|
||||
KnockDownRadius=0
|
||||
FractureMeshRadius=0
|
||||
FracturePartVel=0
|
||||
// ExplosionEffects=KFImpactEffectInfo'FX_Impacts_ARCH.Explosions.MedicGrenade_Explosion'
|
||||
ExplosionSound=AkEvent'WW_WEP_Medic_GrenadeLauncher.Play_WEP_Medic_GrenadeLauncher_Grenade_Explosion'
|
||||
MomentumTransferScale=0
|
||||
|
||||
// Camera Shake
|
||||
CamShake=none
|
||||
CamShakeInnerRadius=0
|
||||
CamShakeOuterRadius=0
|
||||
CamShakeFalloff=1.5f
|
||||
bOrientCameraShakeTowardsEpicenter=true
|
||||
End Object
|
||||
ExplosionTemplate=ExploTemplate0
|
||||
|
||||
Begin Object Class=KFGameExplosion Name=ExploTemplate1
|
||||
Damage=1 //250
|
||||
DamageRadius=100 //450
|
||||
DamageFalloffExponent=0.5f //1.f
|
||||
DamageDelay=0.f
|
||||
|
||||
// Damage Effects
|
||||
KnockDownStrength=0
|
||||
KnockDownRadius=0
|
||||
FractureMeshRadius=0
|
||||
FracturePartVel=0
|
||||
// ExplosionEffects=KFImpactEffectInfo'FX_Impacts_ARCH.Explosions.MedicGrenade_Explosion'
|
||||
ExplosionSound=AkEvent'WW_WEP_Medic_GrenadeLauncher.Play_WEP_Medic_GrenadeLauncher_Grenade_Explosion'
|
||||
MomentumTransferScale=0
|
||||
|
||||
// Camera Shake
|
||||
CamShake=none
|
||||
CamShakeInnerRadius=0
|
||||
CamShakeOuterRadius=0
|
||||
CamShakeFalloff=1.5f
|
||||
bOrientCameraShakeTowardsEpicenter=true
|
||||
End Object
|
||||
HumanExplosionTemplate=ExploTemplate1
|
||||
|
||||
bCanStick=true
|
||||
bCanPin=true
|
||||
|
||||
Begin Object Class=KFProjectileStickHelper_ParasiteImplanter Name=StickHelper0
|
||||
End Object
|
||||
StickHelper=StickHelper0
|
||||
|
||||
ProjDisintegrateTemplate=ParticleSystem'ZED_Siren_EMIT.FX_Siren_grenade_disable_01'
|
||||
|
||||
bShouldEnableIndicator=false;
|
||||
|
||||
ImpactEffects = KFImpactEffectInfo'WEP_ParasiteImplanter_ARCH.Wep_Parasite_Impact_Alt'
|
||||
|
||||
SeedTimerOutEvent = AkEvent'WW_WEP_ParasiteImplanter.Play_WEP_ParasiteImplanter_Seed_Timer_Out';
|
||||
}
|
@ -905,8 +905,8 @@ defaultproperties
|
||||
MaxDamageRadiusPerPercentage=340
|
||||
MinDamageRadiusPerPercentage=160
|
||||
|
||||
MaxDamagePerPercentage=300 //270//180
|
||||
MinDamagePerPercentage=30//90
|
||||
MaxDamagePerPercentage=350 //300
|
||||
MinDamagePerPercentage=35 //30
|
||||
|
||||
MaxCollisionRadius=20
|
||||
MinCollisionRadius=10
|
||||
|
@ -249,6 +249,29 @@ function vector CalculateResidualFlameVelocity( vector HitNormal, vector HitVelD
|
||||
return SpawnDir * ResidualFlameForceMultiplier;
|
||||
}
|
||||
|
||||
simulated protected function PrepareExplosionTemplate()
|
||||
{
|
||||
local Weapon OwnerWeapon;
|
||||
local Pawn OwnerPawn;
|
||||
local KFPerk_Survivalist Perk;
|
||||
|
||||
super(KFProjectile).PrepareExplosionTemplate();
|
||||
OwnerWeapon = Weapon(Owner);
|
||||
if (OwnerWeapon != none)
|
||||
{
|
||||
OwnerPawn = Pawn(OwnerWeapon.Owner);
|
||||
if (OwnerPawn != none)
|
||||
{
|
||||
Perk = KFPerk_Survivalist(KFPawn(OwnerPawn).GetPerk());
|
||||
if (Perk != none)
|
||||
{
|
||||
ExplosionTemplate.DamageRadius *= Perk.GetAoERadiusModifier();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
ProjFlightTemplate=ParticleSystem'WEP_Thermite_EMIT.FX_Harpoon_Projectile'
|
||||
|
@ -0,0 +1,205 @@
|
||||
//=============================================================================
|
||||
// KFProjectileStickHelper_ParasiteImplanter
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
// Killing Floor 2
|
||||
// Copyright (C) 2021 Tripwire Interactive LLC
|
||||
//=============================================================================
|
||||
|
||||
class KFProjectileStickHelper_ParasiteImplanter extends KFProjectileStickHelper;
|
||||
|
||||
simulated function TryStick(vector HitNormal, optional vector HitLocation, optional Actor HitActor)
|
||||
{
|
||||
if( WorldInfo.NetMode != NM_DedicatedServer )
|
||||
{
|
||||
`ImpactEffectManager.PlayImpactEffects(HitLocation, Instigator,, KFProj_Bullet_ParasiteImplanterAlt(Outer).ImpactEffects);
|
||||
}
|
||||
|
||||
super.TryStick(HitNormal, HitLocation, HitActor);
|
||||
}
|
||||
|
||||
/** Stops movement of projectile and calculates orientation to surface */
|
||||
simulated function Stick(Actor HitActor, vector HitLocation, vector HitNormal, const out TraceHitInfo HitInfo)
|
||||
{
|
||||
local int BoneIdx;
|
||||
|
||||
local KFPawn_Monster HitMonster;
|
||||
local array<ImpactInfo> HitZoneImpactList;
|
||||
local vector StartTrace, EndTrace, Direction, ClosestBoneLocation;
|
||||
local name BoneName;
|
||||
|
||||
BoneName = HitInfo.BoneName;
|
||||
|
||||
HitMonster = KFPawn_Monster(HitActor);
|
||||
if (HitMonster != none)
|
||||
{
|
||||
// get injury hit zone
|
||||
StartTrace = HitLocation;
|
||||
Direction = Normal(Velocity);
|
||||
EndTrace = StartTrace + Direction * (HitMonster.CylinderComponent.CollisionRadius * 6.0);
|
||||
TraceProjHitZones(HitMonster, EndTrace, StartTrace, HitZoneImpactList);
|
||||
|
||||
if (BoneName == '')
|
||||
{
|
||||
// get the best bone to attach to
|
||||
ClosestBoneLocation = HitMonster.Mesh.GetClosestCollidingBoneLocation(HitLocation, true, false);
|
||||
BoneName = HitMonster.Mesh.FindClosestBone(ClosestBoneLocation, ClosestBoneLocation);
|
||||
}
|
||||
|
||||
// Deleted damage to monster code, we don't want to do damage on sticking
|
||||
// Bringed damage back
|
||||
if (KFWeapon(Owner) != none)
|
||||
{
|
||||
HitZoneImpactList[0].RayDir = Normal(EndTrace - StartTrace); // add a raydir here since TraceProjHitZones doesn't fill this out (so certain afflictions apply)
|
||||
KFWeapon(Owner).HandleProjectileImpact(WeaponFireMode, HitZoneImpactList[0], PenetrationPower);
|
||||
}
|
||||
}
|
||||
else if (KFPawn_Human(HitActor) != none)
|
||||
{
|
||||
// When it hits a human, use explosion.
|
||||
KFProj_Bullet_ParasiteImplanterAlt(Outer).ExplodeOnHuman(HitLocation, HitNormal, HitActor);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsZero(HitLocation))
|
||||
{
|
||||
|
||||
SetLocation(HitLocation);
|
||||
}
|
||||
|
||||
SetStickOrientation(HitNormal);
|
||||
|
||||
BoneIdx = INDEX_NONE;
|
||||
|
||||
if (BoneName != '')
|
||||
{
|
||||
BoneIdx = GetBoneIndexFromActor(HitActor, BoneName);
|
||||
}
|
||||
|
||||
StickToActor(HitActor, HitInfo.HitComponent, BoneIdx, true);
|
||||
|
||||
if (Role < ROLE_Authority)
|
||||
{
|
||||
Outer.ServerStick(HitActor, BoneIdx, StuckToLocation, StuckToRotation);
|
||||
}
|
||||
|
||||
if (WorldInfo.NetMode != NM_DedicatedServer && StickAkEvent != none)
|
||||
{
|
||||
PlaySoundBase(StickAkEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/** Changes the base of the charge to the stick actor and sets its relative loc/rot */
|
||||
simulated function StickToActor(Actor StickTo, PrimitiveComponent HitComp, int BoneIdx, optional bool bCalculateRelativeLocRot)
|
||||
{
|
||||
local SkeletalMeshComponent SkelMeshComp;
|
||||
local Name BoneName;
|
||||
|
||||
local vector RelStuckToLocation;
|
||||
local rotator RelStuckToRotation;
|
||||
|
||||
local KFPawn StickToPawn;
|
||||
local KFProj_Bullet_ParasiteImplanterAlt ParasiteProj;
|
||||
|
||||
StickToPawn = KFPawn(StickTo);
|
||||
|
||||
if (bCanPin && (StickToPawn == none || StickToPawn.bCanBePinned))
|
||||
{
|
||||
// if StickTo pawn is dead, pin it and keep flying
|
||||
if (Role == ROLE_Authority)
|
||||
{
|
||||
if (StickToPawn != none && !StickToPawn.IsAliveAndWell())
|
||||
{
|
||||
if (PinPawn == none)
|
||||
{
|
||||
Pin(StickTo, BoneIdx);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (WorldInfo.NetMode != NM_DedicatedServer && PinPawn != none)
|
||||
{
|
||||
if (StickToPawn == none)
|
||||
{
|
||||
// Pin pinned pawn to StickTo actor
|
||||
//PinPawn.Mesh.RetardRBLinearVelocity(vector(Rotation), 0.75);
|
||||
PinPawn.Mesh.SetRBPosition(Location, PinBoneName);
|
||||
|
||||
PinConstraint = Spawn(class'RB_ConstraintActorSpawnable',,,Location);
|
||||
PinConstraint.InitConstraint(PinPawn, none, PinBoneName, '');
|
||||
}
|
||||
|
||||
PinPawn = none;
|
||||
}
|
||||
}
|
||||
else if (StickToPawn != none && !StickToPawn.IsAliveAndWell())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SetPhysics(PHYS_None);
|
||||
|
||||
PrevStuckToActor = StuckToActor;
|
||||
StuckToActor = StickTo;
|
||||
StuckToBoneIdx = BoneIdx;
|
||||
|
||||
// if we found a skel mesh, set our base to it and set relative loc/rot
|
||||
if (BoneIdx != INDEX_NONE)
|
||||
{
|
||||
SkelMeshComp = SkeletalMeshComponent(HitComp);
|
||||
|
||||
BoneName = SkelMeshComp.GetBoneName(BoneIdx);
|
||||
|
||||
if (bCalculateRelativeLocRot)
|
||||
{
|
||||
StuckToLocation = Location;
|
||||
StuckToRotation = Rotation;
|
||||
}
|
||||
|
||||
SkelMeshComp.TransformToBoneSpace(BoneName, StuckToLocation, StuckToRotation, RelStuckToLocation, RelStuckToRotation);
|
||||
|
||||
SetBase(StickTo,, SkelMeshComp, BoneName);
|
||||
SetRelativeLocation(RelStuckToLocation);
|
||||
SetRelativeRotation(RelStuckToRotation);
|
||||
|
||||
}
|
||||
// otherwise, just set our base
|
||||
else
|
||||
{
|
||||
if (bCalculateRelativeLocRot)
|
||||
{
|
||||
// set replicated loc/rot
|
||||
StuckToLocation = Location;
|
||||
StuckToRotation = Rotation;
|
||||
}
|
||||
else
|
||||
{
|
||||
// set loc/rot to replicated loc/rot
|
||||
SetLocation(StuckToLocation);
|
||||
SetRotation(StuckToRotation);
|
||||
}
|
||||
|
||||
SetBase(StickTo);
|
||||
}
|
||||
|
||||
ParasiteProj = KFProj_Bullet_ParasiteImplanterAlt(Outer);
|
||||
ParasiteProj.OnActorSticked(StickTo);
|
||||
}
|
||||
|
||||
/** Resets physics/collision vars to defaults */
|
||||
simulated function UnStick()
|
||||
{
|
||||
// local KFPawn_Monster KFPM;
|
||||
|
||||
GravityScale=0.5f;
|
||||
/*
|
||||
KFPM = KFPawn_Monster(StuckToActor);
|
||||
if (KFPM != none && KFPM.Health > 0)
|
||||
{
|
||||
KFPM.ParasiteSeeds.Remove(0, KFPM.ParasiteSeeds.Length - (KFPM.MaxNumSeeds-1));
|
||||
}
|
||||
*/
|
||||
super.UnStick();
|
||||
}
|
117
KFGameContent/Classes/KFSeasonalEventStats_Fall2021.uc
Normal file
117
KFGameContent/Classes/KFSeasonalEventStats_Fall2021.uc
Normal file
@ -0,0 +1,117 @@
|
||||
//=============================================================================
|
||||
// KFSeasonalEventStats_Fall2021
|
||||
//=============================================================================
|
||||
// Tracks event-specific challenges/accomplishments for Fall 2021
|
||||
//=============================================================================
|
||||
// Killing Floor 2
|
||||
// Copyright (C) 2021 Tripwire Interactive LLC
|
||||
//=============================================================================
|
||||
class KFSeasonalEventStats_Fall2021 extends KFSeasonalEventStats;
|
||||
|
||||
var transient private const int BossKillsRequired, EndlessWaveRequired;
|
||||
|
||||
private event Initialize(string MapName)
|
||||
{
|
||||
local string CapsMapName;
|
||||
CapsMapName = Caps(MapName);
|
||||
|
||||
bObjectiveIsValidForMap[0] = 1; // Kill 15 Bosses on any map or mode
|
||||
bObjectiveIsValidForMap[1] = 0; // Complete the Weekly on Netherhold
|
||||
bObjectiveIsValidForMap[2] = 0; // Find the nether heart
|
||||
bObjectiveIsValidForMap[3] = 0; // Unlock the chapel and the dining hall doors
|
||||
bObjectiveIsValidForMap[4] = 0; // Complete wave 15 on Endless Hard or higher difficulty on Netherhold
|
||||
|
||||
if (CapsMapName == "KF-NETHERHOLD")
|
||||
{
|
||||
bObjectiveIsValidForMap[1] = 1;
|
||||
bObjectiveIsValidForMap[2] = 1;
|
||||
bObjectiveIsValidForMap[3] = 1;
|
||||
bObjectiveIsValidForMap[4] = 1;
|
||||
}
|
||||
|
||||
SetSeasonalEventStatsMax(BossKillsRequired, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
private event GrantEventItems()
|
||||
{
|
||||
if (Outer.IsEventObjectiveComplete(0) &&
|
||||
Outer.IsEventObjectiveComplete(1) &&
|
||||
Outer.IsEventObjectiveComplete(2) &&
|
||||
Outer.IsEventObjectiveComplete(3) &&
|
||||
Outer.IsEventObjectiveComplete(4))
|
||||
{
|
||||
// TODO: Uncomment me and set the proper item ID
|
||||
GrantEventItem(8990);
|
||||
}
|
||||
}
|
||||
|
||||
// Kill 15 Bosses on any map or mode
|
||||
simulated function OnBossDied()
|
||||
{
|
||||
local int ObjIdx;
|
||||
ObjIdx = 0;
|
||||
|
||||
// Boss kills in any map
|
||||
if (bObjectiveIsValidForMap[ObjIdx] != 0)
|
||||
{
|
||||
IncrementSeasonalEventStat(ObjIdx, 1);
|
||||
if (Outer.GetSeasonalEventStatValue(ObjIdx) >= BossKillsRequired)
|
||||
{
|
||||
FinishedObjective(SEI_Fall, ObjIdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Complete the Weekly on Netherhold
|
||||
simulated event OnGameWon(class<GameInfo> GameClass, int Difficulty, int GameLength, bool bCoOp)
|
||||
{
|
||||
local int ObjIdx;
|
||||
ObjIdx = 1;
|
||||
|
||||
if (bObjectiveIsValidForMap[ObjIdx] != 0)
|
||||
{
|
||||
if (GameClass == class'KFGameInfo_WeeklySurvival')
|
||||
{
|
||||
FinishedObjective(SEI_Fall, ObjIdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Complete wave 15 on Endless Hard or higher difficulty on Netherhold
|
||||
simulated event OnWaveCompleted(class<GameInfo> GameClass, int Difficulty, int WaveNum)
|
||||
{
|
||||
local int ObjIdx;
|
||||
ObjIdx = 4;
|
||||
|
||||
if (bObjectiveIsValidForMap[ObjIdx] != 0)
|
||||
{
|
||||
if (WaveNum >= EndlessWaveRequired && GameClass == class'KFGameInfo_Endless' && Difficulty >= `DIFFICULTY_HARD)
|
||||
{
|
||||
FinishedObjective(SEI_Fall, ObjIdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
simulated function OnTryCompleteObjective(int ObjectiveIndex, int EventIndex)
|
||||
{
|
||||
local int NetherHeartIdx, ChapelIdx;
|
||||
NetherHeartIdx = 2;
|
||||
ChapelIdx = 3;
|
||||
|
||||
if(EventIndex == SEI_Fall)
|
||||
{
|
||||
if (ObjectiveIndex == NetherHeartIdx || ObjectiveIndex == ChapelIdx)
|
||||
{
|
||||
if (bObjectiveIsValidForMap[ObjectiveIndex] != 0)
|
||||
{
|
||||
FinishedObjective(SEI_Fall, ObjectiveIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
BossKillsRequired=15
|
||||
EndlessWaveRequired=15
|
||||
}
|
@ -9,18 +9,21 @@
|
||||
|
||||
class KFWeapAttach_FAMAS extends KFWeaponAttachment;
|
||||
|
||||
const SecondaryFireAnim = 'Shoot_Secondary';
|
||||
const SecondaryFireIronAnim = 'Shoot_Secondary_Iron';
|
||||
const SecondaryFireAnimLast = 'Shoot_Secondary_Last';
|
||||
const SecondaryFireIronAnimLast = 'Shoot_Secondary_Iron_Last';
|
||||
const SecondaryFireBodyAnim = 'ADD_Shoot_Secondary';
|
||||
const SecondaryFireBodyAnimCH = 'ADD_Shoot_Secondary_CH';
|
||||
const SecondaryFireBodyAnimIron = 'ADD_Shoot_Secondary_Iron';
|
||||
const SecondaryReloadAnimEmpty = 'Reload_Secondary_Empty';
|
||||
const SecondaryReloadAnimHalf = 'Reload_Secondary_Half';
|
||||
const SecondaryReloadAnimEliteEmpty = 'Reload_Secondary_Elite_Empty';
|
||||
const SecondaryReloadAnimEliteHalf = 'Reload_Secondary_Elite_Half';
|
||||
const ShotgunMuzzleSocket = 'ShotgunMuzzleFlash';
|
||||
const SecondaryFireAnim = 'Shoot_Secondary';
|
||||
const SecondaryFireAnimCrouch = 'Shoot_Secondary_CH';
|
||||
const SecondaryFireIronAnim = 'Shoot_Secondary_Iron';
|
||||
const SecondaryFireBodyAnim = 'ADD_Shoot_Secondary';
|
||||
const SecondaryFireBodyAnimCH = 'ADD_Shoot_Secondary_CH';
|
||||
const SecondaryFireBodyAnimIron = 'ADD_Shoot_Secondary_Iron';
|
||||
const SecondaryReloadAnimEmpty = 'Reload_Secondary_Empty';
|
||||
const SecondaryReloadAnimEmptyCrouch = 'Reload_Secondary_Empty_CH';
|
||||
const SecondaryReloadAnimHalf = 'Reload_Secondary_Half';
|
||||
const SecondaryReloadAnimHalfCrouch = 'Reload_Secondary_Half_CH';
|
||||
const SecondaryReloadAnimEliteEmpty = 'Reload_Secondary_Elite_Empty';
|
||||
const SecondaryReloadAnimEliteEmptyCrouch = 'Reload_Secondary_Elite_Empty_CH';
|
||||
const SecondaryReloadAnimEliteHalf = 'Reload_Secondary_Elite_Half';
|
||||
const SecondaryReloadAnimEliteHalfCrouch = 'Reload_Secondary_Elite_Half_CH';
|
||||
const ShotgunMuzzleSocket = 'ShotgunMuzzleFlash';
|
||||
|
||||
var protected transient KFMuzzleFlash ShotgunMuzzleFlash;
|
||||
|
||||
@ -30,18 +33,25 @@ simulated function PlayReloadMagazineAnim(EWeaponState NewWeaponState, KFPawn P)
|
||||
{
|
||||
local name AnimName;
|
||||
|
||||
if(NewWeaponState == WEP_ReloadSecondary || NewWeaponState == WEP_ReloadSecondary_Elite)
|
||||
switch (NewWeaponState)
|
||||
{
|
||||
switch (NewWeaponState)
|
||||
{
|
||||
case WEP_ReloadSecondary:
|
||||
AnimName = (P.MyKFWeapon.AmmoCount[1] == 0) ? SecondaryReloadAnimEmpty : SecondaryReloadAnimHalf;
|
||||
break;
|
||||
case WEP_ReloadSecondary_Elite:
|
||||
AnimName = (P.MyKFWeapon.AmmoCount[1] == 0) ? SecondaryReloadAnimEliteEmpty : SecondaryReloadAnimEliteHalf;
|
||||
break;
|
||||
}
|
||||
|
||||
case WEP_ReloadSecondary:
|
||||
AnimName = (P.bIsCrouched) ? SecondaryReloadAnimHalfCrouch : SecondaryReloadAnimHalf;
|
||||
break;
|
||||
case WEP_ReloadSecondaryEmpty:
|
||||
AnimName = (P.bIsCrouched) ? SecondaryReloadAnimEmptyCrouch : SecondaryReloadAnimEmpty;
|
||||
break;
|
||||
case WEP_ReloadSecondary_Elite:
|
||||
AnimName = (P.bIsCrouched) ? SecondaryReloadAnimEliteHalfCrouch : SecondaryReloadAnimEliteHalf;
|
||||
break;
|
||||
case WEP_ReloadSecondaryEmpty_Elite:
|
||||
AnimName = (P.bIsCrouched) ? SecondaryReloadAnimEliteEmptyCrouch : SecondaryReloadAnimEliteEmpty;
|
||||
break;
|
||||
}
|
||||
|
||||
if (AnimName != '')
|
||||
{
|
||||
PlayCharacterMeshAnim(P, AnimName, true);
|
||||
}
|
||||
else
|
||||
@ -103,21 +113,19 @@ simulated function PlayFireAnim(KFPawn P)
|
||||
}
|
||||
else if (OwnerPawn.FiringMode == 1) // ALT FIRE MODE (Shotgun)
|
||||
{
|
||||
// Anim = (P.MyKFWeapon.AmmoCount[1] == 0) ? SecondaryFireIronAnimLast : SecondaryFireIronAnim;
|
||||
Anim = SecondaryFireIronAnim;
|
||||
|
||||
}
|
||||
}
|
||||
else // Normal anims
|
||||
{
|
||||
if (Pawn(Owner).FiringMode == 0) // DEFAULT FIRE MODE (Rifle)
|
||||
if (OwnerPawn.FiringMode == 0) // DEFAULT FIRE MODE (Rifle)
|
||||
{
|
||||
Anim = WeaponFireAnim;
|
||||
}
|
||||
else if (Pawn(Owner).FiringMode == 1) // ALT FIRE MODE (Shotgun)
|
||||
else if (OwnerPawn.FiringMode == 1) // ALT FIRE MODE (Shotgun)
|
||||
{
|
||||
// Anim = (P.MyKFWeapon.AmmoCount[1] == 0) ? SecondaryFireAnimLast : SecondaryFireAnim;
|
||||
Anim = SecondaryFireAnim;
|
||||
Anim = OwnerPawn.bIsCrouched ? SecondaryFireAnimCrouch : SecondaryFireAnim;
|
||||
}
|
||||
}
|
||||
|
||||
|
106
KFGameContent/Classes/KFWeapAttach_HRG_Energy.uc
Normal file
106
KFGameContent/Classes/KFWeapAttach_HRG_Energy.uc
Normal file
@ -0,0 +1,106 @@
|
||||
//=============================================================================
|
||||
// KFWeapAttach_HRG_Energy
|
||||
//=============================================================================
|
||||
//
|
||||
//=============================================================================
|
||||
// Killing Floor 2
|
||||
// Copyright (C) 2021 Tripwire Interactive LLC
|
||||
//=============================================================================
|
||||
|
||||
class KFWeapAttach_HRG_Energy extends KFWeaponAttachment;
|
||||
|
||||
`define HRG_ENERGY_MIC_LED_INDEX_1 0
|
||||
`define HRG_ENERGY_MIC_SCREEN_INDEX 1
|
||||
`define HRG_ENERGY_MIC_LED_INDEX_2 2
|
||||
|
||||
var MaterialInstanceConstant WeaponMIC_2;
|
||||
var MaterialInstanceConstant WeaponMICScreen;
|
||||
|
||||
simulated function SetWeaponAltFireMode (bool bUsingAltFireMode)
|
||||
{
|
||||
super.SetWeaponAltFireMode(bUsingAltFireMode);
|
||||
UpdateMaterial(bUsingAltFireMode ? 1 : 0);
|
||||
}
|
||||
|
||||
simulated function UpdateMaterial(byte FireMode)
|
||||
{
|
||||
local LinearColor MatColor;
|
||||
|
||||
if (WeapMesh == none)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MatColor = FireMode == 0 ? class'KFWeap_HRG_Energy'.default.DefaultFireMaterialColor : class'KFWeap_HRG_Energy'.default.AltFireMaterialColor;
|
||||
|
||||
if ( WeaponMIC == none )
|
||||
{
|
||||
WeaponMIC = WeapMesh.CreateAndSetMaterialInstanceConstant(`HRG_ENERGY_MIC_LED_INDEX_1);
|
||||
}
|
||||
|
||||
if ( WeaponMIC_2 == none )
|
||||
{
|
||||
WeaponMIC_2 = WeapMesh.CreateAndSetMaterialInstanceConstant(`HRG_ENERGY_MIC_LED_INDEX_2);
|
||||
}
|
||||
|
||||
if (WeaponMICScreen == none)
|
||||
{
|
||||
WeaponMICScreen = WeapMesh.CreateAndSetMaterialInstanceConstant(`HRG_ENERGY_MIC_SCREEN_INDEX);
|
||||
}
|
||||
|
||||
WeaponMIC.SetVectorParameterValue('Vector_GlowColor', MatColor);
|
||||
WeaponMIC_2.SetVectorParameterValue('Vector_GlowColor', MatColor);
|
||||
WeaponMICScreen.SetVectorParameterValue('Color_override', MatColor);
|
||||
}
|
||||
|
||||
/** Plays fire animation on weapon mesh */
|
||||
simulated function PlayWeaponFireAnim()
|
||||
{
|
||||
local float Duration, AnimRateModifier;
|
||||
local name Animation;
|
||||
local KFPawn_Human KFPH;
|
||||
|
||||
KFPH = KFPawn_Human(Instigator);
|
||||
|
||||
AnimRateModifier = (KFPH != none && KFPH.bUsingAltFireMode) ? class'KFWeap_HRG_Energy'.default.SecondaryFireAnimRateModifier : 1.0f;
|
||||
|
||||
if ( Instigator.bIsWalking )
|
||||
{
|
||||
Duration = WeapMesh.GetAnimLength( WeaponIronFireAnim );
|
||||
Animation = WeaponIronFireAnim;
|
||||
}
|
||||
else
|
||||
{
|
||||
Duration = WeapMesh.GetAnimLength( WeaponFireAnim );
|
||||
Animation = WeaponFireAnim;
|
||||
WeapMesh.PlayAnim( WeaponFireAnim, Duration / ThirdPersonAnimRate,, true );
|
||||
}
|
||||
|
||||
WeapMesh.PlayAnim( Animation, Duration / ThirdPersonAnimRate * AnimRateModifier,, true );
|
||||
}
|
||||
|
||||
|
||||
/** Play a 3rd person reload animation */
|
||||
simulated function PlayReloadMagazineAnim(EWeaponState NewWeaponState, KFPawn P)
|
||||
{
|
||||
local name AnimName;
|
||||
|
||||
switch (NewWeaponState)
|
||||
{
|
||||
case WEP_Reload:
|
||||
case WEP_ReloadEmpty:
|
||||
AnimName = (!P.bIsCrouched) ? ReloadHalfAnim : CH_ReloadHalfAnim;
|
||||
break;
|
||||
case WEP_Reload_Elite:
|
||||
case WEP_ReloadEmpty_Elite:
|
||||
AnimName = (!P.bIsCrouched) ? ReloadHalfEliteAnim : CH_ReloadHalfEliteAnim;
|
||||
break;
|
||||
}
|
||||
|
||||
PlayCharacterMeshAnim(P, AnimName, true);
|
||||
}
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
|
||||
}
|
108
KFGameContent/Classes/KFWeapAttach_ParasiteImplanter.uc
Normal file
108
KFGameContent/Classes/KFWeapAttach_ParasiteImplanter.uc
Normal file
@ -0,0 +1,108 @@
|
||||
//=============================================================================
|
||||
// KFWeapAttach_FAMAS
|
||||
//=============================================================================
|
||||
//
|
||||
//=============================================================================
|
||||
// Killing Floor 2
|
||||
// Copyright (C) 2021 Tripwire Interactive LLC
|
||||
//=============================================================================
|
||||
|
||||
class KFWeapAttach_ParasiteImplanter extends KFWeaponAttachment;
|
||||
|
||||
`define PARASITEIMPLANTER_MIC_INDEX 0
|
||||
|
||||
const SecondaryFireAnim = 'Shoot_Secondary';
|
||||
const SecondaryFireAnimCrouch = 'Shoot_Secondary_CH';
|
||||
const SecondaryFireIronAnim = 'Shoot_Secondary_Iron';
|
||||
const SecondaryFireBodyAnim = 'ADD_Shoot_Secondary';
|
||||
const SecondaryFireBodyAnimCH = 'ADD_Shoot_Secondary_CH';
|
||||
const SecondaryFireBodyAnimIron = 'ADD_Shoot_Secondary_Iron';
|
||||
|
||||
/** Material colors applied to different fire modes */
|
||||
var LinearColor NoAmmoMaterialColor;
|
||||
var LinearColor AmmoReadyMaterialColor;
|
||||
|
||||
/** Plays fire animation on weapon mesh */
|
||||
simulated function PlayWeaponFireAnim()
|
||||
{
|
||||
local float Duration;
|
||||
local name Anim;
|
||||
|
||||
if ( Instigator.bIsWalking )
|
||||
{
|
||||
if (Instigator.FiringMode == 0) // DEFAULT FIRE MODE
|
||||
{
|
||||
Anim = WeaponIronFireAnim;
|
||||
}
|
||||
else if (Instigator.FiringMode == 1)
|
||||
{
|
||||
Anim = SecondaryFireIronAnim;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Instigator.FiringMode == 0) // ALT FIRE MODE
|
||||
{
|
||||
Anim = WeaponFireAnim;
|
||||
}
|
||||
else if (Instigator.FiringMode == 1)
|
||||
{
|
||||
Anim = Instigator.bIsCrouched ? SecondaryFireAnimCrouch : SecondaryFireAnim;
|
||||
}
|
||||
}
|
||||
|
||||
Duration = WeapMesh.GetAnimLength( Anim );
|
||||
WeapMesh.PlayAnim( Anim, Duration / ThirdPersonAnimRate,, true );
|
||||
}
|
||||
|
||||
/** Plays fire animation on pawn */
|
||||
simulated function PlayPawnFireAnim( KFPawn P, EAnimSlotStance AnimType )
|
||||
{
|
||||
if (P.FiringMode == 0)
|
||||
{
|
||||
super.PlayPawnFireAnim(P, AnimType);
|
||||
}
|
||||
else if (P.FiringMode == 1)
|
||||
{
|
||||
if ( P.bIsCrouched )
|
||||
{
|
||||
P.PlayBodyAnim(SecondaryFireBodyAnimCH, AnimType, ThirdPersonAnimRate, ShootBlendInTime, ShootBlendOutTime);
|
||||
}
|
||||
else if ( P.bIsWalking )
|
||||
{
|
||||
P.PlayBodyAnim(SecondaryFireBodyAnimIron, AnimType, ThirdPersonAnimRate, ShootBlendInTime, ShootBlendOutTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
P.PlayBodyAnim(SecondaryFireBodyAnim, AnimType, ThirdPersonAnimRate, ShootBlendInTime, ShootBlendOutTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Special event added for weap attachments. Free for use */
|
||||
function OnSpecialEvent(int Arg)
|
||||
{
|
||||
if (Arg <= 2)
|
||||
{
|
||||
UpdateMaterial(Arg == 2);
|
||||
}
|
||||
}
|
||||
|
||||
simulated function UpdateMaterial(bool HasEnoughAmmo)
|
||||
{
|
||||
local LinearColor Value;
|
||||
|
||||
Value = HasEnoughAmmo ? AmmoReadyMaterialColor : NoAmmoMaterialColor;
|
||||
if ( WeaponMIC == None && WeapMesh != None )
|
||||
{
|
||||
WeaponMIC = WeapMesh.CreateAndSetMaterialInstanceConstant(`PARASITEIMPLANTER_MIC_INDEX);
|
||||
}
|
||||
|
||||
WeaponMIC.SetVectorParameterValue('Vector_GlowColor', Value);
|
||||
}
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
NoAmmoMaterialColor=(R=0.0f,G=0.0f,B=0.0f)
|
||||
AmmoReadyMaterialColor=(R=0.08f,G=1.0f,B=0.08f)
|
||||
}
|
@ -387,7 +387,14 @@ simulated state AltReloading extends Reloading
|
||||
Perk = GetPerk();
|
||||
bTacticalReload = (Perk != None && Perk.GetUsingTactialReload(self));
|
||||
|
||||
return (bTacticalReload ? WEP_ReloadSecondary_Elite : WEP_ReloadSecondary);
|
||||
if (AmmoCount[ALTFIRE_FIREMODE] == 0)
|
||||
{
|
||||
return (bTacticalReload ? WEP_ReloadSecondaryEmpty_Elite : WEP_ReloadSecondaryEmpty);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (bTacticalReload ? WEP_ReloadSecondary_Elite : WEP_ReloadSecondary);
|
||||
}
|
||||
}
|
||||
|
||||
simulated event BeginState(Name PreviousStateName)
|
||||
|
@ -661,8 +661,8 @@ defaultproperties
|
||||
HealFullRechargeSeconds=12
|
||||
|
||||
// Heavy Attack Explosion Ammo
|
||||
MagazineCapacity[0]=3
|
||||
SpareAmmoCapacity[0]=12
|
||||
MagazineCapacity[0]=2 //3
|
||||
SpareAmmoCapacity[0]=10 //12
|
||||
InitialSpareMags[0]=1
|
||||
bCanBeReloaded=true
|
||||
bReloadFromMagazine=true
|
||||
@ -687,7 +687,7 @@ defaultproperties
|
||||
|
||||
// Heavy Attack
|
||||
FireModeIconPaths(HEAVY_ATK_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_BluntMelee'
|
||||
InstantHitDamage(HEAVY_ATK_FIREMODE)=130
|
||||
InstantHitDamage(HEAVY_ATK_FIREMODE)=140 //130
|
||||
InstantHitDamageTypes(HEAVY_ATK_FIREMODE) = class'KFDT_Bludgeon_MedicBatHeavy'
|
||||
|
||||
// Heavy Attack Explosion
|
||||
@ -729,12 +729,12 @@ defaultproperties
|
||||
// Explosion
|
||||
ExplosionActorClass = class'KFExplosionActorReplicated'
|
||||
Begin Object Class=KFGameExplosion Name=HeavyAttackHealingExplosion
|
||||
Damage=200
|
||||
Damage=225 //200
|
||||
DamageRadius=500
|
||||
DamageFalloffExponent=0.f
|
||||
DamageDelay=0.f
|
||||
MyDamageType=class'KFDT_Toxic_MedicBatGas'
|
||||
HealingAmount=30
|
||||
HealingAmount=20 //30
|
||||
|
||||
// Damage Effects
|
||||
KnockDownStrength=0
|
||||
|
@ -373,7 +373,21 @@ simulated function float GetReloadRateScale()
|
||||
|
||||
simulated function bool HasAnyAmmo()
|
||||
{
|
||||
return AmmoCount[0] != 0 && SpareAmmoCount[0] != 0;
|
||||
return AmmoCount[0] > 0 || SpareAmmoCount[0] > 0;
|
||||
}
|
||||
|
||||
simulated function int GetMeleeDamage(byte FireModeNum, optional vector RayDir)
|
||||
{
|
||||
local int Damage;
|
||||
|
||||
Damage = GetModifiedDamage(FireModeNum, RayDir);
|
||||
// decode damage scale (see GetDamageScaleByAngle) from the RayDir
|
||||
if ( !IsZero(RayDir) )
|
||||
{
|
||||
Damage = Round(float(Damage) * FMin(VSize(RayDir), 1.f));
|
||||
}
|
||||
|
||||
return Damage;
|
||||
}
|
||||
|
||||
defaultproperties
|
||||
|
192
KFGameContent/Classes/KFWeap_HRG_Boomy.uc
Normal file
192
KFGameContent/Classes/KFWeap_HRG_Boomy.uc
Normal file
@ -0,0 +1,192 @@
|
||||
//=============================================================================
|
||||
// KFWeap_HRG_Boomy
|
||||
//=============================================================================
|
||||
//
|
||||
//=============================================================================
|
||||
// Killing Floor 2
|
||||
// Copyright (C) 2021 Tripwire Interactive LLC
|
||||
//=============================================================================
|
||||
|
||||
class KFWeap_HRG_Boomy extends KFWeap_SMGBase;
|
||||
|
||||
/**
|
||||
* Overriden to use instant hit vfx.
|
||||
* Basically, calculate the hit location so vfx can play
|
||||
*/
|
||||
simulated function Projectile ProjectileFire()
|
||||
{
|
||||
local vector StartTrace, EndTrace, RealStartLoc, AimDir;
|
||||
local ImpactInfo TestImpact;
|
||||
local vector DirA, DirB;
|
||||
local Quat Q;
|
||||
local class<KFProjectile> MyProjectileClass;
|
||||
|
||||
MyProjectileClass = GetKFProjectileClass();
|
||||
|
||||
// This is where we would start an instant trace. (what CalcWeaponFire uses)
|
||||
StartTrace = GetSafeStartTraceLocation();
|
||||
AimDir = Vector(GetAdjustedAim( StartTrace ));
|
||||
|
||||
// this is the location where the projectile is spawned.
|
||||
RealStartLoc = GetPhysicalFireStartLoc(AimDir);
|
||||
|
||||
// if projectile is spawned at different location of crosshair,
|
||||
// then simulate an instant trace where crosshair is aiming at, Get hit info.
|
||||
EndTrace = StartTrace + AimDir * GetTraceRange();
|
||||
TestImpact = CalcWeaponFire( StartTrace, EndTrace );
|
||||
|
||||
// Set flash location to trigger client side effects. Bypass Weapon.SetFlashLocation since
|
||||
// that function is not marked as simulated and we want instant client feedback.
|
||||
// ProjectileFire/IncrementFlashCount has the right idea:
|
||||
// 1) Call IncrementFlashCount on Server & Local
|
||||
// 2) Replicate FlashCount if ( !bNetOwner )
|
||||
// 3) Call WeaponFired() once on local player
|
||||
if( Instigator != None )
|
||||
{
|
||||
Instigator.SetFlashLocation( Self, CurrentFireMode, TestImpact.HitLocation );
|
||||
}
|
||||
|
||||
if( Role == ROLE_Authority || (MyProjectileClass.default.bUseClientSideHitDetection
|
||||
&& MyProjectileClass.default.bNoReplicationToInstigator && Instigator != none
|
||||
&& Instigator.IsLocallyControlled()) )
|
||||
{
|
||||
|
||||
if( StartTrace != RealStartLoc )
|
||||
{
|
||||
// Store the original aim direction without correction
|
||||
DirB = AimDir;
|
||||
|
||||
// Then we realign projectile aim direction to match where the crosshair did hit.
|
||||
AimDir = Normal(TestImpact.HitLocation - RealStartLoc);
|
||||
|
||||
// Store the desired corrected aim direction
|
||||
DirA = AimDir;
|
||||
|
||||
// Clamp the maximum aim adjustment for the AimDir so you don't get wierd
|
||||
// cases where the projectiles velocity is going WAY off of where you
|
||||
// are aiming. This can happen if you are really close to what you are
|
||||
// shooting - Ramm
|
||||
if ( (DirA dot DirB) < MaxAimAdjust_Cos )
|
||||
{
|
||||
Q = QuatFromAxisAndAngle(Normal(DirB cross DirA), MaxAimAdjust_Angle);
|
||||
AimDir = QuatRotateVector(Q,DirB);
|
||||
}
|
||||
}
|
||||
|
||||
return SpawnAllProjectiles(MyProjectileClass, RealStartLoc, AimDir);
|
||||
}
|
||||
|
||||
return None;
|
||||
}
|
||||
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
bHasFireLastAnims=true
|
||||
BonesToLockOnEmpty=(RW_Charging_Handle)
|
||||
|
||||
// Shooting Animations
|
||||
FireSightedAnims[0]=Shoot_Iron
|
||||
FireSightedAnims[1]=Shoot_Iron2
|
||||
FireSightedAnims[2]=Shoot_Iron3
|
||||
|
||||
// FOV
|
||||
MeshFOV=75
|
||||
MeshIronSightFOV=52
|
||||
PlayerIronSightFOV=70
|
||||
|
||||
// Depth of field
|
||||
DOF_FG_FocalRadius=85
|
||||
DOF_FG_MaxNearBlurSize=2.5
|
||||
|
||||
// Content
|
||||
PackageKey="HRG_Boomy"
|
||||
FirstPersonMeshName="WEP_1P_HRG_Boomy_MESH.Wep_1stP_HRG_Boomy_Rig"
|
||||
FirstPersonAnimSetNames(0)="WEP_1P_HRG_Boomy_ANIM.WEP_1stP_HRG_Boomy_Anim"
|
||||
PickupMeshName="WEP_3P_HRG_Boomy_MESH.Wep_3rdP_HRG_Boomy_Pickup"
|
||||
AttachmentArchetypeName="WEP_HRG_Boomy_ARCH.Wep_HRG_Boomy_3P"
|
||||
MuzzleFlashTemplateName="WEP_HRG_Boomy_ARCH.Wep_HRG_Boomy_MuzzleFlash"
|
||||
|
||||
|
||||
// Zooming/Position
|
||||
PlayerViewOffset=(X=5.0,Y=9,Z=-5)
|
||||
IronSightPosition=(X=5,Y=0,Z=0)
|
||||
|
||||
// Ammo
|
||||
MagazineCapacity[0]=24
|
||||
SpareAmmoCapacity[0]=192
|
||||
InitialSpareMags[0]=1
|
||||
bCanBeReloaded=true
|
||||
bReloadFromMagazine=true
|
||||
|
||||
// Recoil
|
||||
maxRecoilPitch=325 //325 //130 //165
|
||||
minRecoilPitch=300 //275 //115 //130
|
||||
maxRecoilYaw=140 //150 //115 //130
|
||||
minRecoilYaw=-140 //-150 //-115 //130
|
||||
RecoilRate=0.085
|
||||
RecoilMaxYawLimit=500
|
||||
RecoilMinYawLimit=65035
|
||||
RecoilMaxPitchLimit=900
|
||||
RecoilMinPitchLimit=65035
|
||||
RecoilISMaxYawLimit=75
|
||||
RecoilISMinYawLimit=65460
|
||||
RecoilISMaxPitchLimit=375
|
||||
RecoilISMinPitchLimit=65460
|
||||
RecoilViewRotationScale=0.25
|
||||
IronSightMeshFOVCompensationScale=1.5
|
||||
HippedRecoilModifier=1.5
|
||||
|
||||
// Inventory / Grouping
|
||||
InventorySize=7
|
||||
GroupPriority=50
|
||||
WeaponSelectTexture=Texture2D'WEP_UI_HRG_Boomy_TEX.UI_WeaponSelect_HRG_Boomy'
|
||||
|
||||
AssociatedPerkClasses(0)=class'KFPerk_Demolitionist'
|
||||
|
||||
// DEFAULT_FIREMODE
|
||||
FireModeIconPaths(DEFAULT_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_BulletAuto'
|
||||
FiringStatesArray(DEFAULT_FIREMODE)=WeaponFiring
|
||||
WeaponFireTypes(DEFAULT_FIREMODE)=EWFT_Projectile
|
||||
WeaponProjectiles(DEFAULT_FIREMODE)=class'KFProj_Bullet_HRG_Boomy'
|
||||
InstantHitDamageTypes(DEFAULT_FIREMODE)=class'KFDT_Ballistic_HRG_Boomy'
|
||||
FireInterval(DEFAULT_FIREMODE)=+0.1667 // 360 RPM
|
||||
Spread(DEFAULT_FIREMODE)=0.01 //0.025
|
||||
InstantHitDamage(DEFAULT_FIREMODE)=25.0
|
||||
FireOffset=(X=30,Y=4.5,Z=-5)
|
||||
|
||||
// ALT_FIREMODE
|
||||
FireModeIconPaths(ALTFIRE_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_BulletSingle'
|
||||
FiringStatesArray(ALTFIRE_FIREMODE)=WeaponSingleFiring
|
||||
WeaponFireTypes(ALTFIRE_FIREMODE)=EWFT_Projectile
|
||||
WeaponProjectiles(ALTFIRE_FIREMODE)=class'KFProj_Bullet_HRG_Boomy'
|
||||
InstantHitDamageTypes(ALTFIRE_FIREMODE)=class'KFDT_Ballistic_HRG_Boomy'
|
||||
FireInterval(ALTFIRE_FIREMODE)=+0.1667 // 360 RPM
|
||||
InstantHitDamage(ALTFIRE_FIREMODE)=25.0
|
||||
Spread(ALTFIRE_FIREMODE)=0.01 //0.025
|
||||
|
||||
// BASH_FIREMODE
|
||||
InstantHitDamageTypes(BASH_FIREMODE)=class'KFDT_Bludgeon_HRG_Boomy'
|
||||
InstantHitDamage(BASH_FIREMODE)=26
|
||||
|
||||
// Fire Effects
|
||||
WeaponFireSnd(DEFAULT_FIREMODE)=(DefaultCue=AkEvent'ww_wep_hrg_boomy.Play_WEP_HRG_Boomy_3P_ShootLoop', FirstPersonCue=AkEvent'ww_wep_hrg_boomy.Play_WEP_HRG_Boomy_1P_ShootLoop')
|
||||
WeaponFireSnd(ALTFIRE_FIREMODE)=(DefaultCue=AkEvent'ww_wep_hrg_boomy.Play_WEP_HRG_Boomy_3P_Shoot', FirstPersonCue=AkEvent'ww_wep_hrg_boomy.Play_WEP_HRG_Boomy_1P_Shoot')
|
||||
WeaponFireLoopEndSnd(DEFAULT_FIREMODE)=(DefaultCue=AkEvent'ww_wep_hrg_boomy.Play_WEP_HRG_Boomy_3P_ShootLoopEnd', FirstPersonCue=AkEvent'ww_wep_hrg_boomy.Play_WEP_HRG_Boomy_1P_ShootLoopEnd')
|
||||
|
||||
WeaponDryFireSnd(DEFAULT_FIREMODE)=AkEvent'WW_WEP_SA_L85A2.Play_WEP_SA_L85A2_Handling_DryFire'
|
||||
WeaponDryFireSnd(ALTFIRE_FIREMODE)=AkEvent'WW_WEP_SA_L85A2.Play_WEP_SA_L85A2_Handling_DryFire'
|
||||
|
||||
// Advanced (High RPM) Fire Effects
|
||||
bLoopingFireAnim(DEFAULT_FIREMODE)=true
|
||||
bLoopingFireSnd(DEFAULT_FIREMODE)=true
|
||||
SingleFireSoundIndex=ALTFIRE_FIREMODE
|
||||
|
||||
// Attachments
|
||||
bHasIronSights=true
|
||||
bHasFlashlight=false
|
||||
|
||||
WeaponUpgrades[1]=(Stats=((Stat=EWUS_Damage0, Scale=1.15f), (Stat=EWUS_Damage1, Scale=1.15f), (Stat=EWUS_Weight, Add=1)))
|
||||
WeaponUpgrades[2]=(Stats=((Stat=EWUS_Damage0, Scale=1.3f), (Stat=EWUS_Damage1, Scale=1.3f), (Stat=EWUS_Weight, Add=2)))
|
||||
WeaponUpgrades[3]=(Stats=((Stat=EWUS_Damage0, Scale=1.45f), (Stat=EWUS_Damage1, Scale=1.45f), (Stat=EWUS_Weight, Add=3)))
|
||||
}
|
510
KFGameContent/Classes/KFWeap_HRG_Energy.uc
Normal file
510
KFGameContent/Classes/KFWeap_HRG_Energy.uc
Normal file
@ -0,0 +1,510 @@
|
||||
//=============================================================================
|
||||
// KFWeap_HRG_Energy
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
// Killing Floor 2
|
||||
// Copyright (C) 2021 Tripwire Interactive LLC
|
||||
//=============================================================================
|
||||
|
||||
class KFWeap_HRG_Energy extends KFWeap_PistolBase;
|
||||
|
||||
`define HRG_ENERGY_MIC_LED_INDEX_1 0
|
||||
`define HRG_ENERGY_MIC_SCREEN_INDEX 1
|
||||
`define HRG_ENERGY_MIC_LED_INDEX_2 2
|
||||
|
||||
/*********************************************************************************************
|
||||
@name Optics UI
|
||||
********************************************************************************************* */
|
||||
var class<KFGFxWorld_MedicOptics> OpticsUIClass;
|
||||
var KFGFxWorld_MedicOptics OpticsUI;
|
||||
|
||||
/** The last updated value for our ammo - Used to know when to update our optics ammo */
|
||||
var byte StoredPrimaryAmmo;
|
||||
var byte StoredSecondaryAmmo;
|
||||
|
||||
var transient float AltFireMaxShots;
|
||||
|
||||
/** Modifier applied to the alt fire animation */
|
||||
var float SecondaryFireAnimRateModifier;
|
||||
|
||||
/** Material colors applied to different fire modes */
|
||||
var LinearColor DefaultFireMaterialColor;
|
||||
var LinearColor AltFireMaterialColor;
|
||||
|
||||
/** How much recoil the altfire should do */
|
||||
var protected const float AltFireRecoilScale;
|
||||
|
||||
simulated event PreBeginPlay()
|
||||
{
|
||||
super.PreBeginPlay();
|
||||
AltFireMaxShots = MagazineCapacity[DEFAULT_FIREMODE] / AmmoCost[ALTFIRE_FIREMODE];
|
||||
}
|
||||
|
||||
simulated function Activate()
|
||||
{
|
||||
super.Activate();
|
||||
UpdateMaterial(bUseAltFireMode ? ALTFIRE_FIREMODE : DEFAULT_FIREMODE);
|
||||
}
|
||||
|
||||
simulated function UpdateMaterial(byte FireMode)
|
||||
{
|
||||
local LinearColor MatColor;
|
||||
MatColor = FireMode == DEFAULT_FIREMODE ? DefaultFireMaterialColor : AltFireMaterialColor;
|
||||
|
||||
if( WeaponMICs.Length > `HRG_ENERGY_MIC_LED_INDEX_1 )
|
||||
{
|
||||
WeaponMICs[`HRG_ENERGY_MIC_LED_INDEX_1].SetVectorParameterValue('Vector_GlowColor', MatColor);
|
||||
}
|
||||
|
||||
if (WeaponMICs.Length > `HRG_ENERGY_MIC_SCREEN_INDEX)
|
||||
{
|
||||
WeaponMICs[`HRG_ENERGY_MIC_SCREEN_INDEX].SetVectorParameterValue('Color_override', MatColor);
|
||||
}
|
||||
|
||||
if( WeaponMICs.Length > `HRG_ENERGY_MIC_LED_INDEX_2 )
|
||||
{
|
||||
WeaponMICs[`HRG_ENERGY_MIC_LED_INDEX_2].SetVectorParameterValue('Vector_GlowColor', MatColor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check target locking - server-side only
|
||||
* HealAmmo Regen client and server
|
||||
*/
|
||||
simulated event Tick( FLOAT DeltaTime )
|
||||
{
|
||||
if (Instigator != none && Instigator.weapon == self)
|
||||
{
|
||||
UpdateOpticsUI();
|
||||
}
|
||||
|
||||
Super.Tick(DeltaTime);
|
||||
}
|
||||
|
||||
/*********************************************************************************************
|
||||
@name Optics UI
|
||||
********************************************************************************************* */
|
||||
|
||||
/** Get our optics movie from the inventory once our InvManager is created */
|
||||
reliable client function ClientWeaponSet(bool bOptionalSet, optional bool bDoNotActivate)
|
||||
{
|
||||
local KFInventoryManager KFIM;
|
||||
|
||||
super.ClientWeaponSet(bOptionalSet, bDoNotActivate);
|
||||
|
||||
if (OpticsUI == none)
|
||||
{
|
||||
KFIM = KFInventoryManager(InvManager);
|
||||
if (KFIM != none)
|
||||
{
|
||||
//Create the screen's UI piece
|
||||
OpticsUI = KFGFxWorld_MedicOptics(KFIM.GetOpticsUIMovie(OpticsUIClass));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function ItemRemovedFromInvManager()
|
||||
{
|
||||
local KFInventoryManager KFIM;
|
||||
local KFWeap_MedicBase KFW;
|
||||
|
||||
Super.ItemRemovedFromInvManager();
|
||||
|
||||
if (OpticsUI != none)
|
||||
{
|
||||
KFIM = KFInventoryManager(InvManager);
|
||||
if (KFIM != none)
|
||||
{
|
||||
// @todo future implementation will have optics in base weapon class
|
||||
foreach KFIM.InventoryActors(class'KFWeap_MedicBase', KFW)
|
||||
{
|
||||
// This is not a MedicBase, no need to check against itself
|
||||
if(KFW.OpticsUI.Class == OpticsUI.class)
|
||||
{
|
||||
// A different weapon is still using this optics class
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//Create the screen's UI piece
|
||||
KFIM.RemoveOpticsUIMovie(OpticsUI.class);
|
||||
|
||||
OpticsUI.Close();
|
||||
OpticsUI = none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Unpause our optics movie and reinitialize our ammo when we equip the weapon */
|
||||
simulated function AttachWeaponTo(SkeletalMeshComponent MeshCpnt, optional Name SocketName)
|
||||
{
|
||||
super.AttachWeaponTo(MeshCpnt, SocketName);
|
||||
|
||||
if (OpticsUI != none)
|
||||
{
|
||||
OpticsUI.SetPause(false);
|
||||
OpticsUI.ClearLockOn();
|
||||
UpdateOpticsUI(true);
|
||||
OpticsUI.SetShotPercentCost( AmmoCost[ALTFIRE_FIREMODE]);
|
||||
}
|
||||
}
|
||||
|
||||
/** Pause the optics movie once we unequip the weapon so it's not playing in the background */
|
||||
simulated function DetachWeapon()
|
||||
{
|
||||
local Pawn OwnerPawn;
|
||||
super.DetachWeapon();
|
||||
|
||||
OwnerPawn = Pawn(Owner);
|
||||
if( OwnerPawn != none && OwnerPawn.Weapon == self )
|
||||
{
|
||||
if (OpticsUI != none)
|
||||
{
|
||||
OpticsUI.SetPause();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update our displayed ammo count if it's changed
|
||||
*/
|
||||
simulated function UpdateOpticsUI(optional bool bForceUpdate)
|
||||
{
|
||||
if (OpticsUI != none && OpticsUI.OpticsContainer != none)
|
||||
{
|
||||
if (AmmoCount[DEFAULT_FIREMODE] != StoredPrimaryAmmo || bForceUpdate)
|
||||
{
|
||||
StoredPrimaryAmmo = AmmoCount[DEFAULT_FIREMODE];
|
||||
OpticsUI.SetPrimaryAmmo(StoredPrimaryAmmo);
|
||||
|
||||
if(AmmoCount[DEFAULT_FIREMODE] < AmmoCost[ALTFIRE_FIREMODE])
|
||||
{
|
||||
OpticsUI.SetHealerCharge(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
OpticsUI.SetHealerCharge((AmmoCount[DEFAULT_FIREMODE] / AmmoCost[ALTFIRE_FIREMODE]) / AltFireMaxShots * 100);
|
||||
}
|
||||
}
|
||||
|
||||
if(OpticsUI.MinPercentPerShot != AmmoCost[ALTFIRE_FIREMODE])
|
||||
{
|
||||
OpticsUI.SetShotPercentCost( AmmoCost[ALTFIRE_FIREMODE] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Healing charge doesn't count as ammo for purposes of inventory management (e.g. switching) */
|
||||
simulated function bool HasAnyAmmo()
|
||||
{
|
||||
return HasSpareAmmo() || HasAmmo(DEFAULT_FIREMODE) || HasSpareAmmo(ALTFIRE_FIREMODE) || HasAmmo(ALTFIRE_FIREMODE);
|
||||
}
|
||||
|
||||
simulated function StartFire(byte FireModeNum)
|
||||
{
|
||||
if (FireModeNum == DEFAULT_FIREMODE && bUseAltFireMode)
|
||||
{
|
||||
if (AmmoCount[FireModeNum] < AmmoCost[ALTFIRE_FIREMODE] && SpareAmmoCount[FireModeNum] > 0)
|
||||
{
|
||||
BeginFire(RELOAD_FIREMODE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
super.StartFire(FireModeNum);
|
||||
}
|
||||
|
||||
simulated function AltFireMode()
|
||||
{
|
||||
if ( !Instigator.IsLocallyControlled() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !bUseAltFireMode && SpareAmmoCount[0] + AmmoCount[0] < AmmoCost[1] )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
super.AltFireMode();
|
||||
UpdateMaterial(bUseAltFireMode ? ALTFIRE_FIREMODE : DEFAULT_FIREMODE);
|
||||
|
||||
NotifyAltFireUsage();
|
||||
}
|
||||
|
||||
/** Overriden to use WeaponAnimSeqNode */
|
||||
simulated function PlayWeaponAnimation(name Sequence, float fDesiredDuration, optional bool bLoop, optional SkeletalMeshComponent SkelMesh)
|
||||
{
|
||||
local float DesiredRate;
|
||||
|
||||
if ( Mesh != none && Instigator != none && WorldInfo.NetMode != NM_DedicatedServer )
|
||||
{
|
||||
if ( WeaponAnimSeqNode != None )
|
||||
{
|
||||
if (WeaponAnimSeqNode.AnimSeq == None || WeaponAnimSeqNode.AnimSeq.SequenceName != Sequence)
|
||||
{
|
||||
WeaponAnimSeqNode.SetAnim(Sequence);
|
||||
}
|
||||
|
||||
if(fDesiredDuration > 0.0 && WeaponAnimSeqNode.AnimSeq.RateScale > 0.0)
|
||||
{
|
||||
DesiredRate = WeaponAnimSeqNode.AnimSeq.SequenceLength / (fDesiredDuration * WeaponAnimSeqNode.AnimSeq.RateScale);
|
||||
WeaponAnimSeqNode.PlayAnim(bLoop, DesiredRate);
|
||||
}
|
||||
else
|
||||
{
|
||||
WeaponAnimSeqNode.PlayAnim(bLoop, DefaultAnimSpeed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PlayFireEffects Is the root function that handles all of the effects associated with
|
||||
* a weapon. This function creates the 1st person effects. It should only be called
|
||||
* on a locally controlled player.
|
||||
*/
|
||||
simulated function PlayFireEffects( byte FireModeNum, optional vector HitLocation )
|
||||
{
|
||||
local name WeaponFireAnimName;
|
||||
local KFPerk CurrentPerk;
|
||||
local float TempTweenTime, AdjustedAnimLength;
|
||||
|
||||
// If we have stopped the looping fire sound to play single fire sounds for zed time
|
||||
// start the looping sound back up again when the time is back above zed time speed
|
||||
if( FireModeNum < bLoopingFireSnd.Length && bLoopingFireSnd[FireModeNum] && !bPlayingLoopingFireSnd )
|
||||
{
|
||||
StartLoopingFireSound(FireModeNum);
|
||||
}
|
||||
|
||||
PlayFiringSound(CurrentFireMode);
|
||||
|
||||
if( Instigator != none )
|
||||
{
|
||||
// Tell our pawn about any changes in animation speed
|
||||
UpdateWeaponAttachmentAnimRate( GetThirdPersonAnimRate() );
|
||||
|
||||
if( Instigator.IsLocallyControlled() )
|
||||
{
|
||||
if( Instigator.IsFirstPerson() )
|
||||
{
|
||||
if ( !bPlayingLoopingFireAnim )
|
||||
{
|
||||
WeaponFireAnimName = GetWeaponFireAnim(FireModeNum);
|
||||
|
||||
if ( WeaponFireAnimName != '' )
|
||||
{
|
||||
AdjustedAnimLength = MySkelMesh.GetAnimLength(WeaponFireAnimName);
|
||||
TempTweenTime = FireTweenTime;
|
||||
|
||||
if (FireModeNum == ALTFIRE_FIREMODE)
|
||||
{
|
||||
AdjustedAnimLength *= SecondaryFireAnimRateModifier;
|
||||
}
|
||||
|
||||
CurrentPerk = GetPerk();
|
||||
if( CurrentPerk != none )
|
||||
{
|
||||
CurrentPerk.ModifyRateOfFire( AdjustedAnimLength, self );
|
||||
|
||||
// We need to unlock the slide if we fire from zero ammo while uber ammo is active
|
||||
if( EmptyMagBlendNode != none
|
||||
&& BonesToLockOnEmpty.Length > 0
|
||||
&& AmmoCount[GetAmmoType(FireModeNum)] == 0
|
||||
&& CurrentPerk.GetIsUberAmmoActive(self) )
|
||||
{
|
||||
EmptyMagBlendNode.SetBlendTarget( 0, 0 );
|
||||
TempTweenTime = 0.f;
|
||||
}
|
||||
}
|
||||
|
||||
PlayAnimation(WeaponFireAnimName, AdjustedAnimLength,, TempTweenTime);
|
||||
}
|
||||
}
|
||||
|
||||
// Start muzzle flash effect
|
||||
CauseMuzzleFlash(FireModeNum);
|
||||
}
|
||||
|
||||
HandleRecoil();
|
||||
ShakeView();
|
||||
|
||||
if (AmmoCount[0] == 0 && ForceReloadTimeOnEmpty > 0)
|
||||
{
|
||||
SetTimer(ForceReloadTimeOnEmpty, false, nameof(ForceReload));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
simulated function ModifyRecoil( out float CurrentRecoilModifier )
|
||||
{
|
||||
if( CurrentFireMode == ALTFIRE_FIREMODE )
|
||||
{
|
||||
CurrentRecoilModifier *= AltFireRecoilScale;
|
||||
}
|
||||
|
||||
super.ModifyRecoil( CurrentRecoilModifier );
|
||||
}
|
||||
|
||||
simulated function NotifyAltFireUsage()
|
||||
{
|
||||
local KFPawn_Human KFPH;
|
||||
|
||||
// Notify 3P to change material.
|
||||
KFPH = KFPawn_Human(Instigator);
|
||||
if (KFPH != none)
|
||||
{
|
||||
KFPH.SetUsingAltFireMode(bUseAltFireMode, true);
|
||||
KFPH.bNetDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
simulated state WeaponEquipping
|
||||
{
|
||||
simulated function BeginState(Name PreviousStateName)
|
||||
{
|
||||
super.BeginState(PreviousStateName);
|
||||
// NotifyAltFireUsage();
|
||||
if (WorldInfo.NetMode == NM_Client || WorldInfo.NetMode == NM_Standalone)
|
||||
{
|
||||
SetTimer(1.0f, false, nameof(NotifyAltFireUsage));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns animation to play based on reload type and status */
|
||||
simulated function name GetReloadAnimName( bool bTacticalReload )
|
||||
{
|
||||
return bTacticalReload ? ReloadNonEmptyMagEliteAnim : ReloadNonEmptyMagAnim;
|
||||
}
|
||||
|
||||
simulated function ConsumeAmmo( byte FireModeNum )
|
||||
{
|
||||
super.ConsumeAmmo(FireModeNum);
|
||||
|
||||
if( bUseAltFireMode && SpareAmmoCount[0] + AmmoCount[0] < AmmoCost[1] )
|
||||
{
|
||||
bUseAltFireMode = false;
|
||||
UpdateMaterial(DEFAULT_FIREMODE);
|
||||
NotifyAltFireUsage();
|
||||
}
|
||||
}
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
// Inventory
|
||||
InventoryGroup=IG_Secondary
|
||||
InventorySize=4
|
||||
GroupPriority=125
|
||||
bCanThrow=true
|
||||
bDropOnDeath=true
|
||||
WeaponSelectTexture=Texture2D'WEP_UI_HRG_Energy_TEX.UI_WeaponSelect_HRG_Energy'
|
||||
SecondaryAmmoTexture=Texture2D'UI_SecondaryAmmo_TEX.MedicDarts'
|
||||
AssociatedPerkClasses(0)=class'KFPerk_Gunslinger'
|
||||
|
||||
// Shooting Animations
|
||||
FireSightedAnims[0]=Shoot_Iron
|
||||
FireSightedAnims[1]=Shoot_Iron2
|
||||
FireSightedAnims[2]=Shoot_Iron3
|
||||
|
||||
// FOV
|
||||
MeshFOV=86
|
||||
MeshIronSightFOV=77
|
||||
PlayerIronSightFOV=77
|
||||
|
||||
// Depth of field
|
||||
DOF_FG_FocalRadius=40
|
||||
DOF_FG_MaxNearBlurSize=3.5
|
||||
|
||||
// Zooming/Position
|
||||
PlayerViewOffset=(X=29.0,Y=13,Z=-4)
|
||||
|
||||
//Content
|
||||
PackageKey="HRG_Energy"
|
||||
FirstPersonMeshName="WEP_1P_HRG_Energy_MESH.Wep_1stP_HRG_Energy_Rig"
|
||||
FirstPersonAnimSetNames(0)="WEP_1P_HRG_Energy_ANIM.WEP_1P_HRG_Energy_ANIM"
|
||||
PickupMeshName="wep_3p_HRG_Energy_mesh.Wep_HRG_Energy_Pickup"
|
||||
AttachmentArchetypeName="WEP_HRG_Energy_ARCH.Wep_HRG_Energy_3P"
|
||||
MuzzleFlashTemplateName="WEP_HRG_Energy_ARCH.Wep_HRG_Energy_MuzzleFlash"
|
||||
|
||||
OpticsUIClass=class'KFGFxWorld_MedicOptics'
|
||||
|
||||
// Zooming/Position
|
||||
IronSightPosition=(X=15,Y=0,Z=0)
|
||||
|
||||
// Ammo
|
||||
MagazineCapacity[0]=15
|
||||
SpareAmmoCapacity[0]=135
|
||||
InitialSpareMags[0]=2
|
||||
bCanBeReloaded=true
|
||||
bReloadFromMagazine=true
|
||||
|
||||
MagazineCapacity[1]=0
|
||||
bCanRefillSecondaryAmmo=false
|
||||
|
||||
// Recoil
|
||||
maxRecoilPitch=475 //250
|
||||
minRecoilPitch=425 //200
|
||||
maxRecoilYaw=130 //100
|
||||
minRecoilYaw=-130 //-100
|
||||
RecoilRate=0.07
|
||||
RecoilMaxYawLimit=500
|
||||
RecoilMinYawLimit=65035
|
||||
RecoilMaxPitchLimit=900
|
||||
RecoilMinPitchLimit=65035
|
||||
RecoilISMaxYawLimit=50
|
||||
RecoilISMinYawLimit=65485
|
||||
RecoilISMaxPitchLimit=250
|
||||
RecoilISMinPitchLimit=65485
|
||||
AltFireRecoilScale=2.0f
|
||||
|
||||
// DEFAULT_FIREMODE
|
||||
FireModeIconPaths(DEFAULT_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_BulletSingle'
|
||||
FiringStatesArray(DEFAULT_FIREMODE)=WeaponSingleFiring
|
||||
WeaponFireTypes(DEFAULT_FIREMODE)=EWFT_InstantHit
|
||||
WeaponProjectiles(DEFAULT_FIREMODE)=class'KFProj_Bullet_HRG_Energy'
|
||||
FireInterval(DEFAULT_FIREMODE)=+0.175 //342 RPM
|
||||
PenetrationPower(DEFAULT_FIREMODE)=1.0
|
||||
InstantHitDamage(DEFAULT_FIREMODE)=90.0 //125.0
|
||||
InstantHitDamageTypes(DEFAULT_FIREMODE)=class'KFDT_Ballistic_HRG_Energy_Primary'
|
||||
Spread(DEFAULT_FIREMODE)=0.015
|
||||
FireOffset=(X=20,Y=4.0,Z=-3)
|
||||
|
||||
// ALTFIRE_FIREMODE
|
||||
FireModeIconPaths(ALTFIRE_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_Electricity'
|
||||
FiringStatesArray(ALTFIRE_FIREMODE)=WeaponFiring
|
||||
WeaponFireTypes(ALTFIRE_FIREMODE)=EWFT_InstantHit
|
||||
FireInterval(ALTFIRE_FIREMODE)=+0.705 //85 RPM
|
||||
WeaponProjectiles(ALTFIRE_FIREMODE)=class'KFProj_Bullet_HRG_Energy_Secondary'
|
||||
InstantHitDamageTypes(ALTFIRE_FIREMODE)=class'KFDT_Ballistic_HRG_Energy_Secondary'
|
||||
InstantHitMomentum(ALTFIRE_FIREMODE)=1.0
|
||||
PenetrationPower(ALTFIRE_FIREMODE)=3.0
|
||||
InstantHitDamage(ALTFIRE_FIREMODE)=300.0 //475.0
|
||||
PenetrationDamageReductionCurve(ALTFIRE_FIREMODE)=(Points=((InVal=0.f,OutVal=0.f),(InVal=1.f, OutVal=1.f)))
|
||||
AmmoCost(ALTFIRE_FIREMODE)=3
|
||||
|
||||
// BASH_FIREMODE
|
||||
InstantHitDamageTypes(BASH_FIREMODE)=class'KFDT_Bludgeon_HRG_Energy'
|
||||
InstantHitDamage(BASH_FIREMODE)=26
|
||||
|
||||
// Fire Effects
|
||||
WeaponFireSnd(DEFAULT_FIREMODE)=(DefaultCue=AkEvent'ww_wep_hrg_energy.Play_WEP_HRG_Energy_3P_Shoot', FirstPersonCue=AkEvent'ww_wep_hrg_energy.Play_WEP_HRG_Energy_1P_Shoot')
|
||||
WeaponFireSnd(ALTFIRE_FIREMODE)=(DefaultCue=AkEvent'ww_wep_hrg_energy.Play_WEP_HRG_Energy_3P_ShootAlt', FirstPersonCue=AkEvent'ww_wep_hrg_energy.Play_WEP_HRG_Energy_1P_ShootAlt')
|
||||
WeaponDryFireSnd(DEFAULT_FIREMODE)=AkEvent'WW_WEP_SA_MedicPistol.Play_SA_MedicPistol_Handling_DryFire'
|
||||
WeaponDryFireSnd(ALTFIRE_FIREMODE)=AkEvent'WW_WEP_SA_MedicDart.Play_WEP_SA_Medic_Dart_DryFire'
|
||||
|
||||
// Attachments
|
||||
bHasIronSights=true
|
||||
bHasFlashlight=false
|
||||
|
||||
WeaponUpgrades[1]=(Stats=((Stat=EWUS_Damage0, Scale=1.15f), (Stat=EWUS_Damage1, Scale=1.15f), (Stat=EWUS_Weight, Add=1)))
|
||||
|
||||
SecondaryFireAnimRateModifier = 2.0f;
|
||||
|
||||
DefaultFireMaterialColor=(R=0.90f,G=0.26f,B=0.0f)
|
||||
AltFireMaterialColor=(R=0.7f,G=0.04f,B=0.9f)
|
||||
|
||||
NumBloodMapMaterials=3
|
||||
// bForceHandleImpacts=true;
|
||||
}
|
@ -842,8 +842,8 @@ defaultproperties
|
||||
ValueIncreaseTime=0.2
|
||||
|
||||
//FOR LERPING DAMANGE
|
||||
MaxDamageByCharge=250 //200 //120
|
||||
MinDamageByCharge=25 //30
|
||||
MaxDamageByCharge=300 //250 //200 //120
|
||||
MinDamageByCharge=30 //25 //30
|
||||
// FOV
|
||||
Meshfov=80
|
||||
MeshIronSightFOV=65 //52
|
||||
@ -870,8 +870,8 @@ defaultproperties
|
||||
|
||||
// Ammo
|
||||
MagazineCapacity[0]=12 //24
|
||||
SpareAmmoCapacity[0]=108 //96 //120
|
||||
InitialSpareMags[0]=2 //1
|
||||
SpareAmmoCapacity[0]=132 //108
|
||||
InitialSpareMags[0]=3 //2
|
||||
AmmoPickupScale[0]=1.5 //1 //0.75
|
||||
bCanBeReloaded=true
|
||||
bReloadFromMagazine=true
|
||||
@ -905,7 +905,7 @@ defaultproperties
|
||||
FiringStatesArray(DEFAULT_FIREMODE)=MineReconstructorCharge
|
||||
WeaponFireTypes(DEFAULT_FIREMODE)=EWFT_Projectile
|
||||
WeaponProjectiles(DEFAULT_FIREMODE)=class'KFProj_Mine_Reconstructor'
|
||||
FireInterval(DEFAULT_FIREMODE)=+0.33 //180 RPMs
|
||||
FireInterval(DEFAULT_FIREMODE)=+0.223 //+0.33
|
||||
InstantHitDamage(DEFAULT_FIREMODE)=120
|
||||
PenetrationPower(DEFAULT_FIREMODE)=0.0;
|
||||
InstantHitDamageTypes(DEFAULT_FIREMODE)=class'KFDT_Toxic_MineReconstructorImpact'
|
||||
@ -914,7 +914,7 @@ defaultproperties
|
||||
// ALT_FIREMODE
|
||||
FiringStatesArray(ALTFIRE_FIREMODE)=WeaponSingleFiring
|
||||
WeaponFireTypes(ALTFIRE_FIREMODE)=EWFT_Custom
|
||||
FireInterval(ALTFIRE_FIREMODE)=+0.25
|
||||
FireInterval(ALTFIRE_FIREMODE)=+0.15 //+0.25
|
||||
AmmoCost(ALTFIRE_FIREMODE)=0
|
||||
|
||||
// BASH_FIREMODE
|
||||
|
228
KFGameContent/Classes/KFWeap_Pistol_Bladed.uc
Normal file
228
KFGameContent/Classes/KFWeap_Pistol_Bladed.uc
Normal file
@ -0,0 +1,228 @@
|
||||
//=============================================================================
|
||||
// KFWeap_Pistol_Bladed
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
// Killing Floor 2
|
||||
// Copyright (C) 2021 Tripwire Interactive LLC
|
||||
//=============================================================================
|
||||
|
||||
class KFWeap_Pistol_Bladed extends KFWeap_MeleeBase;
|
||||
|
||||
/** Returns trader filter index based on weapon type */
|
||||
static simulated event EFilterTypeUI GetTraderFilter()
|
||||
{
|
||||
return FT_Pistol;
|
||||
}
|
||||
|
||||
/** Override melee SetIronSights (which sends to heavy attack) so that this weapon ironsights normally*/
|
||||
simulated function SetIronSights(bool bNewIronSights)
|
||||
{
|
||||
super(KFWeapon).SetIronSights(bNewIronSights);
|
||||
}
|
||||
|
||||
/** Override melee ShouldOwnerWalk which doesn't account for walking when in ironsights */
|
||||
simulated function bool ShouldOwnerWalk()
|
||||
{
|
||||
return super(KFWeapon).ShouldOwnerWalk();
|
||||
}
|
||||
|
||||
|
||||
/** Override to drop the player out of ironsights first */
|
||||
simulated function AltFireMode()
|
||||
{
|
||||
if (!Instigator.IsLocallyControlled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// break out of ironsights when starting to block
|
||||
if (bUsingSights)
|
||||
{
|
||||
SetIronSights(false);
|
||||
}
|
||||
|
||||
StartFire(BLOCK_FIREMODE);
|
||||
}
|
||||
|
||||
simulated state MeleeBlocking
|
||||
{
|
||||
simulated function bool AllowIronSights() { return false; }
|
||||
}
|
||||
|
||||
/** Called during reload state */
|
||||
simulated function bool CanOverrideMagReload(byte FireModeNum)
|
||||
{
|
||||
if (FireModeNum == BLOCK_FIREMODE)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.CanOverrideMagReload(FireModeNum);
|
||||
}
|
||||
|
||||
simulated function StartFire(byte FireModeNum)
|
||||
{
|
||||
if( FireModeNum == DEFAULT_FIREMODE )
|
||||
{
|
||||
if ( ShouldAutoReload(FireModeNum) )
|
||||
{
|
||||
BeginFire(RELOAD_FIREMODE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
super.StartFire(FireModeNum);
|
||||
}
|
||||
|
||||
/*********************************************************************************************
|
||||
* @name Firing / Projectile
|
||||
********************************************************************************************* */
|
||||
/**
|
||||
* See Pawn.ProcessInstantHit
|
||||
* @param DamageReduction: Custom KF parameter to handle penetration damage reduction
|
||||
*/
|
||||
simulated function ProcessInstantHitEx(byte FiringMode, ImpactInfo Impact, optional int NumHits, optional out float out_PenetrationVal, optional int ImpactNum )
|
||||
{
|
||||
local KFPerk InstigatorPerk;
|
||||
|
||||
InstigatorPerk = GetPerk();
|
||||
if( InstigatorPerk != none )
|
||||
{
|
||||
InstigatorPerk.UpdatePerkHeadShots( Impact, InstantHitDamageTypes[FiringMode], ImpactNum );
|
||||
}
|
||||
|
||||
super.ProcessInstantHitEx( FiringMode, Impact, NumHits, out_PenetrationVal, ImpactNum );
|
||||
}
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
// MeleeBase
|
||||
bMeleeWeapon=false
|
||||
// FOV
|
||||
MeshFOV=96
|
||||
MeshIronSightFOV=77
|
||||
PlayerIronSightFOV=77
|
||||
|
||||
// Depth of field
|
||||
DOF_FG_FocalRadius=40
|
||||
DOF_FG_MaxNearBlurSize=3.5
|
||||
|
||||
// Zooming/Position
|
||||
PlayerViewOffset=(X=-15,Y=12,Z=-6)
|
||||
IronSightPosition=(X=0,Y=0,Z=1.0) //(X=-3,Y=-0.38,Z=-0.2)
|
||||
|
||||
// Content
|
||||
PackageKey="BladedPistol"
|
||||
FirstPersonMeshName="WEP_1P_BladedPistol_MESH.WEP_1stP_BladedPistol_Rig"
|
||||
FirstPersonAnimSetNames(0)="WEP_1P_BladedPistol_ANIM.WEP_1stP_BladedPistol_Anim"
|
||||
PickupMeshName="WEP_3P_BladedPistol_MESH.Wep_BladedPistol_Pickup"
|
||||
AttachmentArchetypeName="WEP_BladedPistol_ARCH.Wep_BladedPistol_3P"
|
||||
MuzzleFlashTemplateName="WEP_BladedPistol_ARCH.Wep_BladedPistol_MuzzleFlash"
|
||||
|
||||
// Ammo
|
||||
MagazineCapacity[0]=6
|
||||
SpareAmmoCapacity[0]=72 //96
|
||||
InitialSpareMags[0]=2
|
||||
AmmoPickupScale[0]=1.0 //2.0
|
||||
bCanBeReloaded=true
|
||||
bReloadFromMagazine=true
|
||||
|
||||
// Recoil
|
||||
maxRecoilPitch=330 //400 //250
|
||||
minRecoilPitch=300 //350 //200
|
||||
maxRecoilYaw=90 //120 //100
|
||||
minRecoilYaw=-90 //-120 //-100
|
||||
RecoilRate=0.07
|
||||
RecoilMaxYawLimit=500
|
||||
RecoilMinYawLimit=65035
|
||||
RecoilMaxPitchLimit=900
|
||||
RecoilMinPitchLimit=65035
|
||||
RecoilISMaxYawLimit=50
|
||||
RecoilISMinYawLimit=65485
|
||||
RecoilISMaxPitchLimit=250
|
||||
RecoilISMinPitchLimit=65485
|
||||
|
||||
// DEFAULT_FIREMODE
|
||||
FiringStatesArray(DEFAULT_FIREMODE)=WeaponSingleFiring
|
||||
WeaponFireTypes(DEFAULT_FIREMODE)=EWFT_Projectile
|
||||
WeaponProjectiles(DEFAULT_FIREMODE)=class'KFProj_Blade_BladedPistol'
|
||||
PenetrationPower(DEFAULT_FIREMODE)=3.0
|
||||
FireInterval(DEFAULT_FIREMODE)=+0.25 //+0.3
|
||||
InstantHitDamage(DEFAULT_FIREMODE)=115.0
|
||||
InstantHitDamageTypes(DEFAULT_FIREMODE)=class'KFDT_Slashing_BladedPistol'
|
||||
Spread(DEFAULT_FIREMODE)=0.005 //0.015
|
||||
AmmoCost(DEFAULT_FIREMODE)=1
|
||||
|
||||
FireOffset=(X=30,Y=5,Z=-4)
|
||||
|
||||
FireModeIconPaths(DEFAULT_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_Sawblade'
|
||||
|
||||
// ALT_FIREMODE
|
||||
// FiringStatesArray(ALTFIRE_FIREMODE)=WeaponSingleFiring
|
||||
// WeaponFireTypes(ALTFIRE_FIREMODE)=EWFT_None
|
||||
|
||||
// BASH_FIREMODE
|
||||
InstantHitDamageTypes(BASH_FIREMODE)=class'KFDT_Bludgeon_BladedPistol'
|
||||
InstantHitDamage(BASH_FIREMODE)=75 //26
|
||||
FiringStatesArray(BASH_FIREMODE)=MeleeAttackBasic
|
||||
WeaponFireTypes(BASH_FIREMODE)=EWFT_Custom
|
||||
InstantHitMomentum(BASH_FIREMODE)=10000.f
|
||||
|
||||
// Fire Effects
|
||||
WeaponFireSnd(DEFAULT_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_BladedPistol.Play_WEP_BladedPistol_Fire_3P', FirstPersonCue=AkEvent'WW_WEP_BladedPistol.Play_WEP_BladedPistol_Fire_1P')
|
||||
WeaponDryFireSnd(DEFAULT_FIREMODE)=AkEvent'WW_WEP_BladedPistol.Play_WEP_BladedPistol_Handling_DryFire'
|
||||
|
||||
// RELOAD_FIREMODE
|
||||
FiringStatesArray(RELOAD_FIREMODE)="Reloading"
|
||||
WeaponFireTypes(RELOAD_FIREMODE)=EWFT_InstantHit
|
||||
|
||||
// Attachments
|
||||
bHasIronSights=true
|
||||
bHasFlashlight=true
|
||||
|
||||
AssociatedPerkClasses(0)=class'KFPerk_Gunslinger'
|
||||
AssociatedPerkClasses(1)=class'KFPerk_Berserker'
|
||||
|
||||
|
||||
// Inventory
|
||||
InventoryGroup=IG_Secondary
|
||||
InventorySize=3
|
||||
GroupPriority=25
|
||||
bCanThrow=true
|
||||
bDropOnDeath=true
|
||||
WeaponSelectTexture=Texture2D'WEP_UI_BladedPistol_TEX.UI_WeaponSelect_BladedPistol'
|
||||
bIsBackupWeapon=false
|
||||
|
||||
DualClass=class'KFWeap_Pistol_DualBladed'
|
||||
|
||||
// Custom animations
|
||||
FireSightedAnims=(Shoot_Iron)
|
||||
IdleFidgetAnims=(Guncheck_v1, Guncheck_v2, Guncheck_v3)
|
||||
|
||||
bHasFireLastAnims=true
|
||||
|
||||
BonesToLockOnEmpty=(RW_FrontPivot)
|
||||
|
||||
// default MIC param names
|
||||
BlockEffectsSocketName=BlockEffect
|
||||
// Defensive
|
||||
BlockDamageMitigation=0.60f
|
||||
ParryDamageMitigationPercent=0.5
|
||||
ParryStrength=4
|
||||
BlockHitAnimCooldownTime=0.5f
|
||||
BlockTypes.Add((DmgType=class'KFDT_Bludgeon'))
|
||||
BlockTypes.Add((DmgType=class'KFDT_Slashing'))
|
||||
|
||||
// Block Sounds
|
||||
BlockSound=AkEvent'WW_WEP_Bullet_Impacts.Play_Block_MEL_Crovel'
|
||||
ParrySound=AkEvent'WW_WEP_Bullet_Impacts.Play_Parry_Metal'
|
||||
|
||||
BlockParticleSystem=ParticleSystem'FX_Impacts_EMIT.FX_Block_melee_01'
|
||||
ParryParticleSystem=ParticleSystem'FX_Impacts_EMIT.FX_Parry_melee_01'
|
||||
MeleeBlockHitAnims=(Block_Hit_V1, Block_Hit_V2, Block_Hit_V3);
|
||||
|
||||
//Upgrades
|
||||
WeaponUpgrades[1]=(Stats=((Stat=EWUS_Damage0, Scale=1.15f), (Stat=EWUS_Damage1, Scale=1.15f), (Stat=EWUS_Damage2, Scale=1.15f), (Stat=EWUS_Weight, Add=1)))
|
||||
WeaponUpgrades[2]=(Stats=((Stat=EWUS_Damage0, Scale=1.3f), (Stat=EWUS_Damage1, Scale=1.3f), (Stat=EWUS_Damage2, Scale=1.3f), (Stat=EWUS_Weight, Add=2)))
|
||||
}
|
||||
|
679
KFGameContent/Classes/KFWeap_Pistol_DualBladed.uc
Normal file
679
KFGameContent/Classes/KFWeap_Pistol_DualBladed.uc
Normal file
@ -0,0 +1,679 @@
|
||||
//=============================================================================
|
||||
// KFWeap_Pistol_DualBladed
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
// Killing Floor 2
|
||||
// Copyright (C) 2021 Tripwire Interactive LLC
|
||||
//=============================================================================
|
||||
|
||||
class KFWeap_Pistol_DualBladed extends KFWeap_DualBase;
|
||||
|
||||
/*
|
||||
*
|
||||
* BROUGHT FROM MELEE WEAPON TO SUPPORT PARRYING
|
||||
*
|
||||
*/
|
||||
|
||||
/** These override the base firemodes of the same ID (for readability) */
|
||||
const BLOCK_FIREMODE = 1; // ALTFIRE_FIREMODE
|
||||
|
||||
/*********************************************************************************************
|
||||
* @name Defensive Abilities
|
||||
*********************************************************************************************/
|
||||
|
||||
struct native BlockEffectInfo
|
||||
{
|
||||
var class<DamageType> DmgType;
|
||||
|
||||
/** If != None, overrides the class default FX */
|
||||
var AkEvent BlockSound;
|
||||
var AkEvent ParrySound;
|
||||
var ParticleSystem BlockParticleSys;
|
||||
var ParticleSystem ParryParticleSys;
|
||||
};
|
||||
|
||||
var array<BlockEffectInfo> BlockTypes;
|
||||
|
||||
/** Damage while blocking will be mitigated by this percentage */
|
||||
var() float BlockDamageMitigation;
|
||||
|
||||
/** Parry damage will be mitigated by this percentage */
|
||||
var() float ParryDamageMitigationPercent;
|
||||
/** Hit reaction strength to bypass pawn's ParryStumbleResist */
|
||||
var() byte ParryStrength;
|
||||
|
||||
/** If true, owning pawn moves at a slower (iron sight) walking speed */
|
||||
var bool bMoveAtWalkingSpeed;
|
||||
|
||||
/** Time between block hit reaction anims */
|
||||
var() protected float BlockHitAnimCooldownTime;
|
||||
|
||||
/** The last time we played a block hit reaction anim */
|
||||
var transient protected float LastBlockHitAnimTime;
|
||||
|
||||
/** Animations played on successful block */
|
||||
var array<name> MeleeBlockHitAnims;
|
||||
|
||||
/*********************************************************************************************
|
||||
* @name Effects
|
||||
********************************************************************************************* */
|
||||
/** Block / Parry */
|
||||
var AkBaseSoundObject BlockSound;
|
||||
var AKBaseSoundObject ParrySound;
|
||||
var ParticleSystem BlockParticleSystem;
|
||||
var ParticleSystem ParryParticleSystem;
|
||||
var name BlockEffectsSocketName;
|
||||
|
||||
/** Defensive stance animation names */
|
||||
const MeleeBlockStartAnim = 'Brace_in';
|
||||
const MeleeBlockLoopAnim = 'Brace_loop';
|
||||
const MeleeBlockEndAnim = 'Brace_out';
|
||||
|
||||
var array<name> BonesToLockOnEmpty_Override;
|
||||
|
||||
simulated function NotifyAttackParried();
|
||||
simulated function NotifyAttackBlocked();
|
||||
|
||||
// Global declarations for blocking state
|
||||
simulated function BlockLoopTimer();
|
||||
simulated function ParryCheckTimer();
|
||||
|
||||
/** Called on the server when successfully block/parry an attack */
|
||||
unreliable client function ClientPlayBlockEffects(optional byte BlockTypeIndex=255)
|
||||
{
|
||||
local AkBaseSoundObject Sound;
|
||||
local ParticleSystem PSTemplate;
|
||||
|
||||
GetBlockEffects(BlockTypeIndex, Sound, PSTemplate);
|
||||
PlayLocalBlockEffects(Sound, PSTemplate);
|
||||
}
|
||||
|
||||
/** Called on the server when successfully block/parry an attack */
|
||||
reliable client function ClientPlayParryEffects(optional byte BlockTypeIndex=255)
|
||||
{
|
||||
local AkBaseSoundObject Sound;
|
||||
local ParticleSystem PSTemplate;
|
||||
local KFPerk InstigatorPerk;
|
||||
|
||||
InstigatorPerk = GetPerk();
|
||||
if( InstigatorPerk != none )
|
||||
{
|
||||
InstigatorPerk.SetSuccessfullParry();
|
||||
}
|
||||
|
||||
GetParryEffects(BlockTypeIndex, Sound, PSTemplate);
|
||||
PlayLocalBlockEffects(Sound, PSTemplate);
|
||||
}
|
||||
|
||||
simulated state MeleeBlocking
|
||||
{
|
||||
ignores ForceReload, ShouldAutoReload;
|
||||
|
||||
simulated function bool AllowIronSights() { return false; }
|
||||
|
||||
simulated function byte GetWeaponStateId()
|
||||
{
|
||||
return WEP_MeleeBlock;
|
||||
}
|
||||
|
||||
simulated function BeginState(name PreviousStateName)
|
||||
{
|
||||
local float ParryDuration;
|
||||
|
||||
ParryDuration = PlayBlockStart();
|
||||
|
||||
// Set the duration of the window to parry incoming attacks
|
||||
if ( ParryDuration > 0.f )
|
||||
{
|
||||
SetTimer( ParryDuration, false, nameof(ParryCheckTimer) );
|
||||
}
|
||||
|
||||
NotifyBeginState();
|
||||
}
|
||||
|
||||
simulated function EndState(Name NextStateName)
|
||||
{
|
||||
if ( Instigator.IsLocallyControlled() )
|
||||
{
|
||||
PlayAnimation(MeleeBlockEndAnim);
|
||||
}
|
||||
|
||||
//SetSlowMovement(false);
|
||||
NotifyEndState();
|
||||
}
|
||||
|
||||
/** Return to active state if we're done blocking */
|
||||
simulated function EndFire(byte FireModeNum)
|
||||
{
|
||||
Global.EndFire(FireModeNum);
|
||||
|
||||
// Wait until parry is finished, then check PendingFire to stop blocking
|
||||
if ( !StillFiring(CurrentFireMode) && !IsTimerActive(nameof(ParryCheckTimer)) )
|
||||
{
|
||||
GotoState('BlockingCooldown');
|
||||
}
|
||||
}
|
||||
|
||||
/** After the parry window is finished, check PendingFire to see if we're still blocking */
|
||||
simulated function ParryCheckTimer()
|
||||
{
|
||||
// Check PendingFire to stop blocking
|
||||
if ( !StillFiring(CurrentFireMode) )
|
||||
{
|
||||
GotoState('BlockingCooldown');
|
||||
}
|
||||
}
|
||||
|
||||
/** Grab/Grapple attacks can be parried */
|
||||
function bool IsGrappleBlocked(Pawn InstigatedBy)
|
||||
{
|
||||
local float FacingDot;
|
||||
local vector Dir2d;
|
||||
|
||||
// zero Z to give us a 2d dot product
|
||||
Dir2d = Normal2d(InstigatedBy.Location - Instigator.Location);
|
||||
FacingDot = vector(Instigator.Rotation) dot (Dir2d);
|
||||
|
||||
// Cos(85)
|
||||
if ( FacingDot > 0.087f )
|
||||
{
|
||||
if ( IsTimerActive(nameof(ParryCheckTimer)) )
|
||||
{
|
||||
KFPawn(InstigatedBy).NotifyAttackParried(Instigator, 255);
|
||||
ClientPlayParryEffects();
|
||||
NotifyAttackParried();
|
||||
}
|
||||
else
|
||||
{
|
||||
ClientPlayBlockEffects();
|
||||
NotifyAttackBlocked();
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/** While holding a melee weapon reduce some incoming damage */
|
||||
function AdjustDamage(out int InDamage, class<DamageType> DamageType, Actor DamageCauser)
|
||||
{
|
||||
local float FacingDot;
|
||||
local vector Dir2d;
|
||||
local KFPerk InstigatorPerk;
|
||||
local byte BlockTypeIndex;
|
||||
|
||||
// don't apply block/parry effects for teammates
|
||||
if (Instigator.IsSameTeam(DamageCauser.Instigator))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// zero Z to give us a 2d dot product
|
||||
Dir2d = Normal2d(DamageCauser.Location - Instigator.Location);
|
||||
FacingDot = vector(Instigator.Rotation) dot (Dir2d);
|
||||
|
||||
// Cos(85)
|
||||
if ( FacingDot > 0.087f && CanBlockDamageType(DamageType, BlockTypeIndex) )
|
||||
{
|
||||
InstigatorPerk = GetPerk();
|
||||
|
||||
if ( IsTimerActive(nameof(ParryCheckTimer)) )
|
||||
{
|
||||
InDamage *= GetUpgradedParryDamageMitigation(CurrentWeaponUpgradeIndex);
|
||||
// Notify attacking pawn for effects / animations
|
||||
if ( KFPawn(DamageCauser) != None )
|
||||
{
|
||||
KFPawn(DamageCauser).NotifyAttackParried(Instigator, ParryStrength);
|
||||
}
|
||||
|
||||
// @NOTE: This is now always true per discussion with AndrewL on KFII-29686. Since we always
|
||||
// do the damage mitigation, we should always play the effect regardless of whether the
|
||||
// zed was stumbled or knocked down. -MattF
|
||||
ClientPlayParryEffects(BlockTypeIndex);
|
||||
|
||||
NotifyAttackParried();
|
||||
|
||||
if( InstigatorPerk != none )
|
||||
{
|
||||
InstigatorPerk.SetSuccessfullParry();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
InDamage *= GetUpgradedBlockDamageMitigation(CurrentWeaponUpgradeIndex);
|
||||
ClientPlayBlockEffects(BlockTypeIndex);
|
||||
|
||||
NotifyAttackBlocked();
|
||||
|
||||
if( InstigatorPerk != none )
|
||||
{
|
||||
InstigatorPerk.SetSuccessfullBlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
simulated function BlockLoopTimer()
|
||||
{
|
||||
if( Instigator.IsLocallyControlled() )
|
||||
{
|
||||
PlayAnimation(MeleeBlockLoopAnim, , true);
|
||||
}
|
||||
}
|
||||
|
||||
/** State override for Block_Hit animations */
|
||||
unreliable client function ClientPlayBlockEffects(optional byte BlockTypeIndex=255)
|
||||
{
|
||||
local int AnimIdx;
|
||||
local float Duration;
|
||||
local KFPerk InstigatorPerk;
|
||||
|
||||
Global.ClientPlayBlockEffects(BlockTypeIndex);
|
||||
|
||||
InstigatorPerk = GetPerk();
|
||||
if( InstigatorPerk != none )
|
||||
{
|
||||
InstigatorPerk.SetSuccessfullBlock();
|
||||
}
|
||||
|
||||
if( MeleeBlockHitAnims.Length > 0 && `TimeSince(LastBlockHitAnimTime) > BlockHitAnimCooldownTime && !IsTimerActive(nameof(ParryCheckTimer)) )
|
||||
{
|
||||
AnimIdx = Rand(MeleeBlockHitAnims.Length);
|
||||
Duration = MySkelMesh.GetAnimLength(MeleeBlockHitAnims[AnimIdx]);
|
||||
|
||||
if ( Duration > 0 )
|
||||
{
|
||||
LastBlockHitAnimTime = WorldInfo.TimeSeconds;
|
||||
PlayAnimation(MeleeBlockHitAnims[AnimIdx]);
|
||||
SetTimer(Duration, false, nameof(BlockLoopTimer));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
simulated function float PlayBlockStart()
|
||||
{
|
||||
local float AnimDuration;
|
||||
|
||||
if( Instigator.IsLocallyControlled() )
|
||||
{
|
||||
PlayAnimation(MeleeBlockStartAnim);
|
||||
}
|
||||
|
||||
// set when to start playing the looping anim
|
||||
AnimDuration = MySkelMesh.GetAnimLength(MeleeBlockStartAnim);
|
||||
if ( AnimDuration > 0.f )
|
||||
{
|
||||
SetTimer(AnimDuration, false, nameof(BlockLoopTimer));
|
||||
}
|
||||
else
|
||||
{
|
||||
BlockLoopTimer();
|
||||
}
|
||||
|
||||
// set the parry duration to the same as the block start anim
|
||||
return AnimDuration;
|
||||
}
|
||||
|
||||
/** Called on the client when successfully block/parry an attack */
|
||||
simulated function PlayLocalBlockEffects(AKBaseSoundObject Sound, ParticleSystem PSTemplate)
|
||||
{
|
||||
local vector Loc;
|
||||
local rotator Rot;
|
||||
local ParticleSystemComponent PSC;
|
||||
|
||||
if ( Sound != None )
|
||||
{
|
||||
PlaySoundBase(Sound, true);
|
||||
}
|
||||
|
||||
if ( PSTemplate != None )
|
||||
{
|
||||
if ( MySkelMesh.GetSocketWorldLocationAndRotation(BlockEffectsSocketName, Loc, Rot) )
|
||||
{
|
||||
PSC = WorldInfo.MyEmitterPool.SpawnEmitter(PSTemplate, Loc, Rot);
|
||||
PSC.SetDepthPriorityGroup(SDPG_Foreground);
|
||||
}
|
||||
else
|
||||
{
|
||||
`log(self@GetFuncName()@"missing BlockEffects Socket!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** If true, this damage type can be blocked by the MeleeBlocking state */
|
||||
function bool CanBlockDamageType(class<DamageType> DamageType, optional out byte out_Idx)
|
||||
{
|
||||
local int Idx;
|
||||
|
||||
// Check if this damage should be ignored completely
|
||||
for (Idx = 0; Idx < BlockTypes.length; ++Idx)
|
||||
{
|
||||
if ( ClassIsChildOf(DamageType, BlockTypes[Idx].DmgType) )
|
||||
{
|
||||
out_Idx = Idx;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
out_Idx = INDEX_NONE;
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Returns sound and particle system overrides using index into BlockTypes array */
|
||||
simulated function GetBlockEffects(byte BlockIndex, out AKBaseSoundObject outSound, out ParticleSystem outParticleSys)
|
||||
{
|
||||
outSound = BlockSound;
|
||||
outParticleSys = BlockParticleSystem;
|
||||
|
||||
if ( BlockIndex != 255 )
|
||||
{
|
||||
if ( BlockTypes[BlockIndex].BlockSound != None )
|
||||
{
|
||||
outSound = BlockTypes[BlockIndex].BlockSound;
|
||||
}
|
||||
if ( BlockTypes[BlockIndex].BlockParticleSys != None )
|
||||
{
|
||||
outParticleSys = BlockTypes[BlockIndex].BlockParticleSys;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns sound and particle system overrides using index into BlockTypes array */
|
||||
simulated function GetParryEffects(byte BlockIndex, out AKBaseSoundObject outSound, out ParticleSystem outParticleSys)
|
||||
{
|
||||
outSound = ParrySound;
|
||||
outParticleSys = ParryParticleSystem;
|
||||
|
||||
if ( BlockIndex != 255 )
|
||||
{
|
||||
if ( BlockTypes[BlockIndex].ParrySound != None )
|
||||
{
|
||||
outSound = BlockTypes[BlockIndex].ParrySound;
|
||||
}
|
||||
if ( BlockTypes[BlockIndex].ParryParticleSys != None )
|
||||
{
|
||||
outParticleSys = BlockTypes[BlockIndex].ParryParticleSys;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************
|
||||
* State BlockingCooldown
|
||||
* A short cooldown state to prevent spamming block while still allowing pendingfire to be set
|
||||
*********************************************************************************************/
|
||||
|
||||
// Global declarations for this state
|
||||
simulated function BlockCooldownTimer();
|
||||
|
||||
simulated state BlockingCooldown extends Active
|
||||
{
|
||||
ignores AllowSprinting;
|
||||
|
||||
/** Set cooldown duration */
|
||||
simulated function BeginState( Name PreviousStateName )
|
||||
{
|
||||
SetTimer(0.5, false, nameof(BlockCooldownTimer));
|
||||
Super.BeginState(PreviousStateName);
|
||||
}
|
||||
|
||||
// prevent going to block/parry state
|
||||
simulated function bool HasAmmo( byte FireModeNum, optional int Amount )
|
||||
{
|
||||
if ( FireModeNum == BLOCK_FIREMODE )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Global.HasAmmo(FireModeNum, Amount);
|
||||
}
|
||||
|
||||
// prevent HasAmmo (above) from causing an auto reload
|
||||
simulated function bool ShouldAutoReload(byte FireModeNum)
|
||||
{
|
||||
if ( FireModeNum == BLOCK_FIREMODE )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Global.ShouldAutoReload(FireModeNum);
|
||||
}
|
||||
|
||||
simulated function BlockCooldownTimer()
|
||||
{
|
||||
GotoState('Active');
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* END of parrying code.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Toggle between DEFAULT and ALTFIRE
|
||||
*/
|
||||
simulated function AltFireMode()
|
||||
{
|
||||
if (!Instigator.IsLocallyControlled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// break out of ironsights when starting to block
|
||||
if (bUsingSights)
|
||||
{
|
||||
SetIronSights(false);
|
||||
}
|
||||
|
||||
Super(KFWeapon).StartFire(BLOCK_FIREMODE);
|
||||
}
|
||||
|
||||
/** Called during reload state */
|
||||
simulated function bool CanOverrideMagReload(byte FireModeNum)
|
||||
{
|
||||
if (FireModeNum == BLOCK_FIREMODE)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.CanOverrideMagReload(FireModeNum);
|
||||
}
|
||||
|
||||
/*********************************************************************************************
|
||||
* Upgrades
|
||||
********************************************************************************************/
|
||||
|
||||
static simulated function float GetUpgradedBlockDamageMitigation(int UpgradeIndex)
|
||||
{
|
||||
return GetUpgradedStatValue(default.BlockDamageMitigation, EWUS_BlockDmgMitigation, UpgradeIndex);
|
||||
}
|
||||
|
||||
static simulated function float GetUpgradedParryDamageMitigation(int UpgradeIndex)
|
||||
{
|
||||
return GetUpgradedStatValue(default.ParryDamageMitigationPercent, EWUS_ParryDmgMitigation, UpgradeIndex);
|
||||
}
|
||||
|
||||
simulated function int GetModifiedDamage(byte FireModeNum, optional vector RayDir)
|
||||
{
|
||||
if (FireModeNum == BASH_FIREMODE)
|
||||
{
|
||||
return GetUpgradedStatValue(InstantHitDamage[FireModeNum], EWUS_Damage2, CurrentWeaponUpgradeIndex);
|
||||
}
|
||||
|
||||
return super.GetModifiedDamage(FireModeNum, RayDir);
|
||||
}
|
||||
|
||||
/** Check AmmoCount and update anim tree nodes if needed */
|
||||
simulated function UpdateOutOfAmmoEffects(float BlendTime)
|
||||
{
|
||||
if ( WorldInfo.NetMode == NM_DedicatedServer )
|
||||
return;
|
||||
|
||||
if( EmptyMagBlendNode != None )
|
||||
{
|
||||
// Differentiate Left/Right
|
||||
if ( bAllowClientAmmoTracking && AmmoCount[0] <= 1 )
|
||||
{
|
||||
EmptyMagBlendNode.SetBlendTarget(1, 0);
|
||||
if ( AmmoCount[0] == 0 )
|
||||
{
|
||||
|
||||
EmptyMagBlendNode = AnimNodeBlendPerBone(SkeletalMeshComponent(Mesh).FindAnimNode('EmptyMagBlend'));
|
||||
BuildEmptyMagNodeWeightList( EmptyMagBlendNode, BonesToLockOnEmpty_Override );
|
||||
|
||||
EmptyMagBlendNode.SetBlendTarget(1,0);
|
||||
|
||||
`Log("blending left");
|
||||
EmptyMagBlendNode_L.SetBlendTarget(1,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Unlocks the bolt bone (Called by animnotify) */
|
||||
simulated function ANIMNOTIFY_UnLockBolt()
|
||||
{
|
||||
super.ANIMNOTIFY_UnLockBolt();
|
||||
EmptyMagBlendNode_L.SetBlendTarget(0, 0);
|
||||
|
||||
EmptyMagBlendNode = AnimNodeBlendPerBone(SkeletalMeshComponent(Mesh).FindAnimNode('EmptyMagBlend'));
|
||||
BuildEmptyMagNodeWeightList( EmptyMagBlendNode, BonesToLockOnEmpty);
|
||||
}
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
// Content
|
||||
PackageKey="Dual_BladedPistol"
|
||||
FirstPersonMeshName="WEP_1P_Dual_BladedPistol_MESH.WEP_1stP_DualBladedPistol_Rig"
|
||||
FirstPersonAnimSetNames(0)="WEP_1P_Dual_BladedPistol_ANIM.Wep_1stP_Dual_BladedPistol_ANIM"
|
||||
PickupMeshName="WEP_3P_Dual_BladedPistol_MESH.Wep_Dual_BladedPistol_Pickup"
|
||||
AttachmentArchetypeName="WEP_Dual_BladedPistol_ARCH.Wep_Dual_BladedPistol_3P"
|
||||
MuzzleFlashTemplateName="WEP_Dual_BladedPistol_ARCH.Wep_Dual_BladedPistol_MuzzleFlash"
|
||||
|
||||
Begin Object Name=FirstPersonMesh
|
||||
AnimTreeTemplate=AnimTree'CHR_1P_Arms_ARCH.WEP_1stP_Dual_Animtree_Master'
|
||||
End Object
|
||||
|
||||
FireOffset=(X=30,Y=7,Z=-5)
|
||||
LeftFireOffset=(X=30,Y=-7,Z=-5)
|
||||
|
||||
// Zooming/Position
|
||||
IronSightPosition=(X=-3,Y=0,Z=0)
|
||||
PlayerViewOffset=(X=-15,Y=0,Z=0)
|
||||
|
||||
QuickWeaponDownRotation=(Pitch=-8192,Yaw=0,Roll=0)
|
||||
|
||||
SingleClass=class'KFWeap_Pistol_Bladed'
|
||||
|
||||
// FOV
|
||||
MeshFOV=96
|
||||
MeshIronSightFOV=77
|
||||
PlayerIronSightFOV=77
|
||||
|
||||
// Depth of field
|
||||
DOF_FG_FocalRadius=40
|
||||
DOF_FG_MaxNearBlurSize=3.5
|
||||
|
||||
// Ammo
|
||||
MagazineCapacity[0]=12
|
||||
SpareAmmoCapacity[0]=72 //96
|
||||
InitialSpareMags[0]=1
|
||||
AmmoPickupScale[0]=0.5 //1.0
|
||||
bCanBeReloaded=true
|
||||
bReloadFromMagazine=true
|
||||
|
||||
// Recoil
|
||||
maxRecoilPitch=330 //400 //250
|
||||
minRecoilPitch=300 //350 //200
|
||||
maxRecoilYaw=120 //100
|
||||
minRecoilYaw=-120 //-100
|
||||
RecoilRate=0.07
|
||||
RecoilMaxYawLimit=500
|
||||
RecoilMinYawLimit=65035
|
||||
RecoilMaxPitchLimit=900
|
||||
RecoilMinPitchLimit=65035
|
||||
RecoilISMaxYawLimit=50
|
||||
RecoilISMinYawLimit=65485
|
||||
RecoilISMaxPitchLimit=250
|
||||
RecoilISMinPitchLimit=65485
|
||||
|
||||
// DEFAULT_FIREMODE
|
||||
FiringStatesArray(DEFAULT_FIREMODE)=WeaponSingleFiring
|
||||
WeaponFireTypes(DEFAULT_FIREMODE)=EWFT_Projectile
|
||||
WeaponProjectiles(DEFAULT_FIREMODE)=class'KFProj_Blade_BladedPistol'
|
||||
PenetrationPower(DEFAULT_FIREMODE)=3.0
|
||||
FireInterval(DEFAULT_FIREMODE)=+0.19 //+0.231
|
||||
InstantHitDamage(DEFAULT_FIREMODE)=115.0
|
||||
InstantHitDamageTypes(DEFAULT_FIREMODE)=class'KFDT_Slashing_BladedPistol'
|
||||
Spread(DEFAULT_FIREMODE)=0.005 //0.015
|
||||
|
||||
FireModeIconPaths(DEFAULT_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_Sawblade'
|
||||
|
||||
// MELEE_BLOCK_FIREMODE
|
||||
FiringStatesArray(BLOCK_FIREMODE)=MeleeBlocking
|
||||
WeaponFireTypes(BLOCK_FIREMODE)=EWFT_Custom
|
||||
FireInterval(BLOCK_FIREMODE)=1.f
|
||||
AmmoCost(BLOCK_FIREMODE)=0
|
||||
|
||||
// BASH_FIREMODE
|
||||
InstantHitDamageTypes(BASH_FIREMODE)=class'KFDT_Bludgeon_BladedPistol'
|
||||
InstantHitDamage(BASH_FIREMODE)=75 //26
|
||||
|
||||
// Fire Effects
|
||||
WeaponFireSnd(DEFAULT_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_BladedPistol.Play_WEP_BladedPistol_Fire_3P', FirstPersonCue=AkEvent'WW_WEP_BladedPistol.Play_WEP_BladedPistol_Fire_1P')
|
||||
WeaponDryFireSnd(DEFAULT_FIREMODE)=AkEvent'WW_WEP_BladedPistol.Play_WEP_BladedPistol_Handling_DryFire'
|
||||
|
||||
WeaponFireSnd(ALTFIRE_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_BladedPistol.Play_WEP_BladedPistol_Fire_3P', FirstPersonCue=AkEvent'WW_WEP_BladedPistol.Play_WEP_BladedPistol_Fire_1P')
|
||||
WeaponDryFireSnd(ALTFIRE_FIREMODE)=AkEvent'WW_WEP_BladedPistol.Play_WEP_BladedPistol_Handling_DryFire'
|
||||
|
||||
// Attachments
|
||||
bHasIronSights=true
|
||||
bHasFlashlight=true
|
||||
|
||||
AssociatedPerkClasses(0)=class'KFPerk_Gunslinger'
|
||||
AssociatedPerkClasses(1)=class'KFPerk_Berserker'
|
||||
|
||||
|
||||
// Inventory
|
||||
InventoryGroup= IG_Primary
|
||||
InventorySize=6
|
||||
GroupPriority=45
|
||||
bCanThrow=true
|
||||
bDropOnDeath=true
|
||||
WeaponSelectTexture=Texture2D'WEP_UI_Dual_BladedPistol_TEX.UI_WeaponSelect_Dual_BladedPistol'
|
||||
bIsBackupWeapon=false
|
||||
|
||||
BonesToLockOnEmpty=(RW_FrontPivot)
|
||||
BonesToLockOnEmpty_L=(LW_FrontPivot)
|
||||
BonesToLockOnEmpty_Override=(RW_FrontPivot, LW_FrontPivot)
|
||||
|
||||
bHasFireLastAnims=true
|
||||
|
||||
// default MIC param names
|
||||
BlockEffectsSocketName=BlockEffect
|
||||
// Defensive
|
||||
BlockDamageMitigation=0.60f
|
||||
ParryDamageMitigationPercent=0.5
|
||||
ParryStrength=4
|
||||
BlockHitAnimCooldownTime=0.5f
|
||||
BlockTypes.Add((DmgType=class'KFDT_Bludgeon'))
|
||||
BlockTypes.Add((DmgType=class'KFDT_Slashing'))
|
||||
|
||||
// Block Sounds
|
||||
BlockSound=AkEvent'WW_WEP_Bullet_Impacts.Play_Block_MEL_Crovel'
|
||||
ParrySound=AkEvent'WW_WEP_Bullet_Impacts.Play_Parry_Metal'
|
||||
|
||||
BlockParticleSystem=ParticleSystem'FX_Impacts_EMIT.FX_Block_melee_01'
|
||||
ParryParticleSystem=ParticleSystem'FX_Impacts_EMIT.FX_Parry_melee_01'
|
||||
MeleeBlockHitAnims=(Block_Hit_V1, Block_Hit_V2, Block_Hit_V3);
|
||||
|
||||
// Upgrades
|
||||
UpgradeFireModes(BLOCK_FIREMODE) = 0
|
||||
//Upgrades
|
||||
WeaponUpgrades[1]=(Stats=((Stat=EWUS_Damage0, Scale=1.15f), (Stat=EWUS_Damage1, Scale=1.15f), (Stat=EWUS_Damage2, Scale=1.15f), (Stat=EWUS_Weight, Add=1)))
|
||||
WeaponUpgrades[2]=(Stats=((Stat=EWUS_Damage0, Scale=1.3f), (Stat=EWUS_Damage1, Scale=1.3f), (Stat=EWUS_Damage2, Scale=1.3f), (Stat=EWUS_Weight, Add=2)))
|
||||
}
|
||||
|
428
KFGameContent/Classes/KFWeap_Rifle_ParasiteImplanter.uc
Normal file
428
KFGameContent/Classes/KFWeap_Rifle_ParasiteImplanter.uc
Normal file
@ -0,0 +1,428 @@
|
||||
//=============================================================================
|
||||
// KFWeap_Rifle_ParasiteImplanter
|
||||
//=============================================================================
|
||||
// Weapon code for parasite implanter.
|
||||
//=============================================================================
|
||||
// Killing Floor 2
|
||||
// Copyright (C) 2021 Tripwire Interactive LLC
|
||||
//=============================================================================
|
||||
|
||||
class KFWeap_Rifle_ParasiteImplanter extends KFWeap_ScopedBase;
|
||||
|
||||
`define PARASITE_MIC_LED_INDEX 0
|
||||
|
||||
var float LastFireInterval;
|
||||
|
||||
/** How many seed ammo to recharge per second */
|
||||
var float SeedFullRechargeSeconds;
|
||||
/** How many ammo to recharge per second. */
|
||||
var transient float SeedRechargePerSecond;
|
||||
|
||||
var transient float SeedIncrement;
|
||||
var repnotify byte SeedAmmo;
|
||||
|
||||
const SecondaryFireAnim = 'Shoot_Secondary';
|
||||
const SecondaryFireIronAnim = 'Shoot_Secondary_Iron';
|
||||
|
||||
/** Material colors applied to different fire modes */
|
||||
var LinearColor NoAmmoMaterialColor;
|
||||
var LinearColor AmmoReadyMaterialColor;
|
||||
|
||||
/** How much recoil the altfire should do */
|
||||
var protected const float AltFireRecoilScale;
|
||||
|
||||
replication
|
||||
{
|
||||
if (bNetDirty && Role == ROLE_Authority)
|
||||
SeedAmmo;
|
||||
}
|
||||
|
||||
simulated event ReplicatedEvent(name VarName)
|
||||
{
|
||||
if (VarName == nameof(SeedAmmo))
|
||||
{
|
||||
if (AmmoCount[ALTFIRE_FIREMODE] < AmmoCost[ALTFIRE_FIREMODE] && SeedAmmo >= AmmoCost[ALTFIRE_FIREMODE])
|
||||
{
|
||||
UpdateMaterial(true);
|
||||
}
|
||||
else if (AmmoCount[ALTFIRE_FIREMODE] >= AmmoCost[ALTFIRE_FIREMODE] && SeedAmmo < AmmoCost[ALTFIRE_FIREMODE])
|
||||
{
|
||||
UpdateMaterial(false);
|
||||
}
|
||||
AmmoCount[ALTFIRE_FIREMODE] = SeedAmmo;
|
||||
}
|
||||
else
|
||||
{
|
||||
Super.ReplicatedEvent(VarName);
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************
|
||||
* @name Trader
|
||||
*********************************************************************************************/
|
||||
|
||||
/** Returns trader filter index based on weapon type */
|
||||
static simulated event EFilterTypeUI GetTraderFilter()
|
||||
{
|
||||
if( default.FiringStatesArray[DEFAULT_FIREMODE] == 'WeaponFiring' || default.FiringStatesArray[DEFAULT_FIREMODE] == 'WeaponBurstFiring' )
|
||||
{
|
||||
return FT_Assault;
|
||||
}
|
||||
else // if( FiringStatesArray[DEFAULT_FIREMODE] == 'WeaponSingleFiring')
|
||||
{
|
||||
return FT_Rifle;
|
||||
}
|
||||
}
|
||||
|
||||
simulated event PreBeginPlay()
|
||||
{
|
||||
super.PreBeginPlay();
|
||||
StartSeedRecharge();
|
||||
}
|
||||
|
||||
function StartSeedRecharge()
|
||||
{
|
||||
// local KFPerk InstigatorPerk;
|
||||
local float UsedSeedRechargeTime;
|
||||
|
||||
// begin ammo recharge on server
|
||||
if( Role == ROLE_Authority )
|
||||
{
|
||||
UsedSeedRechargeTime = SeedFullRechargeSeconds;
|
||||
SeedRechargePerSecond = MagazineCapacity[ALTFIRE_FIREMODE] / UsedSeedRechargeTime;
|
||||
SeedIncrement = 0;
|
||||
}
|
||||
}
|
||||
|
||||
function RechargeSeed(float DeltaTime)
|
||||
{
|
||||
if ( Role == ROLE_Authority )
|
||||
{
|
||||
SeedIncrement += SeedRechargePerSecond * DeltaTime;
|
||||
|
||||
if( SeedIncrement >= 1.0 && AmmoCount[ALTFIRE_FIREMODE] < MagazineCapacity[ALTFIRE_FIREMODE] )
|
||||
{
|
||||
AmmoCount[ALTFIRE_FIREMODE]++;
|
||||
SeedIncrement -= 1.0;
|
||||
SeedAmmo = AmmoCount[ALTFIRE_FIREMODE];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Overridden to call StartHealRecharge on server */
|
||||
function GivenTo( Pawn thisPawn, optional bool bDoNotActivate )
|
||||
{
|
||||
super.GivenTo( thisPawn, bDoNotActivate );
|
||||
|
||||
if( Role == ROLE_Authority && !thisPawn.IsLocallyControlled() )
|
||||
{
|
||||
StartSeedRecharge();
|
||||
}
|
||||
}
|
||||
/*********************************************************************************************
|
||||
@name Actor
|
||||
********************************************************************************************* */
|
||||
simulated event Tick( FLOAT DeltaTime )
|
||||
{
|
||||
local bool bWasLowAmmo;
|
||||
bWasLowAmmo = AmmoCount[ALTFIRE_FIREMODE] < AmmoCost[ALTFIRE_FIREMODE];
|
||||
|
||||
if( AmmoCount[ALTFIRE_FIREMODE] < MagazineCapacity[ALTFIRE_FIREMODE] )
|
||||
{
|
||||
RechargeSeed(DeltaTime);
|
||||
}
|
||||
|
||||
if (WorldInfo.NetMode != NM_DedicatedServer)
|
||||
{
|
||||
if (bWasLowAmmo && AmmoCount[ALTFIRE_FIREMODE] >= AmmoCost[ALTFIRE_FIREMODE])
|
||||
{
|
||||
UpdateMaterial(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bWasLowAmmo && AmmoCount[ALTFIRE_FIREMODE] >= AmmoCost[ALTFIRE_FIREMODE])
|
||||
{
|
||||
NotifyAltAmmoReady(true);
|
||||
}
|
||||
}
|
||||
|
||||
Super.Tick(DeltaTime);
|
||||
}
|
||||
|
||||
/*********************************************************************************************
|
||||
* Trader
|
||||
********************************************************************************************/
|
||||
|
||||
/** Allows weapon to set its own trader stats (can set number of stats, names and values of stats) */
|
||||
static simulated event SetTraderWeaponStats( out array<STraderItemWeaponStats> WeaponStats )
|
||||
{
|
||||
super.SetTraderWeaponStats( WeaponStats );
|
||||
|
||||
WeaponStats.Length = WeaponStats.Length + 1;
|
||||
WeaponStats[WeaponStats.Length-1].StatType = TWS_RechargeTime;
|
||||
WeaponStats[WeaponStats.Length-1].StatValue = default.SeedFullRechargeSeconds;
|
||||
}
|
||||
|
||||
/** Seeds doesn't count as ammo for purposes of inventory management (e.g. switching) */
|
||||
simulated function bool HasAnyAmmo()
|
||||
{
|
||||
return HasSpareAmmo() || HasAmmo(DEFAULT_FIREMODE);
|
||||
}
|
||||
|
||||
simulated function ConsumeAmmo( byte FireModeNum )
|
||||
{
|
||||
local bool bWasHighAmmo;
|
||||
|
||||
if( FireModeNum != ALTFIRE_FIREMODE )
|
||||
{
|
||||
Super.ConsumeAmmo(FireModeNum);
|
||||
return;
|
||||
}
|
||||
|
||||
`if(`notdefined(ShippingPC))
|
||||
if( bInfiniteAmmo )
|
||||
{
|
||||
return;
|
||||
}
|
||||
`endif
|
||||
|
||||
bWasHighAmmo = AmmoCount[ALTFIRE_FIREMODE] >= AmmoCost[ALTFIRE_FIREMODE];
|
||||
|
||||
// If AmmoCount is being replicated, don't allow the client to modify it here
|
||||
if (Role == ROLE_Authority)
|
||||
{
|
||||
// Don't consume ammo if magazine size is 0 (infinite ammo with no reload)
|
||||
if (MagazineCapacity[1] > 0 && AmmoCount[1] > 0)
|
||||
{
|
||||
// Reduce ammo amount by heal ammo cost
|
||||
AmmoCount[1] = Max(AmmoCount[1] - AmmoCost[1], 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (WorldInfo.NetMode != NM_DedicatedServer)
|
||||
{
|
||||
if (bWasHighAmmo && AmmoCount[ALTFIRE_FIREMODE] < AmmoCost[ALTFIRE_FIREMODE])
|
||||
{
|
||||
UpdateMaterial(false);
|
||||
}
|
||||
}
|
||||
else if (bWasHighAmmo && AmmoCount[ALTFIRE_FIREMODE] < AmmoCost[ALTFIRE_FIREMODE])
|
||||
{
|
||||
NotifyAltAmmoReady(false);
|
||||
}
|
||||
}
|
||||
|
||||
/** Instead of switch fire mode use as immediate alt fire */
|
||||
simulated function AltFireMode()
|
||||
{
|
||||
if ( !Instigator.IsLocallyControlled() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
StartFire(ALTFIRE_FIREMODE);
|
||||
}
|
||||
|
||||
simulated function float GetFireInterval(byte FireModeNum)
|
||||
{
|
||||
if (FireModeNum == DEFAULT_FIREMODE && AmmoCount[FireModeNum] == 0)
|
||||
{
|
||||
return LastFireInterval;
|
||||
}
|
||||
|
||||
return super.GetFireInterval(FireModeNum);
|
||||
}
|
||||
|
||||
simulated function name GetWeaponFireAnim(byte FireModeNum)
|
||||
{
|
||||
if (FireModeNum == ALTFIRE_FIREMODE)
|
||||
{
|
||||
return bUsingSights ? SecondaryFireIronAnim : SecondaryFireAnim;
|
||||
}
|
||||
|
||||
return super.GetWeaponFireAnim(FireModeNum);
|
||||
}
|
||||
|
||||
simulated function UpdateMaterial(bool HasEnoughAmmo)
|
||||
{
|
||||
local LinearColor MatColor;
|
||||
|
||||
if (WorldInfo.NetMode != NM_DedicatedServer)
|
||||
{
|
||||
MatColor = HasEnoughAmmo ? AmmoReadyMaterialColor : NoAmmoMaterialColor;
|
||||
|
||||
if( WeaponMICs.Length >= `PARASITE_MIC_LED_INDEX )
|
||||
{
|
||||
WeaponMICs[`PARASITE_MIC_LED_INDEX].SetVectorParameterValue('Vector_GlowColor', MatColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Should replicate to 3P to show the alt fire ready
|
||||
*/
|
||||
simulated function NotifyAltAmmoReady(bool bActive)
|
||||
{
|
||||
local KFPawn KFP;
|
||||
|
||||
if (WorldInfo.NetMode != NM_Client)
|
||||
{
|
||||
KFP = KFPawn(Instigator);
|
||||
KFP.OnWeaponSpecialAction(bActive ? 2 : 1);
|
||||
}
|
||||
}
|
||||
|
||||
simulated function ModifyRecoil( out float CurrentRecoilModifier )
|
||||
{
|
||||
if( CurrentFireMode == ALTFIRE_FIREMODE )
|
||||
{
|
||||
CurrentRecoilModifier *= AltFireRecoilScale;
|
||||
}
|
||||
|
||||
super.ModifyRecoil( CurrentRecoilModifier );
|
||||
}
|
||||
|
||||
simulated function bool ShouldAutoReload(byte FireModeNum)
|
||||
{
|
||||
if (FireModeNum == ALTFIRE_FIREMODE)
|
||||
return false;
|
||||
|
||||
return super.ShouldAutoReload(FireModeNum);
|
||||
}
|
||||
|
||||
defaultproperties
|
||||
{
|
||||
SeedFullRechargeSeconds=14 //10
|
||||
|
||||
// Inventory / Grouping
|
||||
InventorySize=7
|
||||
GroupPriority=100
|
||||
WeaponSelectTexture=Texture2D'wep_ui_parasiteimplanter_tex.UI_WeaponSelect_ParasiteImplanter'
|
||||
AssociatedPerkClasses(0)=class'KFPerk_FieldMedic'
|
||||
AssociatedPerkClasses(1)=class'KFPerk_SharpShooter'
|
||||
|
||||
// FOV
|
||||
MeshFOV=70 //65
|
||||
MeshIronSightFOV=27 //25 //45
|
||||
PlayerIronSightFOV=70 //65
|
||||
|
||||
// Depth of field
|
||||
DOF_BlendInSpeed=3.0
|
||||
DOF_FG_FocalRadius=0 //50
|
||||
DOF_FG_MaxNearBlurSize=3.5
|
||||
|
||||
// Content
|
||||
PackageKey="ParasiteImplanter"
|
||||
FirstPersonMeshName="WEP_1P_ParasiteImplanter_MESH.Wep_1stP_ParasiteImplanter_Rig"
|
||||
FirstPersonAnimSetNames(0)="WEP_1P_ParasiteImplanter_ANIM.Wep_1stP_ParasiteImplanter_Anim"
|
||||
PickupMeshName="WEP_3P_ParasiteImplanter_MESH.Wep_3rdP_ParasiteImplanter_Pickup"
|
||||
AttachmentArchetypeName="WEP_ParasiteImplanter_ARCH.Wep_ParasiteImplanter_3P"
|
||||
MuzzleFlashTemplateName="WEP_ParasiteImplanter_ARCH.Wep_ParasiteImplanter_MuzzleFlash"
|
||||
|
||||
// Ammo
|
||||
MagazineCapacity[0]=6
|
||||
SpareAmmoCapacity[0]=78
|
||||
InitialSpareMags[0]=3
|
||||
bCanBeReloaded=true
|
||||
bReloadFromMagazine=true
|
||||
|
||||
MagazineCapacity[1]=100
|
||||
SeedAmmo=100
|
||||
bCanRefillSecondaryAmmo=false
|
||||
|
||||
// Zooming/Position
|
||||
PlayerViewOffset=(X=3.0,Y=8,Z=-1.8)
|
||||
//IronSightPosition=(X=0,Y=-0.07,Z=1.03)
|
||||
IronSightPosition=(X=0,Y=-0.115,Z=1.0425)
|
||||
|
||||
// AI warning system
|
||||
bWarnAIWhenAiming=true
|
||||
AimWarningDelay=(X=0.4f, Y=0.8f)
|
||||
AimWarningCooldown=0.0f
|
||||
|
||||
// Recoil
|
||||
maxRecoilPitch=575 //700
|
||||
minRecoilPitch=425 //600
|
||||
maxRecoilYaw=135
|
||||
minRecoilYaw=-135
|
||||
RecoilRate=0.08
|
||||
RecoilMaxYawLimit=500
|
||||
RecoilMinYawLimit=65035
|
||||
RecoilMaxPitchLimit=1250
|
||||
RecoilMinPitchLimit=64785
|
||||
RecoilISMaxYawLimit=50
|
||||
RecoilISMinYawLimit=65485
|
||||
RecoilISMaxPitchLimit=500
|
||||
RecoilISMinPitchLimit=65485
|
||||
RecoilViewRotationScale=0.6
|
||||
IronSightMeshFOVCompensationScale=1.5
|
||||
AltFireRecoilScale=0.2f
|
||||
|
||||
// Scope Render
|
||||
// 2D scene capture
|
||||
Begin Object Name=SceneCapture2DComponent0
|
||||
//TextureTarget=TextureRenderTarget2D'Wep_Mat_Lib.WEP_ScopeLense_Target'
|
||||
FieldOfView=12.5 //23.0 // "1.5X" = 35.0(our real world FOV determinant)/1.5
|
||||
End Object
|
||||
|
||||
ScopedSensitivityMod=8.0 //16.0
|
||||
ScopeLenseMICTemplate=MaterialInstanceConstant'WEP_1P_ParasiteImplanter_MAT.Wep_1stP_Parasite_Lens_MIC'
|
||||
ScopeMICIndex = 2
|
||||
|
||||
// DEFAULT_FIREMODE
|
||||
FireModeIconPaths(DEFAULT_FIREMODE)=Texture2D'ui_firemodes_tex.UI_FireModeSelect_BulletSingle'
|
||||
FiringStatesArray(DEFAULT_FIREMODE)=WeaponSingleFiring
|
||||
WeaponFireTypes(DEFAULT_FIREMODE)=EWFT_InstantHit
|
||||
WeaponProjectiles(DEFAULT_FIREMODE)=class'KFProj_Bullet_ParasiteImplanter'
|
||||
InstantHitDamage(DEFAULT_FIREMODE)=275 //250
|
||||
InstantHitDamageTypes(DEFAULT_FIREMODE)=class'KFDT_Ballistic_ParasiteImplanter'
|
||||
FireInterval(DEFAULT_FIREMODE)=+1.0 //60 RPM
|
||||
Spread(DEFAULT_FIREMODE)=0.005
|
||||
PenetrationPower(DEFAULT_FIREMODE)=3
|
||||
FireOffset=(X=25,Y=3.0,Z=-2.5)
|
||||
LastFireInterval=0.3
|
||||
|
||||
// ALT_FIREMODE
|
||||
FiringStatesArray(ALTFIRE_FIREMODE)=WeaponSingleFiring
|
||||
WeaponFireTypes(ALTFIRE_FIREMODE)=EWFT_Projectile
|
||||
FireInterval(ALTFIRE_FIREMODE)=+0.5 //+1.0 //+0.175
|
||||
InstantHitDamage(ALTFIRE_FIREMODE)=1.0
|
||||
Spread(ALTFIRE_FIREMODE)=0.005
|
||||
AmmoCost(ALTFIRE_FIREMODE)=50
|
||||
WeaponProjectiles(ALTFIRE_FIREMODE)=class'KFProj_Bullet_ParasiteImplanterAlt'
|
||||
InstantHitDamageTypes(ALTFIRE_FIREMODE)=class'KFDT_Ballistic_ParasiteImplanterAlt'
|
||||
SecondaryAmmoTexture=Texture2D'ui_firemodes_tex.UI_FireModeSelect_Electricity'
|
||||
|
||||
// BASH_FIREMODE
|
||||
InstantHitDamageTypes(BASH_FIREMODE)=class'KFDT_Bludgeon_ParasiteImplanter'
|
||||
InstantHitDamage(BASH_FIREMODE)=26
|
||||
|
||||
// Custom animations
|
||||
FireSightedAnims=(Shoot_Iron)
|
||||
BonesToLockOnEmpty=(RW_Hammer)
|
||||
bHasFireLastAnims=true
|
||||
|
||||
// Fire Effects
|
||||
WeaponFireSnd(DEFAULT_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_ParasiteImplanter.Play_WEP_ParasiteImplanter_3P_Rifle', FirstPersonCue=AkEvent'WW_WEP_ParasiteImplanter.Play_WEP_ParasiteImplanter_1P_Rifle')
|
||||
WeaponDryFireSnd(DEFAULT_FIREMODE)=AkEvent'WW_WEP_ParasiteImplanter.Play_WEP_ParasiteImplanter_Dry_Fire_Rifle'
|
||||
WeaponFireSnd(ALTFIRE_FIREMODE)=(DefaultCue=AkEvent'WW_WEP_ParasiteImplanter.Play_WEP_ParasiteImplanter_3P_Altfire', FirstPersonCue=AkEvent'WW_WEP_ParasiteImplanter.Play_WEP_ParasiteImplanter_1P_Altfire')
|
||||
WeaponDryFireSnd(ALTFIRE_FIREMODE)=AkEvent'WW_WEP_ParasiteImplanter.Play_WEP_ParasiteImplanter_Dry_Fire_Altfire'
|
||||
EjectedShellForegroundDuration=1.5f
|
||||
|
||||
// Attachments
|
||||
bHasIronSights=true
|
||||
bHasFlashlight=false
|
||||
|
||||
WeaponFireWaveForm=ForceFeedbackWaveform'FX_ForceFeedback_ARCH.Gunfire.Medium_Recoil'
|
||||
|
||||
WeaponUpgrades[1]=(Stats=((Stat=EWUS_Damage0, Scale=1.15f), (Stat=EWUS_Weight, Add=1)))
|
||||
|
||||
// From original KFWeap_RifleBase base class
|
||||
AimCorrectionSize=40.f
|
||||
|
||||
NoAmmoMaterialColor=(R=0.0f,G=0.0f,B=0.0f)
|
||||
AmmoReadyMaterialColor=(R=0.08f,G=1.0f,B=0.08f)
|
||||
|
||||
NumBloodMapMaterials=2
|
||||
}
|
Reference in New Issue
Block a user