503 lines
17 KiB
Ucode
503 lines
17 KiB
Ucode
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> damageType, optional int HitIndex )
|
|
{
|
|
local bool bIsHeadshot;
|
|
local KFPlayerReplicationInfo KFPRI;
|
|
local float HeadShotCheckScale;
|
|
|
|
// if (InstigatedBy == none || class<KFWeaponDamageType>(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<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 ( 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<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;
|
|
if (instigatedBy != none)
|
|
BileInstigator = instigatedBy;
|
|
else
|
|
BileInstigator = self;
|
|
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(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> 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<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'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;
|
|
} |