1714 lines
46 KiB
Ucode
1714 lines
46 KiB
Ucode
class ZombieBossOS extends KFMonsterOS;
|
|
|
|
var BossHPNeedle CurrentNeedle;
|
|
var bool bChargingPlayer,bClientCharg,bFireAtWill,bMinigunning,bIsBossView;
|
|
var float RageStartTime,LastChainGunTime,LastMissileTime,LastSneakedTime;
|
|
var bool bClientMiniGunning;
|
|
var name ChargingAnim;
|
|
var byte SyringeCount,ClientSyrCount;
|
|
var int MGFireCounter;
|
|
|
|
var vector TraceHitPos;
|
|
var Emitter mTracer,mMuzzleFlash;
|
|
var bool bClientCloaked;
|
|
var float LastCheckTimes;
|
|
var int HealingLevels[3],HealingAmount;
|
|
var float MGFireDuration;
|
|
var float MGLostSightTimeout;
|
|
var() float MGDamage;
|
|
var() float ClawMeleeDamageRange;
|
|
var() float ImpaleMeleeDamageRange;
|
|
var float LastChargeTime;
|
|
var float LastForceChargeTime;
|
|
var int NumChargeAttacks;
|
|
var float ChargeDamage;
|
|
var float LastDamageTime;
|
|
var float SneakStartTime;
|
|
var int SneakCount;
|
|
var() float PipeBombDamageScale;
|
|
|
|
replication
|
|
{
|
|
reliable if( Role==ROLE_Authority )
|
|
bChargingPlayer,SyringeCount,TraceHitPos,bMinigunning,bIsBossView;
|
|
}
|
|
|
|
simulated function CalcAmbientRelevancyScale()
|
|
{
|
|
CustomAmbientRelevancyScale = 5000/(100 * SoundRadius);
|
|
}
|
|
|
|
function vector ComputeTrajectoryByTime( vector StartPosition, vector EndPosition, float fTimeEnd )
|
|
{
|
|
local vector NewVelocity;
|
|
|
|
NewVelocity = super.ComputeTrajectoryByTime( StartPosition, EndPosition, fTimeEnd );
|
|
|
|
if( PhysicsVolume.IsA( 'KFPhysicsVolume' ) && StartPosition.Z < EndPosition.Z )
|
|
{
|
|
if( PhysicsVolume.Gravity.Z < class'PhysicsVolume'.default.Gravity.Z )
|
|
{
|
|
if( Mass > 900 )
|
|
{
|
|
NewVelocity.Z += 90;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NewVelocity;
|
|
}
|
|
|
|
function ZombieMoan()
|
|
{
|
|
if( !bShotAnim )
|
|
super.ZombieMoan();
|
|
}
|
|
|
|
simulated function SetBurningBehavior(){}
|
|
simulated function UnSetBurningBehavior(){}
|
|
|
|
function bool CanGetOutOfWay()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
simulated function Tick(float DeltaTime)
|
|
{
|
|
local KFHumanPawn HP;
|
|
|
|
super.Tick(DeltaTime);
|
|
|
|
if( Role == ROLE_Authority )
|
|
{
|
|
PipeBombDamageScale -= DeltaTime * 0.33;
|
|
|
|
if( PipeBombDamageScale < 0 )
|
|
{
|
|
PipeBombDamageScale = 0;
|
|
}
|
|
}
|
|
|
|
if( Level.NetMode==NM_DedicatedServer )
|
|
return;
|
|
|
|
bSpecialCalcView = bIsBossView;
|
|
|
|
if( bZapped )
|
|
{
|
|
LastCheckTimes = Level.TimeSeconds;
|
|
}
|
|
else if( bCloaked && Level.TimeSeconds>LastCheckTimes )
|
|
{
|
|
LastCheckTimes = Level.TimeSeconds+0.8;
|
|
|
|
ForEach VisibleCollidingActors(class'KFHumanPawn',HP,1000,Location)
|
|
{
|
|
if( HP.Health <= 0 || !HP.ShowStalkers() )
|
|
continue;
|
|
|
|
if( !bSpotted )
|
|
{
|
|
bSpotted = true;
|
|
CloakBoss();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if( bSpotted )
|
|
{
|
|
bSpotted = false;
|
|
bUnlit = false;
|
|
CloakBoss();
|
|
}
|
|
}
|
|
}
|
|
|
|
simulated function CloakBoss()
|
|
{
|
|
local Controller C;
|
|
local int Index;
|
|
|
|
if( bZapped )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( bSpotted )
|
|
{
|
|
Visibility = 120;
|
|
if( Level.NetMode==NM_DedicatedServer )
|
|
return;
|
|
Skins[0] = Finalblend'KFOldSchoolZeds_Textures.Patriarch.BossGlowFB';
|
|
Skins[1] = Finalblend'KFOldSchoolZeds_Textures.Patriarch.BossGlowFB';
|
|
Skins[2] = Finalblend'KFOldSchoolZeds_Textures.Patriarch.BossGlowFB';
|
|
Skins[3] = Finalblend'KFOldSchoolZeds_Textures.Patriarch.BossGlowFB';
|
|
Skins[4] = Finalblend'KFOldSchoolZeds_Textures.Patriarch.BossGlowFB';
|
|
Skins[5] = Finalblend'KFOldSchoolZeds_Textures.Patriarch.BossGlowFB';
|
|
Skins[6] = Finalblend'KFOldSchoolZeds_Textures.Patriarch.BossGlowFB';
|
|
bUnlit = true;
|
|
return;
|
|
}
|
|
|
|
Visibility = 1;
|
|
bCloaked = true;
|
|
|
|
if( Level.NetMode!=NM_Client )
|
|
{
|
|
For( C=Level.ControllerList; C!=none; C=C.NextController )
|
|
{
|
|
if( C.bIsPlayer && C.Enemy==self )
|
|
C.Enemy = none;
|
|
}
|
|
}
|
|
|
|
if( Level.NetMode==NM_DedicatedServer )
|
|
return;
|
|
|
|
Skins[0] = Shader'KFOldSchoolZeds_Textures.BossCloakShader';
|
|
Skins[1] = Shader'KFOldSchoolZeds_Textures.BossCloakShader';
|
|
Skins[2] = Shader'KFOldSchoolZeds_Textures.BossCloakShader';
|
|
Skins[3] = Shader'KFOldSchoolZeds_Textures.BossCloakShader';
|
|
Skins[4] = Shader'KFOldSchoolZeds_Textures.BossCloakShader';
|
|
Skins[5] = Shader'KFOldSchoolZeds_Textures.BossCloakShader';
|
|
Skins[6] = Texture'KillingFloorLabTextures.LabCommon.voidtex';
|
|
|
|
if(PlayerShadow != none)
|
|
PlayerShadow.bShadowActive = false;
|
|
|
|
Projectors.Remove(0, Projectors.Length);
|
|
bAcceptsProjectors = false;
|
|
|
|
SetOverlayMaterial(FinalBlend'KFOldSchoolZeds_Textures.Patriarch.BossCloakFizzleFB', 1.0, true);
|
|
|
|
if ( FRand() < 0.10 )
|
|
{
|
|
Index = Rand(Level.Game.NumPlayers);
|
|
|
|
for ( C = Level.ControllerList; C != none; C = C.NextController )
|
|
{
|
|
if ( PlayerController(C) != none )
|
|
{
|
|
if ( Index == 0 )
|
|
{
|
|
PlayerController(C).Speech('AUTO', 8, "");
|
|
break;
|
|
}
|
|
|
|
Index--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
simulated function UnCloakBoss()
|
|
{
|
|
if( bZapped )
|
|
{
|
|
return;
|
|
}
|
|
|
|
Visibility = default.Visibility;
|
|
bCloaked = false;
|
|
bSpotted = false;
|
|
bUnlit = false;
|
|
|
|
if( Level.NetMode==NM_DedicatedServer )
|
|
return;
|
|
|
|
Skins = default.Skins;
|
|
|
|
if (PlayerShadow != none)
|
|
PlayerShadow.bShadowActive = true;
|
|
|
|
bAcceptsProjectors = true;
|
|
SetOverlayMaterial( none, 0.0, true );
|
|
}
|
|
|
|
simulated function SetZappedBehavior()
|
|
{
|
|
super.SetZappedBehavior();
|
|
|
|
if( Level.Netmode != NM_DedicatedServer )
|
|
{
|
|
bUnlit = false;
|
|
Skins = default.Skins;
|
|
|
|
if (PlayerShadow != none)
|
|
PlayerShadow.bShadowActive = true;
|
|
|
|
bAcceptsProjectors = true;
|
|
SetOverlayMaterial(Material'KFZED_FX_T.Energy.ZED_overlay_Hit_Shdr', 999, true);
|
|
}
|
|
}
|
|
|
|
simulated function UnSetZappedBehavior()
|
|
{
|
|
super.UnSetZappedBehavior();
|
|
|
|
if( Level.Netmode != NM_DedicatedServer )
|
|
{
|
|
LastCheckTimes = Level.TimeSeconds;
|
|
SetOverlayMaterial(none, 0.0f, true);
|
|
}
|
|
}
|
|
|
|
function SetZapped(float ZapAmount, Pawn Instigator)
|
|
{
|
|
LastZapTime = Level.TimeSeconds;
|
|
|
|
if( bZapped )
|
|
{
|
|
TotalZap = ZapThreshold;
|
|
RemainingZap = ZapDuration;
|
|
}
|
|
else
|
|
{
|
|
TotalZap += ZapAmount;
|
|
|
|
if( TotalZap >= ZapThreshold )
|
|
{
|
|
RemainingZap = ZapDuration;
|
|
bZapped = true;
|
|
}
|
|
}
|
|
ZappedBy = Instigator;
|
|
}
|
|
|
|
simulated function PostBeginPlay()
|
|
{
|
|
super.PostBeginPlay();
|
|
|
|
if( Role < ROLE_Authority )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (Level.Game != none)
|
|
{
|
|
if( Level.Game.NumPlayers == 1 )
|
|
{
|
|
if( Level.Game.GameDifficulty < 2.0 )
|
|
{
|
|
MGDamage = default.MGDamage * 0.375;
|
|
}
|
|
else if( Level.Game.GameDifficulty < 4.0 )
|
|
{
|
|
MGDamage = default.MGDamage * 0.75;
|
|
}
|
|
else if( Level.Game.GameDifficulty < 5.0 )
|
|
{
|
|
MGDamage = default.MGDamage * 1.15;
|
|
}
|
|
else
|
|
{
|
|
MGDamage = default.MGDamage * 1.3;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( Level.Game.GameDifficulty < 2.0 )
|
|
{
|
|
MGDamage = default.MGDamage * 0.375;
|
|
}
|
|
else if( Level.Game.GameDifficulty < 4.0 )
|
|
{
|
|
MGDamage = default.MGDamage * 1.0;
|
|
}
|
|
else if( Level.Game.GameDifficulty < 5.0 )
|
|
{
|
|
MGDamage = default.MGDamage * 1.15;
|
|
}
|
|
else
|
|
{
|
|
MGDamage = default.MGDamage * 1.3;
|
|
}
|
|
}
|
|
}
|
|
|
|
HealingLevels[0] = Health/1.25;
|
|
HealingLevels[1] = Health/2.f;
|
|
HealingLevels[2] = Health/3.2;
|
|
|
|
HealingAmount = Health/4;
|
|
}
|
|
|
|
function bool MakeGrandEntry()
|
|
{
|
|
bShotAnim = true;
|
|
Acceleration = vect(0,0,0);
|
|
SetAnimAction('Entrance');
|
|
HandleWaitForAnim('Entrance');
|
|
GotoState('MakingEntrance');
|
|
|
|
return true;
|
|
}
|
|
|
|
state MakingEntrance
|
|
{
|
|
Ignores RangedAttack;
|
|
|
|
function Tick( float Delta )
|
|
{
|
|
Acceleration = vect(0,0,0);
|
|
|
|
global.Tick(Delta);
|
|
}
|
|
|
|
Begin:
|
|
Sleep(GetAnimDuration('Entrance'));
|
|
GotoState('InitialSneak');
|
|
}
|
|
|
|
simulated function Destroyed()
|
|
{
|
|
if( mTracer!=none )
|
|
mTracer.Destroy();
|
|
if( mMuzzleFlash!=none )
|
|
mMuzzleFlash.Destroy();
|
|
super.Destroyed();
|
|
}
|
|
|
|
simulated Function PostNetBeginPlay()
|
|
{
|
|
EnableChannelNotify ( 1,1);
|
|
AnimBlendParams(1, 1.0, 0.0,, 'Bip01 Spine1');
|
|
super.PostNetBeginPlay();
|
|
TraceHitPos = vect(0,0,0);
|
|
bNetNotify = true;
|
|
}
|
|
|
|
function PlayTakeHit(vector HitLocation, int Damage, class<DamageType> DamageType)
|
|
{
|
|
if( Level.TimeSeconds - LastPainAnim < MinTimeBetweenPainAnims )
|
|
return;
|
|
|
|
if( Damage>=150 || (DamageType.name=='DamTypeStunNade' && rand(5)>3) || (DamageType.name=='DamTypeCrossbowHeadshot' && Damage>=200) )
|
|
PlayDirectionalHit(HitLocation);
|
|
|
|
LastPainAnim = Level.TimeSeconds;
|
|
|
|
if( Level.TimeSeconds - LastPainSound < MinTimeBetweenPainSounds )
|
|
return;
|
|
|
|
LastPainSound = Level.TimeSeconds;
|
|
PlaySound(HitSound[0], SLOT_Pain,2*TransientSoundVolume,,400);
|
|
}
|
|
|
|
function bool OnlyEnemyAround( Pawn Other )
|
|
{
|
|
local Controller C;
|
|
|
|
For( C=Level.ControllerList; C!=none; C=C.NextController )
|
|
{
|
|
if( C.bIsPlayer && C.Pawn!=none && C.Pawn!=Other && ((VSize(C.Pawn.Location-Location)<1500 && FastTrace(C.Pawn.Location,Location))
|
|
|| (VSize(C.Pawn.Location-Other.Location)<1000 && FastTrace(C.Pawn.Location,Other.Location))) )
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function bool IsCloseEnuf( Actor A )
|
|
{
|
|
local vector V;
|
|
|
|
if( A==none )
|
|
return false;
|
|
V = A.Location-Location;
|
|
if( Abs(V.Z)>(CollisionHeight+A.CollisionHeight) )
|
|
return false;
|
|
V.Z = 0;
|
|
return (VSize(V)<(CollisionRadius+A.CollisionRadius+25));
|
|
}
|
|
|
|
function RangedAttack(Actor A)
|
|
{
|
|
local float D;
|
|
local bool bOnlyE;
|
|
local bool bDesireChainGun;
|
|
|
|
if( Controller.LineOfSightTo(A) && FRand() < 0.15 && LastChainGunTime<Level.TimeSeconds )
|
|
{
|
|
bDesireChainGun = true;
|
|
}
|
|
|
|
if ( bShotAnim )
|
|
return;
|
|
|
|
D = VSize(A.Location-Location);
|
|
bOnlyE = (Pawn(A)!=none && OnlyEnemyAround(Pawn(A)));
|
|
|
|
if ( IsCloseEnuf(A) )
|
|
{
|
|
bShotAnim = true;
|
|
if( Health>1500 && Pawn(A)!=none && FRand() < 0.5 )
|
|
{
|
|
SetAnimAction('MeleeImpale');
|
|
}
|
|
else
|
|
{
|
|
SetAnimAction('MeleeClaw');
|
|
PlaySound(sound'Claw2s', SLOT_None);
|
|
}
|
|
}
|
|
else if( Level.TimeSeconds - LastSneakedTime > 20.0 )
|
|
{
|
|
if( FRand() < 0.3 )
|
|
{
|
|
LastSneakedTime = Level.TimeSeconds;
|
|
return;
|
|
}
|
|
SetAnimAction('BossHitF');
|
|
GoToState('SneakAround');
|
|
}
|
|
else if( bChargingPlayer && (bOnlyE || D<200) )
|
|
return;
|
|
else if( !bDesireChainGun && !bChargingPlayer && (D<300 || (D<700 && bOnlyE)) &&
|
|
(Level.TimeSeconds - LastChargeTime > (5.0 + 5.0 * FRand())) )
|
|
{
|
|
SetAnimAction('BossHitF');
|
|
GoToState('Charging');
|
|
}
|
|
else if( LastMissileTime<Level.TimeSeconds && D > 500 )
|
|
{
|
|
if( !Controller.LineOfSightTo(A) || FRand() > 0.75 )
|
|
{
|
|
LastMissileTime = Level.TimeSeconds+FRand() * 5;
|
|
return;
|
|
}
|
|
|
|
LastMissileTime = Level.TimeSeconds + 10 + FRand() * 15;
|
|
|
|
bShotAnim = true;
|
|
Acceleration = vect(0,0,0);
|
|
SetAnimAction('PreFireMG');
|
|
|
|
HandleWaitForAnim('PreFireMG');
|
|
|
|
GoToState('FireMissile');
|
|
}
|
|
else if ( !bWaitForAnim && !bShotAnim && LastChainGunTime<Level.TimeSeconds )
|
|
{
|
|
if ( !Controller.LineOfSightTo(A) || FRand()> 0.85 )
|
|
{
|
|
LastChainGunTime = Level.TimeSeconds+FRand()*4;
|
|
return;
|
|
}
|
|
|
|
LastChainGunTime = Level.TimeSeconds + 5 + FRand() * 10;
|
|
|
|
bShotAnim = true;
|
|
Acceleration = vect(0,0,0);
|
|
SetAnimAction('PreFireMG');
|
|
|
|
HandleWaitForAnim('PreFireMG');
|
|
MGFireCounter = Rand(60) + 35;
|
|
|
|
GoToState('FireChaingun');
|
|
}
|
|
}
|
|
|
|
event Bump(actor Other)
|
|
{
|
|
super(Monster).Bump(Other);
|
|
if( Other==none )
|
|
return;
|
|
|
|
if( Other.IsA('NetKActor') && Physics != PHYS_Falling && !bShotAnim && Abs(Other.Location.Z-Location.Z)<(CollisionHeight+Other.CollisionHeight) )
|
|
{
|
|
Controller.Target = Other;
|
|
Controller.Focus = Other;
|
|
bShotAnim = true;
|
|
Acceleration = (Other.Location-Location);
|
|
SetAnimAction('MeleeClaw');
|
|
PlaySound(sound'Claw2s', SLOT_None);
|
|
HandleWaitForAnim('MeleeClaw');
|
|
}
|
|
}
|
|
|
|
simulated function AddTraceHitFX( vector HitPos )
|
|
{
|
|
local vector Start,SpawnVel,SpawnDir;
|
|
local float hitDist;
|
|
|
|
|
|
PlaySound(sound'KFOldSchoolZeds_Sounds.MinigunFire',SLOT_Misc,2,,1400,0.9+FRand()*0.2);
|
|
Start = GetBoneCoords('tip').Origin;
|
|
if( mTracer==none )
|
|
mTracer = Spawn(class'KFMod.KFNewTracer',,,Start);
|
|
else mTracer.SetLocation(Start);
|
|
if( mMuzzleFlash==none )
|
|
{
|
|
mMuzzleFlash = Spawn(class'NewMinigunMFlashOS');
|
|
AttachToBone(mMuzzleFlash, 'tip');
|
|
}
|
|
else mMuzzleFlash.SpawnParticle(1);
|
|
hitDist = VSize(HitPos - Start) - 50.f;
|
|
|
|
if( hitDist>10 )
|
|
{
|
|
SpawnDir = Normal(HitPos - Start);
|
|
SpawnVel = SpawnDir * 10000.f;
|
|
mTracer.Emitters[0].StartVelocityRange.X.Min = SpawnVel.X;
|
|
mTracer.Emitters[0].StartVelocityRange.X.Max = SpawnVel.X;
|
|
mTracer.Emitters[0].StartVelocityRange.Y.Min = SpawnVel.Y;
|
|
mTracer.Emitters[0].StartVelocityRange.Y.Max = SpawnVel.Y;
|
|
mTracer.Emitters[0].StartVelocityRange.Z.Min = SpawnVel.Z;
|
|
mTracer.Emitters[0].StartVelocityRange.Z.Max = SpawnVel.Z;
|
|
mTracer.Emitters[0].LifetimeRange.Min = hitDist / 10000.f;
|
|
mTracer.Emitters[0].LifetimeRange.Max = mTracer.Emitters[0].LifetimeRange.Min;
|
|
mTracer.SpawnParticle(1);
|
|
}
|
|
Instigator = self;
|
|
|
|
if( HitPos != vect(0,0,0) )
|
|
{
|
|
Spawn(class'ROBulletHitEffect',,, HitPos, Rotator(Normal(HitPos - Start)));
|
|
}
|
|
}
|
|
|
|
simulated function AnimEnd( int Channel )
|
|
{
|
|
local name Sequence;
|
|
local float Frame, Rate;
|
|
|
|
if( Level.NetMode==NM_Client && bMinigunning )
|
|
{
|
|
GetAnimParams( Channel, Sequence, Frame, Rate );
|
|
|
|
if( Sequence != 'PreFireMG' && Sequence != 'FireMG' )
|
|
{
|
|
super.AnimEnd(Channel);
|
|
return;
|
|
}
|
|
|
|
PlayAnim('FireMG');
|
|
bWaitForAnim = true;
|
|
bShotAnim = true;
|
|
IdleTime = Level.TimeSeconds;
|
|
}
|
|
else super.AnimEnd(Channel);
|
|
}
|
|
|
|
state FireChaingun
|
|
{
|
|
function RangedAttack(Actor A)
|
|
{
|
|
Controller.Target = A;
|
|
Controller.Focus = A;
|
|
}
|
|
|
|
function bool ShouldChargeFromDamage()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
function TakeDamage( int Damage, Pawn InstigatedBy, Vector Hitlocation, Vector Momentum, class<DamageType> damageType, optional int HitIndex)
|
|
{
|
|
local float EnemyDistSq, DamagerDistSq;
|
|
|
|
global.TakeDamage(Damage,instigatedBy,hitlocation,Momentum,damageType);
|
|
|
|
if( InstigatedBy != none )
|
|
{
|
|
DamagerDistSq = VSizeSquared(Location - InstigatedBy.Location);
|
|
|
|
if( (ChargeDamage > 200 && DamagerDistSq < (500 * 500)) || DamagerDistSq < (100 * 100) )
|
|
{
|
|
SetAnimAction('BossHitF');
|
|
GoToState('Charging');
|
|
return;
|
|
}
|
|
}
|
|
|
|
if( Controller.Enemy != none && InstigatedBy != none && InstigatedBy != Controller.Enemy )
|
|
{
|
|
EnemyDistSq = VSizeSquared(Location - Controller.Enemy.Location);
|
|
DamagerDistSq = VSizeSquared(Location - InstigatedBy.Location);
|
|
}
|
|
|
|
if( InstigatedBy != none && (DamagerDistSq < EnemyDistSq || Controller.Enemy == none) )
|
|
{
|
|
MonsterController(Controller).ChangeEnemy(InstigatedBy,Controller.CanSee(InstigatedBy));
|
|
Controller.Target = InstigatedBy;
|
|
Controller.Focus = InstigatedBy;
|
|
|
|
if( DamagerDistSq < (500 * 500) )
|
|
{
|
|
SetAnimAction('BossHitF');
|
|
GoToState('Charging');
|
|
}
|
|
}
|
|
}
|
|
|
|
function EndState()
|
|
{
|
|
TraceHitPos = vect(0,0,0);
|
|
bMinigunning = false;
|
|
|
|
AmbientSound = default.AmbientSound;
|
|
SoundVolume=default.SoundVolume;
|
|
SoundRadius=default.SoundRadius;
|
|
MGFireCounter=0;
|
|
|
|
LastChainGunTime = Level.TimeSeconds + 5 + (FRand()*10);
|
|
}
|
|
|
|
function BeginState()
|
|
{
|
|
OnlineHeadshotOffset=default.OnlineHeadshotOffset;
|
|
bFireAtWill = false;
|
|
Acceleration = vect(0,0,0);
|
|
MGLostSightTimeout = 0.0;
|
|
bMinigunning = true;
|
|
}
|
|
|
|
function AnimEnd( int Channel )
|
|
{
|
|
if( MGFireCounter <= 0 )
|
|
{
|
|
bShotAnim = true;
|
|
Acceleration = vect(0,0,0);
|
|
SetAnimAction('FireEndMG');
|
|
HandleWaitForAnim('FireEndMG');
|
|
GoToState('');
|
|
}
|
|
else
|
|
{
|
|
if ( Controller.Enemy != none )
|
|
{
|
|
if ( Controller.LineOfSightTo(Controller.Enemy) && FastTrace(GetBoneCoords('tip').Origin,Controller.Enemy.Location))
|
|
{
|
|
MGLostSightTimeout = 0.0;
|
|
Controller.Focus = Controller.Enemy;
|
|
Controller.FocalPoint = Controller.Enemy.Location;
|
|
}
|
|
else
|
|
{
|
|
MGLostSightTimeout = Level.TimeSeconds + (0.25 + FRand() * 0.35);
|
|
Controller.Focus = none;
|
|
}
|
|
|
|
Controller.Target = Controller.Enemy;
|
|
}
|
|
else
|
|
{
|
|
MGLostSightTimeout = Level.TimeSeconds + (0.25 + FRand() * 0.35);
|
|
Controller.Focus = none;
|
|
}
|
|
|
|
if( !bFireAtWill )
|
|
{
|
|
MGFireDuration = Level.TimeSeconds + (0.75 + FRand() * 0.5);
|
|
}
|
|
else if ( FRand() < 0.03 && Controller.Enemy != none && PlayerController(Controller.Enemy.Controller) != none )
|
|
{
|
|
PlayerController(Controller.Enemy.Controller).Speech('AUTO', 9, "");
|
|
}
|
|
|
|
bFireAtWill = true;
|
|
bShotAnim = true;
|
|
Acceleration = vect(0,0,0);
|
|
|
|
SetAnimAction('FireMG');
|
|
bWaitForAnim = true;
|
|
}
|
|
}
|
|
|
|
function FireMGShot()
|
|
{
|
|
local vector Start,End,HL,HN,Dir;
|
|
local rotator R;
|
|
local Actor A;
|
|
|
|
MGFireCounter--;
|
|
|
|
Start = GetBoneCoords('tip').Origin;
|
|
if( Controller.Focus!=none )
|
|
R = rotator(Controller.Focus.Location-Start);
|
|
else R = rotator(Controller.FocalPoint-Start);
|
|
if( NeedToTurnFor(R) )
|
|
R = Rotation;
|
|
|
|
Dir = Normal(vector(R)+VRand()*0.06); //*0.04
|
|
End = Start+Dir*10000;
|
|
|
|
bBlockHitPointTraces = false;
|
|
A = Trace(HL,HN,End,Start,true);
|
|
bBlockHitPointTraces = true;
|
|
|
|
if( A==none )
|
|
return;
|
|
TraceHitPos = HL;
|
|
if( Level.NetMode!=NM_DedicatedServer )
|
|
AddTraceHitFX(HL);
|
|
|
|
if( A!=Level )
|
|
{
|
|
A.TakeDamage(MGDamage+Rand(3),self,HL,Dir*500,class'DamageType');
|
|
}
|
|
}
|
|
|
|
function bool NeedToTurnFor( rotator targ )
|
|
{
|
|
local int YawErr;
|
|
|
|
targ.Yaw = DesiredRotation.Yaw & 65535;
|
|
YawErr = (targ.Yaw - (Rotation.Yaw & 65535)) & 65535;
|
|
return !((YawErr < 2000) || (YawErr > 64535));
|
|
}
|
|
|
|
Begin:
|
|
While( true )
|
|
{
|
|
Acceleration = vect(0,0,0);
|
|
|
|
if( MGLostSightTimeout > 0 && Level.TimeSeconds > MGLostSightTimeout )
|
|
{
|
|
bShotAnim = true;
|
|
Acceleration = vect(0,0,0);
|
|
SetAnimAction('FireEndMG');
|
|
HandleWaitForAnim('FireEndMG');
|
|
GoToState('');
|
|
}
|
|
|
|
if( MGFireCounter <= 0 )
|
|
{
|
|
bShotAnim = true;
|
|
Acceleration = vect(0,0,0);
|
|
SetAnimAction('FireEndMG');
|
|
HandleWaitForAnim('FireEndMG');
|
|
GoToState('');
|
|
}
|
|
|
|
if( bFireAtWill )
|
|
FireMGShot();
|
|
Sleep(0.05);
|
|
}
|
|
}
|
|
|
|
state FireMissile
|
|
{
|
|
Ignores RangedAttack;
|
|
|
|
function bool ShouldChargeFromDamage()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
function BeginState()
|
|
{
|
|
OnlineHeadshotOffset=default.OnlineHeadshotOffset;
|
|
Acceleration = vect(0,0,0);
|
|
}
|
|
|
|
function AnimEnd( int Channel )
|
|
{
|
|
local vector Start;
|
|
local Rotator R;
|
|
|
|
Start = GetBoneCoords('tip').Origin;
|
|
if ( !SavedFireProperties.bInitialized )
|
|
{
|
|
SavedFireProperties.AmmoClass = MyAmmo.class;
|
|
SavedFireProperties.ProjectileClass = MyAmmo.ProjectileClass;
|
|
SavedFireProperties.WarnTargetPct = 0.15;
|
|
SavedFireProperties.MaxRange = 10000;
|
|
SavedFireProperties.bTossed = false;
|
|
SavedFireProperties.bTrySplash = false;
|
|
SavedFireProperties.bLeadTarget = true;
|
|
SavedFireProperties.bInstantHit = true;
|
|
SavedFireProperties.bInitialized = true;
|
|
}
|
|
R = AdjustAim(SavedFireProperties,Start,100);
|
|
PlaySound(Sound'KFOldSchoolZeds_Sounds.Shared.LAWFire');
|
|
Spawn(class'BossLAWProjOS',,,Start,R);
|
|
|
|
bShotAnim = true;
|
|
Acceleration = vect(0,0,0);
|
|
SetAnimAction('FireEndMG');
|
|
HandleWaitForAnim('FireEndMG');
|
|
|
|
if ( FRand() < 0.05 && Controller.Enemy != none && PlayerController(Controller.Enemy.Controller) != none )
|
|
{
|
|
PlayerController(Controller.Enemy.Controller).Speech('AUTO', 10, "");
|
|
}
|
|
|
|
GoToState('');
|
|
}
|
|
Begin:
|
|
while ( true )
|
|
{
|
|
Acceleration = vect(0,0,0);
|
|
Sleep(0.1);
|
|
}
|
|
}
|
|
|
|
function bool MeleeDamageTarget(int hitdamage, vector pushdir)
|
|
{
|
|
if( Controller.Target!=none && Controller.Target.IsA('NetKActor') )
|
|
pushdir = Normal(Controller.Target.Location-Location)*100000;
|
|
|
|
|
|
return super.MeleeDamageTarget(hitdamage, pushdir);
|
|
}
|
|
|
|
state Charging
|
|
{
|
|
function bool CanSpeedAdjust()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
function bool ShouldChargeFromDamage()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//Dont play hit anims while charging so people don't complain about broken head hitboxes :)
|
|
function OldPlayHit(float Damage, Pawn InstigatedBy, vector HitLocation, class<DamageType> damageType, vector Momentum, optional int HitIndex){}
|
|
|
|
function BeginState()
|
|
{
|
|
bChargingPlayer = true;
|
|
if( Level.NetMode!=NM_DedicatedServer )
|
|
PostNetReceive();
|
|
|
|
NumChargeAttacks = Rand(2) + 1;
|
|
|
|
OnlineHeadshotOffset.Z=60;
|
|
OnlineHeadshotOffset.X=30;
|
|
}
|
|
|
|
function EndState()
|
|
{
|
|
SetGroundSpeed(GetOriginalGroundSpeed());
|
|
bChargingPlayer = false;
|
|
ChargeDamage = 0;
|
|
if( Level.NetMode!=NM_DedicatedServer )
|
|
PostNetReceive();
|
|
|
|
OnlineHeadshotOffset=default.OnlineHeadshotOffset;
|
|
LastChargeTime = Level.TimeSeconds;
|
|
}
|
|
|
|
function Tick( float Delta )
|
|
{
|
|
|
|
if( NumChargeAttacks <= 0 )
|
|
{
|
|
GoToState('');
|
|
}
|
|
|
|
if( Role == ROLE_Authority && bShotAnim)
|
|
{
|
|
if( bChargingPlayer )
|
|
{
|
|
bChargingPlayer = false;
|
|
if( Level.NetMode!=NM_DedicatedServer )
|
|
PostNetReceive();
|
|
}
|
|
SetGroundSpeed(OriginalGroundSpeed * 1.25);
|
|
if( LookTarget!=none )
|
|
{
|
|
Acceleration = AccelRate * Normal(LookTarget.Location - Location);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( !bChargingPlayer )
|
|
{
|
|
bChargingPlayer = true;
|
|
if( Level.NetMode!=NM_DedicatedServer )
|
|
PostNetReceive();
|
|
}
|
|
|
|
if( bZapped )
|
|
{
|
|
SetGroundSpeed(OriginalGroundSpeed * 1.5);
|
|
}
|
|
else
|
|
{
|
|
SetGroundSpeed(OriginalGroundSpeed * 2.5);
|
|
}
|
|
}
|
|
|
|
|
|
Global.Tick(Delta);
|
|
}
|
|
|
|
function bool MeleeDamageTarget(int hitdamage, vector pushdir)
|
|
{
|
|
local bool RetVal;
|
|
|
|
NumChargeAttacks--;
|
|
|
|
RetVal = Global.MeleeDamageTarget(hitdamage, pushdir*1.5);
|
|
if( RetVal )
|
|
GoToState('');
|
|
return RetVal;
|
|
}
|
|
|
|
function RangedAttack(Actor A)
|
|
{
|
|
if( VSize(A.Location-Location)>700 && Level.TimeSeconds - LastForceChargeTime > 3.0 )
|
|
GoToState('');
|
|
Global.RangedAttack(A);
|
|
}
|
|
Begin:
|
|
Sleep(6);
|
|
GoToState('');
|
|
}
|
|
|
|
function BeginHealing()
|
|
{
|
|
MonsterController(Controller).WhatToDoNext(55);
|
|
}
|
|
|
|
|
|
state Healing // Healing
|
|
{
|
|
function bool ShouldChargeFromDamage()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Begin:
|
|
Sleep(GetAnimDuration('Heal'));
|
|
GoToState('');
|
|
}
|
|
|
|
state KnockDown // Knocked
|
|
{
|
|
function bool ShouldChargeFromDamage()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Begin:
|
|
if( Health > 0 )
|
|
{
|
|
Sleep(GetAnimDuration('KnockDown'));
|
|
CloakBoss();
|
|
if( KFGameType(Level.Game).FinalSquadNum == SyringeCount )
|
|
{
|
|
KFGameType(Level.Game).AddBossBuddySquad();
|
|
}
|
|
GotoState('Escaping');
|
|
}
|
|
else
|
|
{
|
|
GotoState('');
|
|
}
|
|
}
|
|
|
|
State Escaping extends Charging // Got hurt and running away...
|
|
{
|
|
function BeginHealing()
|
|
{
|
|
bShotAnim = true;
|
|
Acceleration = vect(0,0,0);
|
|
SetAnimAction('Heal');
|
|
HandleWaitForAnim('Heal');
|
|
|
|
GoToState('Healing');
|
|
}
|
|
|
|
function RangedAttack(Actor A)
|
|
{
|
|
if ( bShotAnim )
|
|
return;
|
|
else if ( IsCloseEnuf(A) )
|
|
{
|
|
if( bCloaked )
|
|
UnCloakBoss();
|
|
bShotAnim = true;
|
|
Acceleration = vect(0,0,0);
|
|
Acceleration = (A.Location-Location);
|
|
SetAnimAction('MeleeClaw');
|
|
PlaySound(sound'Claw2s', SLOT_None);
|
|
}
|
|
}
|
|
|
|
function bool MeleeDamageTarget(int hitdamage, vector pushdir)
|
|
{
|
|
return Global.MeleeDamageTarget(hitdamage, pushdir*1.5);
|
|
}
|
|
|
|
function Tick( float Delta )
|
|
{
|
|
|
|
if( Role == ROLE_Authority && bShotAnim)
|
|
{
|
|
if( bChargingPlayer )
|
|
{
|
|
bChargingPlayer = false;
|
|
if( Level.NetMode!=NM_DedicatedServer )
|
|
PostNetReceive();
|
|
}
|
|
SetGroundSpeed(GetOriginalGroundSpeed());
|
|
}
|
|
else
|
|
{
|
|
if( !bChargingPlayer )
|
|
{
|
|
bChargingPlayer = true;
|
|
if( Level.NetMode!=NM_DedicatedServer )
|
|
PostNetReceive();
|
|
}
|
|
|
|
if( bZapped )
|
|
{
|
|
SetGroundSpeed(OriginalGroundSpeed * 1.5);
|
|
}
|
|
else
|
|
{
|
|
SetGroundSpeed(OriginalGroundSpeed * 2.5);
|
|
}
|
|
}
|
|
|
|
|
|
Global.Tick(Delta);
|
|
}
|
|
|
|
function EndState()
|
|
{
|
|
SetGroundSpeed(GetOriginalGroundSpeed());
|
|
bChargingPlayer = false;
|
|
if( Level.NetMode!=NM_DedicatedServer )
|
|
PostNetReceive();
|
|
if( bCloaked )
|
|
UnCloakBoss();
|
|
}
|
|
|
|
Begin:
|
|
While( true )
|
|
{
|
|
Sleep(0.5);
|
|
if( !bCloaked && !bShotAnim )
|
|
CloakBoss();
|
|
if( !Controller.IsInState('SyrRetreat') && !Controller.IsInState('WaitForAnim'))
|
|
Controller.GoToState('SyrRetreat');
|
|
}
|
|
}
|
|
|
|
State SneakAround extends Escaping // Attempt to sneak around.
|
|
{
|
|
function BeginHealing()
|
|
{
|
|
MonsterController(Controller).WhatToDoNext(56);
|
|
GoToState('');
|
|
}
|
|
|
|
function bool MeleeDamageTarget(int hitdamage, vector pushdir)
|
|
{
|
|
local bool RetVal;
|
|
|
|
RetVal = super.MeleeDamageTarget(hitdamage, pushdir);
|
|
|
|
GoToState('');
|
|
return RetVal;
|
|
}
|
|
|
|
function BeginState()
|
|
{
|
|
super.BeginState();
|
|
SneakStartTime = Level.TimeSeconds;
|
|
}
|
|
|
|
function EndState()
|
|
{
|
|
super.EndState();
|
|
LastSneakedTime = Level.TimeSeconds;
|
|
}
|
|
|
|
|
|
Begin:
|
|
CloakBoss();
|
|
While( true )
|
|
{
|
|
Sleep(0.5);
|
|
|
|
if( Level.TimeSeconds - SneakStartTime > 10.0 )
|
|
{
|
|
GoToState('');
|
|
}
|
|
|
|
if( !bCloaked && !bShotAnim )
|
|
CloakBoss();
|
|
if( !Controller.IsInState('ZombieHunt') && !Controller.IsInState('WaitForAnim') )
|
|
{
|
|
Controller.GoToState('ZombieHunt');
|
|
}
|
|
}
|
|
}
|
|
|
|
State InitialSneak extends SneakAround // Sneak attack the players straight off the bat.
|
|
{
|
|
Begin:
|
|
CloakBoss();
|
|
While( true )
|
|
{
|
|
Sleep(0.5);
|
|
SneakCount++;
|
|
|
|
if( SneakCount > 1000 || (Controller != none && ControllerBossOS(Controller).bAlreadyFoundEnemy) ) //BossZombieController to ControllerBossOS
|
|
{
|
|
GoToState('');
|
|
}
|
|
|
|
if( !bCloaked && !bShotAnim )
|
|
CloakBoss();
|
|
if( !Controller.IsInState('InitialHunting') && !Controller.IsInState('WaitForAnim') )
|
|
{
|
|
Controller.GoToState('InitialHunting');
|
|
}
|
|
}
|
|
}
|
|
|
|
simulated function DropNeedle()
|
|
{
|
|
if( CurrentNeedle!=none )
|
|
{
|
|
DetachFromBone(CurrentNeedle);
|
|
CurrentNeedle.SetLocation(GetBoneCoords('Bip01 R Finger0').Origin);
|
|
CurrentNeedle.DroppedNow();
|
|
CurrentNeedle = none;
|
|
}
|
|
}
|
|
simulated function NotifySyringeA()
|
|
{
|
|
if( Level.NetMode!=NM_Client )
|
|
{
|
|
if( SyringeCount<3 )
|
|
SyringeCount++;
|
|
if( Level.NetMode!=NM_DedicatedServer )
|
|
PostNetReceive();
|
|
}
|
|
if( Level.NetMode!=NM_DedicatedServer )
|
|
{
|
|
DropNeedle();
|
|
CurrentNeedle = Spawn(class'BossHPNeedle');
|
|
AttachToBone(CurrentNeedle,'Bip01 R Finger0');
|
|
}
|
|
}
|
|
function NotifySyringeB()
|
|
{
|
|
if( Level.NetMode != NM_Client )
|
|
{
|
|
Health += HealingAmount;
|
|
bHealed = true;
|
|
}
|
|
}
|
|
simulated function NotifySyringeC()
|
|
{
|
|
if( Level.NetMode!=NM_DedicatedServer && CurrentNeedle!=none )
|
|
{
|
|
CurrentNeedle.Velocity = vect(-45,300,-90) >> Rotation;
|
|
DropNeedle();
|
|
}
|
|
}
|
|
|
|
simulated function PostNetReceive()
|
|
{
|
|
if( bClientMiniGunning != bMinigunning )
|
|
{
|
|
bClientMiniGunning = bMinigunning;
|
|
if( bMinigunning )
|
|
{
|
|
IdleHeavyAnim='FireMG';
|
|
IdleRifleAnim='FireMG';
|
|
IdleCrouchAnim='FireMG';
|
|
IdleWeaponAnim='FireMG';
|
|
IdleRestAnim='FireMG';
|
|
}
|
|
else
|
|
{
|
|
IdleHeavyAnim='BossIdle';
|
|
IdleRifleAnim='BossIdle';
|
|
IdleCrouchAnim='BossIdle';
|
|
IdleWeaponAnim='BossIdle';
|
|
IdleRestAnim='BossIdle';
|
|
}
|
|
}
|
|
|
|
if( bClientCharg!=bChargingPlayer )
|
|
{
|
|
bClientCharg = bChargingPlayer;
|
|
if (bChargingPlayer)
|
|
{
|
|
MovementAnims[0] = ChargingAnim;
|
|
MovementAnims[1] = ChargingAnim;
|
|
MovementAnims[2] = ChargingAnim;
|
|
MovementAnims[3] = ChargingAnim;
|
|
}
|
|
else if( !bChargingPlayer )
|
|
{
|
|
MovementAnims[0] = default.MovementAnims[0];
|
|
MovementAnims[1] = default.MovementAnims[1];
|
|
MovementAnims[2] = default.MovementAnims[2];
|
|
MovementAnims[3] = default.MovementAnims[3];
|
|
}
|
|
}
|
|
else if( ClientSyrCount!=SyringeCount )
|
|
{
|
|
ClientSyrCount = SyringeCount;
|
|
Switch( SyringeCount )
|
|
{
|
|
Case 1:
|
|
SetBoneScale(3,0,'SyringeBoneOne');
|
|
Break;
|
|
Case 2:
|
|
SetBoneScale(3,0,'SyringeBoneOne');
|
|
SetBoneScale(4,0,'SyringeBoneTwo');
|
|
Break;
|
|
Case 3:
|
|
SetBoneScale(3,0,'SyringeBoneOne');
|
|
SetBoneScale(4,0,'SyringeBoneTwo');
|
|
SetBoneScale(5,0,'SyringeBoneThree');
|
|
Break;
|
|
default:
|
|
SetBoneScale(3,1,'SyringeBoneOne');
|
|
SetBoneScale(4,1,'SyringeBoneTwo');
|
|
SetBoneScale(5,1,'SyringeBoneThree');
|
|
Break;
|
|
}
|
|
}
|
|
else if( TraceHitPos!=vect(0,0,0) )
|
|
{
|
|
AddTraceHitFX(TraceHitPos);
|
|
TraceHitPos = vect(0,0,0);
|
|
}
|
|
else if( bClientCloaked!=bCloaked )
|
|
{
|
|
bClientCloaked = bCloaked;
|
|
bCloaked = !bCloaked;
|
|
if( bCloaked )
|
|
UnCloakBoss();
|
|
else CloakBoss();
|
|
bCloaked = bClientCloaked;
|
|
}
|
|
}
|
|
|
|
simulated function int DoAnimAction( name AnimName )
|
|
{
|
|
if(AnimName=='MeleeImpale' || AnimName=='MeleeClaw' || AnimName=='BossHitF')
|
|
{
|
|
AnimBlendParams(1, 1.0, 0.0,, 'Bip01 Spine1');
|
|
PlayAnim(AnimName,, 0.0, 1);
|
|
return 1;
|
|
}
|
|
return super.DoAnimAction(AnimName);
|
|
}
|
|
|
|
simulated event SetAnimAction(name NewAction)
|
|
{
|
|
local int meleeAnimIndex;
|
|
|
|
if( NewAction=='' )
|
|
return;
|
|
if(NewAction == 'Claw')
|
|
{
|
|
meleeAnimIndex = Rand(3);
|
|
NewAction = meleeAnims[meleeAnimIndex];
|
|
CurrentDamtype = ZombieDamType[meleeAnimIndex];
|
|
}
|
|
|
|
ExpectingChannel = DoAnimAction(NewAction);
|
|
|
|
if( Controller != none )
|
|
{
|
|
ControllerBossOS(Controller).AnimWaitChannel = ExpectingChannel;
|
|
}
|
|
|
|
if( AnimNeedsWait(NewAction) )
|
|
{
|
|
bWaitForAnim = true;
|
|
}
|
|
else
|
|
{
|
|
bWaitForAnim = false;
|
|
}
|
|
|
|
if( Level.NetMode!=NM_Client )
|
|
{
|
|
AnimAction = NewAction;
|
|
bResetAnimAct = true;
|
|
|
|
ResetAnimActTime = Level.TimeSeconds+0.3;
|
|
}
|
|
}
|
|
|
|
simulated function HandleWaitForAnim( name NewAnim )
|
|
{
|
|
local float RageAnimDur;
|
|
|
|
Controller.GoToState('WaitForAnim');
|
|
RageAnimDur = GetAnimDuration(NewAnim);
|
|
|
|
ControllerBossOS(Controller).SetWaitForAnimTimout(RageAnimDur,NewAnim); //BossZombieController to ControllerBossOS
|
|
}
|
|
|
|
simulated function bool AnimNeedsWait(name TestAnim)
|
|
{
|
|
if(TestAnim == 'FireMG' ||TestAnim == 'PreFireMG' || TestAnim == 'FireEndMG' || TestAnim == 'Heal'
|
|
|| TestAnim == 'KnockDown' || TestAnim == 'Entrance' || TestAnim == 'VictoryLaugh' )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
simulated function HandleBumpGlass()
|
|
{
|
|
}
|
|
|
|
|
|
function bool FlipOver()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
function bool ShouldChargeFromDamage()
|
|
{
|
|
if( (SyringeCount==0 && Health<HealingLevels[0]) || (SyringeCount==1 && Health<HealingLevels[1]) || (SyringeCount==2 && Health<HealingLevels[2]) )
|
|
{
|
|
return false;
|
|
}
|
|
else if( !bChargingPlayer && Level.TimeSeconds - LastForceChargeTime > (5.0 + 5.0 * FRand()) )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
function TakeDamage( int Damage, Pawn InstigatedBy, Vector Hitlocation, Vector Momentum, class<DamageType> damageType, optional int HitIndex)
|
|
{
|
|
local float DamagerDistSq;
|
|
local float UsedPipeBombDamScale;
|
|
|
|
if ( class<DamTypeCrossbow>(damageType) == none && class<DamTypeCrossbowHeadShot>(damageType) == none )
|
|
{
|
|
bOnlyDamagedByCrossbow = false;
|
|
}
|
|
|
|
if ( class<DamTypePipeBomb>(damageType) != none )
|
|
{
|
|
UsedPipeBombDamScale = FMax(0,(1.0 - PipeBombDamageScale));
|
|
|
|
PipeBombDamageScale += 0.075;
|
|
|
|
if( PipeBombDamageScale > 1.0 )
|
|
{
|
|
PipeBombDamageScale = 1.0;
|
|
}
|
|
|
|
Damage *= UsedPipeBombDamScale;
|
|
}
|
|
|
|
super.TakeDamage(Damage,instigatedBy,hitlocation,Momentum,damageType);
|
|
|
|
if( Level.TimeSeconds - LastDamageTime > 10 )
|
|
{
|
|
ChargeDamage = 0;
|
|
}
|
|
else
|
|
{
|
|
LastDamageTime = Level.TimeSeconds;
|
|
ChargeDamage += Damage;
|
|
}
|
|
|
|
if( ShouldChargeFromDamage() && ChargeDamage > 200 )
|
|
{
|
|
if( InstigatedBy != none )
|
|
{
|
|
DamagerDistSq = VSizeSquared(Location - InstigatedBy.Location);
|
|
|
|
if( DamagerDistSq < (700 * 700) )
|
|
{
|
|
SetAnimAction('BossHitF');
|
|
ChargeDamage=0;
|
|
LastForceChargeTime = Level.TimeSeconds;
|
|
GoToState('Charging');
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( Health<=0 || SyringeCount==3 || IsInState('Escaping') || IsInState('KnockDown'))
|
|
return;
|
|
|
|
if( ((SyringeCount==0 && Health<HealingLevels[0]) || (SyringeCount==1 && Health<HealingLevels[1]) || (SyringeCount==2 && Health<HealingLevels[2]) ))
|
|
{
|
|
bShotAnim = true;
|
|
Acceleration = vect(0,0,0);
|
|
SetAnimAction('KnockDown');
|
|
HandleWaitForAnim('KnockDown');
|
|
KFMonsterController(Controller).bUseFreezeHack = true;
|
|
GoToState('KnockDown');
|
|
}
|
|
}
|
|
|
|
function OldPlayHit(float Damage, Pawn InstigatedBy, vector HitLocation, class<DamageType> damageType, vector Momentum, optional int HitIndex)
|
|
{
|
|
if(LastChainGunTime<Level.TimeSeconds + 1 || LastMissileTime<Level.TimeSeconds + 1)
|
|
return;
|
|
else
|
|
super.OldPlayHit(Damage,InstigatedBy,HitLocation,damageType,Momentum,HitIndex);
|
|
}
|
|
|
|
function DoorAttack(Actor A)
|
|
{
|
|
if ( bShotAnim )
|
|
return;
|
|
else if ( A!=none )
|
|
{
|
|
Controller.Target = A;
|
|
bShotAnim = true;
|
|
Acceleration = vect(0,0,0);
|
|
SetAnimAction('PreFireMG');
|
|
HandleWaitForAnim('PreFireMG');
|
|
MGFireCounter = Rand(20);
|
|
GoToState('FireMissile');
|
|
}
|
|
}
|
|
|
|
function RemoveHead();
|
|
function PlayDirectionalHit(Vector HitLoc);
|
|
|
|
function bool SameSpeciesAs(Pawn P)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
function bool SetBossLaught()
|
|
{
|
|
local Controller C;
|
|
local string sHealthInfo;
|
|
|
|
GoToState('');
|
|
bShotAnim = true;
|
|
Acceleration = vect(0,0,0);
|
|
SetAnimAction('VictoryLaugh');
|
|
HandleWaitForAnim('VictoryLaugh');
|
|
bIsBossView = true;
|
|
bSpecialCalcView = true;
|
|
|
|
sHealthInfo = class'Utility'.static.ParseTagsStatic("^r^" $ MenuName $ "^w^'s health is ^b^" $ health $ " ^w^/ ^b^" $ HealthMax $ "^w^. Syringes used - ^b^" $ SyringeCount);
|
|
|
|
for (C = Level.ControllerList; C != none; C = C.NextController)
|
|
{
|
|
// ignore Messaging Spectators (Web Admin)
|
|
if (c.bIsPlayer && PlayerController(C) != none)
|
|
{
|
|
PlayerController(C).SetViewTarget(self);
|
|
PlayerController(C).ClientSetViewTarget(self);
|
|
PlayerController(C).ClientSetBehindView(true);
|
|
|
|
// send a cute message to loosers
|
|
PlayerController(C).teamMessage(none, sHealthInfo, 'ZombieBossOS');
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
simulated function bool SpectatorSpecialCalcView(PlayerController Viewer, out Actor ViewActor, out vector CameraLocation, out rotator CameraRotation)
|
|
{
|
|
Viewer.bBehindView = true;
|
|
ViewActor = self;
|
|
CameraRotation.Yaw = Rotation.Yaw-32768;
|
|
CameraRotation.Pitch = 0;
|
|
CameraRotation.Roll = Rotation.Roll;
|
|
CameraLocation = Location + (vect(80,0,80) >> Rotation);
|
|
return true;
|
|
}
|
|
|
|
function Died(Controller Killer, class<DamageType> damageType, vector HitLocation)
|
|
{
|
|
local Controller C;
|
|
|
|
super.Died(Killer,damageType,HitLocation);
|
|
|
|
KFGameType(Level.Game).DoBossDeath();
|
|
|
|
For( C=Level.ControllerList; C!=none; C=C.NextController )
|
|
{
|
|
if( PlayerController(C)!=none )
|
|
{
|
|
PlayerController(C).SetViewTarget(self);
|
|
PlayerController(C).ClientSetViewTarget(self);
|
|
PlayerController(C).bBehindView = true;
|
|
PlayerController(C).ClientSetBehindView(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
function ClawDamageTarget()
|
|
{
|
|
local vector PushDir;
|
|
local name Anim;
|
|
local float frame,rate;
|
|
local float UsedMeleeDamage;
|
|
local bool bDamagedSomeone;
|
|
local KFHumanPawn P;
|
|
local Actor OldTarget;
|
|
|
|
if( MeleeDamage > 1 )
|
|
{
|
|
UsedMeleeDamage = (MeleeDamage - (MeleeDamage * 0.05)) + (MeleeDamage * (FRand() * 0.1));
|
|
}
|
|
else
|
|
{
|
|
UsedMeleeDamage = MeleeDamage;
|
|
}
|
|
|
|
GetAnimParams(1, Anim,frame,rate);
|
|
|
|
if( Anim == 'MeleeImpale' )
|
|
{
|
|
MeleeRange = ImpaleMeleeDamageRange;
|
|
}
|
|
else
|
|
{
|
|
MeleeRange = ClawMeleeDamageRange;
|
|
}
|
|
|
|
if(Controller!=none && Controller.Target!=none)
|
|
PushDir = (damageForce * Normal(Controller.Target.Location - Location));
|
|
else
|
|
PushDir = damageForce * vector(Rotation);
|
|
|
|
if( Anim == 'MeleeImpale' )
|
|
{
|
|
bDamagedSomeone = MeleeDamageTarget(UsedMeleeDamage, PushDir);
|
|
}
|
|
else
|
|
{
|
|
OldTarget = Controller.Target;
|
|
|
|
foreach DynamicActors(class'KFHumanPawn', P)
|
|
{
|
|
if ( (P.Location - Location) dot PushDir > 0.0 )
|
|
{
|
|
Controller.Target = P;
|
|
bDamagedSomeone = bDamagedSomeone || MeleeDamageTarget(UsedMeleeDamage, damageForce * Normal(P.Location - Location));
|
|
}
|
|
}
|
|
|
|
Controller.Target = OldTarget;
|
|
}
|
|
|
|
MeleeRange = default.MeleeRange;
|
|
}
|
|
|
|
static simulated function PreCacheMaterials(LevelInfo myLevel)
|
|
{
|
|
myLevel.AddPrecacheMaterial(FinalBlend'KFPatch2.BossHairFB');
|
|
myLevel.AddPrecacheMaterial(FinalBlend'KFOldSchoolZeds_Textures.Patriarch.BossCloakFizzleFB');
|
|
myLevel.AddPrecacheMaterial(Finalblend'KFOldSchoolZeds_Textures.Patriarch.BossGlowFB');
|
|
myLevel.AddPrecacheMaterial(Texture'KFPatch2.BossBits');
|
|
myLevel.AddPrecacheMaterial(Texture'KFPatch2.GunPoundSkin');
|
|
myLevel.AddPrecacheMaterial(Texture'KFPatch2.BossGun');
|
|
myLevel.AddPrecacheMaterial(Texture'KillingFloorLabTextures.LabCommon.voidtex');
|
|
myLevel.AddPrecacheMaterial(Shader'KFPatch2.LaserShader');
|
|
myLevel.AddPrecacheMaterial(Shader'KFOldSchoolZeds_Textures.BossCloakShader');
|
|
}
|
|
|
|
defaultproperties
|
|
{
|
|
ChargingAnim="RunF"
|
|
HealingLevels(0)=5600
|
|
HealingLevels(1)=3500
|
|
HealingLevels(2)=2187
|
|
HealingAmount=1750
|
|
MGDamage=6.000000
|
|
ClawMeleeDamageRange=85.000000
|
|
ImpaleMeleeDamageRange=45.000000
|
|
MoanVoice=SoundGroup'KFOldSchoolZeds_Sounds.Patriarch.Patriarch_Speech'
|
|
ZapThreshold=5.000000
|
|
ZappedDamageMod=1.250000
|
|
ZapResistanceScale=1.000000
|
|
bHarpoonToHeadStuns=False
|
|
bHarpoonToBodyStuns=False
|
|
DamageToMonsterScale=5.000000
|
|
ZombieFlag=3
|
|
MeleeDamage=100
|
|
damageForce=170000
|
|
bFatAss=True
|
|
KFRagdollName="FleshPoundRag"
|
|
JumpSound=Sound'KFOldSchoolZeds_Sounds.Shared.Male_ZombieJump'
|
|
bMeleeStunImmune=True
|
|
CrispUpThreshhold=1
|
|
bCanDistanceAttackDoors=True
|
|
bUseExtendedCollision=True
|
|
ColOffset=(Z=65.000000)
|
|
ColRadius=27.000000
|
|
ColHeight=25.000000
|
|
PlayerCountHealthScale=0.750000
|
|
BurningWalkFAnims(0)="WalkF"
|
|
BurningWalkFAnims(1)="WalkF"
|
|
BurningWalkFAnims(2)="WalkF"
|
|
BurningWalkAnims(0)="WalkF"
|
|
BurningWalkAnims(1)="WalkF"
|
|
BurningWalkAnims(2)="WalkF"
|
|
OnlineHeadshotOffset=(X=2.000000,Y=-6.000000,Z=74.000000)
|
|
OnlineHeadshotScale=1.100000
|
|
MotionDetectorThreat=10.000000
|
|
bBoss=True
|
|
HitSound(0)=SoundGroup'KFOldSchoolZeds_Sounds.Patriarch.Patriarch_Pain'
|
|
DeathSound(0)=SoundGroup'KFOldSchoolZeds_Sounds.Shared.Male_ZombieDeath'
|
|
ScoringValue=500
|
|
IdleHeavyAnim="BossIdle"
|
|
IdleRifleAnim="BossIdle"
|
|
RagDeathVel=80.000000
|
|
RagDeathUpKick=100.000000
|
|
MeleeRange=10.000000
|
|
GroundSpeed=120.000000
|
|
WaterSpeed=120.000000
|
|
HealthMax=4000.000000
|
|
Health=4000
|
|
HeadRadius=8.200000
|
|
HeadHeight=8.500000
|
|
MenuName="Patriarch 2.5"
|
|
ControllerClass=Class'KFOldSchoolZeds.ControllerBossOS'
|
|
MovementAnims(0)="WalkF"
|
|
MovementAnims(1)="WalkF"
|
|
MovementAnims(2)="WalkF"
|
|
MovementAnims(3)="WalkF"
|
|
TurnLeftAnim="BossHitF"
|
|
TurnRightAnim="BossHitF"
|
|
AirAnims(0)="JumpInAir"
|
|
AirAnims(1)="JumpInAir"
|
|
AirAnims(2)="JumpInAir"
|
|
AirAnims(3)="JumpInAir"
|
|
TakeoffAnims(0)="JumpTakeOff"
|
|
TakeoffAnims(1)="JumpTakeOff"
|
|
TakeoffAnims(2)="JumpTakeOff"
|
|
TakeoffAnims(3)="JumpTakeOff"
|
|
LandAnims(0)="JumpLanded"
|
|
LandAnims(1)="JumpLanded"
|
|
LandAnims(2)="JumpLanded"
|
|
LandAnims(3)="JumpLanded"
|
|
AirStillAnim="JumpInAir"
|
|
TakeoffStillAnim="JumpTakeOff"
|
|
IdleCrouchAnim="BossIdle"
|
|
IdleWeaponAnim="BossIdle"
|
|
IdleRestAnim="BossIdle"
|
|
AmbientSound=Sound'KFOldSchoolZeds_Sounds.Shared.Male_ZombieBreath'
|
|
Mesh=SkeletalMesh'KFBossOld.Boss'
|
|
PrePivot=(Z=3.000000)
|
|
Skins(0)=FinalBlend'KFPatch2.BossHairFB'
|
|
Skins(1)=Texture'KFPatch2.BossBits'
|
|
Skins(2)=Texture'KFPatch2.GunPoundSkin'
|
|
Skins(3)=Texture'KFPatch2.BossGun'
|
|
Skins(4)=Texture'KFPatch2.BossBits'
|
|
Skins(5)=Texture'KFPatch2.BossBits'
|
|
Skins(6)=Shader'KFPatch2.LaserShader'
|
|
bNetNotify=False
|
|
Mass=1000.000000
|
|
RotationRate=(Yaw=36000,Roll=0)
|
|
}
|