//============================================================================= // KFGFXHudWrapper_Versus //============================================================================= // HUD class for Versus mode //============================================================================= // Killing Floor 2 // Copyright (C) 2016 Tripwire Interactive LLC //============================================================================= class KFGFXHudWrapper_Versus extends KFGFXHudWrapper; /** Cached GRI reference */ var KFGameReplicationInfoVersus MyKFGRIV; var Class HumanHUDClass; var Class ZedHUDClass; var() float ZedPlayerHudLocX, ZedPlayerHudLocY; var int HumanStatusBarLengthMax; const FriendlyZedInfoShowDistanceSQ = 562000; /** Boss icon texture/values */ var const Texture2D BossIconTexture; var const color BossIconColor; /** String displayed to player zeds waiting for the next spawn cycle */ var localized string WaitingToSpawnString; /** String displayed to player zeds when the takeover timer is active */ var localized string ZedTakeOverActiveString; /** String displayed to human players when the round is over */ var localized string PerkSwitchAllowedString; var int LastTeamIndex; simulated function PostBeginPlay() { local KFPawn_Monster KFP; super.PostBeginPlay(); // If we have a new HUD, try to cache a reference to boss pawn foreach WorldInfo.AllPawns( class'KFPawn_Monster', KFP ) { if (KFP.static.IsABoss()) { BossRef = KFInterface_MonsterBoss(KFP); break; } } } function CreateHUDMovie(optional bool bForce) { if (!class'WorldInfo'.static.IsMenuLevel()) { if(KFPlayerOwner != none && KFPlayerOwner.PlayerReplicationInfo.GetTeamNum() != LastTeamIndex || bForce) { LastTeamIndex = KFPlayerOwner.GetTeamNum(); if(HudMovie != none) { RemoveMovies(); } HudMovie = new GetHUDClass(); HudMovie.SetTimingMode(TM_Real); HudMovie.Init(class'Engine'.static.GetEngine().GamePlayers[HudMovie.LocalPlayerOwnerIndex]); } } } function class GetHUDClass() { if( KFPlayerOwner != none && KFPlayerOwner.GetTeamNum() == 255 && KFPlayerOwner.PlayerReplicationInfo != none && !KFPlayerOwner.PlayerReplicationInfo.bOnlySpectator ) { return ZedHUDClass; } return HumanHUDClass; } /** * @brief Main canvas draw function */ function DrawHUD() { local float ThisDot; local vector ViewLocation, ViewVector, TestPawnLocation; local rotator ViewRotation; local Pawn TestPawn; local KFPawn_Human HumanPawn; local array VisibleHumanPlayers; local array HiddenHumanPlayers; local byte MyTeamNum; super.DrawHUD(); // Don't draw canvas HUD in cinematic mode if( WorldInfo.GRI == none || (KFPlayerOwner != none && KFPlayerOwner.bCinematicMode) ) { return; } if( KFPlayerOwner.PlayerCamera != none ) { KFPlayerOwner.PlayerCamera.GetCameraViewPoint( ViewLocation, ViewRotation ); } // Enable stencil test Canvas.EnableStencilTest(true); // Cache off view rotation vector ViewVector = vector(ViewRotation); MyTeamNum = KFPlayerOwner.GetTeamNum(); // Cache GRI if( MyKFGRIV == none ) { MyKFGRIV = KFGameReplicationInfoVersus( WorldInfo.GRI ); } if( MyKFGRIV == none ) { return; } if( KFPlayerOwner != none && MyTeamNum == 255 ) { foreach WorldInfo.AllPawns( class'Pawn', TestPawn ) { // Only player-controlled pawns if( TestPawn.PlayerReplicationInfo == none ) { continue; } if( TestPawn.IsAliveAndWell() && TestPawn.Mesh.SkeletalMesh != none && TestPawn.Mesh.bAnimTreeInitialised && TestPawn != KFPlayerOwner.Pawn ) { if( TestPawn.Mesh != none && `TimeSince( TestPawn.Mesh.LastRenderTime ) < 0.2f ) { TestPawnLocation = TestPawn.Mesh.GetPosition() + ( TestPawn.CylinderComponent.CollisionHeight * vect(0,0,1) ); ThisDot = Normal(TestPawnLocation - ViewLocation) dot ViewVector; if( ThisDot > 0.f ) { HumanPawn = KFPawn_Human(TestPawn); if( HumanPawn != none ) { if( DrawPreciseHumanPlayerInfo( HumanPawn ) ) { VisibleHumanPlayers.AddItem( HumanPawn.PlayerReplicationInfo ); } else { HiddenHumanPlayers.Insert( 0, 1 ); HiddenHumanPlayers[0].HumanPawn = HumanPawn; HiddenHumanPlayers[0].HumanPRI = HumanPawn.PlayerReplicationInfo; } }/* //Not supposed to be drawing a bar above zed characters else if( MyTeamNum == 255 && TestPawn.GetTeamNum() == 255 ) { if( VSizeSq( KFPlayerOwner.ViewTarget.Location - TestPawnLocation ) <= FriendlyZedInfoShowDistanceSQ ) { DrawFriendlyZedPawnIcon( TestPawn ); } }*/ } } else if( TestPawn.GetTeamNum() == 0 ) { HiddenHumanPlayers.Insert( 0, 1 ); HiddenHumanPlayers[0].HumanPawn = TestPawn; HiddenHumanPlayers[0].HumanPRI = TestPawn.PlayerReplicationInfo; } } } if( !KFGRI.bHidePawnIcons ) { CheckAndDrawHiddenPlayerIcons( VisibleHumanPlayers, HiddenHumanPlayers ); } } // Draw boss pawn icon if needed CheckAndDrawBossPawnIcon( ViewLocation, ViewVector ); // Disable stencil test Canvas.EnableStencilTest(false); // Draw spawn time remaining if( (MyTeamNum == 255 || MyKFGRIV.bRoundIsOver) && !MyKFGRIV.bMatchIsOver && (PlayerOwner.Pawn == none || PlayerOwner.Pawn.bPlayedDeath) && PlayerOwner.CanRestartPlayer() ) { if( MyKFGRIV.TimeUntilNextSpawn != 255 || MyKFGRIV.PlayerZedSpawnWaitTimeData.bTakeOverActive ) { DrawRemainingTimeUntilSpawn( MyKFGRIV.TimeUntilNextSpawn, MyKFGRIV.PlayerZedSpawnWaitTimeData.bTakeOverActive ); } } } /** * @brief Checks if a boss icon should be drawn * * @param ViewLocation Thew local player's ViewLocation * @param ViewVector Thew local player's ViewVector * */ simulated function CheckAndDrawBossPawnIcon( vector ViewLocation, vector ViewVector ) { local float ThisDot; local vector BossPawnLocation; local KFPawn_Monster BossPawn; if (BossRef == none) { return; } BossPawn = BossRef.GetMonsterPawn(); if( BossPawn != none && BossPawn.Mesh.SkeletalMesh != none && BossPawn.Mesh.bAnimTreeInitialised && BossPawn != PlayerOwner.Pawn && BossPawn.IsAliveAndWell() && `TimeSince( BossPawn.Mesh.LastRenderTime ) > 0.2f && (PlayerOwner.GetTeamNum() == 255 || BossPawn.ShouldDrawBossIcon()) ) { BossPawnLocation = BossPawn.Mesh.GetPosition(); ThisDot = Normal( (BossPawnLocation + (BossPawn.CylinderComponent.CollisionHeight * vect(0,0,1))) - ViewLocation ) dot ViewVector; if( ThisDot > 0.f ) { DrawBossPawnIcon( BossPawnLocation ); } } } /** * @brief Draws a visible zed team mate's info * * @param MonsterPawn The zed's pawn */ simulated function DrawFriendlyZedPawnIcon( Pawn MonsterPawn ) { local float Percentage; local float BarHeight, BarLength; local vector ScreenPos, TargetLocation; local FontRenderInfo MyFontRenderInfo; local float FontScale; //local color TempColor; MyFontRenderInfo = Canvas.CreateFontRenderInfo( true ); BarLength = FMin(HumanStatusBarLengthMax * (float(Canvas.SizeX) / 1024.f), HumanStatusBarLengthMax) * FriendlyHudScale; BarHeight = FMin(8.f * (float(Canvas.SizeX) / 1024.f), 8.f) * FriendlyHudScale; TargetLocation = MonsterPawn.Mesh.GetPosition() + ( MonsterPawn.CylinderComponent.CollisionHeight * vect(0,0,2.2f) ); ScreenPos = Canvas.Project(TargetLocation); if( ScreenPos.X < 0 || ScreenPos.X > Canvas.SizeX || ScreenPos.Y < 0 || ScreenPos.Y > Canvas.SizeY ) { return; } //Draw health bar Percentage = FMin(float(MonsterPawn.Health) / float(MonsterPawn.HealthMax), 100); DrawKFBar(Percentage, BarLength, BarHeight, ScreenPos.X - (BarLength *0.5f), ScreenPos.Y, HealthColor); //Draw player name (Top) FontScale = class'KFGameEngine'.Static.GetKFFontScale(); Canvas.Font = class'KFGameEngine'.Static.GetKFCanvasFont(); Canvas.SetDrawColorStruct(PlayerBarTextColor); Canvas.SetPos(ScreenPos.X - (BarLength *0.5f), ScreenPos.Y - BarHeight * 3); Canvas.DrawText( MonsterPawn.PlayerReplicationInfo.PlayerName,,FontScale * FriendlyHudScale,FontScale * FriendlyHudScale, MyFontRenderInfo ); } /** * @brief Draws a visible human player's info * * @param KFPH The player's pawn * @return true if successfully drawn */ function bool DrawPreciseHumanPlayerInfo( KFPawn_Human KFPH ) { local float Percentage; local float BarHeight, BarLength; local vector ScreenPos, TargetLocation; local KFPlayerReplicationInfo KFPRI; local float IconSizeMult; KFPRI = KFPlayerReplicationInfo(KFPH.PlayerReplicationInfo); if( KFPRI == none ) { return false; } BarLength = FMin( HumanStatusBarLengthMax * (float(Canvas.SizeX) / 1024.f), HumanStatusBarLengthMax ) * FriendlyHudScale; BarHeight = FMin( 8.f * (float(Canvas.SizeX) / 1024.f), 8.f ) * FriendlyHudScale; TargetLocation = KFPH.Mesh.GetPosition() + ( KFPH.CylinderComponent.CollisionHeight * vect(0,0,2.2f) ); ScreenPos = Canvas.Project(TargetLocation); if( ScreenPos.X < 0 || ScreenPos.X > Canvas.SizeX || ScreenPos.Y < 0 || ScreenPos.Y > Canvas.SizeY ) { return true; } //Draw health bar Percentage = FMin( float(KFPH.Health) / float(KFPH.HealthMax), 100 ); DrawKFBar( Percentage, BarLength, BarHeight, ScreenPos.X - BarLength * 0.5f, ScreenPos.Y, HealthColor ); //Draw armor bar Percentage = FMin(float(KFPH.Armor) / float(KFPH.MaxArmor), 100); DrawKFBar(Percentage, BarLength, BarHeight, ScreenPos.X - (BarLength *0.5f), ScreenPos.Y - BarHeight, ArmorColor); IconSizeMult = PlayerStatusIconSize * FriendlyHudScale * 0.5f; ScreenPos.X -= IconSizeMult; ScreenPos.Y -= IconSizeMult * 2.5; Canvas.SetDrawColor(255,255,255,255); Canvas.SetPos( ScreenPos.X, ScreenPos.Y ); Canvas.DrawTile( GenericHumanIconTexture, PlayerStatusIconSize * FriendlyHudScale, PlayerStatusIconSize * FriendlyHudScale, 0, 0, 256, 256 ); return true; } /** * @brief Draws an icon projecting the boss' world position on the screen * * @param BossPawn The boss' pawn */ function DrawBossPawnIcon( vector BossLocation ) { local vector ScreenPos, TargetLocation; local float IconSizeMult; if (BossRef == none) { return; } TargetLocation = BossLocation + ( BossRef.GetMonsterPawn().CylinderComponent.CollisionHeight * vect(0,0,2.2f) ); ScreenPos = Canvas.Project( TargetLocation ); IconSizeMult = PlayerStatusIconSize * FriendlyHudScale * 0.5f; ScreenPos.X -= IconSizeMult; ScreenPos.Y -= IconSizeMult; if( ScreenPos.X < 0 || ScreenPos.X > Canvas.SizeX || ScreenPos.Y < 0 || ScreenPos.Y > Canvas.SizeY ) { return; } // Draw boss icon Canvas.SetDrawColorStruct( BossIconColor ); Canvas.SetPos( ScreenPos.X, ScreenPos.Y ); Canvas.DrawTile( BossIconTexture, PlayerStatusIconSize * FriendlyHudScale, PlayerStatusIconSize * FriendlyHudScale, 0, 0, 256, 256 ); } function DrawRemainingTimeUntilSpawn( byte RemainingTime, bool bTakeOverIsActive ) { local vector2D ScreenPos; local int ShadowSize; local float TextScale, XL, YL; local string ActualString; local FontRenderInfo MyFontRenderInfo; MyFontRenderInfo = Canvas.CreateFontRenderInfo( true ); if( bTakeOverIsActive && PlayerOwner.GetTeamNum() == 255 ) { ActualString = ZedTakeOverActiveString; } else { if( PlayerOwner.GetTeamNum() == 0 && MyKFGRIV.bRoundIsOver ) { ActualString = Repl( PerkSwitchAllowedString, "%x%", RemainingTime, true ); } else { ActualString = Repl( WaitingToSpawnString, "%x%", RemainingTime, true ); } } TextScale = class'KFGameEngine'.Static.GetKFFontScale() * (Canvas.ClipY / 768.f); Canvas.Font = class'KFGameEngine'.Static.GetKFCanvasFont(); Canvas.TextSize( Repl( WaitingToSpawnString, "%x%", "00", true ), XL, YL, TextScale, TextScale ); ScreenPos.X = (Canvas.ClipX * 0.5f) - (XL * 0.5f); ScreenPos.Y = Canvas.ClipY * 0.25f; // Drop shadow ShadowSize = int( Canvas.ClipY / 360.f ); Canvas.SetPos( ScreenPos.X + ShadowSize, ScreenPos.Y + ShadowSize ); Canvas.SetDrawColor( 0, 0, 0, 160 ); Canvas.DrawText( ActualString,, TextScale, TextScale, MyFontRenderInfo ); // Text Canvas.SetPos( ScreenPos.X, ScreenPos.Y ); Canvas.SetDrawColor( 255, 255, 255, 255 ); Canvas.DrawText( ActualString,, TextScale, TextScale, MyFontRenderInfo ); } DefaultProperties { LastTeamIndex=-1 HUDClass=class'KFGFxMoviePlayer_HUD' HumanHUDClass=class'KFGFxMoviePlayer_HUD' ZedHUDClass=class'KFGFxMoviePlayer_HUD_Versus' ZedPlayerHudLocX=0.25 ZedPlayerHudLocY=0.85 HumanStatusBarLengthMax = 80.0f; BossIconTexture=Texture2D'ZED_Patriarch_UI.ZED-VS_Icon_Boss' BossIconColor=(R=255, G=255, B=255, A=192) }