2020-12-13 15:01:13 +00:00
//=============================================================================
// KFAfflictionManager
//=============================================================================
// Handles negative status effects that can be applied to a KFPawn
//=============================================================================
// Killing Floor 2
// Copyright (C) 2015 Tripwire Interactive LLC
//=============================================================================
class KFAfflictionManager extends Object within KFPawn
native ( Pawn ) ;
2021-03-02 11:56:51 +00:00
const STUN _GUARANTEED _POWER = 10000. f ;
2020-12-13 15:01:13 +00:00
/** Abstracted body parts that can be associated with multiple zones */
enum EHitZoneBodyPart
{
BP _Torso , // default to generic body shot
BP _Head ,
BP _LeftArm ,
BP _RightArm ,
BP _LeftLeg ,
BP _RightLeg ,
BP _Special ,
} ;
/** Index into IncapSettingsInfo.Vulnerability[] */
enum EAfflictionVulnerabilityType
{
AV _Default ,
AV _Head ,
AV _Legs ,
AV _Arms ,
AV _Special ,
} ;
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Affliction Classes
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
/ * *
* Full body incap with stackable IncapPower
* @ todo : this data is now all static and should be moved to an archetype or to KFAffliction
* /
struct native IncapSettingsInfo
{
/** How long this incap lasts once triggered. Only applies to non-specialmove entries */
var ( ) float Duration ;
/** How long this pawn is immune to additional incap of this type. If > 0, resets strength to zero on activation */
var ( ) float Cooldown ;
/** How long this pawn is immune to additional incap of children of this type */
var ( ) float ChildAfflictionCooldown ;
/** Array mapped to EHitZoneBodyPart. If out of bounds default to body (index 0) */
var ( ) array < float > Vulnerability ;
structdefaultproperties
{
Duration = 5.0
}
} ;
/* Types of stacking afflictions that are used to index the IncapSettings array */
enum EAfflictionType
{
/** Place most common afflictions at top because array will resize up to the enum value */
/** All Pawns */
AF _EMP ,
AF _FirePanic ,
/** hit reactions (flinch) */
AF _MeleeHit ,
AF _GunHit ,
/** common */
AF _Stumble ,
AF _Stun ,
AF _Poison ,
AF _Snare ,
/** uncommon */
AF _Knockdown ,
AF _Freeze ,
AF _Microwave ,
AF _Bleed ,
AF _Custom1 ,
AF _Custom2 ,
AF _Custom3 ,
/** Dummy entry to avoid AF_MAX native collision */
EAfflictionType _Blank
} ;
/** Assign relevant class to each affliction corresponding to EAfflictionType */
var array < class < KFAfflictionBase > > AfflictionClasses ;
/** Intanced affliction one per EAfflictionType that remain for the Pawn's lifespawn */
var array < KFAfflictionBase > Afflictions ;
/** Afflictions that need updating each tick (e.g. Fire Panic) */
var array < KFAfflictionBase > AfflictionTickArray ;
/** Debugging */
var bool bDebugLog ;
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Specific settings that have not been fully converted to the new system
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
/** How long does a pawn have to be burning over the heat threshhold to get to fully charred skin */
var float FireFullyCharredDuration ;
/** When over this % on the FirePanicResist.StackedPower, apply charring to the skin shader. Think of it like how "hot" the character needs to get before its shader gets char applied */
var float FireCharPercentThreshhold ;
cpptext
{
/ * * S t a c k i n g a f f l i c t i o n s m u s t d e c a y P o w e r a n d c h e c k i f D u r a t i o n i s o v e r . T h i s i s d o n e
* in c ++ for speed , but could be done in script for custom afflictions * /
/** SERVER ONLY - Clears or stacked incap effects when they need to be deactivated */
virtual void TickStackedIncapEffects ( FLOAT DeltaTime , AKFPawn * P ) ;
}
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* @ name Take Damage
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
/** Check, and if needed activate afflictions after being hit (Server only) */
function NotifyTakeHit ( Controller DamageInstigator , vector HitDir , class < KFDamageType > DamageType , Actor DamageCauser )
{
local KFPerk InstigatorPerk ;
if ( DamageType == none )
{
return ;
}
// Allow damage instigator perk to modify reaction
if ( DamageInstigator != None && DamageInstigator . bIsPlayer )
{
InstigatorPerk = KFPlayerController ( DamageInstigator ) . GetPerk ( ) ;
}
// For now all below effects are for Zeds
if ( GetTeamNum ( ) > 254 && ! bPlayedDeath )
{
ProcessSpecialMoveAfflictions ( InstigatorPerk , HitDir , DamageType , DamageCauser ) ;
ProcessHitReactionAfflictions ( InstigatorPerk , DamageType , DamageCauser ) ;
}
ProcessEffectBasedAfflictions ( InstigatorPerk , DamageType , DamageCauser ) ;
}
/ * *
* Client side test to predict whether or not DoPauseAI is called . May not always
* be correct but as long as we use split - body anims it will still look okay
* @ note : With the new cumulative system this is completely artificial
* /
function byte GetPredictedHitReaction ( class < KFDamageType > DamageType , EHitZoneBodyPart BodyPart )
{
// This may not always match the server's result, but as long
// as we avoid playing FullBody anims it should look okay even if DoPauseAI is skipped.
if ( DamageType . default . MeleeHitPower > 0 )
{
return HIT _Heavy ;
}
else if ( DamageType . default . GunHitPower > 0 )
{
return HIT _Medium ;
}
return HIT _Light ;
}
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* @ name Internal ( On Hit )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
/** Reaction based afflictions only apply to living pawns */
protected function ProcessSpecialMoveAfflictions ( KFPerk InstigatorPerk , vector HitDir , class < KFDamageType > DamageType , Actor DamageCauser )
{
local EHitZoneBodyPart BodyPart ;
local byte HitZoneIdx ;
local float KnockdownPower , StumblePower , StunPower , SnarePower , FreezePower ;
local float KnockdownModifier , StumbleModifier , StunModifier ;
local KFInterface _DamageCauser KFDmgCauser ;
local KFWeapon DamageWeapon ;
// This is for damage over time, DoT shall never have momentum
if ( IsZero ( HitDir ) )
{
return ;
}
2021-06-02 20:06:18 +00:00
// HitZoneIdx = HitFxInfo.HitBoneIndex;
HitZoneIdx = LastHitZoneIndex ;
2020-12-13 15:01:13 +00:00
BodyPart = ( HitZoneIdx != 255 && HitZoneIdx < HitZones . Length ) ? HitZones [ HitZoneIdx ] . Limb : BP _Torso ;
// Get upgraded affliction power
DamageWeapon = class 'KFPerk' . static . GetWeaponFromDamageCauser ( DamageCauser ) ;
if ( DamageWeapon != none )
{
KnockdownPower = DamageWeapon . GetUpgradedAfflictionPower ( AF _Knockdown , DamageType . default . KnockdownPower ) ;
StumblePower = DamageWeapon . GetUpgradedAfflictionPower ( AF _Stumble , DamageType . default . StumblePower ) ;
StunPower = DamageWeapon . GetUpgradedAfflictionPower ( AF _Stun , DamageType . default . StunPower ) ;
SnarePower = DamageWeapon . GetUpgradedAfflictionPower ( AF _Snare , DamageType . default . SnarePower ) ;
FreezePower = DamageWeapon . GetUpgradedAfflictionPower ( AF _Freeze , DamageType . default . FreezePower ) ;
}
else
{
KnockdownPower = DamageType . default . KnockdownPower ;
StumblePower = DamageType . default . StumblePower ;
StunPower = DamageType . default . StunPower ;
SnarePower = DamageType . default . SnarePower ;
FreezePower = DamageType . default . FreezePower ;
}
KFDmgCauser = KFInterface _DamageCauser ( DamageCauser ) ;
if ( KFDmgCauser != None )
{
KnockdownPower *= KFDmgCauser . GetIncapMod ( ) ;
StumblePower *= KFDmgCauser . GetIncapMod ( ) ;
StunPower *= KFDmgCauser . GetIncapMod ( ) ;
SnarePower *= KFDmgCauser . GetIncapMod ( ) ;
}
KnockdownModifier = 1. f ;
StumbleModifier = 1. f ;
StunModifier = 1. f ;
// Allow for known afflictions to adjust reaction
KnockdownModifier += GetAfflictionKnockdownModifier ( ) ;
StumbleModifier += GetAfflictionStumbleModifier ( ) ;
StunModifier += GetAfflictionStunModifier ( ) ;
// Allow damage instigator perk to modify reaction
if ( InstigatorPerk != None )
{
KnockdownModifier += InstigatorPerk . GetKnockdownPowerModifier ( DamageType , BodyPart , bIsSprinting ) ;
StumbleModifier += InstigatorPerk . GetStumblePowerModifier ( Outer , DamageType , , BodyPart ) ;
StunModifier += InstigatorPerk . GetStunPowerModifier ( DamageType , HitZoneIdx ) ;
//Snare power doesn't scale DT, it exists on its own (Ex: Gunslinger Skullcracker)
SnarePower += InstigatorPerk . GetSnarePowerModifier ( DamageType , HitZoneIdx ) ;
}
KnockdownPower *= KnockdownModifier ;
StumblePower *= StumbleModifier ;
StunPower *= StunModifier ;
2021-03-02 11:56:51 +00:00
// [RMORENO @ SABER3D] //Overriding stun power with a High number so we can assure the stun independently of weapon, Zed resistances, body part hit. This does NOT ignores other factors like cooldowns.
if ( InstigatorPerk != None && InstigatorPerk . IsStunGuaranteed ( DamageType , HitZoneIdx ) )
2020-12-13 15:01:13 +00:00
{
2021-03-02 11:56:51 +00:00
StunPower = STUN _GUARANTEED _POWER ;
2020-12-13 15:01:13 +00:00
}
2021-03-02 11:56:51 +00:00
2020-12-13 15:01:13 +00:00
// increment affliction power
if ( KnockdownPower > 0 && CanDoSpecialmove ( SM _Knockdown ) )
{
AccrueAffliction ( AF _Knockdown , KnockdownPower , BodyPart , InstigatorPerk ) ;
}
if ( StunPower > 0 && CanDoSpecialmove ( SM _Stunned ) )
{
AccrueAffliction ( AF _Stun , StunPower , BodyPart , InstigatorPerk ) ;
}
if ( StumblePower > 0 && CanDoSpecialmove ( SM _Stumble ) )
{
AccrueAffliction ( AF _Stumble , StumblePower , BodyPart , InstigatorPerk ) ;
}
if ( FreezePower > 0 && CanDoSpecialMove ( SM _Frozen ) )
{
AccrueAffliction ( AF _Freeze , FreezePower , BodyPart , InstigatorPerk ) ;
}
if ( SnarePower > 0 )
{
AccrueAffliction ( AF _Snare , SnarePower , BodyPart , InstigatorPerk ) ;
}
}
/** Afflications which pause AI behavior temporarily */
protected function ProcessHitReactionAfflictions ( KFPerk InstigatorPerk , class < KFDamageType > DamageType , Actor DamageCauser )
{
local EHitZoneBodyPart BodyPart ;
local byte HitZoneIdx ;
local float ReactionModifier , MeleeHitPower , GunHitPower ;
local KFWeapon DamageWeapon ;
local KFInterface _DamageCauser KFDmgCauser ;
ReactionModifier = 1. f ;
// Allow damage instigator perk to modify reaction
if ( InstigatorPerk != None )
{
ReactionModifier = InstigatorPerk . GetReactionModifier ( DamageType ) ;
}
// Finally, 'Pause' the AI if we're going to play a medium or heavy hit reaction anim in TryPlayHitReactionAnim
if ( MyKFAIC != None )
{
HitZoneIdx = HitFxInfo . HitBoneIndex ;
BodyPart = ( HitZoneIdx != 255 && HitZoneIdx < HitZones . Length ) ? HitZones [ HitZoneIdx ] . Limb : BP _Torso ;
// Get upgraded affliction power
DamageWeapon = class 'KFPerk' . static . GetWeaponFromDamageCauser ( DamageCauser ) ;
if ( DamageWeapon != none )
{
MeleeHitPower = DamageWeapon . GetUpgradedAfflictionPower ( AF _MeleeHit , DamageType . default . MeleeHitPower ) ;
GunHitPower = DamageWeapon . GetUpgradedAfflictionPower ( AF _GunHit , DamageType . default . GunHitPower ) ;
}
else
{
MeleeHitPower = DamageType . default . MeleeHitPower ;
GunHitPower = DamageType . default . GunHitPower ;
}
KFDmgCauser = KFInterface _DamageCauser ( DamageCauser ) ;
if ( KFDmgCauser != None )
{
MeleeHitPower *= KFDmgCauser . GetIncapMod ( ) ;
GunHitPower *= KFDmgCauser . GetIncapMod ( ) ;
}
// Check hard hit reaction
if ( MeleeHitPower > 0 )
{
AccrueAffliction ( AF _MeleeHit , MeleeHitPower * ReactionModifier , BodyPart , InstigatorPerk ) ;
}
// Force recovery time for the headless hit. GetTimerCount() is a dirty way to do this only on the frame of CauseHeadTrauma()
if ( HitZoneIdx == HZI _Head && IsHeadless ( ) && GetTimerCount ( 'BleedOutTimer' , Outer ) == 0. f )
{
AccrueAffliction ( AF _MeleeHit , 100. f , BodyPart , InstigatorPerk ) ;
}
// Check medium hit reaction
if ( GunHitPower > 0 )
{
AccrueAffliction ( AF _GunHit , GunHitPower * ReactionModifier , BodyPart , InstigatorPerk ) ;
}
}
}
/** Effect based afflictions can apply even on dead bodies */
protected function ProcessEffectBasedAfflictions ( KFPerk InstigatorPerk , class < KFDamageType > DamageType , Actor DamageCauser )
{
local KFWeapon DamageWeapon ;
local float BurnPower , EMPPower , PoisonPower , MicrowavePower , BleedPower ;
local KFInterface _DamageCauser KFDmgCauser ;
// Get upgraded affliction power
DamageWeapon = class 'KFPerk' . static . GetWeaponFromDamageCauser ( DamageCauser ) ;
if ( DamageWeapon != none )
{
BurnPower = DamageWeapon . GetUpgradedAfflictionPower ( AF _FirePanic , DamageType . default . BurnPower ) ;
EMPPower = DamageWeapon . GetUpgradedAfflictionPower ( AF _EMP , DamageType . default . EMPPower ) ;
PoisonPower = DamageWeapon . GetUpgradedAfflictionPower ( AF _Poison , DamageType . default . PoisonPower ) ;
MicrowavePower = DamageWeapon . GetUpgradedAfflictionPower ( AF _Microwave , DamageType . default . MicrowavePower ) ;
BleedPower = DamageWeapon . GetUpgradedAfflictionPower ( AF _Bleed , DamageType . default . BleedPower ) ;
}
else
{
BurnPower = DamageType . default . BurnPower ;
EMPPower = DamageType . default . EMPPower ;
PoisonPower = DamageType . default . PoisonPower ;
MicrowavePower = DamageType . default . MicrowavePower ;
BleedPower = DamageType . default . BleedPower ;
}
KFDmgCauser = KFInterface _DamageCauser ( DamageCauser ) ;
if ( KFDmgCauser != None )
{
BurnPower *= KFDmgCauser . GetIncapMod ( ) ;
EMPPower *= KFDmgCauser . GetIncapMod ( ) ;
PoisonPower *= KFDmgCauser . GetIncapMod ( ) ;
MicrowavePower *= KFDmgCauser . GetIncapMod ( ) ;
BleedPower *= KFDmgCauser . GetIncapMod ( ) ;
}
// these afflictions can apply on killing blow, but fire can apply after death
if ( bPlayedDeath && WorldInfo . TimeSeconds > TimeOfDeath )
{
// If we're already dead, go ahead and apply burn stacking power, just
// so we can do the burn effects
if ( BurnPower > 0 )
{
AccrueAffliction ( AF _FirePanic , BurnPower ) ;
}
}
else
{
if ( EMPPower > 0 )
{
AccrueAffliction ( AF _EMP , EMPPower ) ;
}
else if ( InstigatorPerk != none && InstigatorPerk . ShouldGetDaZeD ( DamageType ) )
{
AccrueAffliction ( AF _EMP , InstigatorPerk . GetDaZedEMPPower ( ) ) ;
}
if ( BurnPower > 0 )
{
AccrueAffliction ( AF _FirePanic , BurnPower ) ;
}
if ( PoisonPower > 0 || DamageType . static . AlwaysPoisons ( ) )
{
AccrueAffliction ( AF _Poison , PoisonPower ) ;
}
if ( MicrowavePower > 0 )
{
AccrueAfflictionMicrowave ( AF _Microwave , MicrowavePower , DamageType . default . bHasToSpawnMicrowaveFire ) ;
}
if ( BleedPower > 0 )
{
AccrueAffliction ( AF _Bleed , BleedPower ) ;
}
}
}
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* @ name Stacked / Accumulated Afflications
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
/ * *
* Adds StackedPower
* @ return true if the affliction effect should be applied
* /
function AccrueAffliction ( EAfflictionType Type , float InPower , optional EHitZoneBodyPart BodyPart , optional KFPerk InstigatorPerk )
{
if ( InPower <= 0 || Type >= IncapSettings . Length )
{
return ; // immune
}
if ( ! VerifyAfflictionInstance ( Type , InstigatorPerk ) )
{
return ; // cannot create instance
}
// for radius damage apply falloff using most recent HitFxInfo
if ( HitFxInfo . bRadialDamage && HitFxRadialInfo . RadiusDamageScale != 255 )
{
InPower *= ByteToFloat ( HitFxRadialInfo . RadiusDamageScale ) ;
` log(Type@"Applied damage falloff modifier of"@ByteToFloat(HitFxRadialInfo.RadiusDamageScale), bDebugLog);
}
// scale by character vulnerability
if ( IncapSettings [ Type ] . Vulnerability . Length > 0 )
{
InPower *= GetAfflictionVulnerability ( Type , BodyPart ) ;
` log(Type@"Applied hit zone vulnerability modifier of"@GetAfflictionVulnerability(Type, BodyPart)@"for"@BodyPart, bDebugLog);
}
// allow owning pawn final adjustment
AdjustAffliction ( InPower ) ;
if ( InPower > 0 )
{
Afflictions [ Type ] . Accrue ( InPower ) ;
}
}
/ * *
* Adds StackedPower
* @ return true if the affliction effect should be applied
* /
function AccrueAfflictionMicrowave ( EAfflictionType Type , float InPower , bool bHasToSpawnFire , optional EHitZoneBodyPart BodyPart , optional KFPerk InstigatorPerk )
{
if ( InPower <= 0 || Type >= IncapSettings . Length )
{
return ; // immune
}
if ( ! VerifyAfflictionInstance ( Type , InstigatorPerk ) )
{
return ; // cannot create instance
}
// for radius damage apply falloff using most recent HitFxInfo
if ( HitFxInfo . bRadialDamage && HitFxRadialInfo . RadiusDamageScale != 255 )
{
InPower *= ByteToFloat ( HitFxRadialInfo . RadiusDamageScale ) ;
` log(Type@"Applied damage falloff modifier of"@ByteToFloat(HitFxRadialInfo.RadiusDamageScale), bDebugLog);
}
// scale by character vulnerability
if ( IncapSettings [ Type ] . Vulnerability . Length > 0 )
{
InPower *= GetAfflictionVulnerability ( Type , BodyPart ) ;
` log(Type@"Applied hit zone vulnerability modifier of"@GetAfflictionVulnerability(Type, BodyPart)@"for"@BodyPart, bDebugLog);
}
// allow owning pawn final adjustment
AdjustAffliction ( InPower ) ;
if ( InPower > 0 )
{
KFAffliction _Microwave ( Afflictions [ Type ] ) . bHasToSpawnFire = bHasToSpawnFire ;
Afflictions [ Type ] . Accrue ( InPower ) ;
}
}
/** Returns an index into the vulnerabilities array based on what part of the body was hit */
simulated function float GetAfflictionVulnerability ( EAfflictionType i , EHitZoneBodyPart BodyPart )
{
local EAfflictionVulnerabilityType j ;
switch ( BodyPart )
{
case BP _Head :
j = AV _Head ;
break ;
case BP _LeftArm :
case BP _RightArm :
j = AV _Arms ;
break ;
case BP _LeftLeg :
case BP _RightLeg :
j = AV _Legs ;
break ;
case BP _Special :
j = AV _Special ;
break ;
}
if ( j > AV _Default && j < IncapSettings [ i ] . Vulnerability . Length )
{
return IncapSettings [ i ] . Vulnerability [ j ] ;
}
return IncapSettings [ i ] . Vulnerability [ AV _Default ] ;
}
/** Called whenever we need may need to initiatize the affliction class instance */
simulated function bool VerifyAfflictionInstance ( EAfflictionType Type , optional KFPerk InstigatorPerk )
{
if ( Type >= Afflictions . Length || Afflictions [ Type ] == None )
{
if ( Type < AfflictionClasses . Length && AfflictionClasses [ Type ] != None )
{
Afflictions [ Type ] = new ( Outer ) AfflictionClasses [ Type ] ;
// Cache a reference to the owner to avoid passing parameters around.
Afflictions [ Type ] . Init ( Outer , Type , InstigatorPerk ) ;
}
else
{
` log(GetFuncName() @ "Failed with afflication:" @ Type @ "class:" @ AfflictionClasses[Type] @ Self);
Afflictions [ Type ] = None ;
return FALSE ;
}
}
return true ;
}
/** Accessor to get affliction duration for attack cooldowns in verus*/
function float GetAfflictionDuration ( EAfflictionType Type )
{
if ( Type < IncapSettings . Length )
{
return IncapSettings [ Type ] . Duration ;
}
}
/** Accessor to get known affliction knockdown modifier */
function float GetAfflictionKnockdownModifier ( )
{
local float KnockdownModifier ;
local int i ;
KnockdownModifier = 0. f ;
for ( i = 0 ; i < Afflictions . Length ; ++ i )
{
if ( Afflictions [ i ] != none )
{
KnockdownModifier += Afflictions [ i ] . GetKnockdownModifier ( ) ;
}
}
return KnockdownModifier ;
}
/** Accessor to get known affliction Stumble modifier */
function float GetAfflictionStumbleModifier ( )
{
local float StumbleModifier ;
local int i ;
StumbleModifier = 0. f ;
for ( i = 0 ; i < Afflictions . Length ; ++ i )
{
if ( Afflictions [ i ] != none )
{
StumbleModifier += Afflictions [ i ] . GetStumbleModifier ( ) ;
}
}
return StumbleModifier ;
}
/** Accessor to get known affliction Stun modifier */
function float GetAfflictionStunModifier ( )
{
local float StunModifier ;
local int i ;
StunModifier = 0. f ;
for ( i = 0 ; i < Afflictions . Length ; ++ i )
{
if ( Afflictions [ i ] != none )
{
StunModifier += Afflictions [ i ] . GetStunModifier ( ) ;
}
}
return StunModifier ;
}
/** Accessor to get known affliction Damage modifier */
function float GetAfflictionDamageModifier ( )
{
local float DamageModifier ;
local int i ;
DamageModifier = 1. f ;
for ( i = 0 ; i < Afflictions . Length ; ++ i )
{
if ( Afflictions [ i ] != none )
{
DamageModifier += Afflictions [ i ] . GetDamageModifier ( ) ;
}
}
return DamageModifier ;
}
/** Accessor to get known affliction speed modifier - Multiplicative from all mods */
function float GetAfflictionSpeedModifier ( )
{
local float SpeedModifier ;
local int i ;
SpeedModifier = 1. f ;
for ( i = 0 ; i < Afflictions . Length ; ++ i )
{
if ( Afflictions [ i ] != none )
{
SpeedModifier *= Afflictions [ i ] . GetSpeedModifier ( ) ;
}
}
return SpeedModifier ;
}
function float GetAfflictionAttackSpeedModifier ( )
{
local float SpeedModifier ;
local int i ;
SpeedModifier = 1. f ;
for ( i = 0 ; i < Afflictions . Length ; ++ i )
{
if ( Afflictions [ i ] != none )
{
SpeedModifier *= Afflictions [ i ] . GetAttackSpeedModifier ( ) ;
}
}
return SpeedModifier ;
}
/** Turns off all affliction sounds / effects */
simulated function Shutdown ( )
{
local int i ;
// Call deactivate, but let the strength decay naturally before removing from array
for ( i = Afflictions . Length - 1 ; i >= 0 ; -- i )
{
if ( Afflictions [ i ] != None )
{
Afflictions [ i ] . Shutdown ( ) ;
}
}
}
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* @ name Functions that are needed clientside for VFX .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
/** Called from the pawn when we need to update FX outside of the affliction class (e.g. client repnotify) */
function ToggleEffects ( EAfflictionType Type , bool bPrimary , optional bool bSecondary )
{
if ( WorldInfo . NetMode == NM _DedicatedServer )
{
return ;
}
// After death FX are soley owned by the affliction class (simplifies TearOff/Replication issues)
if ( bPlayedDeath )
{
return ;
}
// If the value is zero no need to create an instance
if ( Type >= Afflictions . Length || Afflictions [ Type ] == None )
{
if ( ( ! bPrimary && ! bSecondary ) || ! VerifyAfflictionInstance ( Type ) )
{
return ; // cannot create instance
}
}
Afflictions [ Type ] . ToggleEffects ( bPrimary , bSecondary ) ;
}
function UpdateMaterialParameter ( EAfflictionType Type , float Value )
{
if ( WorldInfo . NetMode == NM _DedicatedServer )
{
return ;
}
// If the value is zero no need to create an instance
if ( Type >= Afflictions . Length || Afflictions [ Type ] == None )
{
if ( Value == 0 || ! VerifyAfflictionInstance ( Type ) )
{
return ; // cannot create instance
}
}
Afflictions [ Type ] . SetMaterialParameter ( Value ) ;
}
defaultproperties
{
AfflictionClasses ( AF _EMP ) = class 'KFAffliction_EMP'
AfflictionClasses ( AF _FirePanic ) = class 'KFAffliction_Fire'
AfflictionClasses ( AF _Poison ) = class 'KFAffliction_Poison'
AfflictionClasses ( AF _Microwave ) = class 'KFAffliction_Microwave'
AfflictionClasses ( AF _Freeze ) = class 'KFAffliction_Freeze'
AfflictionClasses ( AF _GunHit ) = class 'KFAffliction_MediumRecovery'
AfflictionClasses ( AF _MeleeHit ) = class 'KFAffliction_HeavyRecovery'
AfflictionClasses ( AF _Stun ) = class 'KFAffliction_Stun'
AfflictionClasses ( AF _Stumble ) = class 'KFAffliction_Stumble'
AfflictionClasses ( AF _Knockdown ) = class 'KFAffliction_Knockdown'
AfflictionClasses ( AF _Snare ) = class 'KFAffliction_Snare'
AfflictionClasses ( AF _Bleed ) = class 'KFAffliction_Bleed'
}