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

410 lines
12 KiB
Ucode

class ZombieScrakeOS extends KFMonsterOS;
var bool bCharging;
var float DistBeforeSaw;
var bool bEnableOldScrakeBehavior;
replication
{
reliable if(Role == ROLE_Authority)
bCharging;
}
simulated function PostNetBeginPlay()
{
EnableChannelNotify ( 1,1);
AnimBlendParams(1, 1.0, 0.0,, SpineBone1);
super.PostNetBeginPlay();
}
simulated function PostNetReceive()
{
if (bCharging)
MovementAnims[0]='ZombieRun';
else if( !(bCrispified && bBurnified) )
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('ChargeToMarker') )
{
GotoState('ChargeToMarker');
}
else
{
NumZCDHits = 1;
if( IsInState('ChargeToMarker') )
{
GotoState('');
}
}
}
else
{
if( IsInState('ChargeToMarker') )
{
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( bCharging && NumZCDHits > 1 )
{
GotoState('ChargeToMarker');
}
else
{
GotoState('');
}
}
simulated function SetBurningBehavior()
{
if( Role == Role_Authority && IsInState('RunningState') )
{
super.SetBurningBehavior();
GotoState('');
}
super.SetBurningBehavior();
}
function RangedAttack(Actor A)
{
local float Dist;
Dist = VSize(A.Location - Location);
if ( bShotAnim || Physics == PHYS_Swimming)
return;
else if ( Dist < (MeleeRange - DistBeforeSaw + CollisionRadius + A.CollisionRadius) && CanAttack(A) )
{
//Reset to default when you swing
OnlineHeadshotOffset = default.OnlineHeadshotOffset;
bShotAnim = true;
SetAnimAction(MeleeAnims[Rand(2)]);
CurrentDamType = ZombieDamType[0];
PlaySound(sound'Claw2s', SLOT_None);
GoToState('SawingLoop');
}
if(AnimAction == MeleeAnims[0])
MeleeDamage = Max( (DifficultyDamageModifer() * default.MeleeDamage * 0.85), 1 );
else if(AnimAction == MeleeAnims[1])
MeleeDamage = Max( (DifficultyDamageModifer() * default.MeleeDamage * 1.15), 1 );
if( !bShotAnim && !bDecapitated && !bEnableOldScrakeBehavior )
{
if ( Level.Game.GameDifficulty < 5.0 )
{
if ( float(Health)/HealthMax < 0.5 )
GoToState('RunningState');
}
else
{
if ( float(Health)/HealthMax < 0.75 )
GoToState('RunningState');
}
}
}
state RunningState
{
//Fixes slow charge for charging zeds
//Credits:NikC for forum link, aleat0r for the code
simulated function float GetOriginalGroundSpeed()
{
return 3.5 * OriginalGroundSpeed;
}
simulated function SetZappedBehavior()
{
Global.SetZappedBehavior();
GoToState('');
}
function bool CanSpeedAdjust()
{
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()
{
if( bZapped )
GoToState('');
else
{
SetGroundSpeed(OriginalGroundSpeed * 3.5);
bCharging = true;
if( Level.NetMode!=NM_DedicatedServer )
PostNetReceive();
OnlineHeadshotOffset.Z = 41;
OnlineHeadshotOffset.X = 30;
OnlineHeadshotOffset.Y = -10;
NetUpdateTime = Level.TimeSeconds - 1;
}
}
function EndState()
{
if( !bZapped )
SetGroundSpeed(GetOriginalGroundSpeed());
bCharging = false;
if( Level.NetMode!=NM_DedicatedServer )
PostNetReceive();
OnlineHeadshotOffset = default.OnlineHeadshotOffset;
}
function RemoveHead()
{
GoToState('');
Global.RemoveHead();
}
function RangedAttack(Actor A)
{
local float Dist;
Dist = VSize(A.Location - Location);
DistBeforeSaw = 20.0;
if ( bShotAnim || Physics == PHYS_Swimming)
return;
else if ( Dist < (MeleeRange - DistBeforeSaw + CollisionRadius + A.CollisionRadius) && CanAttack(A) )
{
bShotAnim = true;
if(Level.Game.GameDifficulty < 5.0)
SetAnimAction(MeleeAnims[Rand(2)]);
else
SetAnimAction(MeleeAnims[0]);
CurrentDamType = ZombieDamType[0];
GoToState('SawingLoop');
OnlineHeadshotOffset = default.OnlineHeadshotOffset;
}
}
}
state RunningToMarker extends RunningState
{
}
State SawingLoop
{
function bool CanSpeedAdjust()
{
return false;
}
function RangedAttack(Actor A)
{
if ( bShotAnim )
return;
else if ( CanAttack(A) )
{
Acceleration = vect(0,0,0);
bShotAnim = true;
MeleeDamage = default.MeleeDamage*0.6;
SetAnimAction('SawImpaleLoop');
CurrentDamType = ZombieDamType[0];
}
else GoToState('');
}
function AnimEnd( int Channel )
{
super.AnimEnd(Channel);
if( Controller!=none && Controller.Enemy!=none )
RangedAttack(Controller.Enemy);
}
function EndState()
{
MeleeDamage = Max( DifficultyDamageModifer() * default.MeleeDamage, 1 );
SetGroundSpeed(GetOriginalGroundSpeed());
bCharging = false;
if( Level.NetMode!=NM_DedicatedServer )
PostNetReceive();
}
}
function TakeDamage( int Damage, Pawn InstigatedBy, Vector Hitlocation, Vector Momentum, class<DamageType> damageType, optional int HitIndex)
{
local bool bIsHeadShot;
bIsHeadShot = IsHeadShot(Hitlocation, normal(Momentum), 1.0);
if ( Level.Game.GameDifficulty >= 5.0 && bIsHeadshot && (class<DamTypeCrossbow>(damageType) != none || class<DamTypeCrossbowHeadShot>(damageType) != none) )
{
Damage *= 0.5;
}
super.takeDamage(Damage, instigatedBy, hitLocation, momentum, damageType, HitIndex);
if ( Level.Game.GameDifficulty >= 5.0 && !IsInState('SawingLoop') && !IsInState('RunningState') && float(Health) / HealthMax < 0.75 )
RangedAttack(InstigatedBy);
}
function PlayTakeHit(vector HitLocation, int Damage, class<DamageType> DamageType)
{
super(ZombieScrake).PlayTakeHit(HitLocation,Damage,DamageType);
}
simulated function int DoAnimAction( name AnimName )
{
if( AnimName=='SawZombieAttack1' || AnimName=='SawZombieAttack2' /*|| AnimName=='SawImpaleLoop' */)
{
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( AnimNeedsWait(NewAction) )
bWaitForAnim = true;
if( Level.NetMode!=NM_Client )
{
AnimAction = NewAction;
bResetAnimAct = true;
ResetAnimActTime = Level.TimeSeconds+0.3;
}
}
simulated function bool AnimNeedsWait(name TestAnim)
{
if( TestAnim == 'SawImpaleLoop' || TestAnim == 'DoorBash' || TestAnim == 'KnockDown' )
return true;
return false;
}
simulated function SpawnGibs(Rotator HitRotation, float ChunkPerterbation)
{
super.SpawnGibs(HitRotation,ChunkPerterbation);
}
static simulated function PreCacheMaterials(LevelInfo myLevel)
{
myLevel.AddPrecacheMaterial(Texture'KFOldSchoolZeds_Textures.Scrake.ScrakeSkin');
myLevel.AddPrecacheMaterial(TexOscillator'KFOldSchoolZeds_Textures.Scrake.SawChainOSC');
myLevel.AddPrecacheMaterial(Texture'KFOldSchoolZeds_Textures.Scrake.ScrakeFrockSkin');
myLevel.AddPrecacheMaterial(Texture'KFOldSchoolZeds_Textures.Scrake.ScrakeSawSkin');
}
defaultproperties
{
MeleeAnims(0)="SawZombieAttack1"
MeleeAnims(1)="SawZombieAttack2"
MoanVoice=SoundGroup'KFOldSchoolZeds_Sounds.Scrake.Scrake_Speech'
BleedOutDuration=6.000000
bCannibal=True
ZapThreshold=1.250000
ZappedDamageMod=1.250000
bHarpoonToBodyStuns=False
DamageToMonsterScale=8.000000
ZombieFlag=3
MeleeDamage=20
damageForce=-100000
bFatAss=True
KFRagdollName="FleshPoundRag"
JumpSound=Sound'KFOldSchoolZeds_Sounds.Shared.Male_ZombieJump'
bMeleeStunImmune=True
Intelligence=BRAINS_Mammal
bUseExtendedCollision=True
ColOffset=(Z=55.000000)
ColRadius=29.000000
ColHeight=18.000000
PlayerCountHealthScale=0.500000
PoundRageBumpDamScale=0.010000
OnlineHeadshotOffset=(X=10.000000,Y=-7.000000,Z=58.000000)
OnlineHeadshotScale=1.200000
HeadHealth=650.000000
PlayerNumHeadHealthScale=0.300000
MotionDetectorThreat=3.000000
HitSound(0)=SoundGroup'KFOldSchoolZeds_Sounds.Shared.Male_ZombiePain'
DeathSound(0)=SoundGroup'KFOldSchoolZeds_Sounds.Shared.Male_ZombieDeath'
ScoringValue=75
IdleHeavyAnim="SawZombieIdle"
IdleRifleAnim="SawZombieIdle"
MeleeRange=60.000000
GroundSpeed=85.000000
WaterSpeed=75.000000
HealthMax=1000.000000
Health=1000
HeadRadius=8.000000
HeadHeight=6.000000
AmbientSoundScaling=5.000000
MenuName="Scrake 2.5"
ControllerClass=Class'KFOldSchoolZeds.ControllerScrakeOS'
MovementAnims(0)="SawZombieWalk"
MovementAnims(1)="SawZombieWalk"
MovementAnims(2)="SawZombieWalk"
MovementAnims(3)="SawZombieWalk"
WalkAnims(0)="SawZombieWalk"
WalkAnims(1)="SawZombieWalk"
WalkAnims(2)="SawZombieWalk"
WalkAnims(3)="SawZombieWalk"
IdleCrouchAnim="SawZombieIdle"
IdleWeaponAnim="SawZombieIdle"
IdleRestAnim="SawZombieIdle"
AmbientSound=Sound'KFOldSchoolZeds_Sounds.Scrake.Saw_Idle'
Mesh=SkeletalMesh'KFCharacterModelsOldSchool.SawZombie'
PrePivot=(Z=0.000000)
Skins(0)=Texture'KFOldSchoolZeds_Textures.Scrake.ScrakeSkin'
Skins(1)=TexOscillator'KFOldSchoolZeds_Textures.Scrake.SawChainOSC'
Skins(2)=Texture'KFOldSchoolZeds_Textures.Scrake.ScrakeFrockSkin'
Skins(3)=Texture'KFOldSchoolZeds_Textures.Scrake.ScrakeSawSkin'
SoundRadius=200.000000
Mass=500.000000
RotationRate=(Yaw=45000,Roll=0)
}