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

1492 lines
50 KiB
Ucode

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 <KFGibOS> HeadStubClassOS;
var class <KFGibOS> MonsterHeadGibletOS;
var class <KFGibOS> MonsterThighGibletOS;
var class <KFGibOS> MonsterArmGibletOS;
var class <KFGibOS> MonsterLegGibletOS;
var class <KFGibOS> MonsterTorsoGibletOS;
var class <KFGibOS> 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<material> MixTexturePool;
var protected array<material> 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<SeveredAppendage> 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> 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> 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<DamTypeBurned>(DamageType) != none || class<DamTypeFlamethrower>(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<xEmitter> 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<Level.TimeSeconds )
{
AnimAction = '';
bResetAnimAct = false;
}
if ( Controller != none )
{
LookTarget = Controller.Enemy;
}
if ( Role == ROLE_Authority && bDecapitated )
{
if ( BleedOutTime > 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<level.TimeSeconds )
{
--BileCount;
NextBileTime+=BileFrequency;
TakeBileDamage();
}
if( bZapped && Role == ROLE_Authority )
{
RemainingZap -= DeltaTime;
if( RemainingZap <= 0 )
{
RemainingZap = 0;
bZapped = false;
ZappedBy = none;
ZapThreshold *= ZapResistanceScale;
}
}
if( !bZapped && TotalZap > 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> 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> 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<KFWeaponDamageType>(damageType) != none && class<KFWeaponDamageType>(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<DamTypeTrenchgun>(damageType) != none ||
class<DamTypeFlareRevolver>(damageType) != none ||
class<DamTypeMAC10MPInc>(damageType) != none)
{
FireDamageClass = damageType;
}
else
{
FireDamageClass = class'DamTypeFlamethrower';
}
}
if ( class<DamTypeMAC10MPInc>(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<KFWeaponDamageType>(damageType)!=none &&
class<KFWeaponDamageType>(damageType).default.bCheckForHeadShots )
{
HeadShotCheckScale = 1.0;
// Do larger headshot checks if it is a melee attach
if( class<DamTypeMelee>(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<DamTypeBurned>(DamageType) == none && class<DamTypeFlamethrower>(DamageType) == none )
{
if(class<KFWeaponDamageType>(damageType)!=none)
Damage = Damage * class<KFWeaponDamageType>(damageType).default.HeadShotDamageMult;
if ( class<DamTypeMelee>(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<KFWeaponDamageType>(damageType) != none && instigatedBy != none && KFPlayerController(instigatedBy.Controller) != none )
{
bLaserSightedEBRM14Headshotted = M14EBRBattleRifle(instigatedBy.Weapon) != none && M14EBRBattleRifle(instigatedBy.Weapon).bLaserActive;
Class<KFWeaponDamageType>(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<DamTypeVomit>(DamageType)!=none) // Same rules apply to zombies as players.
{
BileCount=7;
BileInstigator = instigatedBy;
LastBileDamagedByType=class<DamTypeVomit>(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> 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> 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'
}