- Shiver's base health decreased from 350 to 250; - Shiver can't teleport while headless.
		
			
				
	
	
		
			452 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Ucode
		
	
	
	
	
	
			
		
		
	
	
			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
 | |
| }
 |