NicePack/sources/Zeds/Nice/NiceZombieShiver.uc
Anton Tarasenko 05c473b072 Nerf shiver's health and teleportation
- Shiver's base health decreased from 350 to 250;
- Shiver can't teleport while headless.
2020-04-21 13:57:32 +07:00

452 lines
14 KiB
Ucode

// Different naming scheme 'cause kf-scrntestingrounds has a stupid restriction on what zeds can be used in it's spawns
class NiceZombieShiver extends NiceZombieShiverBase;
var float TeleportBlockTime;
var float HeadOffsetY;
var transient bool bRunning, bClientRunning;
replication
{
reliable if ( Role == ROLE_Authority)
bRunning;
}
simulated function PostNetReceive()
{
super.PostNetReceive();
if( bClientRunning != bRunning )
{
bClientRunning = bRunning;
if( bRunning ) {
MovementAnims[0] = RunAnim;
}
else {
MovementAnims[0] = WalkAnim;
}
}
}
simulated function PostBeginPlay()
{
Super.PostBeginPlay();
if (Level.NetMode != NM_DedicatedServer)
{
MatAlphaSkin = ColorModifier(Level.ObjectPool.AllocateObject(class'ColorModifier'));
if (MatAlphaSkin != none)
{
MatAlphaSkin.Color = class'Canvas'.static.MakeColor(255, 255, 255, 255);
MatAlphaSkin.RenderTwoSided = false;
MatAlphaSkin.AlphaBlend = true;
MatAlphaSkin.Material = Skins[0];
Skins[0] = MatAlphaSkin;
}
}
}
simulated function Destroyed()
{
if (Level.NetMode != NM_DedicatedServer && MatAlphaSkin != none)
{
Skins[0] = default.Skins[0];
Level.ObjectPool.FreeObject(MatAlphaSkin);
}
Super.Destroyed();
}
// Overridden to add HeadOffsetY
function bool IsHeadShot(vector loc, vector ray, float AdditionalScale)
{
local coords C;
local vector HeadLoc, B, M, diff;
local float t, DotMM, Distance;
local int look;
local bool bUseAltHeadShotLocation;
local bool bWasAnimating;
if (HeadBone == '')
return False;
// If we are a dedicated server estimate what animation is most likely playing on the client
if (Level.NetMode == NM_DedicatedServer)
{
if (Physics == PHYS_Falling)
PlayAnim(AirAnims[0], 1.0, 0.0);
else if (Physics == PHYS_Walking)
{
// Only play the idle anim if we're not already doing a different anim.
// This prevents anims getting interrupted on the server and borking things up - Ramm
if( !IsAnimating(0) && !IsAnimating(1) )
{
if (bIsCrouched)
{
PlayAnim(IdleCrouchAnim, 1.0, 0.0);
}
else
{
bUseAltHeadShotLocation=true;
}
}
else
{
bWasAnimating = true;
}
if ( bDoTorsoTwist )
{
SmoothViewYaw = Rotation.Yaw;
SmoothViewPitch = ViewPitch;
look = (256 * ViewPitch) & 65535;
if (look > 32768)
look -= 65536;
SetTwistLook(0, look);
}
}
else if (Physics == PHYS_Swimming)
PlayAnim(SwimAnims[0], 1.0, 0.0);
if( !bWasAnimating )
{
SetAnimFrame(0.5);
}
}
if( bUseAltHeadShotLocation )
{
HeadLoc = Location + (OnlineHeadshotOffset >> Rotation);
AdditionalScale *= OnlineHeadshotScale;
}
else
{
C = GetBoneCoords(HeadBone);
HeadLoc = C.Origin + (HeadHeight * HeadScale * AdditionalScale * C.XAxis)
+ HeadOffsetY * C.YAxis;
}
//ServerHeadLocation = HeadLoc;
// Express snipe trace line in terms of B + tM
B = loc;
M = ray * (2.0 * CollisionHeight + 2.0 * CollisionRadius);
// Find Point-Line Squared Distance
diff = HeadLoc - B;
t = M Dot diff;
if (t > 0)
{
DotMM = M dot M;
if (t < DotMM)
{
t = t / DotMM;
diff = diff - (t * M);
}
else
{
t = 1;
diff -= M;
}
}
else
t = 0;
Distance = Sqrt(diff Dot diff);
return (Distance < (HeadRadius * HeadScale * AdditionalScale));
}
function bool FlipOver()
{
if ( super.FlipOver() ) {
TeleportBlockTime = Level.TimeSeconds + 3.0; // can't teleport during stun
// do not rotate while stunned
Controller.Focus = none;
Controller.FocalPoint = Location + 512*vector(Rotation);
}
return false;
}
simulated function StopBurnFX()
{
if (bBurnApplied)
{
MatAlphaSkin.Material = Texture'PatchTex.Common.ZedBurnSkin';
Skins[0] = MatAlphaSkin;
}
Super.StopBurnFX();
}
function RangedAttack(Actor A)
{
if (bShotAnim || Physics == PHYS_Swimming)
return;
else if (CanAttack(A))
{
bShotAnim = true;
SetAnimAction('Claw');
return;
}
}
state Running
{
function Tick(float Delta)
{
Global.Tick(Delta);
if (RunUntilTime < Level.TimeSeconds)
GotoState('');
GroundSpeed = GetOriginalGroundSpeed();
}
function BeginState()
{
bRunning = true;
RunUntilTime = Level.TimeSeconds + PeriodRunBase + FRand() * PeriodRunRan;
MovementAnims[0] = RunAnim;
}
function EndState()
{
bRunning = false;
GroundSpeed = global.GetOriginalGroundSpeed();
RunCooldownEnd = Level.TimeSeconds + PeriodRunCoolBase + FRand() * PeriodRunCoolRan;
MovementAnims[0] = WalkAnim;
}
function float GetOriginalGroundSpeed()
{
return global.GetOriginalGroundSpeed() * 2.5;
}
function bool CanSpeedAdjust()
{
return false;
}
}
/*function TakeDamage(int Damage, Pawn InstigatedBy, Vector HitLocation, Vector Momentum, class<DamageType> DamType, optional int HitIndex)
{
if (InstigatedBy == none || class<KFWeaponDamageType>(DamType) == none)
Super(Monster).TakeDamage(Damage, instigatedBy, hitLocation, momentum, DamType); // skip none-reference error
else
Super(KFMonster).TakeDamage(Damage, instigatedBy, hitLocation, momentum, DamType);
}*/
// returns true also for KnockDown (stun) animation -- PooSH
simulated function bool AnimNeedsWait(name TestAnim)
{
if( TestAnim == 'DoorBash' || TestAnim == 'KnockDown' )
{
return true;
}
return ExpectingChannel == 0;
}
simulated function float GetOriginalGroundSpeed()
{
local float result;
result = OriginalGroundSpeed;
if( bZedUnderControl )
result *= 1.25;
return result;
}
simulated function HandleAnimation(float Delta)
{
// hehehe
}
simulated function Tick(float Delta)
{
Super.Tick(Delta);
if (Health > 0 && !bBurnApplied)
{
if (Level.NetMode != NM_DedicatedServer)
HandleAnimation(Delta);
// Handle targetting
if (Level.NetMode != NM_Client && !bDecapitated)
{
if (Controller == none || Controller.Target == none || !Controller.LineOfSightTo(Controller.Target))
{
if (bCanSeeTarget) bCanSeeTarget = false;
}
else
{
if (!bCanSeeTarget)
{
bCanSeeTarget = true;
SeeTargetTime = Level.TimeSeconds;
}
else if (Level.TimeSeconds > SeeTargetTime + PeriodSeeTarget)
{
if (VSize(Controller.Target.Location - Location) < MaxTeleportDist)
{
if (VSize(Controller.Target.Location - Location) > MinTeleportDist || !Controller.ActorReachable(Controller.Target))
{
if (CanTeleport())
StartTelePort();
}
else
{
if (CanRun())
GotoState('Running');
}
}
}
}
}
}
// Handle client-side teleport variables
if (!bBurnApplied)
{
if (Level.NetMode != NM_DedicatedServer && OldFadeStage != FadeStage)
{
OldFadeStage = FadeStage;
if (FadeStage == 2)
AlphaFader = 0;
else
AlphaFader = 255;
}
// Handle teleporting
if (FadeStage == 1) // Fade out (pre-teleport)
{
AlphaFader = FMax(AlphaFader - Delta * 512, 0);
if (Level.NetMode != NM_Client && AlphaFader == 0)
{
SetCollision(true, true);
FlashTeleport();
SetCollision(false, false);
FadeStage = 2;
}
}
else if (FadeStage == 2) // Fade in (post-teleport)
{
AlphaFader = FMin(AlphaFader + Delta * 512, 255);
if (Level.NetMode != NM_Client && AlphaFader == 255)
{
FadeStage = 0;
SetCollision(true, true);
GotoState('Running');
}
}
if (Level.NetMode != NM_DedicatedServer && ColorModifier(Skins[0]) != none)
ColorModifier(Skins[0]).Color.A = AlphaFader;
}
}
//can't teleport if set on fire
function bool CanTeleport()
{
if (HeadHealth <= 0) return false;
return !bFlashTeleporting && !bOnFire && Physics == PHYS_Walking && Level.TimeSeconds > TeleportBlockTime
&& LastFlashTime + 7.5 < Level.TimeSeconds && !bIsStunned;
}
function bool CanRun()
{
local float distanceToTargetSquared;
if(controller == none) return false;
if(controller.focus != none){
distanceToTargetSquared = VSize(controller.focus.location - location);
if(distanceToTargetSquared > 900 * 2500) // (30 * 50)^2 / 30 meters
return false;
}
return (!bFlashTeleporting && !IsInState('Running') && RunCooldownEnd < Level.TimeSeconds);
}
function StartTeleport()
{
FadeStage = 1;
AlphaFader = 255;
SetCollision(false, false);
bFlashTeleporting = true;
}
function FlashTeleport()
{
local Actor Target;
local vector OldLoc;
local vector NewLoc;
local vector HitLoc;
local vector HitNorm;
local rotator RotOld;
local rotator RotNew;
local float LandTargetDist;
local int iEndAngle;
local int iAttempts;
if (Controller == none || Controller.Target == none)
return;
Target = Controller.Target;
RotOld = rotator(Target.Location - Location);
RotNew = RotOld;
OldLoc = Location;
for (iEndAngle = 0; iEndAngle < MaxTeleportAngles; iEndAngle++)
{
RotNew = RotOld;
RotNew.Yaw += iEndAngle * (65536 / MaxTelePortAngles);
for (iAttempts = 0; iAttempts < MaxTeleportAttempts; iAttempts++)
{
LandTargetDist = Target.CollisionRadius + CollisionRadius +
MinLandDist + (MaxLandDist - MinLandDist) * (iAttempts / (MaxTeleportAttempts - 1.0));
NewLoc = Target.Location - vector(RotNew) * LandTargetDist; // Target.Location - Location
NewLoc.Z = Target.Location.Z;
if (Trace(HitLoc, HitNorm, NewLoc + vect(0, 0, -500), NewLoc) != none)
NewLoc.Z = HitLoc.Z + CollisionHeight;
// Try a new location
if (SetLocation(NewLoc))
{
SetPhysics(PHYS_Walking);
if (Controller.PointReachable(Target.Location))
{
Velocity = vect(0, 0, 0);
Acceleration = vect(0, 0, 0);
SetRotation(rotator(Target.Location - Location));
PlaySound(Sound'ScrnZedPack_S.Shiver.ShiverWarpGroup', SLOT_Interact, 4.0);
Controller.GotoState('');
MonsterController(Controller).WhatToDoNext(0);
goto Teleported;
}
}
// Reset location
SetLocation(OldLoc);
}
}
Teleported:
bFlashTeleporting = false;
LastFlashTime = Level.TimeSeconds;
}
function Died(Controller Killer, class<DamageType> damageType, vector HitLocation)
{
// (!)
Super.Died(Killer, damageType, HitLocation);
}
function RemoveHead()
{
local class<KFWeaponDamageType> KFDamType;
KFDamType = class<KFWeaponDamageType>(LastDamagedByType);
if ( KFDamType != none && !KFDamType.default.bIsPowerWeapon
&& !KFDamType.default.bSniperWeapon && !KFDamType.default.bIsMeleeDamage
&& !KFDamType.default.bIsExplosive && !KFDamType.default.bDealBurningDamage
&& !ClassIsChildOf(KFDamType, class'DamTypeDualies')
&& !ClassIsChildOf(KFDamType, class'DamTypeMK23Pistol')
&& !ClassIsChildOf(KFDamType, class'DamTypeMagnum44Pistol') )
{
LastDamageAmount *= 3.5; //significantly raise decapitation bonus for Assault Rifles
//award shiver kill on decap for Commandos
if ( KFPawn(LastDamagedBy)!=none && KFPlayerController(LastDamagedBy.Controller) != none
&& KFSteamStatsAndAchievements(KFPlayerController(LastDamagedBy.Controller).SteamStatsAndAchievements) != none )
{
KFDamType.Static.AwardKill(
KFSteamStatsAndAchievements(KFPlayerController(LastDamagedBy.Controller).SteamStatsAndAchievements),
KFPlayerController(LastDamagedBy.Controller), self);
}
}
if (IsInState('Running'))
GotoState('');
Super(NiceMonster).RemoveHead();
}
function bool CheckMiniFlinch(int flinchScore, Pawn instigatedBy, Vector hitLocation, Vector momentum, class<NiceWeaponDamageType> damageType, float headshotLevel, KFPlayerReplicationInfo KFPRI){
if(IsInState('Running'))
return false;
return super.CheckMiniFlinch(flinchScore, instigatedBy, hitLocation, momentum, damageType, headshotLevel, KFPRI);
}
simulated function int DoAnimAction( name AnimName )
{
if (AnimName=='Claw' || AnimName=='Claw2' || AnimName=='Claw3')
{
AnimBlendParams(1, 1.0, 0.1,, FireRootBone);
PlayAnim(AnimName,, 0.1, 1);
return 1;
}
return Super.DoAnimAction(AnimName);
}
defaultproperties
{
HeadOffsetY=-3.000000
idleInsertFrame=0.468000
PlayerCountHealthScale=0.200000
OnlineHeadshotOffset=(X=19.000000,Z=39.000000)
ScoringValue=15
HealthMax=300.000000
Health=300
HeadRadius=8.000000
HeadHeight=3.000000
}