class WMAIController_ZedHusk_Omega extends KFAIController_ZedHusk; var float LastFireBallBarrageTime; var float BaseTimeBetweenFireBallBarrages; var float TimeBetweenFireBallBarrages; var float FireballBarrageRandomizedValue; var int MinDistanceForFireBallBarrage; var int MaxDistanceForFireBallBarrage; var float BaseHealthPercentForSprint; var const float FireballBarrageFireIntervalNormal; var const float FireballBarrageFireIntervalHard; var const float FireballBarrageFireIntervalSuicidal; var const float FireballBarrageFireIntervalHellOnEarth; var const float RequiredHealthPercentForSprintNormal; var const float RequiredHealthPercentForSprintHard; var const float RequiredHealthPercentForSprintSuicidal; var const float RequiredHealthPercentForSprintHellOnEarth; event PostBeginPlay() { super.PostBeginPlay(); if (Skill == class'KFGameDifficultyInfo'.static.GetDifficultyValue(0)) // Normal { BaseTimeBetweenFireBallBarrages = FireballBarrageFireIntervalNormal; BaseHealthPercentForSprint = RequiredHealthPercentForSprintNormal; } else if (Skill <= class'KFGameDifficultyInfo'.static.GetDifficultyValue(1)) // Hard { BaseTimeBetweenFireBallBarrages = FireballBarrageFireIntervalHard; BaseHealthPercentForSprint = RequiredHealthPercentForSprintHard; } else if (Skill <= class'KFGameDifficultyInfo'.static.GetDifficultyValue(2)) // Suicidal { BaseTimeBetweenFireBallBarrages = FireballBarrageFireIntervalSuicidal; BaseHealthPercentForSprint = RequiredHealthPercentForSprintSuicidal; } else // Hell on Earth { BaseTimeBetweenFireBallBarrages = FireballBarrageFireIntervalHellOnEarth; BaseHealthPercentForSprint = RequiredHealthPercentForSprintHellOnEarth; } } simulated function Tick(float DeltaTime) { local float DistToTargetSq; if (Role == ROLE_Authority && Enemy != None && MyKFPawn != None) { if (`TimeSince(LastCheckSpecialMoveTime) >= CheckSpecialMoveTime && !MyKFPawn.IsDoingSpecialMove()) { if (GetActiveCommand() != None && !GetActiveCommand().IsA('AICommand_SpecialMove')) { if (WorldInfo.FastTrace(Enemy.Location, Pawn.Location, , True)) { DistToTargetSq = VSizeSq(Enemy.Location - Pawn.Location); if (!IsSuicidal() && CanDoFireballBarrage(DistToTargetSq)) { if (KFGameInfo(WorldInfo.Game) != None && KFGameInfo(WorldInfo.Game).GameConductor != None) { KFGameInfo(WorldInfo.Game).GameConductor.UpdateOverallAttackCoolDowns(self); } class'WMAICommand_HuskOmegaFireBallBarrageAttack'.static.FireBallBarrageAttack(self); TimeBetweenFireBallBarrages = BaseTimeBetweenFireBallBarrages + RandRange(-FireballBarrageRandomizedValue, FireballBarrageRandomizedValue); } } } } } super.Tick(DeltaTime); } function bool CanDoFireballBarrage(float DistToTargetSq) { if(!CheckOverallCooldownTimer()) return False; return ((LastFireBallBarrageTime == 0 || (`TimeSince(LastFireBallBarrageTime) > TimeBetweenFireBallBarrages)) && DistToTargetSq >= Square(MinDistanceForFireBallBarrage) && DistToTargetSq <= Square(MaxDistanceForFireBallBarrage) && MyKFPawn.CanDoSpecialMove(SM_Custom1)) && IsCeilingClear(); } function bool IsCeilingClear() { local vector TraceStart, TraceEnd, Extent; if (MyKFPawn == None) { return False; } TraceStart = MyKFPawn.Location + vect(0,0,1) * MyKFPawn.GetCollisionHeight(); TraceEnd = TraceStart + vect(0,0,1) * 175.0f; Extent.X = MyKFPawn.GetCollisionRadius() * 2.0f; Extent.Y = Extent.X; Extent.Z = 1.0f; return MyKFPawn.FastTrace(TraceEnd, TraceStart, Extent, True); } function bool ShouldSprint() { if (GetHealthPercentage() <= BaseHealthPercentForSprint) return True; else return super.ShouldSprint(); } function ShootRandomFireball(class FireballClass) { local vector SocketLocation, DirToEnemy; local KFProj_Husk_Fireball MyFireball; local vector randVectorDraw; local KFPawn_ZedHusk MyHuskPawn; if (MyKFPawn == None) { return; } SocketLocation = MyKFPawn.GetPawnViewLocation(); if (Role == ROLE_Authority) { randVectorDraw.X = FRand() * 2.0f - 1.0f; randVectorDraw.Y = FRand() * 2.0f - 1.0f; randVectorDraw.Z = FRand() + 0.1f; DirToEnemy = normal(randVectorDraw); MyHuskPawn = KFPawn_ZedHusk(MyKFPawn); // Shoot the fireball MyFireball = Spawn(FireballClass, MyKFPawn, , SocketLocation, Rotator(DirToEnemy)); MyFireball.Instigator = MyKFPawn; MyFireball.InstigatorController = self; // Set our difficulty setings MyFireball.ExplosionTemplate.MomentumTransferScale = MyHuskPawn.FireballSettings.ExplosionMomentum * 0.5f; MyFireball.bSpawnGroundFire = False; // Fire MyFireball.Init(DirToEnemy); } } function ShootFireballBarrage(class FireballClass, vector FireballOffset) { local vector SocketLocation, DirToEnemy; local KFProj_Husk_Fireball MyFireball; local Vector AimLocation, GroundAimLocation; local float SplashAimChance; local vector randVectorDraw; local float randDraw; local KFPawn_ZedHusk MyHuskPawn; if (MyKFPawn == None) { return; } SocketLocation = MyKFPawn.GetPawnViewLocation() + (FireballOffset >> Pawn.GetViewRotation()); if (MyKFPawn.Health > 0.0f && Role == ROLE_Authority && Enemy != None) { AimLocation = Enemy.Location; SplashAimChance = 0.6f; randDraw = FRand(); if (randDraw < SplashAimChance) { // Simple pass at making the Husk try and do splash damage when it shoots at a player rather than just shoot directly at them (and most likely miss) GroundAimLocation = Enemy.Location - (vect(0,0,1) * Enemy.GetCollisionHeight()); if (GroundAimLocation.Z < SocketLocation.Z) { AimLocation = GroundAimLocation; } } randVectorDraw = VRand(); DirToEnemy = normal(AimLocation - SocketLocation) + randVectorDraw * FireballAimError; DirToEnemy.Z = 1.1f + FRand() * 0.3f; DirToEnemy.X += FRand() * 0.2f - 0.1f; DirToEnemy.Y += FRand() * 0.2f - 0.1f; DirToEnemy = normal(DirToEnemy); MyHuskPawn = KFPawn_ZedHusk(MyKFPawn); // Shoot the fireball MyFireball = Spawn(FireballClass, MyKFPawn,, SocketLocation, Rotator(DirToEnemy)); MyFireball.Instigator = MyKFPawn; MyFireball.InstigatorController = self; // Set our difficulty setings MyFireball.ExplosionTemplate.MomentumTransferScale = MyHuskPawn.FireballSettings.ExplosionMomentum; MyFireball.bSpawnGroundFire = MyHuskPawn.FireballSettings.bSpawnGroundFire; // Fire MyFireball.Init(DirToEnemy); LastFireBallBarrageTime = WorldInfo.TimeSeconds; } } defaultproperties { bUseDesiredRotationForMelee=False bCanTeleportCloser=False // Behaviors EvadeGrenadeChance=0.8f CheckSpecialMoveTime=0.25f // Fireball MinDistanceForFireBall=300 MaxDistanceForFireBall=3000 FireballFireIntervalNormal=4.0f FireballFireIntervalHard=3.3f FireballFireIntervalSuicidal=2.8f FireballFireIntervalHellOnEarth=2.2f FireballRandomizedValue=2.5f SplashAimChanceNormal=0.25f SplashAimChanceHard=0.35f SplashAimChanceSuicidal=0.5f SplashAimChanceHellOnEarth=0.75f FireballSpeed=4100.0f FireballAimError=0.03f FireballLeadTargetAimError=0.03f bDebugAimError=False bCanLeadTarget=False // Fireball Barrage MinDistanceForFireBallBarrage=600 MaxDistanceForFireBallBarrage=750 FireballBarrageFireIntervalNormal=3.5f FireballBarrageFireIntervalHard=3.0f FireballBarrageFireIntervalSuicidal=2.5f FireballBarrageFireIntervalHellOnEarth=2.0f FireballBarrageRandomizedValue=2.0f // Sprint RequiredHealthPercentForSprintNormal=0.7f RequiredHealthPercentForSprintHard=0.8f RequiredHealthPercentForSprintSuicidal=0.87f RequiredHealthPercentForSprintHellOnEarth=0.95f // FlameThrower TimeBetweenFlameThrower=8.0f MaxDistanceForFlameThrower=450 LowIntensityAttackScaleOfFireballInterval=1.25f // Suicide MinDistanceToSuicide=425 RequiredHealthPercentForSuicide=0.2f Name="Default__WMAIController_ZedHusk_Omega" }