rott/kf_sources/KFChar/Classes/ZombieGorefast.uc
2026-07-14 20:27:09 +07:00

370 lines
8.8 KiB
Ucode

// Zombie Monster for KF Invasion gametype
// GOREFAST.
// He's speedy, and swings with a Single enlongated arm, affording him slightly more range
class ZombieGoreFast extends ZombieGoreFastBase
abstract;
#exec OBJ LOAD FILE=PlayerSounds.uax
//----------------------------------------------------------------------------
// NOTE: All Variables are declared in the base class to eliminate hitching
//----------------------------------------------------------------------------
simulated function PostNetReceive()
{
if( !bZapped )
{
if (bRunning)
MovementAnims[0]='ZombieRun';
else MovementAnims[0]=default.MovementAnims[0];
}
}
// This zed has been taken control of. Boost its health and speed
function SetMindControlled(bool bNewMindControlled)
{
if( bNewMindControlled )
{
NumZCDHits++;
// if we hit him a couple of times, make him rage!
if( NumZCDHits > 1 )
{
if( !IsInState('RunningToMarker') )
{
GotoState('RunningToMarker');
}
else
{
NumZCDHits = 1;
if( IsInState('RunningToMarker') )
{
GotoState('');
}
}
}
else
{
if( IsInState('RunningToMarker') )
{
GotoState('');
}
}
if( bNewMindControlled != bZedUnderControl )
{
SetGroundSpeed(OriginalGroundSpeed * 1.25);
Health *= 1.25;
HealthMax *= 1.25;
}
}
else
{
NumZCDHits=0;
}
bZedUnderControl = bNewMindControlled;
}
// Handle the zed being commanded to move to a new location
function GivenNewMarker()
{
if( bRunning && NumZCDHits > 1 )
{
GotoState('RunningToMarker');
}
else
{
GotoState('');
}
}
function RangedAttack(Actor A)
{
Super.RangedAttack(A);
if( !bShotAnim && !bDecapitated && VSize(A.Location-Location)<=700 )
GoToState('RunningState');
}
state RunningState
{
// Set the zed to the zapped behavior
simulated function SetZappedBehavior()
{
Global.SetZappedBehavior();
GoToState('');
}
// Don't override speed in this state
function bool CanSpeedAdjust()
{
return false;
}
function BeginState()
{
if( bZapped )
{
GoToState('');
}
else
{
SetGroundSpeed(OriginalGroundSpeed * 1.875);
bRunning = true;
if( Level.NetMode!=NM_DedicatedServer )
PostNetReceive();
NetUpdateTime = Level.TimeSeconds - 1;
}
}
function EndState()
{
if( !bZapped )
{
SetGroundSpeed(GetOriginalGroundSpeed());
}
bRunning = False;
if( Level.NetMode!=NM_DedicatedServer )
PostNetReceive();
RunAttackTimeout=0;
NetUpdateTime = Level.TimeSeconds - 1;
}
function RemoveHead()
{
GoToState('');
Global.RemoveHead();
}
function RangedAttack(Actor A)
{
local float ChargeChance;
// Decide what chance the gorefast has of charging during an attack
if( Level.Game.GameDifficulty < 2.0 )
{
ChargeChance = 0.1;
}
else if( Level.Game.GameDifficulty < 4.0 )
{
ChargeChance = 0.2;
}
else if( Level.Game.GameDifficulty < 5.0 )
{
ChargeChance = 0.3;
}
else // Hardest difficulty
{
ChargeChance = 0.4;
}
if ( bShotAnim || Physics == PHYS_Swimming)
return;
else if ( CanAttack(A) )
{
bShotAnim = true;
// Randomly do a moving attack so the player can't kite the zed
if( FRand() < ChargeChance )
{
SetAnimAction('ClawAndMove');
RunAttackTimeout = GetAnimDuration('GoreAttack1', 1.0);
}
else
{
SetAnimAction('Claw');
Controller.bPreparingMove = true;
Acceleration = vect(0,0,0);
// Once we attack stop running
GoToState('');
}
return;
}
}
simulated function Tick(float DeltaTime)
{
// Keep moving toward the target until the timer runs out (anim finishes)
if( RunAttackTimeout > 0 )
{
RunAttackTimeout -= DeltaTime;
if( RunAttackTimeout <= 0 && !bZedUnderControl )
{
RunAttackTimeout = 0;
GoToState('');
}
}
// Keep the gorefast moving toward its target when attacking
if( Role == ROLE_Authority && bShotAnim && !bWaitForAnim )
{
if( LookTarget!=None )
{
Acceleration = AccelRate * Normal(LookTarget.Location - Location);
}
}
global.Tick(DeltaTime);
}
Begin:
GoTo('CheckCharge');
CheckCharge:
if( Controller!=None && Controller.Target!=None && VSize(Controller.Target.Location-Location)<700 )
{
Sleep(0.5+ FRand() * 0.5);
//log("Still charging");
GoTo('CheckCharge');
}
else
{
//log("Done charging");
GoToState('');
}
}
// State where the zed is charging to a marked location.
state RunningToMarker extends RunningState
{
simulated function Tick(float DeltaTime)
{
// Keep moving toward the target until the timer runs out (anim finishes)
if( RunAttackTimeout > 0 )
{
RunAttackTimeout -= DeltaTime;
if( RunAttackTimeout <= 0 && !bZedUnderControl )
{
RunAttackTimeout = 0;
GoToState('');
}
}
// Keep the gorefast moving toward its target when attacking
if( Role == ROLE_Authority && bShotAnim && !bWaitForAnim )
{
if( LookTarget!=None )
{
Acceleration = AccelRate * Normal(LookTarget.Location - Location);
}
}
global.Tick(DeltaTime);
}
Begin:
GoTo('CheckCharge');
CheckCharge:
if( bZedUnderControl || (Controller!=None && Controller.Target!=None && VSize(Controller.Target.Location-Location)<700) )
{
Sleep(0.5+ FRand() * 0.5);
GoTo('CheckCharge');
}
else
{
GoToState('');
}
}
// Overridden to handle playing upper body only attacks when moving
simulated event SetAnimAction(name NewAction)
{
local int meleeAnimIndex;
local bool bWantsToAttackAndMove;
if( NewAction=='' )
Return;
bWantsToAttackAndMove = NewAction == 'ClawAndMove';
if( NewAction == 'Claw' )
{
meleeAnimIndex = Rand(3);
NewAction = meleeAnims[meleeAnimIndex];
CurrentDamtype = ZombieDamType[meleeAnimIndex];
}
if( bWantsToAttackAndMove )
{
ExpectingChannel = AttackAndMoveDoAnimAction(NewAction);
}
else
{
ExpectingChannel = DoAnimAction(NewAction);
}
if( !bWantsToAttackAndMove && AnimNeedsWait(NewAction) )
{
bWaitForAnim = true;
}
else
{
bWaitForAnim = false;
}
if( Level.NetMode!=NM_Client )
{
AnimAction = NewAction;
bResetAnimAct = True;
ResetAnimActTime = Level.TimeSeconds+0.3;
}
}
// Handle playing the anim action on the upper body only if we're attacking and moving
simulated function int AttackAndMoveDoAnimAction( name AnimName )
{
local int meleeAnimIndex;
if( AnimName == 'ClawAndMove' )
{
meleeAnimIndex = Rand(3);
AnimName = meleeAnims[meleeAnimIndex];
CurrentDamtype = ZombieDamType[meleeAnimIndex];
}
if( AnimName=='GoreAttack1' || AnimName=='GoreAttack2' )
{
AnimBlendParams(1, 1.0, 0.0,, FireRootBone);
PlayAnim(AnimName,, 0.1, 1);
return 1;
}
return super.DoAnimAction( AnimName );
}
simulated function HideBone(name boneName)
{
// Gorefast does not have a left arm and does not need it to be hidden
if (boneName != LeftFArmBone)
{
super.HideBone(boneName);
}
}
static simulated function PreCacheMaterials(LevelInfo myLevel)
{//should be derived and used.
myLevel.AddPrecacheMaterial(Combiner'KF_Specimens_Trip_T.gorefast_cmb');
myLevel.AddPrecacheMaterial(Combiner'KF_Specimens_Trip_T.gorefast_env_cmb');
myLevel.AddPrecacheMaterial(Texture'KF_Specimens_Trip_T.gorefast_diff');
}
defaultproperties
{
//-------------------------------------------------------------------------------
// NOTE: Most Default Properties are set in the base class to eliminate hitching
//-------------------------------------------------------------------------------
EventClasses(0)="KFChar.ZombieGorefast_STANDARD"
ControllerClass=Class'KFChar.GorefastController'
// The gorefasts left arm is already set to gibbed so that shooting his nub will not create severed limbs
bLeftArmGibbed=true
}