class KFMonsterOS extends KFMonster hidecategories(AnimTweaks,DeRes,Force,Gib,Karma,Udamage,UnrealPawn) Abstract; #exec OBJ LOAD FILE=KFOldSchoolZeds_Textures.utx #exec OBJ LOAD FILE=KFPatch2.utx #exec OBJ LOAD FILE=KFOldSchoolZeds_Sounds.uax #exec OBJ LOAD FILE=KF_M79Snd.uax #exec OBJ LOAD FILE=KFCharacterModelsOldSchool.ukx #exec OBJ LOAD FILE=KFBossOld.ukx var KFGibOS HeadStubOS; var class HeadStubClassOS; var class MonsterHeadGibletOS; var class MonsterThighGibletOS; var class MonsterArmGibletOS; var class MonsterLegGibletOS; var class MonsterTorsoGibletOS; var class MonsterLowerTorsoGibletOS; var Vector LastBloodHitDirection; // Zed specific vars moved to their respective classes // Enabling these via casting from the mutator "works" // But it does not pass to child classes for whatever reason // (KFMonsterOS has it enabled, but zeds that spawn won't) //var bool bEnableOldHeadshotBehavior; //var bool bDisableHealthScaling; //var bool bEnableRandomSkins; // contains textures for mixed zed variants var protected array MixTexturePool; var protected array MixHairPool; var private bool bHeadSpawned; // Zeds shouldn't be doing this at all function bool CanGetOutOfWay() { return false; } // shut these, since we dont' use them simulated function SpawnSeveredGiblet(class GibClass, Vector Location, Rotator Rotation, float GibPerterbation, rotator SpawnRotation){} simulated function SpawnGibs(Rotator HitRotation, float ChunkPerterbation){} simulated function PostBeginPlay() { super.PostBeginPlay(); // N.B. this must be commented at some point! // draw some accurate heads (i hope :D) // it will be deleted on it's own if (!bHeadSpawned) { spawn(class'DebugHeadHitbox', self); bHeadSpawned = true; } SpawnClientExtendedZCollision(); } // Fix client side projectors (i.e. ebr laser dot) // NOTE: No special destroy code is needed. EZCollision is already // destroyed on any zed that has it (not role-dependent). final private function SpawnClientExtendedZCollision() { local vector AttachPos; // Auth has already created this hitbox. if (Role == ROLE_Authority) return; if (bUseExtendedCollision && MyExtCollision == none) { MyExtCollision = spawn(class'ClientExtendedZCollision', self); // Slightly smaller version for non auth clients MyExtCollision.SetCollisionSize(ColRadius * 0.9f, ColHeight * 0.9f); MyExtCollision.bHardAttach = true; AttachPos = Location + (ColOffset >> Rotation); MyExtCollision.SetLocation(AttachPos); MyExtCollision.SetPhysics(PHYS_None); MyExtCollision.SetBase(self); SavedExtCollision = MyExtCollision.bCollideActors; } } function bool FlipOver() { if( Physics==PHYS_Falling ) SetPhysics(PHYS_Walking); bShotAnim = true; SetAnimAction('KnockDown'); Acceleration = vect(0, 0, 0); Velocity.X = 0; Velocity.Y = 0; Controller.GoToState('WaitForAnim'); KFMonsterController(Controller).Focus = none; KFMonsterController(Controller).FocalPoint = KFMonsterController(Controller).LastSeenPos; KFMonsterController(Controller).bUseFreezeHack = true; return true; } simulated function DoDamageFX( Name boneName, int Damage, class DamageType, Rotator r ) { local float DismemberProbability; local bool bDidSever; local bool bExtraGib; if ( FRand() > 0.3f || Damage > 30 || Health <= 0 ) { HitFX[HitFxTicker].damtype = DamageType; if( Health <= 0 ) { switch( boneName ) { case 'Bip01 L Foot': boneName = 'Bip01 L Thigh'; break; case 'Bip01 R Foot': boneName = 'Bip01 R Thigh'; break; case 'Bip01 R Hand': boneName = 'rfarm'; break; case 'Bip01 L Hand': boneName = 'Bip01 L Forearm'; break; case 'Bip01 R Clavicle': case 'Bip01 L Clavicle': boneName = 'Bip01 Spine'; break; } if( DamageType.default.bAlwaysSevers || (Damage == 1000) ) { HitFX[HitFxTicker].bSever = true; bDidSever = true; if ( boneName == 'none' ) { boneName = 'Bip01 R Forearm'; bExtraGib = true; } } else if( (Damage*DamageType.default.GibModifier > 50+120*FRand()-9999999999) && (Damage >= 0) ) { HitFX[HitFxTicker].bSever = true; boneName = 'Bip01 R Forearm'; bExtraGib = true; } else { DismemberProbability = Abs( (Health - Damage*DamageType.default.GibModifier) / 130.0f ); switch( boneName ) { case 'Bip01 L Thigh': case 'Bip01 R Thigh': case 'Bip01 R Forearm': case 'Bip01 L Forearm': case 'Bip01 Spine': case 'Bip01 Head': if( FRand() < DismemberProbability ) HitFX[HitFxTicker].bSever = true; break; case 'Bip01 Head': boneName = 'Bip01 Head'; case 'Bip01 Head': if( FRand() < DismemberProbability * 0.3 ) { HitFX[HitFxTicker].bSever = true; if ( FRand() < 0.65 ) bExtraGib = true; } break; } } } if ( DamageType.default.bNeverSevers || class'GameInfo'.static.UseLowGore() || (Level.Game != none && Level.Game.PreventSever(self, boneName, Damage, DamageType)) ) { HitFX[HitFxTicker].bSever = false; bDidSever = false; bExtraGib = false; } HitFX[HitFxTicker].bone = boneName; HitFX[HitFxTicker].rotDir = r; HitFxTicker = HitFxTicker + 1; if( HitFxTicker > ArrayCount(HitFX)-1 ) HitFxTicker = 0; if ( bExtraGib ) { if ( FRand() < 0.25 ) { DoDamageFX('Bip01 L Forearm',1000,DamageType,r); DoDamageFX('Bip01 R Forearm',1000,DamageType,r); } else if ( FRand() < 0.35 ) DoDamageFX('Bip01 L Thigh',1000,DamageType,r); else if ( FRand() < 0.5 ) DoDamageFX('Bip01 Head',1000,DamageType,r); else DoDamageFX('Bip01 Head',1000,DamageType,r); } } } simulated function PlayDying(class DamageType, vector HitLoc) { local float frame, rate; local name seq; local LavaDeath LD; local MiscEmmiter BE; if(bDecapitated) { HideBone('bip01 head'); if (HeadStubOS == none && HeadStubClassOS != none) { HeadStubOS = Spawn(HeadStubClassOS,self); AttachToBone( HeadStubOS,'Bip01 head'); } } if (Gored>0) { if (Gored == 1) HideBone('Bip01 L Clavicle'); else if (Gored == 2) HideBone('Bip01 R Clavicle'); else if (Gored == 3) HideBone('Bip01 Spine2'); else if (Gored == 4) HideBone('Bip01 Spine1'); else if (Gored == 5) { HideBone('Bip01'); bHidden = true; } } AmbientSound = none; bCanTeleport = false; bReplicateMovement = false; bTearOff = true; bPlayedDeath = true; StopBurnFX(); if (CurrentCombo != none) CurrentCombo.Destroy(); HitDamageType = DamageType; TakeHitLocation = HitLoc; bSTUNNED = false; bMovable = true; if ( class(DamageType) != none || class(DamageType) != none ) { ZombieCrispUp(); } ProcessHitFX() ; if ( DamageType != none ) { if ( DamageType.default.bSkeletize ) { SetOverlayMaterial(DamageType.default.DamageOverlayMaterial, 4.0, true); if (!bSkeletized) { if ( (Level.NetMode != NM_DedicatedServer) && (SkeletonMesh != none) ) { if ( DamageType.default.bLeaveBodyEffect ) { BE = spawn(class'MiscEmmiter',self); if ( BE != none ) { BE.DamageType = DamageType; BE.HitLoc = HitLoc; bFrozenBody = true; } } GetAnimParams( 0, seq, frame, rate ); LinkMesh(SkeletonMesh, true); Skins.Length = 0; PlayAnim(seq, 0, 0); SetAnimFrame(frame); } if (Physics == PHYS_Walking) Velocity = Vect(0,0,0); SetTearOffMomemtum(GetTearOffMomemtum() * 0.25); bSkeletized = true; if ( (Level.NetMode != NM_DedicatedServer) && (DamageType == class'FellLava') ) { LD = spawn(class'LavaDeath', , , Location + vect(0, 0, 10), Rotation ); if ( LD != none ) LD.SetBase(self); PlaySound( sound'KFOldSchoolZeds_Sounds.BExplosion5', SLOT_None, 1.5*TransientSoundVolume ); } } } else if ( DamageType.default.DeathOverlayMaterial != none ) SetOverlayMaterial(DamageType.default.DeathOverlayMaterial, DamageType.default.DeathOverlayTime, true); else if ( (DamageType.default.DamageOverlayMaterial != none) && (Level.DetailMode != DM_Low) && !Level.bDropDetail ) SetOverlayMaterial(DamageType.default.DamageOverlayMaterial, 2*DamageType.default.DamageOverlayTime, true); } AnimBlendParams(1, 0.0); FireState = FS_None; GotoState('ZombieDyingOS'); if ( BE != none ) return; PlayDyingAnimation(DamageType, HitLoc); } State ZombieDyingDecay extends ZombieDying { ignores AnimEnd, Trigger, Bump, HitWall, HeadVolumeChange, PhysicsVolumeChange, Falling, BreathTimer, Died, RangedAttack, TakeDamage; } //Until I can fix Decay not being enabled, I'll make corpses decay & not eat bullets here State ZombieDyingOS extends Dying { ignores AnimEnd, Trigger, Bump, HitWall, HeadVolumeChange, PhysicsVolumeChange, Falling, BreathTimer, Died, RangedAttack; function bool CanGetOutOfWay() { return false; } simulated function Landed(vector HitNormal) { SetPhysics(PHYS_None); SetCollision(false, false, false); if ( !IsAnimating(0) ) LandThump(); super.Landed(HitNormal); } simulated function Timer() { if( Level.NetMode==NM_DedicatedServer ) { Destroy(); return; } if( Physics!=PHYS_None ) { if( VSize(Velocity)>10 ) { SetTimer(1,false); return; } //This just spams the clients log, get rid of it //Disable('TakeDamage'); SetPhysics(PHYS_None); SetTimer(30,false); if(PlayerShadow != none) PlayerShadow.bShadowActive = false; } else if( (Level.TimeSeconds-LastRenderTime)>40 || Level.bDropDetail ) Destroy(); else SetTimer(5,false); } simulated function BeginState() { if( Controller!=none ) Controller.Destroy(); if( Level.NetMode==NM_DedicatedServer ) SetTimer(1,false); //Don't eat bullets or block shit bBlockHitPointTraces=false; bBlockPlayers=false; bBlockProjectiles=false; SetTimer(5,false); } } simulated function ProcessHitFX() { local Coords boneCoords; local class HitEffects[4]; local int i,j; local float GibPerterbation; if( (Level.NetMode == NM_DedicatedServer) || bSkeletized || (Mesh == SkeletonMesh)) { SimHitFxTicker = HitFxTicker; return; } for ( SimHitFxTicker = SimHitFxTicker; SimHitFxTicker != HitFxTicker; SimHitFxTicker = (SimHitFxTicker + 1) % ArrayCount(HitFX) ) { j++; if ( j > 30 ) { SimHitFxTicker = HitFxTicker; return; } if( (HitFX[SimHitFxTicker].damtype == none) || (Level.bDropDetail && (Level.TimeSeconds - LastRenderTime > 3) && !IsHumanControlled()) ) continue; boneCoords = GetBoneCoords( HitFX[SimHitFxTicker].bone ); if ( !Level.bDropDetail && !class'GameInfo'.static.NoBlood() && !bSkeletized && !class'GameInfo'.static.UseLowGore()) { AttachEffect( GibGroupClass.static.GetBloodEmitClass(), HitFX[SimHitFxTicker].bone, boneCoords.Origin, HitFX[SimHitFxTicker].rotDir ); HitFX[SimHitFxTicker].damtype.static.GetHitEffects( HitEffects, Health ); if( !PhysicsVolume.bWaterVolume ) { for( i = 0; i < ArrayCount(HitEffects); i++ ) { if( HitEffects[i] == none ) continue; AttachEffect( HitEffects[i], HitFX[SimHitFxTicker].bone, boneCoords.Origin, HitFX[SimHitFxTicker].rotDir ); } } } if( HitFX[SimHitFxTicker].bSever ) { GibPerterbation = HitFX[SimHitFxTicker].damtype.default.GibPerterbation; bFlaming = HitFX[SimHitFxTicker].DamType.default.bFlaming; switch( HitFX[SimHitFxTicker].bone ) { case 'Bip01 L Thigh': case 'Bip01 R Thigh': Spawn(class'BrainSplashOS',,,boneCoords.Origin,self.Rotation); SpawnGiblet( GetGibClass(EGT_Calf), boneCoords.Origin, HitFX[SimHitFxTicker].rotDir, GibPerterbation ); SpawnGiblet( GetGibClass(EGT_Calf), boneCoords.Origin, HitFX[SimHitFxTicker].rotDir, GibPerterbation ); PlaySound(sound'KFOldSchoolZeds_Sounds.Shared.Gibbing_Sound1', SLOT_Misc,255); GibCountCalf -= 2; break; case 'Bip01 R Forearm': case 'Bip01 L Forearm': Spawn(class'BrainSplashOS',,,boneCoords.Origin,self.Rotation); SpawnGiblet( GetGibClass(EGT_UpperArm), boneCoords.Origin, HitFX[SimHitFxTicker].rotDir, GibPerterbation ); SpawnGiblet( GetGibClass(EGT_Forearm), boneCoords.Origin, HitFX[SimHitFxTicker].rotDir, GibPerterbation ); PlaySound(sound'KFOldSchoolZeds_Sounds.Shared.Gibbing_Sound2', SLOT_Misc,255); GibCountForearm--; GibCountUpperArm--; break; case 'Bip01 Head': Spawn(class'BrainSplashOS',,,boneCoords.Origin,self.Rotation); SpawnGiblet( GetGibClass(EGT_Head), boneCoords.Origin, HitFX[SimHitFxTicker].rotDir, GibPerterbation ); PlaySound(sound'KFOldSchoolZeds_Sounds.Shared.Gibbing_Sound2', SLOT_Misc,255); GibCountTorso--; break; case 'Bip01 Spine': case 'Bip01 Spine': SpawnGiblet( GetGibClass(EGT_Torso), boneCoords.Origin, HitFX[SimHitFxTicker].rotDir, GibPerterbation ); PlaySound(sound'KFOldSchoolZeds_Sounds.Shared.Gibbing_Sound3', SLOT_Misc,255); GibCountTorso--; bGibbed = true; while( GibCountHead-- > 0 ) SpawnGiblet( GetGibClass(EGT_Head), boneCoords.Origin, HitFX[SimHitFxTicker].rotDir, GibPerterbation ); while( GibCountForearm-- > 0 ) SpawnGiblet( GetGibClass(EGT_UpperArm), boneCoords.Origin, HitFX[SimHitFxTicker].rotDir, GibPerterbation ); while( GibCountUpperArm-- > 0 ) SpawnGiblet( GetGibClass(EGT_Forearm), boneCoords.Origin, HitFX[SimHitFxTicker].rotDir, GibPerterbation ); if ( !bFlaming && !Level.bDropDetail && (Level.DetailMode != DM_Low) && PlayerCanSeeMe() ) { GibPerterbation = FMin(1.0, 1.5 * GibPerterbation); PlaySound(sound'KFOldSchoolZeds_Sounds.Shared.Gibbing_Sound4', SLOT_Misc,255); SpawnGiblet( GetGibClass(EGT_Calf), boneCoords.Origin, HitFX[SimHitFxTicker].rotDir, GibPerterbation ); SpawnGiblet( GetGibClass(EGT_Calf), boneCoords.Origin, HitFX[SimHitFxTicker].rotDir, GibPerterbation ); SpawnGiblet( GetGibClass(EGT_UpperArm), boneCoords.Origin, HitFX[SimHitFxTicker].rotDir, GibPerterbation ); SpawnGiblet( GetGibClass(EGT_Forearm), boneCoords.Origin, HitFX[SimHitFxTicker].rotDir, GibPerterbation ); } break; } if (!bDecapitated) HideBone(HitFX[SimHitFxTicker].bone); } } } simulated function DecapFX( Vector DecapLocation, Rotator DecapRotation, bool bSpawnDetachedHead, optional bool bNoBrainBits ) { local float GibPerterbation; local BrainSplashOS SplatExplosion; if ( class'GameInfo'.static.UseLowGore() ) { CuteDecapFX(); return; } bNoBrainBitEmitter = bNoBrainBits; GibPerterbation = 0.060000; if(bSpawnDetachedHead) { SpecialHideHead(); } else { HideBone(HeadBone); } if ( !bSpawnDetachedHead && !bNoBrainBits && EffectIsRelevant(DecapLocation,false) ) { SpawnGiblet( class'KFGibBrainOS',DecapLocation, self.Rotation, GibPerterbation) ; SpawnGiblet( class'KFGibBrainbOS',DecapLocation, self.Rotation, GibPerterbation) ; SpawnGiblet( class'KFGibBrainOS',DecapLocation, self.Rotation, GibPerterbation) ; } SplatExplosion = Spawn(class 'BrainSplashOS',self,, DecapLocation ); } // swapped SeveredHead with HeadStubOS simulated function SpecialHideHead() { local int BoneScaleSlot; local coords boneCoords; if (HeadStubOS == none && HeadStubClassOS != none) { boneScaleSlot = 4; HeadStubOS = Spawn(HeadStubClassOS,self); boneCoords = GetBoneCoords('Bip01 Head'); AttachToBone(HeadStubOS, 'Bip01 Head'); } else { return; } SetBoneScale(BoneScaleSlot, 0.0, 'Bip01 Head'); } simulated function CuteDecapFX() { local int LeftRight; LeftRight = 1; if ( rand(10) > 5 ) { LeftRight = -1; } NeckRot.Yaw = -clamp(rand(24000), 14000, 24000); NeckRot.Roll = LeftRight * clamp(rand(8000), 2000, 8000); NeckRot.Pitch = LeftRight * clamp(rand(12000), 2000, 12000); // was 'neck' SetBoneRotation('Bip01 Neck', NeckRot); RemoveHead(); } simulated function HideBone(name boneName) { local int BoneScaleSlot; if( boneName == 'lthigh' ) boneScaleSlot = 0; else if ( boneName == 'rthigh' ) boneScaleSlot = 1; else if( boneName == 'rfarm' ) boneScaleSlot = 2; else if ( boneName == 'lfarm' ) boneScaleSlot = 3; else if ( boneName == 'head' ) boneScaleSlot = 4; else if ( boneName == 'spine' ) boneScaleSlot = 5; SetBoneScale(BoneScaleSlot, 0.0, BoneName); } simulated function Tick(float DeltaTime) { local PlayerController P; local float DistSquared; local float GibPerterbation; local BrainSplashOS SplatExplosion; local Vector SplatLocation; local Rotator R; local GibExplosionOS GibbedExplosion; if (AnimAction == 'KnockDown') { Acceleration = vect(0,0,0); Velocity = vect(0,0,0); } if( bDestroyNextTick && TimeSetDestroyNextTickTime < Level.TimeSeconds ) { Destroy(); } if ( Level.NetMode != NM_Client && CanSpeedAdjust() ) { if ( Level.NetMode == NM_Standalone ) { if ( Level.TimeSeconds - LastRenderTime > 5.0 ) { P = Level.GetLocalPlayerController(); if ( P != none && P.Pawn != none ) { if ( Level.TimeSeconds - LastViewCheckTime > 1.0 ) { LastViewCheckTime = Level.TimeSeconds; DistSquared = VSizeSquared(P.Pawn.Location - Location); if( (!P.Pawn.Region.Zone.bDistanceFog || (DistSquared < Square(P.Pawn.Region.Zone.DistanceFogEnd))) && FastTrace(Location + EyePosition(), P.Pawn.Location + P.Pawn.EyePosition()) ) { LastSeenOrRelevantTime = Level.TimeSeconds; SetGroundSpeed(GetOriginalGroundSpeed()); } else { SetGroundSpeed(default.GroundSpeed * (HiddenGroundSpeed / default.GroundSpeed)); } } } } else { LastSeenOrRelevantTime = Level.TimeSeconds; SetGroundSpeed(GetOriginalGroundSpeed()); } } else if ( Level.NetMode == NM_DedicatedServer ) { if ( Level.TimeSeconds - LastReplicateTime > 0.5 ) { SetGroundSpeed(default.GroundSpeed * (300.0 / default.GroundSpeed)); } else { LastSeenOrRelevantTime = Level.TimeSeconds; SetGroundSpeed(GetOriginalGroundSpeed()); } } else if ( Level.NetMode == NM_ListenServer ) { if ( Level.TimeSeconds - LastReplicateTime > 0.5 && Level.TimeSeconds - LastRenderTime > 5.0 ) { P = Level.GetLocalPlayerController(); if ( P != none && P.Pawn != none ) { if ( Level.TimeSeconds - LastViewCheckTime > 1.0 ) { LastViewCheckTime = Level.TimeSeconds; DistSquared = VSizeSquared(P.Pawn.Location - Location); if ( (!P.Pawn.Region.Zone.bDistanceFog || (DistSquared < Square(P.Pawn.Region.Zone.DistanceFogEnd))) && FastTrace(Location + EyePosition(), P.Pawn.Location + P.Pawn.EyePosition()) ) { LastSeenOrRelevantTime = Level.TimeSeconds; SetGroundSpeed(GetOriginalGroundSpeed()); } else { SetGroundSpeed(default.GroundSpeed * (300.0 / default.GroundSpeed)); } } } } else { LastSeenOrRelevantTime = Level.TimeSeconds; SetGroundSpeed(GetOriginalGroundSpeed()); } } } if ( bResetAnimAct && ResetAnimActTime 0 && Level.TimeSeconds - BleedOutTime >= 0 ) { Died(LastDamagedBy.Controller,class'DamTypeBleedOut',Location); BleedOutTime=0; } } if ( Level.NetMode!=NM_DedicatedServer ) { TickFX(DeltaTime); if( LookTarget!=none && Health >= 1 ) { R = Normalize(rotator(LookTarget.Location-Location)-Rotation); R.Pitch = 0; R.Roll = 0; if( R.Yaw>18000 ) R.Yaw = 18000; else if( R.Yaw<-18000 ) R.Yaw = -18000; R.Pitch = R.Yaw; R.Yaw = 0; SetBoneDirection('Bip01 Head',R*-1.8,,0.5); } else SetBoneDirection('Bip01 Head',rot(0,0,0),,0.5); if ( bBurnified && !bBurnApplied ) { if ( !bGibbed ) { StartBurnFX(); } } else if ( !bBurnified && bBurnApplied ) { StopBurnFX(); } if ( bAshen && Level.NetMode == NM_Client && !class'GameInfo'.static.UseLowGore() ) { ZombieCrispUp(); bAshen = false; } if(bDecapitated && !bPlayBrainSplash ) { SplatLocation = self.Location; SplatLocation.z += CollisionHeight; GibPerterbation = 0.060000; HideBone('bip01 head'); if (HeadStubOS == none && HeadStubClassOS != none) { HeadStubOS = Spawn(HeadStubClassOS,self,'',Location); AttachToBone( HeadStubOS,'Bip01 head'); } if ( EffectIsRelevant(Location,false) ) { SpawnGiblet( class'KFGibBrainOS',SplatLocation, self.Rotation, GibPerterbation ) ; SpawnGiblet( class'KFGibBrainbOS',SplatLocation, self.Rotation, GibPerterbation ) ; SpawnGiblet( class'KFGibBrainOS',SplatLocation, self.Rotation, GibPerterbation ) ; } SplatExplosion = Spawn(class 'BrainSplashOS',self,, SplatLocation ); bPlayBrainSplash = true; } if (Gored>0 && !bPlayGoreSplash) { SplatLocation = self.Location; SplatLocation.z += (CollisionHeight - (CollisionHeight * 0.5)); GibPerterbation = 0.060000; if (Gored == 1) HideBone('Bip01 L Clavicle'); else if (Gored == 2) HideBone('Bip01 R Clavicle'); else if (Gored == 3) { HideBone('Bip01 Spine2'); if (GoredMat != none) Skins[0] = GoredMat; } else if (Gored == 4) HideBone('Bip01 Spine1'); if ( EffectIsRelevant(Location,false) && Gored < 5 ) { Spawn(class'BrainSplashOS',,,SplatLocation,self.Rotation); SpawnGiblet( class'KFGibBrainOS',SplatLocation, self.Rotation, GibPerterbation ) ; SpawnGiblet( class'KFGibBrainbOS',SplatLocation, self.Rotation, GibPerterbation ) ; SpawnGiblet( class'KFGibBrainOS',SplatLocation, self.Rotation, GibPerterbation ) ; } else if ( EffectIsRelevant(Location,false) && Gored == 5 ) { Spawn(class'BodySplashOS',,,SplatLocation,self.Rotation); if (!bDecapitated) SpawnGiblet(MonsterHeadGibletOS,SplatLocation, self.Rotation, GibPerterbation ) ; SpawnGiblet(MonsterTorsoGibletOS,SplatLocation, self.Rotation, GibPerterbation ) ; SpawnGiblet(MonsterLowerTorsoGibletOS,SplatLocation, self.Rotation, GibPerterbation ) ; SpawnGiblet(MonsterArmGibletOS,SplatLocation, self.Rotation, GibPerterbation ) ; SpawnGiblet(MonsterArmGibletOS,SplatLocation, self.Rotation, GibPerterbation ) ; SpawnGiblet(MonsterThighGibletOS,SplatLocation, self.Rotation, GibPerterbation ) ; SpawnGiblet(MonsterThighGibletOS,SplatLocation, self.Rotation, GibPerterbation ) ; SpawnGiblet(MonsterLegGibletOS,SplatLocation, self.Rotation, GibPerterbation ) ; SpawnGiblet(MonsterLegGibletOS,SplatLocation, self.Rotation, GibPerterbation ) ; GibbedExplosion = Spawn(class'GibExplosionOS',self,, SplatLocation ); } SplatExplosion = Spawn(class 'BrainSplashOS',self,, SplatLocation ); bPlayGoreSplash = true; } } if ( DECAP ) { if ( Level.TimeSeconds > (DecapTime + 2.0) && Controller != none ) { DECAP = false; MonsterController(Controller).ExecuteWhatToDoNext(); } } if ( BileCount > 0 && NextBileTime 0 && ((Level.TimeSeconds - LastZapTime) > 0.1) ) { TotalZap -= DeltaTime; } if( bZapped != bOldZapped ) { if( bZapped ) { SetZappedBehavior(); } else { UnSetZappedBehavior(); } bOldZapped = bZapped; } if( bHarpoonStunned != bOldHarpoonStunned ) { if( bHarpoonStunned ) { SetBurningBehavior(); } else { UnSetBurningBehavior(); } bOldHarpoonStunned = bHarpoonStunned; } } //Slow rage from burn damage fix function TakeFireDamage(int Damage,pawn Instigator) { local Vector DummyHitLoc,DummyMomentum; TakeDamage(Damage, BurnInstigator, DummyHitLoc, DummyMomentum, FireDamageClass); if ( BurnDown > 0 ) { // Decrement the number of FireDamage calls left before our Zombie is extinguished :) BurnDown --; } // Melt em' :) if ( BurnDown < CrispUpThreshhold ) { ZombieCrispUp(); } if ( BurnDown == 0 ) { bBurnified = false; if( !bZapped ) { SetGroundSpeed(GetOriginalGroundSpeed()); } } } function DoorAttack(Actor A) { if ( bShotAnim || Physics == PHYS_Swimming) return; else if ( CanAttack(A) ) { bShotAnim = true; SetAnimAction('Claw'); PlaySound(sound'Claw2s', SLOT_None); return; } } function ClawDamageTarget() { local vector PushDir; local float UsedMeleeDamage; if( MeleeDamage > 1 ) { UsedMeleeDamage = (MeleeDamage - (MeleeDamage * 0.05)) + (MeleeDamage * (FRand() * 0.1)); } else { UsedMeleeDamage = MeleeDamage; } if(Controller!=none && Controller.Target!=none) PushDir = (damageForce * Normal(Controller.Target.Location - Location)); else PushDir = damageForce * vector(Rotation); if ( MeleeDamageTarget(UsedMeleeDamage, PushDir) ) PlayZombieAttackHitSound(); } function PlayZombieAttackHitSound() { local int MeleeAttackSounds; MeleeAttackSounds = rand(4); switch(MeleeAttackSounds) { case 0: PlaySound(sound'KFOldSchoolZeds_Sounds.Melee_Hit1', SLOT_Interact); break; case 1: PlaySound(sound'KFOldSchoolZeds_Sounds.Melee_Hit2', SLOT_Interact); break; case 2: PlaySound(sound'KFOldSchoolZeds_Sounds.Melee_Hit3', SLOT_Interact); break; case 3: PlaySound(sound'KFOldSchoolZeds_Sounds.Melee_Hit4', SLOT_Interact); break; } } function BodyPartRemoval(int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, class damageType) { local float Threshold; if ( Health - Damage < 0) { if( DamageType.name != 'DamTypeShotgun' && DamageType.name != 'DamTypeDBShotgun' && DamageType.name != 'DamTypeAxe') Threshold = 0.5; else Threshold = 0.25; if ((Health - Damage) < (0-(Threshold * HealthMax)) && (Health - Damage) > (0-((Threshold * 1.2) * HealthMax)) ) Gored = rand(4)+1; else if ((Health - Damage) <= (0-(1.0 * HealthMax))) { if( damageType == class 'DamTypeFrag' || damageType == class 'DamTypeLAW' || damageType == class 'DamTypeM79Grenade' || damageType == class 'DamTypeM203Grenade' || damageType == class 'DamTypePipeBomb' || damageType == class 'DamTypeSealSquealExplosion') Gored = 5; } if(Gored > 0) { if( instigatedBy!=none ) Died(instigatedBy.Controller,damageType,hitlocation); else Died(none,damageType,hitlocation); } } } function TakeDamage(int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, class damageType, optional int HitIndex ) { local bool bIsHeadshot; local KFPlayerReplicationInfo KFPRI; local float HeadShotCheckScale; LastDamagedBy = instigatedBy; LastDamagedByType = damageType; HitMomentum = VSize(momentum); LastHitLocation = hitlocation; LastMomentum = momentum; if ( KFPawn(instigatedBy) != none && instigatedBy.PlayerReplicationInfo != none ) { KFPRI = KFPlayerReplicationInfo(instigatedBy.PlayerReplicationInfo); } // Scale damage if the Zed has been zapped if( bZapped ) { Damage *= ZappedDamageMod; } // Zeds and fire dont mix. if ( class(damageType) != none && class(damageType).default.bDealBurningDamage ) { if( BurnDown<=0 || Damage > LastBurnDamage ) { // LastBurnDamage variable is storing last burn damage (unperked) received, // which will be used to make additional damage per every burn tick (second). LastBurnDamage = Damage; // FireDamageClass variable stores damage type, which started zed's burning // and will be passed to this function again every next burn tick (as damageType argument) if ( class(damageType) != none || class(damageType) != none || class(damageType) != none) { FireDamageClass = damageType; } else { FireDamageClass = class'DamTypeFlamethrower'; } } if ( class(damageType) == none ) { Damage *= 1.5; // Increase burn damage 1.5 times, except MAC10. } // BurnDown variable indicates how many ticks are remaining for zed to burn. // It is 0, when zed isn't burning (or stopped burning). // So all the code below will be executed only, if zed isn't already burning if( BurnDown<=0 ) { if( HeatAmount>4 || Damage >= 15 ) { bBurnified = true; BurnDown = 10; // Inits burn tick count to 10 SetGroundSpeed(GroundSpeed *= 0.80); // Lowers movement speed by 20% BurnInstigator = instigatedBy; SetTimer(1.0,false); // Sets timer function to be executed each second } else HeatAmount++; } } if ( !bDecapitated && class(damageType)!=none && class(damageType).default.bCheckForHeadShots ) { HeadShotCheckScale = 1.0; // Do larger headshot checks if it is a melee attach if( class(damageType) != none ) { HeadShotCheckScale *= 1.25; } bIsHeadShot = IsHeadShot(hitlocation, normal(momentum), HeadShotCheckScale); bLaserSightedEBRM14Headshotted = bIsHeadshot && M14EBRBattleRifle(instigatedBy.Weapon) != none && M14EBRBattleRifle(instigatedBy.Weapon).bLaserActive; } else { bLaserSightedEBRM14Headshotted = bLaserSightedEBRM14Headshotted && bDecapitated; } if ( KFPRI != none ) { if ( KFPRI.ClientVeteranSkill != none ) { Damage = KFPRI.ClientVeteranSkill.Static.AddDamage(KFPRI, self, KFPawn(instigatedBy), Damage, DamageType); } } if ( damageType != none && LastDamagedBy.IsPlayerPawn() && LastDamagedBy.Controller != none ) { if ( KFMonsterController(Controller) != none ) { KFMonsterController(Controller).AddKillAssistant(LastDamagedBy.Controller, FMin(Health, Damage)); } } if ( (bDecapitated || bIsHeadShot) && class(DamageType) == none && class(DamageType) == none ) { if(class(damageType)!=none) Damage = Damage * class(damageType).default.HeadShotDamageMult; if ( class(damageType) == none && KFPRI != none && KFPRI.ClientVeteranSkill != none ) { Damage = float(Damage) * KFPRI.ClientVeteranSkill.Static.GetHeadShotDamMulti(KFPRI, KFPawn(instigatedBy), DamageType); } LastDamageAmount = Damage; if( !bDecapitated ) { if( bIsHeadShot ) { // Play a sound when someone gets a headshot TODO: Put in the real sound here if( bIsHeadShot ) { PlaySound(sound'KF_EnemyGlobalSndTwo.Impact_Skull', SLOT_None,2.0,true,500); } HeadHealth -= LastDamageAmount; if( HeadHealth <= 0 || Damage > Health ) { RemoveHead(); } } // Award headshot here, not when zombie died. if( bDecapitated && Class(damageType) != none && instigatedBy != none && KFPlayerController(instigatedBy.Controller) != none ) { bLaserSightedEBRM14Headshotted = M14EBRBattleRifle(instigatedBy.Weapon) != none && M14EBRBattleRifle(instigatedBy.Weapon).bLaserActive; Class(damageType).Static.ScoredHeadshot(KFSteamStatsAndAchievements(PlayerController(instigatedBy.Controller).SteamStatsAndAchievements), self.Class, bLaserSightedEBRM14Headshotted); } } } // Client check for Gore FX BodyPartRemoval(Damage,instigatedBy,hitlocation,momentum,damageType); if( Health-Damage > 0 && DamageType!=class'DamTypeFrag' && DamageType!=class'DamTypePipeBomb' && DamageType!=class'DamTypeM79Grenade' && DamageType!=class'DamTypeM32Grenade' && DamageType!=class'DamTypeM203Grenade' && DamageType!=class'DamTypeDwarfAxe' && DamageType!=class'DamTypeSPGrenade' && DamageType!=class'DamTypeSealSquealExplosion' && DamageType!=class'DamTypeSeekerSixRocket') { Momentum = vect(0,0,0); } if(class(DamageType)!=none) // Same rules apply to zombies as players. { BileCount=7; BileInstigator = instigatedBy; LastBileDamagedByType=class(DamageType); if(NextBileTime< Level.TimeSeconds ) NextBileTime = Level.TimeSeconds+BileFrequency; } if ( KFPRI != none && Health-Damage <= 0 && KFPRI.ClientVeteranSkill != none && KFPRI.ClientVeteranSkill.static.KilledShouldExplode(KFPRI, KFPawn(instigatedBy)) ) { Super(pawn).takeDamage(Damage + 600, instigatedBy, hitLocation, momentum, damageType); HurtRadius(500, 1000, class'DamTypeFrag', 100000, Location); } else { Super(pawn).takeDamage(Damage, instigatedBy, hitLocation, momentum, damageType); } if( bIsHeadShot && Health <= 0 ) { KFGameType(Level.Game).DramaticEvent(0.03); } bBackstabbed = false; } function PlayHit(float Damage, Pawn InstigatedBy, vector HitLocation, class damageType, vector Momentum, optional int HitIdx ) { local Vector HitNormal; local Vector HitRay ; local Name HitBone; local float HitBoneDist; local PlayerController PC; local bool bShowEffects, bRecentHit; local BloodSpurtOS BloodHit; bRecentHit = Level.TimeSeconds - LastPainTime < 0.2; LastDamageAmount = Damage; if(KFMonsterController(Controller).bUseFreezeHack == false) OldPlayHit(Damage, InstigatedBy, HitLocation, DamageType,Momentum); if ( Damage <= 0 ) return; if( Health>0 && Damage>(float(default.Health)/1.5) ) FlipOver(); PC = PlayerController(Controller); bShowEffects = ( (Level.NetMode != NM_Standalone) || (Level.TimeSeconds - LastRenderTime < 2.5) || ((InstigatedBy != none) && (PlayerController(InstigatedBy.Controller) != none)) || (PC != none) ); if ( !bShowEffects ) return; if ( BurnDown > 0 && !bBurnified ) { bBurnified = true; } HitRay = vect(0,0,0); if( InstigatedBy != none ) HitRay = Normal(HitLocation-(InstigatedBy.Location+(vect(0,0,1)*InstigatedBy.EyeHeight))); if( DamageType.default.bLocationalHit ) { CalcHitLoc( HitLocation, HitRay, HitBone, HitBoneDist ); if ( bZapped && DamageType.name != 'DamTypeZEDGun' ) { PlaySound(class'ZedGunProjectile'.default.ExplosionSound,,class'ZedGunProjectile'.default.ExplosionSoundVolume); Spawn(class'ZedGunProjectile'.default.ExplosionEmitter,,,HitLocation + HitNormal*20,rotator(HitNormal)); } } else { HitLocation = Location ; HitBone = FireRootBone; HitBoneDist = 0.0f; } if( DamageType.default.bAlwaysSevers && DamageType.default.bSpecial ) HitBone = 'head'; if( InstigatedBy != none ) HitNormal = Normal( Normal(InstigatedBy.Location-HitLocation) + VRand() * 0.2 + vect(0,0,2.8) ); else HitNormal = Normal( Vect(0,0,1) + VRand() * 0.2 + vect(0,0,2.8) ); if ( DamageType.default.bCausesBlood && DamageType != class 'Burned' ) { if ( class'GameInfo'.static.UseLowGore() ) { if ( class'GameInfo'.static.NoBlood() ) BloodHit = BloodSpurtOS(Spawn( GibGroupClass.default.NoBloodHitClass,InstigatedBy,, HitLocation )); else BloodHit = BloodSpurtOS(Spawn( GibGroupClass.default.LowGoreBloodHitClass,InstigatedBy,, HitLocation )); } else BloodHit = BloodSpurtOS(Spawn(GibGroupClass.default.BloodHitClass,InstigatedBy,, HitLocation, Rotator(HitNormal))); if ( BloodHit != none ) { BloodHit.bMustShow = !bRecentHit; if ( Momentum != vect(0,0,0) ) { BloodHit.HitDir = Momentum; LastBloodHitDirection = BloodHit.HitDir; } else { if ( InstigatedBy != none ) BloodHit.HitDir = Location - InstigatedBy.Location; else BloodHit.HitDir = Location - HitLocation; BloodHit.HitDir.Z = 0; } } } if ( (DamageType.name == 'DamTypeShotgun' || DamageType.name == 'DamTypeDBShotgun' || DamageType.name == 'DamTypeFrag') && (Health < 0) && (InstigatedBy != none) && (VSize(InstigatedBy.Location - Location) < 350) ) DoDamageFX( HitBone, 800*Damage, DamageType, Rotator(HitNormal) ); else DoDamageFX( HitBone, Damage, DamageType, Rotator(HitNormal) ); if (DamageType.default.DamageOverlayMaterial != none && Damage > 0 ) SetOverlayMaterial( DamageType.default.DamageOverlayMaterial, DamageType.default.DamageOverlayTime, false ); } // added HeadStubOS simulated function Destroyed() { if (HeadStubOS != none) HeadStubOS.Destroy(); super.Destroyed(); } //todo: simplify using int i? simulated function ZombieCrispUp() { local int i; super.ZombieCrispUp(); for (i = 0; i < Skins.Length; i++) { Skins[i]=Texture'KFOldSchoolZeds_Textures.Shared.BurntZedSkin'; } } simulated function SetBurningBehavior() { if( Role == Role_Authority ) { Intelligence = BRAINS_Retarded; SetGroundSpeed(OriginalGroundSpeed * 0.8); AirSpeed *= 0.8; WaterSpeed *= 0.8; if( Controller != none ) { MonsterController(Controller).Accuracy = -5; } } } // copy-paste, just to replace the blood streak decal event KImpact(actor other, vector pos, vector impactVel, vector impactNorm) { local int numSounds, soundNum; local vector WallHit, WallNormal; local Actor WallActor; local KFBloodStreakDecalOS Streak; local float VelocitySquared; local float RagHitVolume; local float StreakDist; numSounds = RagImpactSounds.Length; if ( LastStreakLocation == vect(0,0,0) ) { StreakDist = 0; } else { StreakDist = VSizeSquared(LastStreakLocation - pos); } LastStreakLocation = pos; WallActor = Trace(WallHit, WallNormal, pos - impactNorm * 16, pos + impactNorm * 16, false); if ( WallActor != none && Level.TimeSeconds > LastStreakTime + BloodStreakInterval && !class'GameInfo'.static.UseLowGore() ) { if ( StreakDist < 1400 ) { return; } Streak = spawn(class'KFBloodStreakDecalOS',,, WallHit, rotator(-WallNormal)); LastStreakTime = Level.TimeSeconds; } if ( numSounds > 0 && Level.TimeSeconds > RagLastSoundTime + RagImpactSoundInterval ) { VelocitySquared = VSizeSquared(impactVel); RagHitVolume = FMin(2.0, (VelocitySquared / 40000)); soundNum = Rand(numSounds); PlaySound(RagImpactSounds[soundNum], SLOT_None, RagHitVolume); RagLastSoundTime = Level.TimeSeconds; } } function Died(Controller Killer, class damageType, vector HitLocation) { AmbientSound = none; super.Died( Killer, damageType, HitLocation ); } defaultproperties { HeadStubClassOS=Class'KFOldSchoolZeds.GibHeadStumpOS' MonsterHeadGibletOS=Class'KFOldSchoolZeds.ClotGibHeadOS' MonsterThighGibletOS=Class'KFOldSchoolZeds.ClotGibThighOS' MonsterArmGibletOS=Class'KFOldSchoolZeds.ClotGibArmOS' MonsterLegGibletOS=Class'KFOldSchoolZeds.ClotGibLegOS' MonsterTorsoGibletOS=Class'KFOldSchoolZeds.ClotGibTorsoOS' MonsterLowerTorsoGibletOS=Class'KFOldSchoolZeds.ClotGibLowerTorsoOS' MixTexturePool(0)=Texture'KFOldSchoolZeds_Textures.Bloat.BloatSkin' MixTexturePool(1)=Texture'KFOldSchoolZeds_Textures.clot.ClotSkin' MixTexturePool(2)=Texture'KFOldSchoolZeds_Textures.clot.ClotSkinVariant2' MixTexturePool(3)=Texture'KFOldSchoolZeds_Textures.Crawler.CrawlerSkin' MixTexturePool(4)=Texture'KFOldSchoolZeds_Textures.Fleshpound.PoundSkin' MixTexturePool(5)=Texture'KFOldSchoolZeds_Textures.GoreFast.GorefastSkin' MixTexturePool(6)=Texture'KFOldSchoolZeds_Textures.Gunpound.GunPoundSkin' MixTexturePool(7)=Texture'KFOldSchoolZeds_Textures.Patriarch.PatriarchSkin' MixTexturePool(8)=Texture'KFOldSchoolZeds_Textures.siren.SirenSkin' MixTexturePool(9)=Texture'KFOldSchoolZeds_Textures.Stalker.StalkerSkin' MixHairPool(0)=FinalBlend'KFOldSchoolZeds_Textures.Patriarch.BossHairFB' MixHairPool(1)=FinalBlend'KFOldSchoolZeds_Textures.Crawler.CrawlerHairFB' MixHairPool(2)=FinalBlend'KFOldSchoolZeds_Textures.siren.SirenHairFB' MixHairPool(3)=FinalBlend'KFOldSchoolZeds_Textures.Stalker.StalkerHairFB' MoanVolume=10.000000 RagMaxSpinAmount=1.000000 BloodStreakInterval=0.500000 MonsterHeadGiblet=None MonsterThighGiblet=None MonsterArmGiblet=None MonsterLegGiblet=None MonsterTorsoGiblet=None MonsterLowerTorsoGiblet=None ExtCollAttachBoneName="bip01 Spine" LeftShoulderBone="Bip01 L Clavicle" RightShoulderBone="Bip01 R Clavicle" LeftThighBone="Bip01 L Thigh" RightThighBone="Bip01 R Thigh" LeftFArmBone="Bip01 L Forearm" LeftFootBone="Bip01 L Foot" RightFootBone="Bip01 R Foot" LeftHandBone="bip01 l hand" RightHandBone="Bip01 R Hand" NeckBone="Bip01 Neck" ProjectileBloodSplatClass=None ObliteratedEffectClass=Class'KFOldSchoolZeds.GibExplosionOS' GibGroupClass=Class'KFOldSchoolZeds.KFNoGibGroupOS' SoundGroupClass=Class'KFOldSchoolZeds.KFMaleZombieSoundsOS' FireRootBone="bip01 Spine" DeResTime=0.000000 RagdollLifeSpan=0.000000 RagDeathVel=150.000000 RagShootStrength=6000.000000 RagSpinScale=2.500000 RagDeathUpKick=170.000000 RagGravScale=1.500000 RagImpactSounds(0)=Sound'KFOldSchoolZeds_Sounds.Shared.Breakbone_01' RagImpactSounds(1)=Sound'KFOldSchoolZeds_Sounds.Shared.Breakbone_02' RagImpactSounds(2)=Sound'KFOldSchoolZeds_Sounds.Shared.Breakbone_03' RagImpactSoundInterval=0.500000 ControllerClass=Class'KFOldSchoolZeds.KFMonsterControllerOS' RootBone= HeadBone="Bip01 Head" SpineBone1="Bip01 Spine1" SpineBone2= SoundVolume=200 Mass=300.000000 Begin Object Class=KarmaParamsSkel Name=PawnKParams KConvulseSpacing=(Max=2.200000) KLinearDamping=0.150000 KAngularDamping=0.050000 KBuoyancy=1.000000 KStartEnabled=True KVelDropBelowThreshold=50.000000 bHighDetailOnly=False KFriction=0.600000 KRestitution=0.300000 KImpactThreshold=250.000000 End Object KParams=KarmaParamsSkel'KFOldSchoolZeds.KFMonsterOS.PawnKParams' }