440 lines
18 KiB
Ucode
440 lines
18 KiB
Ucode
//=============================================================================
|
|
// KFAIController_ZedDAR
|
|
//=============================================================================
|
|
// Base AI controller for evil DAR robots.
|
|
//=============================================================================
|
|
// Killing Floor 2
|
|
// Copyright (C) 2018 Tripwire Interactive LLC
|
|
//=============================================================================
|
|
class KFAIController_ZedDAR extends KFAIController_Ranged
|
|
abstract;
|
|
|
|
var float MinRangeAttackDist;
|
|
var float MaxRangeAttackDist;
|
|
var float LastRangeAttackTime;
|
|
var float TimeBetweenRangeAttacks;
|
|
var float BaseTimeBetweenRangeAttacks;
|
|
var float TimeBetweenRangeAttackVariance;
|
|
var float CheckSpecialMoveTime;
|
|
var float LastCheckSpecialMoveTime;
|
|
|
|
var name FiringSocketName;
|
|
|
|
var protected float RangeAttackIntervalNormal;
|
|
var protected float RangeAttackIntervalHard;
|
|
var protected float RangeAttackIntervalSuicidal;
|
|
var protected float RangeAttackIntervalHellOnEarth;
|
|
|
|
var float HeadLossAttackTimeDebuff;
|
|
var float HeadLossAccuracyDebuffPct;
|
|
|
|
var float AimError;
|
|
|
|
var bool bAllowedToSprint;
|
|
var bool bCanEvade;
|
|
|
|
var int ArmorLossStumblePower;
|
|
|
|
event PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
|
|
BaseTimeBetweenRangeAttacks = GetAttackIntervalByDifficulty();
|
|
|
|
TimeBetweenRangeAttacks = BaseTimeBetweenRangeAttacks;
|
|
if(TimeBetweenRangeAttackVariance > 0)
|
|
{
|
|
TimeBetweenRangeAttacks += RandRange(-TimeBetweenRangeAttackVariance, TimeBetweenRangeAttackVariance);
|
|
}
|
|
}
|
|
|
|
function float GetAttackIntervalByDifficulty()
|
|
{
|
|
if (Skill == class'KFGameDifficultyInfo'.static.GetDifficultyValue(0)) // Normal
|
|
{
|
|
return RangeAttackIntervalNormal;
|
|
}
|
|
else if (Skill <= class'KFGameDifficultyInfo'.static.GetDifficultyValue(1)) // Hard
|
|
{
|
|
return RangeAttackIntervalHard;
|
|
}
|
|
else if (Skill <= class'KFGameDifficultyInfo'.static.GetDifficultyValue(2)) // Suicidal
|
|
{
|
|
return RangeAttackIntervalSuicidal;
|
|
}
|
|
else if (Skill <= class'KFGameDifficultyInfo'.static.GetDifficultyValue(3)) // Hell on Earth
|
|
{
|
|
return RangeAttackIntervalHellOnEarth;
|
|
}
|
|
|
|
return RangeAttackIntervalNormal;
|
|
}
|
|
|
|
function bool CanDoRangedAttack(float DistanceToTargetSqr)
|
|
{
|
|
if (!CheckOverallCooldownTimer())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return ((LastRangeAttackTime == 0 || (`TimeSince(LastRangeAttackTime) > TimeBetweenRangeAttacks)) &&
|
|
DistanceToTargetSqr >= Square(MinRangeAttackDist) &&
|
|
DistanceToTargetSqr <= Square(MaxRangeAttackDist) &&
|
|
MyKFPawn.CanDoSpecialMove(SM_StandAndShootAttack));
|
|
}
|
|
|
|
simulated function Tick(float DeltaTime)
|
|
{
|
|
local float DistToTargetSqr;
|
|
|
|
Super.Tick(DeltaTime);
|
|
|
|
if (Role == ROLE_Authority && Enemy != none && MyKFPawn != none)
|
|
{
|
|
if (`TimeSince(LastCheckSpecialMoveTime) >= CheckSpecialMoveTime && !MyKFPawn.IsDoingSpecialMove() )
|
|
{
|
|
if (GetActiveCommand() != none && !GetActiveCommand().IsA('AICommand_SpecialMove'))
|
|
{
|
|
// Trace from worldinfo, open doors ignore traces from zeds
|
|
if (WorldInfo.FastTrace(Enemy.Location, Pawn.Location, , true))
|
|
{
|
|
DistToTargetSqr = VSizeSq(Enemy.Location - Pawn.Location);
|
|
if (CanDoRangedAttack(DistToTargetSqr))
|
|
{
|
|
if (KFGameInfo(WorldInfo.Game) != none && KFGameInfo(WorldInfo.Game).GameConductor != none)
|
|
{
|
|
KFGameInfo(WorldInfo.Game).GameConductor.UpdateOverallAttackCoolDowns(self);
|
|
}
|
|
|
|
StartRangedAttack();
|
|
if(TimeBetweenRangeAttackVariance > 0)
|
|
{
|
|
TimeBetweenRangeAttacks = BaseTimeBetweenRangeAttacks + RandRange(-TimeBetweenRangeAttackVariance, TimeBetweenRangeAttackVariance);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
LastCheckSpecialMoveTime = WorldInfo.TimeSeconds;
|
|
}
|
|
|
|
if (MyKFPawn.IsDoingSpecialMove(SM_StandAndShootAttack))
|
|
{
|
|
Focus = none;
|
|
SetFocalPoint(Enemy.Location);
|
|
}
|
|
else if (Focus == none)
|
|
{
|
|
Focus = Enemy;
|
|
}
|
|
}
|
|
}
|
|
|
|
event bool SetEnemy(Pawn NewEnemy)
|
|
{
|
|
if (MyKFPawn == none || MyKFPawn.IsDoingSpecialMove(SM_StandAndShootAttack))
|
|
{
|
|
if (MyKFPawn.NeedToTurn(NewEnemy.Location))
|
|
{
|
|
`AILog( GetFuncName() $ "() rejecting " $ NewEnemy $ " because current enemy (" $ Enemy $ ") we would need to turn to see it", 'SetEnemy' );
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return super.SetEnemy(NewEnemy);
|
|
}
|
|
|
|
function StartRangedAttack();
|
|
|
|
function FireRangedAttack(class<KFProjectile> RangedProjectileClass, vector ProjectileOffset)
|
|
{
|
|
local vector SocketLocation, DirToEnemy, HitLocation, HitNormal;
|
|
local KFProjectile SpawnedProjectile;
|
|
local actor HitActor;
|
|
local Vector AimLocation, AimDispalcement;
|
|
local vector displacementToHitLoc;
|
|
local float distanceToHitLoc;
|
|
|
|
if (MyKFPawn == none)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (bDebugAimError)
|
|
{
|
|
// Render debug lines and simulate several shots at once to evaluate aimerror
|
|
DebugAimError(FiringSocketName);
|
|
return;
|
|
}
|
|
|
|
SocketLocation = GetStartFireLocation() + (ProjectileOffset >> Pawn.GetViewRotation());
|
|
if (MyKFPawn.Health > 0.f && Role == ROLE_Authority && MyKFPawn.IsDoingSpecialMove(SM_StandAndShootAttack))
|
|
{
|
|
AimLocation = Enemy.Location;
|
|
HitActor = WorldInfo.Trace(HitLocation, HitNormal, AimLocation, SocketLocation, true);
|
|
|
|
// Don't shoot if it's too close
|
|
if (HitActor == Enemy)
|
|
{
|
|
if (!bCanLeadTarget)
|
|
{
|
|
DirToEnemy = normal(AimLocation - SocketLocation);
|
|
|
|
`AILog_Ext( GetFuncName() @ "Leading - HitActor: " @ HitActor @ " Is My Enemy: " @ Enemy, 'FireBall', self );
|
|
}
|
|
else
|
|
{
|
|
DirToEnemy = normal(CalcAimLocToHit(AimLocation, SocketLocation, RangedProjectileClass.default.Speed, RangedProjectileClass.default.Speed, Enemy.Velocity) - SocketLocation);
|
|
|
|
`AILog_Ext( GetFuncName() @ "Not Leading - HitActor: " @ HitActor @ " Is My Enemy: " @ Enemy, 'FireBall', self );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// If our path to the enemy is blocked, try his last known position
|
|
AimLocation = AICommand_RangedAttack(GetActiveCommand()).LastKnownEnemyLocation;
|
|
HitActor = Trace(HitLocation, HitNormal, AimLocation, SocketLocation, true);
|
|
|
|
displacementToHitLoc = HitLocation - SocketLocation;
|
|
distanceToHitLoc = VSize(displacementToHitLoc);
|
|
|
|
// If there is an object in front of us, cancel the attack
|
|
if (distanceToHitLoc < MinRangeAttackDist)
|
|
{
|
|
`AILog_Ext( GetFuncName() @ "- HitActor: " @ HitActor @ " Is NOT My Enemy: " @ Enemy @ " and distanceToHitLoc: " @ distanceToHitLoc @ " is too close so not firing!!!", 'FireBall', self );
|
|
MyKFPawn.SpecialMoves[SM_StandAndShootAttack].AbortedByAICommand();
|
|
LastRangeAttackTime = WorldInfo.TimeSeconds;
|
|
return;
|
|
}
|
|
else // Otherwise fire at the enemies last known position
|
|
{
|
|
DirToEnemy = normal((AimLocation - SocketLocation));
|
|
|
|
`AILog_Ext( GetFuncName() @ "- Fire at enemy last known position : " @ Enemy @ AimLocation, 'FireBall', self );
|
|
}
|
|
}
|
|
|
|
AimDispalcement = VRand();
|
|
DirToEnemy += (AimDispalcement * AimError);
|
|
|
|
// Shoot the fireball
|
|
SpawnedProjectile = Spawn(RangedProjectileClass, MyKFPawn, , SocketLocation, Rotator(DirToEnemy));
|
|
SpawnedProjectile.Instigator = MyKFPawn;
|
|
SpawnedProjectile.InstigatorController = self;
|
|
|
|
// Fire
|
|
SpawnedProjectile.Init(DirToEnemy);
|
|
|
|
LastRangeAttackTime = WorldInfo.TimeSeconds;
|
|
}
|
|
}
|
|
|
|
function vector GetStartFireLocation()
|
|
{
|
|
return MyKFPawn.GetPawnViewLocation();
|
|
}
|
|
|
|
function bool ShouldSprint()
|
|
{
|
|
return bAllowedToSprint && super.ShouldSprint();
|
|
}
|
|
|
|
function bool CanEvade(optional bool bOverrideSpecialMove)
|
|
{
|
|
return bCanEvade && super.CanEvade(bOverrideSpecialMove);
|
|
}
|
|
|
|
function OnArmorLoss(name ArmorName)
|
|
{
|
|
MyKFPawn.AfflictionHandler.AccrueAffliction(AF_Stumble, ArmorLossStumblePower);
|
|
|
|
if(ArmorName == 'head')
|
|
{
|
|
BaseTimeBetweenRangeAttacks += HeadLossAttackTimeDebuff;
|
|
AimError *= (1.f + HeadLossAccuracyDebuffPct);
|
|
}
|
|
else if (ArmorName == 'front')
|
|
{
|
|
bCanSprint = false;
|
|
bAllowedToSprint = false;
|
|
bCanEvade = false;
|
|
MyKFPawn.bIsSprinting = false;
|
|
}
|
|
}
|
|
|
|
defaultproperties
|
|
{
|
|
// ---------------------------------------------
|
|
// Danger Evasion Settings
|
|
DangerEvadeSettings.Empty
|
|
DangerEvadeSettings(0)={(ClassName="KFProj_Bullet_Pellet",
|
|
Cooldowns=(3.0, 2.0, 1.0, 0.75), // Normal, Hard, Suicidal, HoE
|
|
EvadeChances=(0.1, 0.3, 0.5, 0.7),
|
|
ReactionDelayRanges={((X=0.0, Y=0.2), (X=0.0, Y=0.0), (X=0.0, Y=0.15), (X=0.0, Y=0.00))},
|
|
SoloChanceMultiplier=1.0)}
|
|
DangerEvadeSettings(1)={(ClassName="KFProj_Nail_Nailgun",
|
|
Cooldowns=(3.0, 2.0, 1.0, 0.75), // Normal, Hard, Suicidal, HoE
|
|
EvadeChances=(0.1, 0.3, 0.5, 0.7),
|
|
ReactionDelayRanges={((X=0.0, Y=0.2), (X=0.0, Y=0.0), (X=0.0, Y=0.15), (X=0.0, Y=0.00))},
|
|
SoloChanceMultiplier=1.0)}
|
|
DangerEvadeSettings(2)={(ClassName="KFProj_Bullet_DragonsBreath",
|
|
Cooldowns=(3.0, 2.0, 1.0, 0.75), // Normal, Hard, Suicidal, HoE
|
|
EvadeChances=(0.1, 0.3, 0.5, 0.7),
|
|
ReactionDelayRanges={((X=0.0, Y=0.2), (X=0.0, Y=0.0), (X=0.0, Y=0.15), (X=0.0, Y=0.00))},
|
|
SoloChanceMultiplier=1.0)}
|
|
DangerEvadeSettings(3)={(ClassName="KFProj_HighExplosive_M79",
|
|
Cooldowns=(3.0, 2.0, 1.0, 0.75), // Normal, Hard, Suicidal, HoE
|
|
EvadeChances=(0.1, 0.3, 0.5, 0.7),
|
|
ForcedEvadeChances={((FL=0.0, FR=0.0), (FL=0.5, FR=0.5), (FL=0.5, FR=0.5), (FL=0.5, FR=0.5))},
|
|
ReactionDelayRanges={((X=0.0, Y=0.2), (X=0.0, Y=0.0), (X=0.0, Y=0.15), (X=0.0, Y=0.05))},
|
|
SoloChanceMultiplier=1.0)}
|
|
DangerEvadeSettings(4)={(ClassName="KFProj_HighExplosive_M32",
|
|
Cooldowns=(3.0, 2.0, 1.0, 0.75), // Normal, Hard, Suicidal, HoE
|
|
EvadeChances=(0.1, 0.3, 0.5, 0.7),
|
|
ForcedEvadeChances={((FL=0.0, FR=0.0), (FL=0.5, FR=0.5), (FL=0.5, FR=0.5), (FL=0.5, FR=0.5))},
|
|
ReactionDelayRanges={((X=0.0, Y=0.2), (X=0.0, Y=0.0), (X=0.0, Y=0.15), (X=0.0, Y=0.05))},
|
|
SoloChanceMultiplier=1.0)}
|
|
DangerEvadeSettings(5)={(ClassName="KFProj_Rocket_RPG7",
|
|
Cooldowns=(3.0, 2.0, 1.0, 0.75), // Normal, Hard, Suicidal, HoE
|
|
EvadeChances=(0.1, 0.3, 0.5, 0.7),
|
|
ForcedEvadeChances={((FL=0.0, FR=0.0), (FL=0.5, FR=0.5), (FL=0.5, FR=0.5), (FL=0.5, FR=0.5))},
|
|
ReactionDelayRanges={((X=0.0, Y=0.2), (X=0.0, Y=0.0), (X=0.0, Y=0.15), (X=0.0, Y=0.05))},
|
|
SoloChanceMultiplier=1.0)}
|
|
DangerEvadeSettings(6)={(ClassName="KFDT_Explosive_M16M203",
|
|
Cooldowns=(3.0, 2.0, 1.0, 0.75), // Normal, Hard, Suicidal, HoE
|
|
EvadeChances=(0.1, 0.3, 0.5, 0.7),
|
|
ForcedEvadeChances={((FL=0.0, FR=0.0), (FL=0.5, FR=0.5), (FL=0.5, FR=0.5), (FL=0.5, FR=0.5))},
|
|
ReactionDelayRanges={((X=0.0, Y=0.2), (X=0.0, Y=0.0), (X=0.0, Y=0.15), (X=0.0, Y=0.05))},
|
|
SoloChanceMultiplier=1.0)}
|
|
DangerEvadeSettings(7)={(ClassName="KFDT_Explosive_HRGIncendiaryRifle",
|
|
Cooldowns=(3.0, 2.0, 1.0, 0.75), // Normal, Hard, Suicidal, HoE
|
|
EvadeChances=(0.1, 0.3, 0.5, 0.7),
|
|
ForcedEvadeChances={((FL=0.0, FR=0.0), (FL=0.5, FR=0.5), (FL=0.5, FR=0.5), (FL=0.5, FR=0.5))},
|
|
ReactionDelayRanges={((X=0.0, Y=0.2), (X=0.0, Y=0.0), (X=0.0, Y=0.15), (X=0.0, Y=0.05))},
|
|
SoloChanceMultiplier=1.0)}
|
|
|
|
|
|
//shooting fire
|
|
DangerEvadeSettings(8)={(ClassName="KFProj_CaulkNBurn_GroundFire",
|
|
Cooldowns=(3.0, 2.0, 1.5, 1.0), // Normal, Hard, Suicidal, HoE
|
|
EvadeChances=(0.1, 0.3, 0.5, 0.7),
|
|
ReactionDelayRanges={((X=0.3, Y=0.5), (X=0.3, Y=0.5), (X=0.3, Y=0.5), (X=0.3, Y=0.5))},
|
|
SoloChanceMultiplier=1.0)}
|
|
DangerEvadeSettings(9)={(ClassName="KFProj_FlameThrower_GroundFire",
|
|
Cooldowns=(3.0, 2.0, 1.5, 1.0), // Normal, Hard, Suicidal, HoE
|
|
EvadeChances=(0.4, 0.5, 0.6, 0.7),
|
|
ReactionDelayRanges={((X=0.3, Y=0.5), (X=0.3, Y=0.5), (X=0.3, Y=0.5), (X=0.3, Y=0.5))},
|
|
SoloChanceMultiplier=1.0)}
|
|
DangerEvadeSettings(10)={(ClassName="KFWeap_Flame_CaulkBurn",
|
|
Cooldowns=(3.0, 2.0, 1.5, 1.0), // Normal, Hard, Suicidal, HoE
|
|
EvadeChances=(0.4, 0.5, 0.6, 0.7),
|
|
ReactionDelayRanges={((X=0.3, Y=0.5), (X=0.3, Y=0.5), (X=0.3, Y=0.5), (X=0.3, Y=0.5))},
|
|
SoloChanceMultiplier=1.0)}
|
|
DangerEvadeSettings(11)={(ClassName="KFWeap_Flame_Flamethrower",
|
|
Cooldowns=(3.0, 2.0, 1.5, 1.0), // Normal, Hard, Suicidal, HoE
|
|
EvadeChances=(0.4, 0.5, 0.6, 0.7),
|
|
ReactionDelayRanges={((X=0.3, Y=0.5), (X=0.3, Y=0.5), (X=0.3, Y=0.5), (X=0.3, Y=0.5))},
|
|
SoloChanceMultiplier=1.0)}
|
|
DangerEvadeSettings(12)={(ClassName="KFWeap_Beam_Microwave",
|
|
Cooldowns=(3.0, 2.0, 1.5, 1.0), // Normal, Hard, Suicidal, HoE
|
|
EvadeChances=(0.4, 0.5, 0.6, 0.7),
|
|
ReactionDelayRanges={((X=0.3, Y=0.5), (X=0.3, Y=0.5), (X=0.3, Y=0.5), (X=0.3, Y=0.5))},
|
|
SoloChanceMultiplier=1.0)}
|
|
|
|
|
|
//Aimed weapons it dodges //sharpshooter
|
|
DangerEvadeSettings(13)={(ClassName="KFWeap_Bow_Crossbow",
|
|
Cooldowns=(2.3, 2.3, 2.3, 1.3), // Normal, Hard, Suicidal, HoE
|
|
EvadeChances=(0.08, 0.1, 0.2, 0.35),
|
|
ForcedEvadeChances={((FL=0.5, FR=0.5), (FL=0.5, FR=0.5), (FL=0.5, FR=0.5), (FL=0.5, FR=0.5))},
|
|
ReactionDelayRanges={((X=0.0, Y=0.15), (X=0.0, Y=0.15), (X=0.0, Y=0.15), (X=0.0, Y=0.15))},
|
|
SoloChanceMultiplier=1.0)}
|
|
DangerEvadeSettings(14)={(ClassName="KFWeap_Rifle_M14EBR",
|
|
Cooldowns=(2.3, 2.3, 2.3, 1.3), // Normal, Hard, Suicidal, HoE
|
|
EvadeChances=(0.08, 0.1, 0.2, 0.35),
|
|
ForcedEvadeChances={((FL=0.5, FR=0.5), (FL=0.5, FR=0.5), (FL=0.5, FR=0.5), (FL=0.5, FR=0.5))},
|
|
ReactionDelayRanges={((X=0.0, Y=0.15), (X=0.0, Y=0.15), (X=0.0, Y=0.15), (X=0.0, Y=0.15))},
|
|
SoloChanceMultiplier=1.0)}
|
|
DangerEvadeSettings(15)={(ClassName="KFWeap_Rifle_Winchester1894",
|
|
Cooldowns=(2.3, 2.3, 2.3, 1.3), // Normal, Hard, Suicidal, HoE
|
|
EvadeChances=(0.08, 0.1, 0.2, 0.35),
|
|
ForcedEvadeChances={((FL=0.5, FR=0.5), (FL=0.5, FR=0.5), (FL=0.5, FR=0.5), (FL=0.5, FR=0.5))},
|
|
ReactionDelayRanges={((X=0.0, Y=0.15), (X=0.0, Y=0.15), (X=0.0, Y=0.15), (X=0.0, Y=0.15))},
|
|
SoloChanceMultiplier=1.0)}
|
|
DangerEvadeSettings(16)={(ClassName="KFWeap_Rifle_RailGun",
|
|
Cooldowns=(2.3, 2.3, 2.3, 1.3), // Normal, Hard, Suicidal, HoE
|
|
EvadeChances=(0.08, 0.1, 0.2, 0.35),
|
|
ForcedEvadeChances={((FL=0.5, FR=0.5), (FL=0.5, FR=0.5), (FL=0.5, FR=0.5), (FL=0.5, FR=0.5))},
|
|
ReactionDelayRanges={((X=0.0, Y=0.15), (X=0.0, Y=0.15), (X=0.0, Y=0.15), (X=0.0, Y=0.15))},
|
|
SoloChanceMultiplier=1.0)}
|
|
|
|
//Grenades
|
|
DangerEvadeSettings(17)={(ClassName="KFProj_FragGrenade",
|
|
Cooldowns=(3.0, 2.0, 1.0, 0.75), // Normal, Hard, Suicidal, HoE
|
|
EvadeChances=(0.1, 0.2, 0.5, 0.8),
|
|
ForcedEvadeChances={((FL=0.0, FR=0.0), (FL=0.5, FR=0.5), (FL=0.5, FR=0.5), (FL=0.5, FR=0.5))},
|
|
ReactionDelayRanges={((X=0.0, Y=0.2), (X=0.0, Y=0.0), (X=0.0, Y=0.15), (X=0.0, Y=0.05))},
|
|
SoloChanceMultiplier=1.0)}
|
|
DangerEvadeSettings(18)={(ClassName="KFProj_MolotovGrenade",
|
|
Cooldowns=(3.0, 2.0, 1.0, 0.75), // Normal, Hard, Suicidal, HoE
|
|
EvadeChances=(0.1, 0.2, 0.5, 0.8),
|
|
ForcedEvadeChances={((FL=0.0, FR=0.0), (FL=0.5, FR=0.5), (FL=0.5, FR=0.5), (FL=0.5, FR=0.5))},
|
|
ReactionDelayRanges={((X=0.0, Y=0.2), (X=0.0, Y=0.0), (X=0.0, Y=0.15), (X=0.0, Y=0.05))},
|
|
SoloChanceMultiplier=1.0)}
|
|
DangerEvadeSettings(19)={(ClassName="KFProj_DynamiteGrenade",
|
|
Cooldowns=(3.0, 2.0, 1.0, 0.75), // Normal, Hard, Suicidal, HoE
|
|
EvadeChances=(0.1, 0.2, 0.5, 0.8),
|
|
ForcedEvadeChances={((FL=0.0, FR=0.0), (FL=0.5, FR=0.5), (FL=0.5, FR=0.5), (FL=0.5, FR=0.5))},
|
|
ReactionDelayRanges={((X=0.0, Y=0.2), (X=0.0, Y=0.0), (X=0.0, Y=0.15), (X=0.0, Y=0.05))},
|
|
SoloChanceMultiplier=1.0)}
|
|
DangerEvadeSettings(20)={(ClassName="KFProj_NailBombGrenade",
|
|
Cooldowns=(3.0, 2.0, 1.0, 0.75), // Normal, Hard, Suicidal, HoE
|
|
EvadeChances=(0.1, 0.2, 0.5, 0.8),
|
|
ForcedEvadeChances={((FL=0.0, FR=0.0), (FL=0.5, FR=0.5), (FL=0.5, FR=0.5), (FL=0.5, FR=0.5))},
|
|
ReactionDelayRanges={((X=0.0, Y=0.2), (X=0.0, Y=0.0), (X=0.0, Y=0.15), (X=0.0, Y=0.05))},
|
|
SoloChanceMultiplier=1.0)}
|
|
DangerEvadeSettings(21)={(ClassName="KFProj_HEGrenade",
|
|
Cooldowns=(3.0, 2.0, 1.0, 0.75), // Normal, Hard, Suicidal, HoE
|
|
EvadeChances=(0.1, 0.2, 0.5, 0.8),
|
|
ForcedEvadeChances={((FL=0.0, FR=0.0), (FL=0.5, FR=0.5), (FL=0.5, FR=0.5), (FL=0.5, FR=0.5))},
|
|
ReactionDelayRanges={((X=0.0, Y=0.2), (X=0.0, Y=0.0), (X=0.0, Y=0.15), (X=0.0, Y=0.05))},
|
|
SoloChanceMultiplier=1.0)}
|
|
|
|
// Ground Fire
|
|
DangerEvadeSettings(22)={(ClassName="KFProj_Flame_HRGIncendiaryRifle",
|
|
Cooldowns=(3.0, 2.0, 1.5, 1.0), // Normal, Hard, Suicidal, HoE
|
|
EvadeChances=(0.1, 0.3, 0.5, 0.7),
|
|
ReactionDelayRanges={((X=0.3, Y=0.5), (X=0.3, Y=0.5), (X=0.3, Y=0.5), (X=0.3, Y=0.5))},
|
|
SoloChanceMultiplier=1.0)}
|
|
|
|
BaseShapeOfProjectileForCalc=(X=10,Y=10,Z=10)
|
|
bUseDesiredRotationForMelee=false
|
|
bCanTeleportCloser=false
|
|
|
|
// ---------------------------------------------
|
|
// Behaviors
|
|
|
|
EvadeGrenadeChance=0.9f
|
|
CheckSpecialMoveTime=0.25f
|
|
SprintWithinEnemyRange=(X=500.f,Y=5000.f) //X=800.f,Y=1500
|
|
|
|
RangeAttackIntervalNormal=7.0
|
|
RangeAttackIntervalHard=6.0
|
|
RangeAttackIntervalSuicidal=5.0
|
|
RangeAttackIntervalHellOnEarth=4.0
|
|
|
|
TimeBetweenRangeAttackVariance=1.0
|
|
|
|
MinRangeAttackDist=300
|
|
MaxRangeAttackDist=4000
|
|
|
|
HeadLossAttackTimeDebuff=2.f
|
|
HeadLossAccuracyDebuffPct=2.0f //0.25
|
|
|
|
AimError=0.03f
|
|
|
|
ArmorLossStumblePower=100
|
|
|
|
bAllowedToSprint=true
|
|
bCanEvade=true
|
|
}
|