class stub_Monster extends KFMonster; var transient float fLastAttackTime; //============================================================================= // controller == none fix //============================================================================= // when you kill zeds before they fall into stun // should i check it before whole function body?? 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; // fix! if (Controller != none && KFMonsterController(Controller) != none) { Controller.GoToState('WaitForAnim'); KFMonsterController(Controller).bUseFreezeHack = true; } return true; } simulated function HandleBumpGlass() { Acceleration = vect(0,0,0); Velocity = vect(0,0,0); SetAnimAction(MeleeAnims[0]); bShotAnim = true; // fix! if (Controller != none) controller.GotoState('WaitForAnim'); } //============================================================================= // instigatedBy == none fix //============================================================================= function TakeDamage(int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, class damageType, optional int HitIndex ) { local bool bIsHeadshot; local KFPlayerReplicationInfo KFPRI; local float HeadShotCheckScale; // if (InstigatedBy == none || class(DamType) == none) LastDamagedBy = instigatedBy; LastDamagedByType = damageType; HitMomentum = VSize(momentum); LastHitLocation = hitlocation; LastMomentum = momentum; if ( instigatedBy != none && 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 ( LastDamagedBy != none && 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; if (instigatedBy != none) BileInstigator = instigatedBy; else BileInstigator = self; 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(Monster).takeDamage(Damage + 600, instigatedBy, hitLocation, momentum, damageType); HurtRadius(500, 1000, class'DamTypeFrag', 100000, Location); } else { Super(Monster).takeDamage(Damage, instigatedBy, hitLocation, momentum, damageType); } // if (Damage*1.5 >= default.Health || (Damage > 200 && KFDamType != none && KFDamType.default.bSniperWeapon && ZedVictim.IsA('ZombieHusk') )) // { // ZedVictim.Controller.Focus = none; // ZedVictim.Controller.FocalPoint = ZedVictim.Location + 512 * vector(ZedVictim.Rotation); // } // block yet another zed time call // if( bIsHeadShot && Health <= 0 ) // { // KFGameType(Level.Game).DramaticEvent(0.03); // } bBackstabbed = false; } // attempt to fix ground speed bugs 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 ) { // was `default.GroundSpeed` SetGroundSpeed(GetOriginalGroundSpeed()); } } } //============================================================================= // fix for zed corpse collision shit //============================================================================= //Stops the green shit when a player dies. simulated function PlayDying(class DamageType, vector HitLoc) { local float frame, rate; local name seq; local LavaDeath LD; local MiscEmmiter BE; AmbientSound = None; bCanTeleport = false; // sjs - fix karma going crazy when corpses land on teleporters bReplicateMovement = false; bTearOff = true; bPlayedDeath = true; StopBurnFX(); if (CurrentCombo != None) CurrentCombo.Destroy(); HitDamageType = DamageType; // these are replicated to other clients 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'WeaponSounds.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); } // stop shooting AnimBlendParams(1, 0.0); FireState = FS_None; // Try to adjust around performance //log(Level.DetailMode); LifeSpan = RagdollLifeSpan; GotoState('ZombieDying'); if ( BE != None ) return; PlayDyingAnimation(DamageType, HitLoc); // ADDITION for collision fix bBlockActors = false; bBlockPlayers = false; bBlockProjectiles = false; bProjTarget = false; bBlockZeroExtentTraces = false; bBlockNonZeroExtentTraces = false; bBlockHitPointTraces = false; } state ZombieDying { simulated function BeginState() { // ADDITION for collision fix bBlockActors = false; bBlockPlayers = false; bBlockProjectiles = false; bProjTarget = false; bBlockZeroExtentTraces = false; bBlockNonZeroExtentTraces = false; bBlockHitPointTraces = false; if (bDestroyNextTick) { // If we've flagged this character to be destroyed next tick, handle that if (TimeSetDestroyNextTickTime < Level.TimeSeconds) Destroy(); else SetTimer(0.01, false); } else { if (bTearOff && (Level.NetMode == NM_DedicatedServer) || class'GameInfo'.static.UseLowGore()) LifeSpan = 1.0; else SetTimer(2.0, false); } SetPhysics(PHYS_Falling); if (Controller != None) Controller.Destroy(); } } //============================================================================= // lets limit some zeds attack abilities //============================================================================= function bool MeleeDamageTarget(int hitdamage, vector pushdir) { local vector HitLocation, HitNormal; local actor HitActor; local Name TearBone; local float dummy; local Emitter BloodHit; // local vector TraceDir; // Never should be done on client. if (Level.NetMode == NM_Client || Controller == None) return false; // try to limit some zeds if ((ClassIsChildOf(self.class, class'ZombieCrawler') || ClassIsChildOf(self.class, class'ZombieFleshpound')) && (Level.TimeSeconds < class'stub_Monster'.default.fLastAttackTime)) return false; // ATTENTION!!! is 0.3 secs ok? class'stub_Monster'.default.fLastAttackTime = Level.TimeSeconds + 0.3f; if (Controller.Target!=none && Controller.Target.IsA('KFDoorMover')) { Controller.Target.TakeDamage(hitdamage, self ,HitLocation,pushdir, CurrentDamType); return true; } // need to uncomment this and check :D // ClearStayingDebugLines(); // TraceDir = Normal(Controller.Target.Location - Location); // DrawStayingDebugLine(Location, Location + (TraceDir * (MeleeRange * 1.4 + Controller.Target.CollisionRadius + CollisionRadius)) , 255,255,0); // check if still in melee range if ( (Controller.target != None) && (bSTUNNED == false) && (DECAP == false) && (VSize(Controller.Target.Location - Location) <= MeleeRange * 1.4 + Controller.Target.CollisionRadius + CollisionRadius) && ((Physics == PHYS_Flying) || (Physics == PHYS_Swimming) || (Abs(Location.Z - Controller.Target.Location.Z) <= FMax(CollisionHeight, Controller.Target.CollisionHeight) + 0.5 * FMin(CollisionHeight, Controller.Target.CollisionHeight))) ) { // See if a trace would hit a pawn (Have to turn of hit point collision so trace doesn't hit the Human Pawn's bullet whiz cylinder) bBlockHitPointTraces = false; HitActor = Trace(HitLocation, HitNormal, Controller.Target.Location , Location + EyePosition(), true); bBlockHitPointTraces = true; // If the trace wouldn't hit a pawn, do the old thing of just checking if there is something blocking the trace if (Pawn(HitActor) == none) { // Have to turn of hit point collision so trace doesn't hit the Human Pawn's bullet whiz cylinder bBlockHitPointTraces = false; HitActor = Trace(HitLocation, HitNormal, Controller.Target.Location, Location, false); bBlockHitPointTraces = true; if (HitActor != none) return false; } if (KFHumanPawn(Controller.Target) != none) { //TODO - line below was KFPawn. Does this whole block need to be KFPawn, or is it OK as KFHumanPawn? KFHumanPawn(Controller.Target).TakeDamage(hitdamage, Instigator ,HitLocation,pushdir, CurrentDamType); //class 'KFmod.ZombieMeleeDamage'); if (KFHumanPawn(Controller.Target).Health <=0) { if (!class'GameInfo'.static.UseLowGore()) { BloodHit = Spawn(class'KFMod.FeedingSpray',self,,Controller.Target.Location,rotator(pushdir)); // KFHumanPawn(Controller.Target).SpawnGibs(rotator(pushdir), 1); TearBone=KFPawn(Controller.Target).GetClosestBone(HitLocation,Velocity,dummy); KFHumanPawn(Controller.Target).HideBone(TearBone); } // Give us some Health back if (Health <= (1.0-FeedThreshold)*HealthMax) { Health += FeedThreshold*HealthMax * Health/HealthMax; } } } else if (Controller.target != None) { // Do more damage if you are attacking another zed so that zeds don't just stand there whacking each other forever! - Ramm if (KFMonster(Controller.Target) != none) hitdamage *= DamageToMonsterScale; Controller.Target.TakeDamage(hitdamage, self ,HitLocation,pushdir, CurrentDamType); //class 'KFmod.ZombieMeleeDamage'); } return true; } return false; }