// Completely invisible Stalker // (c) PooSH, 2014 // used 'ClawAndMove' code from Scary Ghost's SuperStaler // Ported to 'NiceMonster' parent class class NiceZombieGhost extends NiceZombieStalker; // max distance squared for player to see cloacked Stalkers. // Beyond that distance Stalkers will appear completely invisible. var float CloakDistanceSqr; // Unclock distance squared for Commandos var float UncloakDistanceSqr; var const Material CloakMat; var const Material InvisibleMat; var const Material UncloakMat, UncloakFBMat; var const Material GlowFX; static simulated function PreCacheMaterials(LevelInfo myLevel) { myLevel.AddPrecacheMaterial(default.CloakMat); myLevel.AddPrecacheMaterial(default.InvisibleMat); myLevel.AddPrecacheMaterial(default.UncloakMat); myLevel.AddPrecacheMaterial(default.UncloakFBMat); myLevel.AddPrecacheMaterial(default.GlowFX); myLevel.AddPrecacheMaterial(Combiner'KF_Specimens_Trip_T.stalker_env_cmb'); myLevel.AddPrecacheMaterial(Texture'KF_Specimens_Trip_T.stalker_diff'); myLevel.AddPrecacheMaterial(Texture'KF_Specimens_Trip_T.stalker_spec'); myLevel.AddPrecacheMaterial(Combiner'KF_Specimens_Trip_T.StalkerCloakOpacity_cmb'); myLevel.AddPrecacheMaterial(Material'KF_Specimens_Trip_T.StalkerCloakEnv_rot'); myLevel.AddPrecacheMaterial(Material'KF_Specimens_Trip_T.stalker_opacity_osc'); myLevel.AddPrecacheMaterial(Material'KFCharacters.StalkerSkin'); } simulated function PostNetBeginPlay() { super.PostNetBeginPlay(); if ( LocalKFHumanPawn != none ) { CloakDistanceSqr = fmax(CloakDistanceSqr, 3.0 * UncloakDistanceSqr * LocalKFHumanPawn.GetStalkerViewDistanceMulti()); UncloakDistanceSqr *= LocalKFHumanPawn.GetStalkerViewDistanceMulti(); } } function RenderOverlays(Canvas Canvas) { Canvas.SetDrawColor(0, 92, 255, 255); super.RenderOverlays(Canvas); } // makes Stalker invisible or glowing (for commando) simulated function CloakStalker() { // No cloaking if zapped if( bZapped ) { return; } if ( bSpotted ) { if( Level.NetMode == NM_DedicatedServer ) return; Skins[0] = GlowFX; Skins[1] = GlowFX; bUnlit = true; } else if ( !bDecapitated && !bCrispified ) // No head, no cloak, honey. updated : Being charred means no cloak either :D { Visibility = 1; bCloaked = true; if( Level.NetMode == NM_DedicatedServer ) Return; Skins[0] = InvisibleMat; Skins[1] = InvisibleMat; bUnlit = false; // Invisible - no shadow if(PlayerShadow != none) PlayerShadow.bShadowActive = false; if(RealTimeShadow != none) RealTimeShadow.Destroy(); // Remove/disallow projectors on invisible people Projectors.Remove(0, Projectors.Length); bAcceptsProjectors = false; SetOverlayMaterial(Material'KFX.FBDecloakShader', 0.25, true); } } simulated function UnCloakStalker() { if( bZapped ) { return; } if( !bCrispified ) { LastUncloakTime = Level.TimeSeconds; Visibility = default.Visibility; bCloaked = false; bUnlit = false; // 25% chance of our Enemy saying something about us being invisible if( Level.NetMode!=NM_Client && !KFGameType(Level.Game).bDidStalkerInvisibleMessage && FRand()<0.25 && Controller.Enemy!=none && PlayerController(Controller.Enemy.Controller)!=none ) { PlayerController(Controller.Enemy.Controller).Speech('AUTO', 17, ""); KFGameType(Level.Game).bDidStalkerInvisibleMessage = true; } if( Level.NetMode == NM_DedicatedServer ) Return; if ( Skins[0] != UncloakMat ) { Skins[1] = FinalBlend'KF_Specimens_Trip_T.stalker_fb'; Skins[0] = UncloakMat; if (PlayerShadow != none) PlayerShadow.bShadowActive = true; bAcceptsProjectors = true; SetOverlayMaterial(Material'KFX.FBDecloakShader', 0.25, true); } } } function RemoveHead() { Super(NiceMonster).RemoveHead(); if (!bCrispified) { Skins[1] = UncloakFBMat; Skins[0] = UncloakMat; } } simulated function PlayDying(class DamageType, vector HitLoc) { Super(NiceMonster).PlayDying(DamageType,HitLoc); if(bUnlit) bUnlit=!bUnlit; LocalKFHumanPawn = none; if (!bCrispified) { Skins[1] = UncloakFBMat; Skins[0] = UncloakMat; } } simulated function Tick(float DeltaTime) { local float DistanceSqr; Super(NiceMonster).Tick(DeltaTime); // Keep the stalker moving toward its target when attacking if( Role == ROLE_Authority && bShotAnim && !bWaitForAnim && !bZapped ) { if( LookTarget!=none ) { Acceleration = AccelRate * Normal(LookTarget.Location - Location); } } if( Level.NetMode==NM_DedicatedServer ) Return; // Servers aren't intrested in this info. if( bZapped ) { // Make sure we check if we need to be cloaked as soon as the zap wears off NextCheckTime = Level.TimeSeconds; } else if( Level.TimeSeconds > NextCheckTime && Health > 0 ) { NextCheckTime = Level.TimeSeconds + 0.5; bSpotted = false; if ( LocalKFHumanPawn != none ) { DistanceSqr = VSizeSquared(Location - LocalKFHumanPawn.Location); if( LocalKFHumanPawn.Health > 0 && LocalKFHumanPawn.ShowStalkers() && DistanceSqr < UncloakDistanceSqr ) { bSpotted = True; if ( Skins[0] != GlowFX ) { Skins[0] = GlowFX; Skins[1] = GlowFX; bUnlit = true; } } else if ( DistanceSqr < CloakDistanceSqr ) { if ( bCloaked && Skins[0] != CloakMat ) { Skins[0] = CloakMat; Skins[1] = CloakMat; bUnlit = false; } } else if ( Skins[0] != InvisibleMat ) { CloakStalker(); } } } } function RangedAttack(Actor A) { if ( !bShotAnim && Physics != PHYS_Swimming && CanAttack(A) ) { bShotAnim = true; SetAnimAction('ClawAndMove'); } } // copied from ZombieSuperStalker (c) Scary Ghost simulated event SetAnimAction(name NewAction) { if( NewAction=='' ) Return; ExpectingChannel = AttackAndMoveDoAnimAction(NewAction); bWaitForAnim= false; if( Level.NetMode!=NM_Client ) { AnimAction = NewAction; bResetAnimAct = True; ResetAnimActTime = Level.TimeSeconds+0.3; } } // copied from ZombieSuperStalker (c) Scary Ghost simulated function int AttackAndMoveDoAnimAction( name AnimName ) { local int meleeAnimIndex; local float duration; if( AnimName == 'ClawAndMove' ) { meleeAnimIndex = Rand(3); AnimName = meleeAnims[meleeAnimIndex]; duration= GetAnimDuration(AnimName, 1.0); } if( AnimName=='StalkerSpinAttack' || AnimName=='StalkerAttack1' || AnimName=='JumpAttack') { AnimBlendParams(1, 1.0, 0.0,, FireRootBone); PlayAnim(AnimName,, 0.1, 1); return 1; } return super.DoAnimAction( AnimName ); } defaultproperties { CloakDistanceSqr=62500.000000 UncloakDistanceSqr=360000.000000 CloakMat=Shader'KF_Specimens_Trip_T.stalker_invisible' InvisibleMat=Shader'KF_Specimens_Trip_T.patriarch_invisible' UncloakMat=Shader'KF_Specimens_Trip_T.stalker_invisible' UncloakFBMat=Shader'KF_Specimens_Trip_T.stalker_invisible' MenuName="Ghost" Skins(0)=Shader'KF_Specimens_Trip_T.patriarch_invisible' Skins(1)=Shader'KF_Specimens_Trip_T.patriarch_invisible' }