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, 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, optional int HitIndex) { local bool bIsHeadShot; bIsHeadShot = IsHeadShot(Hitlocation, normal(Momentum), 1.0); if ( Level.Game.GameDifficulty >= 5.0 && bIsHeadshot && (class(damageType) != none || class(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) { 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) }