1
0
KF2-Dev-Scripts/KFGame/Classes/KFHUDBase.uc
2023-09-21 22:31:11 +03:00

1682 lines
54 KiB
Ucode

//=============================================================================
// KFHUDBase
//=============================================================================
// The Killing Floor 2 base HUD class
//=============================================================================
// Killing Floor 2
// Copyright (C) 2015 Tripwire Interactive LLC
// Based on UDKHUD/UTBASEHUD Copyright 1998-2012 Epic Games, Inc.
// - Christian "schneidzekk" Schneider 8/22/2012
//=============================================================================
class KFHUDBase extends HUD
native(UI)
dependson(KFWeapon)
config(Game);
`include(KFProfileSettings.uci)
/** Cached a typed Player controller. Unlike PawnOwner we only set this once in PostBeginPlay */
var KFPlayerController KFPlayerOwner;
/** Cached reference to the GRI */
var KFGameReplicationInfo KFGRI;
var const Texture2D IconHudTexture;
var const Texture2D IconHighLightTexture;
/** Various colors */
var const color BlackColor, GoldColor;
var const color LightGoldColor;
var const color LightGreenColor, YellowColor, OrangeColor, RedHealthColor;
var const color ArmorColor, HealthColor, ClassicArmorColor, ClassicHealthColor, NonPlayerHealth, HealthBeingRegeneratedColor;
var const color PlayerBarBGColor, PlayerBarTextColor, PlayerBarIconColor, PlayerBarShadowColor;
var const color SupplierActiveColor, SupplierUsableColor, SupplierHalfUsableColor;
var const color ZedIconColor;
/** Holds the scaling factor given the current resolution. This is calculated in PostRender() */
var float ResolutionScale, ResolutionScaleX;
var float VoiceCommsIconHighlightScale;
var int CurrentVoiceCommsHighlightAlpha;
var int CurrentAlphaDelta;
var float MinScreenClampPos;
var float MaxScreenClampPos;
var float MaxDrawDistanceObjective;
var float PrestigeIconScale;
/*********************************************************************************************
Friendly HUD
********************************************************************************************* */
var config float FriendlyHudScale;
var config bool bFriendlyHUDVisible;
/*********************************************************************************************
DrawGlowText()
********************************************************************************************* */
var font GlowFonts[2]; // 0 = the Glow, 1 = Text
var FontRenderInfo TextRenderInfo;
/** How long should the pulse take total */
var float PulseDuration;
/** When should the pulse switch from Out to in */
var float PulseSplit;
/** How much should the text pulse - NOTE this will be added to 1.0 (so PulseMultipler 0.5 = 1.5) */
var float PulseMultiplier;
/*********************************************************************************************
Debugging Related (showdebug)
********************************************************************************************* */
var bool bCachedShowOverlays;
var const FontRenderInfo Text_NoClipShadowed;
/*********************************************************************************************
Crosshair - Added by Ramm
********************************************************************************************* */
/** Whether the crosshair should be drawn at this moment */
var bool bDrawCrosshair;
/** Whether or not we should force draw the crosshair for debugging (Toggled from exec ToggleCrosshair in KFCheatManager) */
var bool bForceDrawCrosshair;
/** The target crosshair spread we are blending to */
var float TargetCrossHairMod;
/** The current crosshair spread value */
var float CurrentCrossHairMod;
/** Base size of the weapon crosshair */
var(Crosshair) float BaseCrosshairSize;
/** Used to scale the spread of the crosshair based on the Spread of the weapon */
var(Crosshair) InterpCurveFloat CrosshairAccuracyScale;
/** If true, we will alter the crosshair when it's over a friendly */
var bool bCrosshairOnFriendly;
/** Make the crosshair green (found valid friendly) */
var bool bGreenCrosshair;
//-----------------------------------------------------------------------------------------
var Texture2d PlayerStatusBarBGTexture;
var const float PlayerStatusBarLengthMax;
var const float PlayerStatusIconSize;
/** Classic Health Bar Colors */
var config bool ClassicPlayerInfo;
// Players that are not visible
struct sHiddenHumanPawnInfo
{
var Pawn HumanPawn;
var PlayerReplicationInfo HumanPRI;
};
var float HumanPlayerIconInterpMult;
/** Texture used for the generic human icon */
var const Texture2D GenericHumanIconTexture;
/** Texture used for the generic zed icon */
var const Texture2D GenericZedIconTexture;
/** Texture used for the VIP representation over a player */
var const Texture2D VIPIconTexture;
var const float OriginalVIPIconSize;
/**
* Draw a glowing string
*/
native function DrawGlowText(string Text, float X, float Y, optional float MaxHeightInPixels=0.0, optional float PulseTime=-100.0, optional bool bRightJustified);
simulated function PostBeginPlay()
{
local KFProfileSettings Profile;
super.PostBeginPlay();
bDrawCrosshair = class'KFGameEngine'.static.IsCrosshairEnabled();
bCachedShowOverlays = bShowOverlays;
KFPlayerOwner = KFPlayerController(PlayerOwner);
if( KFPlayerOwner != none && KFPlayerOwner.OnlineSub != none )
{
Profile = KFProfileSettings(KFPlayerOwner.OnlineSub.PlayerInterface.GetProfileSettings( LocalPlayer(PlayerOwner.Player).ControllerId ));
if( Profile != none )
{
FriendlyHudScale = Profile.GetProfileFloat( KFID_FriendlyHudScale );
//Clamping the value here in case we receive some crazy number
FClamp( FriendlyHudScale, 0.25, 1.f);
}
}
}
/**
* Pre-Calculate most common values, to avoid doing 1200 times the same operations
*/
function PreCalcValues()
{
super.PreCalcValues();
// Let the PC know that the resolution has changed
if ( KFPlayerOwner != None )
{
KFPlayerOwner.NotifyResolutionChanged(SizeX, SizeY);
}
}
/**
* Reset movies since resolution changed
*/
function ResolutionChanged()
{
}
/**
* Currently used to let some actors render HUD debug text
*/
function SetShowOverlays( bool bShow )
{
bShowOverlays = bShow;
}
/**
* Draw the crosshair
*/
function DrawCrosshair()
{
local float CrosshairSize;
local float CrossHairSpread;
local KFPawn KFP;
local KFWeapon KFWP;
local bool bMonsterPawn, bDrawCrosshairNoWeapon;
local byte CrossHairAlpha;
local float WeaponAccuracyAdjust;
local float WeaponRecoilAdjust;
local float WeaponRecoilMod;
local KFPerk MyKFPerk;
CrosshairSize = 6;
// Only draw the crosshair if we're not in a vehicle and we have a living pawn
if ( PlayerOwner.Pawn != none && PlayerOwner.Pawn.Health > 0 )
{
if (PlayerOwner.ViewTarget != PlayerOwner.Pawn)
{
return;
}
KFWP = KFWeapon(PlayerOwner.Pawn.Weapon);
MyKFPerk = KFPlayerController(PlayerOwner).GetPerk();
bMonsterPawn = PlayerOwner.GetTeamNum() == 255;
// If our pawn class uses a crosshair regardless of weapon, draw it
KFP = KFPawn( PlayerOwner.Pawn );
bDrawCrosshairNoWeapon = KFP.bNeedsCrosshair;
// Don't draw the crosshair if we're not a monster with a weapon class, or we're not forcing the crosshair for the zed without a weapon
if( bMonsterPawn )
{
if( !bDrawCrosshairNoWeapon )
{
return;
}
}
// Don't draw the crosshair if we don't have a weapon, or are using ironsights
if( !bDrawCrosshairNoWeapon )
{
if( (!bMonsterPawn && MyKFPerk == none) || KFWP == none || !bForceDrawCrosshair && (KFWP.bUsingSights /*|| KFWP.bResting*/) )
{
return;
}
// Skip if weapon is missing spread settings
if ( KFWP.Spread.Length == 0 && !bForceDrawCrosshair && !KFWP.bForceCrosshair)
{
return;
}
}
// Don't draw the crosshair if our special move won't allow it
if( KFP.IsDoingSpecialMove() && !KFP.SpecialMoves[KFP.SpecialMove].CanDrawCrosshair() )
{
return;
}
if (KFWP != none)
{
TargetCrossHairMod = (1.f + KFWP.GetUpgradedSpread()) ** 2;
}
else
{
TargetCrossHairMod = 1.0;
}
// Have the crosshair really small if we are forcing it for debugging
if( bForceDrawCrosshair )
{
TargetCrossHairMod = 0.0000001;
}
else if( bDrawCrosshairNoWeapon )
{
// Just picked a number for zeds
TargetCrossHairMod = 0.4;
}
// Scale up the crosshair if the player is focusing - TODO: make this more precise based on FOV
/*if( KFPlayerController(PlayerOwner) != none && KFPlayerController(PlayerOwner).bIsFocusing )
{
TargetCrossHairMod *= 2.15;
}*/
if( KFWP != none )
{
if( !bForceDrawCrosshair && !KFWP.bForceCrosshair)
{
WeaponAccuracyAdjust = EvalInterpCurveFloat(CrosshairAccuracyScale, KFWP.GetUpgradedSpread());
// Scale spread based on weapon accuracy
TargetCrossHairMod *= WeaponAccuracyAdjust;
}
WeaponRecoilMod = KFWP.RecoilPitchPercentage > KFWP.RecoilYawPercentage ? KFWP.RecoilPitchPercentage : KFWP.RecoilYawPercentage;
// Scale up the recoil spread based on how far away the weapon has rotated from center due to recoil
WeaponRecoilAdjust = Lerp(1.0,2.5,WeaponRecoilMod);
// Scale spread based on weapon recoil
TargetCrossHairMod *= WeaponRecoilAdjust;
}
// Figure out the crosshair spread based on the pawn and weapon's state
if ( MyKFPerk == none || !MyKFPerk.IsShootAndMoveActive() )
{
if( PlayerOwner.Pawn.Physics == PHYS_Falling )
{
if( KFWP == none )
{
TargetCrossHairMod *= class'KFWeapon'.default.FallingRecoilModifier;
}
else
{
TargetCrossHairMod *= KFWP.FallingRecoilModifier;
}
}
else if( KFP != none && KFP.bIsSprinting )
{
TargetCrossHairMod *= 3.0;
}
else
{
if( PlayerOwner.Pawn.bIsCrouched )
{
if( KFWP == none )
{
TargetCrossHairMod *= class'KFWeapon'.default.CrouchSpreadMod;
}
else
{
TargetCrossHairMod *= KFWP.CrouchSpreadMod;
}
}
if( VSizeSq(PlayerOwner.Pawn.Velocity) > 50 && (KFWP == none || !KFWP.bZoomingOut) )
{
if( KFWP == none )
{
TargetCrossHairMod *= class'KFWeapon'.default.JoggingRecoilModifier;
}
else if( !KFWP.bZoomingOut )
{
TargetCrossHairMod *= KFWP.JoggingRecoilModifier;
}
}
if( MyKFPerk != none )
{
MyKFPerk.ModifySpread(TargetCrossHairMod);
}
}
}
// Blend the crosshair spread in
if( CurrentCrossHairMod > TargetCrossHairMod )
{
CurrentCrossHairMod -= RenderDelta * 6.0;
if( CurrentCrossHairMod < TargetCrossHairMod )
{
CurrentCrossHairMod = TargetCrossHairMod;
}
}
else if( CurrentCrossHairMod < TargetCrossHairMod )
{
CurrentCrossHairMod += RenderDelta * 6.0;
if( CurrentCrossHairMod > TargetCrossHairMod )
{
CurrentCrossHairMod = TargetCrossHairMod;
}
}
// Set the stock crosshair spread and scale it based on screen resolution
CrosshairSize *= RatioY;
CrossHairSpread = BaseCrosshairSize * RatioY * CurrentCrossHairMod;
// Set the crosshair alpha = TODO: Move this to a config?
CrossHairAlpha=210;
// If we're doing crosshair debugging then turn on the center dot
if( bForceDrawCrosshair )
{
// Center
Canvas.SetDrawColor(255, 255, 255, CrossHairAlpha);
Canvas.SetPos(CenterX, CenterY);
Canvas.DrawRect(1, 1);
}
// Left side
// Drop shadow
Canvas.SetDrawColor(0, 0, 0, CrossHairAlpha);
Canvas.SetPos(CenterX - (CrosshairSize + CrossHairSpread) - 1, CenterY - 1);
Canvas.DrawRect(CrosshairSize + 1, 3);
// Crosshair
Canvas.SetDrawColor(255, 255, 255, CrossHairAlpha);
Canvas.SetPos(CenterX - (CrosshairSize + CrossHairSpread), CenterY);
Canvas.DrawRect(CrosshairSize, 1);
// Right side
// Drop shadow
Canvas.SetDrawColor(0, 0, 0, CrossHairAlpha);
Canvas.SetPos(CenterX + CrossHairSpread + 1, CenterY - 1);
Canvas.DrawRect(CrosshairSize + 1, 3);
// Crosshair
Canvas.SetDrawColor(255, 255, 255, CrossHairAlpha);
Canvas.SetPos(CenterX + CrossHairSpread + 1, CenterY);
Canvas.DrawRect(CrosshairSize, 1);
// Top
// Drop shadow
Canvas.SetDrawColor(0, 0, 0, CrossHairAlpha);
Canvas.SetPos(CenterX - 1, CenterY - (CrosshairSize + CrossHairSpread) - 1);
Canvas.DrawRect(3, CrosshairSize + 1);
// Crosshair
Canvas.SetDrawColor(255, 255, 255, CrossHairAlpha);
Canvas.SetPos(CenterX, CenterY - (CrosshairSize + CrossHairSpread));
Canvas.DrawRect(1, CrosshairSize);
// Bottom
// Drop shadow
Canvas.SetDrawColor(0, 0, 0, CrossHairAlpha);
Canvas.SetPos(CenterX - 1, CenterY + CrossHairSpread + 1);
Canvas.DrawRect(3, CrosshairSize + 1);
// Crosshair
Canvas.SetDrawColor(255, 255, 255, CrossHairAlpha);
Canvas.SetPos(CenterX, CenterY + CrossHairSpread + 1);
Canvas.DrawRect(1, CrosshairSize);
}
}
/*
* Complete close of Scoreboard. Fired from Flash
* when the "close" animation is finished.
*/
function OnCloseAnimComplete()
{
}
/*
* Complete open of Scoreboard. Fired from Flash
* when the "open" animation is finished.
*/
function OnOpenAnimComplete()
{
}
/**
* Destroy existing Movies
*/
function RemoveMovies()
{
}
/**
* Toggles visibility of normal in-game HUD
*/
function SetVisible(bool bNewVisible)
{
bShowHUD = bNewVisible;
}
/**
* Called when pause menu is opened
*/
function CloseOtherMenus();
/*
* Toggle the Pause Menu on or off.
*
*/
function TogglePauseMenu()
{
}
/*
* Complete necessary actions for OnPauseMenuClose.
* Fired from Flash.
*/
function CompletePauseMenuClose()
{
}
/* toggles displaying scoreboard (used by console controller)
*/
exec function ReleaseShowScores()
{
}
/**
* Returns the index of the local player that owns this HUD
*/
function int GetLocalPlayerOwnerIndex()
{
return class'Engine'.static.GetEngine().GamePlayers.Find(LocalPlayer(PlayerOwner.Player));
}
/*
* SetShowScores() override to display GFx Scoreboard.
* If the scoreboard has been loaded, this will play the appropriate
* Flash animation.
*/
exec function SetShowScores(bool bEnableShowScores)
{
}
/**
* Toggles display of the leaderboard
*/
exec function ToggleLeaderboard()
{
}
/**
* Displays/closes the leaderboard
*/
exec function SetShowLeaderboard(bool bEnableLeaderboard)
{
}
//Given a input command of the form GBA_ and its mapping store that in a lookup for future use
function DrawToolTip(Canvas Cvs, PlayerController PC, string Command, float X, float Y, float U, float V, float UL, float VL, float ResScale, optional Texture2D IconTexture = default.IconHudTexture, optional float Alpha=1.0)
{
}
function bool CheckCrosshairOnFriendly()
{
return true;
}
simulated function DrawShadowedTile(texture2D Tex, float X, float Y, float XL, float YL, float U, float V, float UL, float VL, Color TileColor, Optional bool bScaleToRes)
{
local Color B;
B = BlackColor;
B.A = TileColor.A;
XL *= (bScaleToRes) ? ResolutionScale : 1.0;
YL *= (bScaleToRes) ? ResolutionScale : 1.0;
Canvas.SetPos(X+1,Y+1);
Canvas.DrawColor = B;
Canvas.DrawTile(Tex,XL,YL,U,V,UL,VL);
Canvas.SetPos(X,Y);
Canvas.DrawColor = TileColor;
Canvas.DrawTile(Tex,XL,YL,U,V,UL,VL);
}
simulated function DrawShadowedStretchedTile(texture2D Tex, float X, float Y, float XL, float YL, float U, float V, float UL, float VL, Color TileColor, Optional bool bScaleToRes)
{
local LinearColor C,B;
C = ColorToLinearColor(TileColor);
B = ColorToLinearColor(BlackColor);
B.A = C.A;
XL *= (bScaleToRes) ? ResolutionScale : 1.0;
YL *= (bScaleToRes) ? ResolutionScale : 1.0;
Canvas.SetPos(X+1,Y+1);
Canvas.DrawTileStretched(Tex,XL,YL,U,V,UL,VL,B);
Canvas.SetPos(X,Y);
Canvas.DrawColor = TileColor;
Canvas.DrawTileStretched(Tex,XL,YL,U,V,UL,VL,C);
}
simulated function DrawShadowedRotatedTile(texture2D Tex, Rotator Rot, float X, float Y, float XL, float YL, float U, float V, float UL, float VL, Color TileColor, Optional bool bScaleToRes)
{
local Color B;
B = BlackColor;
B.A = TileColor.A;
XL *= (bScaleToRes) ? ResolutionScale : 1.0;
YL *= (bScaleToRes) ? ResolutionScale : 1.0;
Canvas.SetPos(X+1,Y+1);
Canvas.DrawColor = B;
Canvas.DrawRotatedTile(Tex,Rot,XL,YL,U,V,UL,VL);
Canvas.SetPos(X,Y);
Canvas.DrawColor = TileColor;
Canvas.DrawRotatedTile(Tex,Rot,XL,YL,U,V,UL,VL);
}
/**
* @brief Main canvas draw function
*/
function DrawHUD()
{
local KFPawn_Human KFPH;
local KFPawn_Scripted KFPS;
local vector ViewLocation, ViewVector, PlayerPartyInfoLocation;
local rotator ViewRotation;
local array<PlayerReplicationInfo> VisibleHumanPlayers;
local array<sHiddenHumanPawnInfo> HiddenHumanPlayers;
local Actor LocActor;
// Draw weapon HUD underneath everything else
if( KFPlayerOwner != none && KFPlayerOwner.Pawn != none && KFPlayerOwner.Pawn.Weapon != none )
{
KFPlayerOwner.Pawn.Weapon.DrawHUD( self, Canvas );
}
super.DrawHUD();
// Cache GRI
if( KFGRI == none )
{
KFGRI = KFGameReplicationInfo( WorldInfo.GRI );
}
// Don't draw canvas HUD in cinematic mode
if( KFPlayerOwner != none && KFPlayerOwner.bCinematicMode )
{
return;
}
LocActor = KFPlayerOwner.ViewTarget != none ? KFPlayerOwner.ViewTarget : KFPlayerOwner;
// Draw the crosshair for casual mode
if( KFPlayerOwner != none && (bDrawCrosshair || bForceDrawCrosshair || KFPlayerOwner.GetTeamNum() == 255) )
{
DrawCrosshair();
}
// Friendly player status
if( PlayerOwner.GetTeamNum() == 0 )
{
if (KFPlayerOwner.bFriendlyUIEnabled)
{
if( KFPlayerOwner != none )
{
KFPlayerOwner.GetPlayerViewPoint( ViewLocation, ViewRotation );
}
ViewVector = vector(ViewRotation);
Canvas.EnableStencilTest(true);
foreach WorldInfo.AllPawns( class'KFPawn_Human', KFPH )
{
if( KFPH.IsAliveAndWell() && KFPH != KFPlayerOwner.Pawn && KFPH.Mesh.SkeletalMesh != none && KFPH.Mesh.bAnimTreeInitialised )
{
PlayerPartyInfoLocation = KFPH.Mesh.GetPosition() + ( KFPH.CylinderComponent.CollisionHeight * vect(0,0,1) );
if(`TimeSince(KFPH.Mesh.LastRenderTime) < 0.2f && Normal(PlayerPartyInfoLocation - ViewLocation) dot ViewVector > 0.f )
{
if( DrawFriendlyHumanPlayerInfo(KFPH) )
{
VisibleHumanPlayers.AddItem( KFPH.PlayerReplicationInfo );
}
else
{
HiddenHumanPlayers.Insert( 0, 1 );
HiddenHumanPlayers[0].HumanPawn = KFPH;
HiddenHumanPlayers[0].HumanPRI = KFPH.PlayerReplicationInfo;
}
}
else
{
HiddenHumanPlayers.Insert( 0, 1 );
HiddenHumanPlayers[0].HumanPawn = KFPH;
HiddenHumanPlayers[0].HumanPRI = KFPH.PlayerReplicationInfo;
}
}
}
foreach WorldInfo.AllPawns(class'KFPawn_Scripted', KFPS)
{
if (KFPS.ShouldShowOnHUD())
{
PlayerPartyInfoLocation = KFPS.Mesh.GetPosition() + (KFPS.CylinderComponent.CollisionHeight * vect(0,0,1));
DrawScriptedPawnInfo(KFPS, Normal(PlayerPartyInfoLocation - ViewLocation) dot ViewVector, `TimeSince(KFPS.Mesh.LastRenderTime) < 0.2f);
}
}
if( !KFGRI.bHidePawnIcons )
{
// Draw hidden players
CheckAndDrawHiddenPlayerIcons( VisibleHumanPlayers, HiddenHumanPlayers );
// Draw last remaining zeds
CheckAndDrawRemainingZedIcons();
if (KFGRI.IsBountyHunt())
{
CheckAndDrawBountyHudIcons();
}
if (KFGRI.IsContaminationMode())
{
// While on trader time we let previsualize the next objective icon, so players can get ready
if (KFGRI.bWaveIsActive == false)
{
if (KFGRI.WaveNum != (KFGRI.WaveMax - 1))
{
CheckDrawContaminationModeObjectiveHUD(ViewLocation, ViewVector);
}
}
else if (KFGRI.ObjectiveInterface != none && KFGRI.ObjectiveInterface.IsActive())
{
//Draw our current objective location
CheckDrawObjectiveHUD(ViewLocation, ViewVector, LocActor);
}
}
else
{
//Draw our current objective location
CheckDrawObjectiveHUD(ViewLocation, ViewVector, LocActor);
}
}
Canvas.EnableStencilTest(false);
}
else
{
if( !KFGRI.bHidePawnIcons )
{
// Draw last remaining zeds
CheckAndDrawRemainingZedIcons();
if (KFGRI.IsBountyHunt())
{
CheckAndDrawBountyHudIcons();
}
}
}
}
}
function CheckDrawContaminationModeObjectiveHUD(vector ViewLocation, vector ViewVector)
{
local float ThisDot;
local vector TargetLocation;
local KFInterface_MapObjective Objective;
Objective = KFInterface_MapObjective(KFGRI.NextObjective);
if (Objective != none)
{
TargetLocation = Objective.GetIconLocation();
ThisDot = Normal((TargetLocation + (class'KFPawn_Human'.default.CylinderComponent.CollisionHeight * vect(0, 0, 1))) - ViewLocation) dot ViewVector;
if (ThisDot > 0)
{
DrawContaminationModeObjectiveHUD();
}
}
}
function CheckDrawObjectiveHUD(vector ViewLocation, vector ViewVector, Actor LocActor)
{
local float ThisDot;
local vector TargetLocation;
if (KFGRI.CurrentObjective != none && KFGRI.ObjectiveInterface != none)
{
KFGRI.ObjectiveInterface.DrawHUD(self, Canvas);
TargetLocation = KFGRI.ObjectiveInterface.GetIconLocation();
ThisDot = Normal((TargetLocation + (class'KFPawn_Human'.default.CylinderComponent.CollisionHeight * vect(0, 0, 1))) - ViewLocation) dot ViewVector;
if (ThisDot > 0 &&
KFGRI.ObjectiveInterface.ShouldShowObjectiveHUD() &&
(!KFGRI.ObjectiveInterFace.HasObjectiveDrawDistance() || VSizeSq(TargetLocation - LocActor.Location) < MaxDrawDistanceObjective))
{
DrawObjectiveHUD();
}
}
}
simulated function DrawPerkIcons(KFPawn_Human KFPH, float PerkIconSize, float PerkIconPosX, float PerkIconPosY, float SupplyIconPosX, float SupplyIconPosY, bool bDropShadow)
{
local byte PrestigeLevel;
local KFPlayerReplicationInfo KFPRI;
local color TempColor;
local float ResModifier;
KFPRI = KFPlayerReplicationInfo(KFPH.PlayerReplicationInfo);
if (KFPRI == none)
{
return;
}
PrestigeLevel = KFPRI.GetActivePerkPrestigeLevel();
ResModifier = WorldInfo.static.GetResolutionBasedHUDScale() * FriendlyHudScale;
if (KFPRI.CurrentVoiceCommsRequest == VCT_NONE && KFPRI.CurrentPerkClass != none && PrestigeLevel > 0)
{
Canvas.SetPos(PerkIconPosX, PerkIconPosY);
Canvas.DrawTile(KFPRI.CurrentPerkClass.default.PrestigeIcons[PrestigeLevel - 1], PerkIconSize, PerkIconSize, 0, 0, 256, 256);
}
if (PrestigeLevel > 0)
{ //icon slot in image is not centered
Canvas.SetPos(PerkIconPosX + (PerkIconSize * (1 - PrestigeIconScale)) / 2, PerkIconPosY + PerkIconSize * 0.05f);
Canvas.DrawTile(KFPRI.GetCurrentIconToDisplay(), PerkIconSize * PrestigeIconScale, PerkIconSize * PrestigeIconScale, 0, 0, 256, 256);
}
else
{
Canvas.SetPos(PerkIconPosX, PerkIconPosY);
Canvas.DrawTile(KFPRI.GetCurrentIconToDisplay(), PerkIconSize, PerkIconSize, 0, 0, 256, 256);
}
if (KFPRI.PerkSupplyLevel > 0 && KFPRI.CurrentPerkClass.static.GetInteractIcon() != none)
{
if (!bDropShadow)
{
if (KFPRI.PerkSupplyLevel == 2)
{
if (KFPRI.bPerkPrimarySupplyUsed && KFPRI.bPerkSecondarySupplyUsed)
{
TempColor = SupplierActiveColor;
}
else if (KFPRI.bPerkPrimarySupplyUsed || KFPRI.bPerkSecondarySupplyUsed)
{
TempColor = SupplierHalfUsableColor;
}
else
{
TempColor = SupplierUsableColor;
}
}
else if (KFPRI.PerkSupplyLevel == 1)
{
TempColor = KFPRI.bPerkPrimarySupplyUsed ? SupplierActiveColor : SupplierUsableColor;
}
Canvas.SetDrawColorStruct(TempColor);
}
Canvas.SetPos(SupplyIconPosX, SupplyIconPosY); //offset so that supplier icon shows up on the correct side of the player's health bar
Canvas.DrawTile(KFPRI.CurrentPerkClass.static.GetInteractIcon(), (PlayerStatusIconSize * 0.75) * ResModifier, (PlayerStatusIconSize * 0.75) * ResModifier, 0, 0, 256, 256);
}
}
/**
* @brief Draws name, perk etc over a human player's head
*
* @param KFPH Human player's pawn
* @return true if draw was successful
*/
simulated function bool DrawFriendlyHumanPlayerInfo( KFPawn_Human KFPH )
{
local float Percentage, PercentageHealth, PercentageHealthMissing, PercentageHealthToRegen;
local float BarHeight, BarLength;
local vector ScreenPos, TargetLocation;
local KFPlayerReplicationInfo KFPRI;
local FontRenderInfo MyFontRenderInfo;
local float FontScale;
local float ResModifier;
local float PerkIconPosX, PerkIconPosY, SupplyIconPosX, SupplyIconPosY, PerkIconSize;
local color CurrentArmorColor, CurrentHealthColor;
local float VIPIconSize, VIPIconPosX, VIPIconPosY;
ResModifier = WorldInfo.static.GetResolutionBasedHUDScale() * FriendlyHudScale;
KFPRI = KFPlayerReplicationInfo(KFPH.PlayerReplicationInfo);
if( KFPRI == none )
{
return false;
}
MyFontRenderInfo = Canvas.CreateFontRenderInfo( true );
BarLength = FMin(PlayerStatusBarLengthMax * (Canvas.ClipX / 1024.f), PlayerStatusBarLengthMax) * ResModifier;
BarHeight = FMin(8.f * (Canvas.ClipX / 1024.f), 8.f) * ResModifier;
TargetLocation = KFPH.Mesh.GetPosition() + ( KFPH.CylinderComponent.CollisionHeight * vect(0,0,2.5f) );
ScreenPos = Canvas.Project( TargetLocation );
if( ScreenPos.X < 0 || ScreenPos.X > Canvas.ClipX || ScreenPos.Y < 0 || ScreenPos.Y > Canvas.ClipY )
{
return false;
}
//Draw player name (Top)
FontScale = class'KFGameEngine'.Static.GetKFFontScale() * FriendlyHudScale;
Canvas.Font = class'KFGameEngine'.Static.GetKFCanvasFont();
// drop shadow for player name text
Canvas.SetDrawColorStruct(PlayerBarShadowColor);
Canvas.SetPos(ScreenPos.X - (BarLength * 0.5f) + 1, ScreenPos.Y - 2.5f * BarHeight + (36 * FontScale * ResModifier) + 1); //KFII-52291: -2.5 is a bit of a magic number, but it works (intuition says it should be 0 if we look at where armor bar is being drawn).
Canvas.DrawText(KFPRI.PlayerName, , FontScale, FontScale, MyFontRenderInfo);
Canvas.SetDrawColorStruct(PlayerBarTextColor);
Canvas.SetPos(ScreenPos.X - (BarLength * 0.5f), ScreenPos.Y - 2.5f * BarHeight + (36 * FontScale * ResModifier)); //KFII-52291: -2.5 is a bit of a magic number, but it works (intuition says it should be 0 if we look at where armor bar is being drawn).
Canvas.DrawText(KFPRI.PlayerName, , FontScale, FontScale, MyFontRenderInfo);
//Draw armor bar
Percentage = FMin(float(KFPH.Armor) / float(KFPH.MaxArmor), 100);
CurrentArmorColor = ClassicPlayerInfo ? ClassicArmorColor : ArmorColor;
DrawKFBar(Percentage, BarLength, BarHeight, ScreenPos.X - (BarLength * 0.5f), ScreenPos.Y + BarHeight + (36 * FontScale * ResModifier), CurrentArmorColor);
//Draw health bar
PercentageHealth = FMin(float(KFPH.Health) / float(KFPH.HealthMax), 100);
CurrentHealthColor = ClassicPlayerInfo ? ClassicHealthColor : HealthColor;
DrawKFBar(PercentageHealth, BarLength, BarHeight, ScreenPos.X - (BarLength * 0.5f), ScreenPos.Y + BarHeight * 2 + (36 * FontScale * ResModifier), CurrentHealthColor);
//Draw health being regenerated bar
PercentageHealthToRegen = FMin(float(KFPH.HealthToRegen) / float(KFPH.HealthMax), 100);
PercentageHealthMissing = FMin((float(KFPH.HealthMax) - float(KFPH.Health)) / float(KFPH.HealthMax), 100);
PercentageHealthToRegen = FMin(PercentageHealthToRegen, PercentageHealthMissing);
CurrentHealthColor = HealthBeingRegeneratedColor;
DrawKFBar(1, PercentageHealthToRegen * BarLength, BarHeight, ScreenPos.X + BarLength * (PercentageHealth - 0.5f), ScreenPos.Y + BarHeight * 2 + (36 * FontScale * ResModifier), HealthBeingRegeneratedColor);
if (KFGRI != none
&& KFGRI.IsVIPMode()
&& KFPH.PlayerReplicationInfo != none
&& KFGRI.VIPModeData.VIPPlayer != none
&& KFPH.PlayerReplicationInfo == KFGRI.VIPModeData.VIPPlayer)
{
// Draw VIP Icon
VIPIconSize = OriginalVIPIconSize * ResModifier;
VIPIconPosX = ScreenPos.X - VIPIconSize * 0.5f;
VIPIconPosY = ScreenPos.Y - 2.5f * BarHeight + (36 * FontScale * ResModifier) - 20.f * ResModifier - VIPIconSize * 0.5f - 1.f;
DrawVIPIcon(VIPIconSize , VIPIconPosX, VIPIconPosY);
}
if( KFPRI.CurrentPerkClass == none )
{
return false;
}
// drop shadow for perk name text
Canvas.SetDrawColorStruct(PlayerBarShadowColor);
Canvas.SetPos(ScreenPos.X - (BarLength * 0.5f) + 1, ScreenPos.Y + BarHeight * 3 + (36 * FontScale * ResModifier) + 1);
Canvas.DrawText(KFPRI.GetActivePerkLevel() @KFPRI.CurrentPerkClass.default.PerkName, , FontScale, FontScale, MyFontRenderInfo);
//Draw perk level and name text
Canvas.SetDrawColorStruct(PlayerBarTextColor);
Canvas.SetPos(ScreenPos.X - (BarLength * 0.5f), ScreenPos.Y + BarHeight * 3 + (36 * FontScale * ResModifier));
Canvas.DrawText(KFPRI.GetActivePerkLevel() @KFPRI.CurrentPerkClass.default.PerkName, , FontScale, FontScale, MyFontRenderInfo);
// drop shadow for perk icon
Canvas.SetDrawColorStruct(PlayerBarShadowColor);
PerkIconSize = PlayerStatusIconSize * ResModifier;
PerkIconPosX = ScreenPos.X - (BarLength * 0.5f) - PerkIconSize + 1;
PerkIconPosY = ScreenPos.Y + (36 * FontScale * ResModifier) + 1;
SupplyIconPosX = ScreenPos.X + (BarLength * 0.5f) + 1;
SupplyIconPosY = PerkIconPosY + 4 * ResModifier;
DrawPerkIcons(KFPH, PerkIconSize, PerkIconPosX, PerkIconPosY, SupplyIconPosX, SupplyIconPosY, true);
//draw perk icon
Canvas.SetDrawColorStruct(PlayerBarIconColor);
PerkIconPosX = ScreenPos.X - (BarLength * 0.5f) - PerkIconSize;
PerkIconPosY = ScreenPos.Y + (36 * FontScale * ResModifier);
SupplyIconPosX = ScreenPos.X + (BarLength * 0.5f);
SupplyIconPosY = PerkIconPosY + 4 * ResModifier;
DrawPerkIcons(KFPH, PerkIconSize, PerkIconPosX, PerkIconPosY, SupplyIconPosX, SupplyIconPosY, false);
return true;
}
simulated function DrawVIPIcon(float VIPIconSize, float VIPIconPosX, float VIPIconPosY)
{
Canvas.SetPos(VIPIconPosX, VIPIconPosY);
Canvas.DrawTile(VIPIconTexture, VIPIconSize, VIPIconSize, 0, 0, 256, 256);
}
simulated function bool DrawScriptedPawnInfo(KFPawn_Scripted KFPS, float NormalizedAngle, bool bRendered)
{
local float Percentage;
local float BarHeight, BarLength;
local vector ScreenPos, TargetLocation;
local float FontScale;
local float ResModifier;
if (KFPS.bHidden)
{
//do not draw a hidden actor
return false;
}
ResModifier = WorldInfo.static.GetResolutionBasedHUDScale() * FriendlyHudScale;
BarLength = FMin(PlayerStatusBarLengthMax * (Canvas.ClipX / 1024.f), PlayerStatusBarLengthMax) * ResModifier;
BarHeight = FMin(8.f * (Canvas.ClipX / 1024.f), 8.f) * ResModifier;
TargetLocation = KFPS.Mesh.GetPosition() + (KFPS.CylinderComponent.CollisionHeight * vect(0,0,2.5f));
ScreenPos = Canvas.Project(TargetLocation);
if (NormalizedAngle > 0)
{
if (ScreenPos.X < 0 || ScreenPos.X > Canvas.ClipX || ScreenPos.Y < 0 || ScreenPos.Y > Canvas.ClipY)
{
ScreenPos.x = Canvas.ClipX - ScreenPos.x;
ScreenPos = GetClampedScreenPosition(ScreenPos);
//return false;
}
else
{
ScreenPos.x = FClamp(ScreenPos.x, PlayerStatusIconSize, Canvas.ClipX - PlayerStatusIconSize);
}
}
else
{
ScreenPos = GetClampedScreenPosition(ScreenPos);
}
//Draw health bar
FontScale = class'KFGameEngine'.Static.GetKFFontScale() * FriendlyHudScale;
Percentage = FMin(float(KFPS.Health) / float(KFPS.HealthMax), 1);
// Make sure that the entire health bar is on screen
ScreenPos.X = FClamp(ScreenPos.X, BarLength * 0.5f, Canvas.ClipX - BarLength * 0.5f);
DrawKFBar(Percentage, BarLength, BarHeight, ScreenPos.X - (BarLength * 0.5f), ScreenPos.Y + BarHeight * 2 + (36 * FontScale * ResModifier), GetHealthStateColor(KFPS));
if (KFGRI != none && KFGRI.ObjectiveInterface != none)
{
Canvas.SetDrawColorStruct(PlayerBarShadowColor);
}
Canvas.SetPos(ScreenPos.X - PlayerStatusIconSize * ResModifier * 0.5f + 1, ScreenPos.Y - (PlayerStatusIconSize * ResModifier) + 1);
Canvas.DrawTile(KFPS.GetStateIconTexture(), PlayerStatusIconSize * ResModifier, PlayerStatusIconSize * ResModifier, 0, 0, 256, 256);
if (KFGRI != none && KFGRI.ObjectiveInterface != none)
{
Canvas.SetDrawColorStruct(KFGRI.ObjectiveInterface.GetIconColor());
}
Canvas.SetPos(ScreenPos.X - PlayerStatusIconSize * ResModifier * 0.5f, ScreenPos.Y - (PlayerStatusIconSize * ResModifier));
Canvas.DrawTile(KFPS.GetStateIconTexture(), PlayerStatusIconSize * ResModifier, PlayerStatusIconSize * ResModifier, 0, 0, 256, 256);
return true;
}
simulated function color GetHealthStateColor(const out KFPawn_Scripted KFPS)
{
if (KFPS != none)
{
return KFPS.ScriptedCharArch.States[KFPS.CurrentState].PawnHealthBarColor;
}
}
simulated function bool DrawContaminationModeObjectiveHUD()
{
local float IconCenteringLength;
local vector ScreenPos, TargetLocation;
local float ResModifier;
local KFInterface_MapObjective Objective;
Objective = KFInterface_MapObjective(KFGRI.NextObjective);
ResModifier = WorldInfo.static.GetResolutionBasedHUDScale() * FriendlyHudScale;
TargetLocation = Objective.GetIconLocation();
ScreenPos = Canvas.Project( TargetLocation );
// if not using the progress bar, center the remaining icon
IconCenteringLength = PlayerStatusIconSize * ResModifier * 0.5;
if (Objective.GetIcon() != none)
{
Canvas.SetDrawColorStruct(PlayerBarShadowColor);
Canvas.SetPos((ScreenPos.X - IconCenteringLength) + 1, ScreenPos.Y + 1);
Canvas.DrawTile(Objective.GetIcon(), PlayerStatusIconSize * ResModifier, PlayerStatusIconSize * ResModifier, 0, 0, 256, 256);
Canvas.SetDrawColorStruct(Objective.GetIconColor());
Canvas.SetPos(ScreenPos.X - IconCenteringLength, ScreenPos.Y);
Canvas.DrawTile(Objective.GetIcon(), PlayerStatusIconSize * ResModifier, PlayerStatusIconSize * ResModifier, 0, 0, 256, 256);
}
return true;
}
simulated function bool DrawObjectiveHUD()
{
local float Percentage;
local float BarHeight, BarLength, IconCenteringLength;
local vector ScreenPos, TargetLocation;
local float ResModifier;
ResModifier = WorldInfo.static.GetResolutionBasedHUDScale() * FriendlyHudScale;
//Get actor from GRI
if(KFGRI.ObjectiveInterface == none)
{
return false;
}
if (!KFGRI.ObjectiveInterface.ShouldDrawIcon())
{
return false;
}
TargetLocation = KFGRI.ObjectiveInterface.GetIconLocation();
ScreenPos = Canvas.Project( TargetLocation );
if( ScreenPos.X < 0 || ScreenPos.X > Canvas.ClipX || ScreenPos.Y < 0 || ScreenPos.Y > Canvas.ClipY )
{
//if it is off screen, do not render
return false;
}
//Draw progress bar
if (KFGRI.ObjectiveInterface.UsesProgress())
{
BarLength = FMin(PlayerStatusBarLengthMax * (Canvas.ClipX / 1024.f), PlayerStatusBarLengthMax) * ResModifier;
BarHeight = FMin(8.f * (Canvas.ClipX / 1024.f), 8.f) * ResModifier;
Percentage = FMin(KFGRI.ObjectiveInterface.GetProgress(), 1);
DrawKFBar(Percentage, BarLength, BarHeight, ScreenPos.X - (BarLength * 0.5f), ScreenPos.Y, NonPlayerHealth);
}
else
{
// if not using the progress bar, center the remaining icon
IconCenteringLength = PlayerStatusIconSize * ResModifier * 0.5;
}
//draw objective icon
if (KFGRI.ObjectiveInterface.GetIcon() != none)
{
Canvas.SetDrawColorStruct(PlayerBarShadowColor);
Canvas.SetPos((ScreenPos.X - (BarLength * 0.75) - IconCenteringLength) + 1, (ScreenPos.Y - BarHeight * 2.0) + 1);
Canvas.DrawTile(KFGRI.ObjectiveInterface.GetIcon(), PlayerStatusIconSize * ResModifier, PlayerStatusIconSize * ResModifier, 0, 0, 256, 256);
Canvas.SetDrawColorStruct(KFGRI.ObjectiveInterface.GetIconColor());
Canvas.SetPos(ScreenPos.X - (BarLength * 0.75) - IconCenteringLength, ScreenPos.Y - BarHeight * 2.0);
Canvas.DrawTile(KFGRI.ObjectiveInterface.GetIcon(), PlayerStatusIconSize * ResModifier, PlayerStatusIconSize * ResModifier, 0, 0, 256, 256);
}
return true;
}
/**
* @brief Generic function to draw health and armor bars
*
* @param BarPercentage Fill percentage
* @param BarLength total length
* @param BarHeight total height
* @param XPos Horizontal screen position
* @param YPos Vertical screen position
* @param BarColor The bar's foreground color
*/
simulated function DrawKFBar( float BarPercentage, float BarLength, float BarHeight, float XPos, float YPos, Color BarColor )
{
//background for status bar
Canvas.SetDrawColorStruct(PlayerBarBGColor);
Canvas.SetPos(XPos, YPos);
Canvas.DrawTile(PlayerStatusBarBGTexture, BarLength, BarHeight, 0, 0, 32, 32);
//Forground for status bar.
Canvas.SetDrawColorStruct(BarColor);
Canvas.SetPos(XPos, YPos + 1); // Adjust pos for border
Canvas.DrawTile(PlayerStatusBarBGTexture, (BarLength - 2.0) * BarPercentage, BarHeight - 2.0, 0, 0, 32, 32);
}
/**
* @brief Checks if hidden player's icon should be drawn
*
* @param VisibleHumanPlayers A list of visible players
* @param HiddenHumanPlayers A list of hidden players
*/
simulated function CheckAndDrawHiddenPlayerIcons( array<PlayerReplicationInfo> VisibleHumanPlayers, array<sHiddenHumanPawnInfo> HiddenHumanPlayers )
{
local int i, HiddenHumanIndex;
local PlayerReplicationInfo PRI;
local vector ViewLocation, ViewVector, PawnLocation;
local rotator ViewRotation;
local KFPlayerReplicationInfo KFPRI;
// GRI hasn't replicated yet
if( WorldInfo.GRI == none )
{
return;
}
if( KFPlayerOwner.PlayerCamera != none )
{
KFPlayerOwner.PlayerCamera.GetCameraViewPoint( ViewLocation, ViewRotation );
}
ViewVector = vector(ViewRotation);
for( i = 0; i < WorldInfo.GRI.PRIArray.Length; i++ )
{
PawnLocation = vect(0,0,0);
// Avoid casting until we've got some simple checks out of the way
PRI = WorldInfo.GRI.PRIArray[i];
if( VisibleHumanPlayers.Find( PRI ) != INDEX_NONE ||
KFPlayerOwner.PlayerReplicationInfo == PRI ||
PRI.GetTeamNum() == 255 )
{
continue;
}
// Use the real pawn location if the pawn is still relevant
HiddenHumanIndex = HiddenHumanPlayers.Find( 'HumanPRI', PRI );
if( HiddenHumanIndex != INDEX_NONE
&& HiddenHumanPlayers[HiddenHumanIndex].HumanPawn != none
&& HiddenHumanPlayers[HiddenHumanIndex].HumanPawn.Mesh.SkeletalMesh != none
&& HiddenHumanPlayers[HiddenHumanIndex].HumanPawn.Mesh.bAnimTreeInitialised )
{
PawnLocation = HiddenHumanPlayers[HiddenHumanIndex].HumanPawn.Mesh.GetPosition();
KFPRI = KFPlayerReplicationInfo( PRI );
if( KFPRI != none )
{
KFPRI.SetSmoothedPawnIconLocation( PawnLocation );
}
}
// Otherwise we'll use our replicated location
if( IsZero(PawnLocation) )
{
KFPRI = KFPlayerReplicationInfo( PRI );
if( KFPRI != none )
{
PawnLocation = KFPRI.GetSmoothedPawnIconLocation( HumanPlayerIconInterpMult );
if( IsZero(PawnLocation) || KFPRI.PlayerHealth <= 0 )
{
continue;
}
}
else
{
continue;
}
}
DrawHiddenHumanPlayerIcon(PRI, PawnLocation, ViewLocation, ViewVector);
}
}
/**
* @brief Draws an icon when human players are hidden but in the field of view
*
* @param PRI Player's PlayerReplicationInfo
* @param IconWorldLocation The "player's" location in the world
* @Note:This is the one we want to clamp
*/
function DrawHiddenHumanPlayerIcon(PlayerReplicationInfo PRI, vector IconWorldLocation, vector ViewLocation, vector ViewVector)
{
local vector ReferencePosition, UpVector, ScreenPos, VIPIconPos, ViewLeftVector;
local float IconSizeMult;
local KFPlayerReplicationInfo KFPRI;
local Texture2D PlayerIcon;
local float ResModifier;
local float VIPIconSize;
local float NormalizedAngle, NormalizedAngleWithLeftView;
ResModifier = WorldInfo.static.GetResolutionBasedHUDScale() * FriendlyHudScale;
KFPRI = KFPlayerReplicationInfo(PRI);
if( KFPRI == none )
{
return;
}
ReferencePosition = IconWorldLocation + (class'KFPawn_Human'.default.CylinderComponent.CollisionHeight * vect(0, 0, 2));
NormalizedAngle = Normal(ReferencePosition - ViewLocation) dot ViewVector;
ScreenPos = Canvas.Project(ReferencePosition);
if (KFGRI != none
&& KFGRI.IsVIPMode()
&& KFGRI.VIPModeData.VIPPlayer != none
&& PRI != none
&& PRI == KFGRI.VIPModeData.VIPPlayer)
{
VIPIconSize = OriginalVIPIconSize * ResModifier;
VIPIconPos = ScreenPos;
VIPIconPos.X -= VIPIconSize * 0.5f;
// If the player is on front of you
if (NormalizedAngle > 0)
{
// Adjust on X
if (ScreenPos.X < 0 || ScreenPos.X > (Canvas.ClipX - VIPIconSize))
{
if (ScreenPos.X < 0)
{
VIPIconPos.X = 0;
}
else
{
VIPIconPos.X = Canvas.ClipX - VIPIconSize;
}
}
// Adjust on Y
if (ScreenPos.Y < 0 || ScreenPos.Y > (Canvas.ClipY - VIPIconSize))
{
if (ScreenPos.Y < 0)
{
VIPIconPos.Y = 0;
}
else
{
VIPIconPos.Y = Canvas.ClipY - VIPIconSize;
}
}
}
// If the player is behind you
else
{
// New to know if Player is on your left or on your right side..
UpVector.Z = 1;
ViewLeftVector = ViewVector cross UpVector;
NormalizedAngleWithLeftView = Normal(ReferencePosition - ViewLocation) dot ViewLeftVector;
// The X position clamps between minimum and maximum, we don't interpolate in the middle as it makes more difficult for the player to understand
// Where the VIP is
// Adjust on X
if (NormalizedAngleWithLeftView > 0)
{
VIPIconPos.X = 0;
}
else
{
VipIconPos.X = Canvas.ClipX - VIPIconSize;
}
// Adjust on Y
if (ScreenPos.Y < 0 || ScreenPos.Y > (Canvas.ClipY - VIPIconSize))
{
if (ScreenPos.Y < 0)
{
VIPIconPos.Y = 0;
}
else
{
VIPIconPos.Y = Canvas.ClipY - VIPIconSize;
}
}
}
Canvas.SetDrawColorStruct(PlayerBarIconColor);
DrawVIPIcon(VIPIconSize, VIPIconPos.X, VIPIconPos.Y);
}
// Fudge by icon size
IconSizeMult = (PlayerStatusIconSize * 0.8) * ResModifier;
ScreenPos.X -= IconSizeMult;
ScreenPos.Y -= IconSizeMult;
if (NormalizedAngle > 0)
{
if (ScreenPos.X < 0 || ScreenPos.X > Canvas.ClipX || ScreenPos.Y < 0 || ScreenPos.Y > Canvas.ClipY )
{
if (KFPRI.CurrentVoiceCommsRequest != VCT_NONE)
{
if (CurrentVoiceCommsHighlightAlpha >= 255)
{
CurrentAlphaDelta = -5;
}
else if (CurrentVoiceCommsHighlightAlpha <= 0)
{
CurrentAlphaDelta = 5;
}
ScreenPos.X = Canvas.ClipX - ScreenPos.x;
ScreenPos = GetClampedScreenPosition(ScreenPos);
CurrentVoiceCommsHighlightAlpha += CurrentAlphaDelta;
clamp(CurrentVoiceCommsHighlightAlpha, 0, 255);
Canvas.SetDrawColor(255, 255, 255, CurrentVoiceCommsHighlightAlpha);
Canvas.SetPos(ScreenPos.X - (IconSizeMult * VoiceCommsIconHighlightScale / 2), ScreenPos.Y - (IconSizeMult * VoiceCommsIconHighlightScale / 2));
Canvas.DrawTile(IconHighLightTexture, IconSizeMult + (IconSizeMult * VoiceCommsIconHighlightScale), IconSizeMult + (IconSizeMult * VoiceCommsIconHighlightScale), 0, 0, 128, 128);
}
else
{
return;
}
}
}
else if (KFPRI.CurrentVoiceCommsRequest != VCT_NONE)
{
if (CurrentVoiceCommsHighlightAlpha >= 255)
{
CurrentAlphaDelta = -5;
}
else if (CurrentVoiceCommsHighlightAlpha <= 0)
{
CurrentAlphaDelta = 5;
}
CurrentVoiceCommsHighlightAlpha += CurrentAlphaDelta;
clamp(CurrentVoiceCommsHighlightAlpha, 0, 255);
ScreenPos = GetClampedScreenPosition(ScreenPos);
Canvas.SetDrawColor(255, 255, 255, CurrentVoiceCommsHighlightAlpha);
Canvas.SetPos(ScreenPos.X - (IconSizeMult * VoiceCommsIconHighlightScale / 2), ScreenPos.Y - (IconSizeMult * VoiceCommsIconHighlightScale / 2));
Canvas.DrawTile(IconHighLightTexture, IconSizeMult + (IconSizeMult * VoiceCommsIconHighlightScale), IconSizeMult + (IconSizeMult * VoiceCommsIconHighlightScale), 0, 0, 128, 128);
}
else
{
return;
}
PlayerIcon = PlayerOwner.GetTeamNum() == 0 ? KFPRI.GetCurrentIconToDisplay() : GenericHumanIconTexture;
// Draw human icon
Canvas.SetDrawColor(0, 0, 0, 255);
Canvas.SetPos(ScreenPos.X + 1, ScreenPos.Y + 1);
Canvas.DrawTile(PlayerIcon, IconSizeMult, IconSizeMult, 0, 0, 256, 256);
Canvas.SetDrawColor(255, 255, 255, 192);
Canvas.SetPos( ScreenPos.X, ScreenPos.Y );
Canvas.DrawTile( PlayerIcon, IconSizeMult, IconSizeMult, 0, 0, 256, 256 );
}
//These will be clamped
/** Draws icons for the last few remaining zeds */
function CheckAndDrawRemainingZedIcons()
{
local Pawn P;
local vector ViewLocation, ViewDir, PawnLocation;
local rotator ViewRotation;
local KFPawn_Monster Monster;
if( KFGRI == none
|| KFPlayerOwner == none
|| KFPlayerOwner.PlayerCamera == none
|| KFGRI.IsBossWave()
|| KFGRI.IsEndlessWave()
|| KFGRI.AIRemaining > class'KFGameInfo'.static.GetNumAlwaysRelevantZeds())
{
return;
}
KFPlayerOwner.PlayerCamera.GetCameraViewPoint( ViewLocation, ViewRotation );
ViewDir = vector( ViewRotation );
foreach WorldInfo.AllPawns( class'Pawn', P )
{
// Only draw hidden pawns
if( P.Mesh.SkeletalMesh == none
|| !P.Mesh.bAnimTreeInitialised
|| P.GetTeamNum() == PlayerOwner.GetTeamNum()
|| !P.IsAliveAndWell() )
//|| `TimeSince(P.Mesh.LastRenderTime) < 0.2f )
{
continue;
}
Monster = KFPawn_Monster(P);
if (Monster != none && Monster.bIsBountyHuntObjective)
{
continue;
}
PawnLocation = P.Mesh.GetPosition();
DrawZedIcon( P, PawnLocation
, Normal((PawnLocation + (P.CylinderComponent.CollisionHeight * vect(0, 0, 1))) - ViewLocation) dot ViewDir
, ZedIconColor, 1.f);
}
}
function CheckAndDrawBountyHudIcons()
{
local KFPawn_Monster Monster;
local vector ViewLocation, ViewDir, PawnLocation;
local rotator ViewRotation;
local color ZedColor;
local float WaveProgress;
if( KFGRI == none
|| KFPlayerOwner == none
|| KFPlayerOwner.PlayerCamera == none
|| KFGRI.IsBossWave()
|| KFGRI.IsEndlessWave())
{
return;
}
KFPlayerOwner.PlayerCamera.GetCameraViewPoint( ViewLocation, ViewRotation );
ViewDir = vector( ViewRotation );
if (KFGRI.WaveTotalAICount > 0)
{
WaveProgress = float(KFGRI.AIRemaining) / float(KFGRI.WaveTotalAICount);
}
else
{
WaveProgress = 1.f;
}
foreach WorldInfo.AllPawns( class'KFPawn_Monster', Monster )
{
if (Monster.bIsBountyHuntObjective == false)
{
continue;
}
if (Monster.IsAliveAndWell() == false)
{
continue;
}
if (Monster.Mesh.SkeletalMesh != none
&& Monster.Mesh.bAnimTreeInitialised)
{
PawnLocation = Monster.Mesh.GetPosition();
}
else
{
PawnLocation = Monster.Location;
}
ZedColor = ZedIconColor;
if (Monster.bIsBountyHuntOnLastTier)
{
// Red (R = 255, G = 0, B = 0, A = 192)
ZedColor.R = 255;
ZedColor.G = 0;
ZedColor.B = 0;
}
else if (WaveProgress < 0.5f)
{
// Orange (R = 255, G = 128, B = 0, A = 192)
ZedColor.R = 255;
ZedColor.G = 128;
ZedColor.B = 0;
}
else
{
// Yellow (R = 255, G = 255, B = 0, A = 192)
ZedColor.R = 255;
ZedColor.G = 255;
ZedColor.B = 0;
}
DrawZedIcon( Monster, PawnLocation
, Normal((PawnLocation + (Monster.CylinderComponent.CollisionHeight * vect(0, 0, 1))) - ViewLocation) dot ViewDir
, ZedColor, 1.5f);
}
}
/** Draws a zed icon */
function DrawZedIcon( Pawn ZedPawn, vector PawnLocation, float NormalizedAngle, color ColorToUse, float SizeMultiplier )
{
local vector ScreenPos, TargetLocation;
local float IconSizeMult;
local float ResModifier;
ResModifier = WorldInfo.static.GetResolutionBasedHUDScale() * FriendlyHudScale;
TargetLocation = PawnLocation + ( vect(0,0,2.5f) * ZedPawn.CylinderComponent.CollisionHeight );
ScreenPos = Canvas.Project( TargetLocation );
IconSizeMult = PlayerStatusIconSize * ResModifier * 0.5f * SizeMultiplier;
ScreenPos.X -= IconSizeMult;
ScreenPos.Y -= IconSizeMult;
if (NormalizedAngle > 0)
{
if (ScreenPos.X < 0 || ScreenPos.X > Canvas.ClipX || ScreenPos.Y < 0 || ScreenPos.Y > Canvas.ClipY)
{
ScreenPos.x = Canvas.ClipX - ScreenPos.x;
ScreenPos = GetClampedScreenPosition(ScreenPos);
}
else
{
ScreenPos.x = FClamp(ScreenPos.x, PlayerStatusIconSize, Canvas.ClipX - (PlayerStatusIconSize));
}
}
else
{
ScreenPos = GetClampedScreenPosition(ScreenPos);
}
// Draw boss icon
Canvas.SetDrawColorStruct( ColorToUse );
Canvas.SetPos( ScreenPos.X, ScreenPos.Y );
Canvas.DrawTile( GenericZedIconTexture, IconSizeMult, IconSizeMult, 0, 0, 128, 128 );
}
simulated function vector GetClampedScreenPosition(vector OldScreenPosition)
{
local vector ScreenPos;
local float ResModifier;
local float YRange;
YRange = MaxScreenClampPos * Canvas.ClipY - MinScreenClampPos * Canvas.ClipY;
ResModifier = WorldInfo.static.GetResolutionBasedHUDScale() * FriendlyHudScale;
ScreenPos.x = OldScreenPosition.x < (Canvas.ClipX / 2) ? Canvas.ClipX - (PlayerStatusIconSize * ResModifier) : PlayerStatusIconSize * ResModifier; //flipped do to being behind you
OldScreenPosition.y = fclamp(OldScreenPosition.y, 0, Canvas.ClipY);
ScreenPos.y = (OldScreenPosition.y / Canvas.ClipY) * YRange + (Canvas.ClipY - YRange) / 2;
return ScreenPos;
}
/*********************************************************************************************
`* Pausing
********************************************************************************************* */
/**
* Pauses or unpauses the game due to main window's focus being lost.
* @param Enable tells whether to enable or disable the pause state
*/
event OnLostFocusPause(bool bEnable)
{
// don't pause or unpause after toggling external UI if we have menus up (menu toggling handles pausing on standalone)
// (see KFPlayerController::OnExternalUIChanged)
if( WorldInfo.NetMode == NM_Standalone && KFPlayerOwner.MyGFxManager.bMenusOpen )
{
return;
}
super.OnLostFocusPause( bEnable );
}
/*********************************************************************************************
`* Debugging
********************************************************************************************* */
/** Add an actor to the list so that it will recieve a PostRenderFor() */
function SetPostRenderingFor( bool bOn, Actor A )
{
if( bOn )
{
A.bPostRenderIfNotVisible = true;
if( !bShowOverlays )
{
SetShowOverlays( true );
}
AddPostRenderedActor(A);
}
else
{
bPostRenderIfNotVisible = default.bPostRenderIfNotVisible;
SetShowOverlays( default.bShowOverlays );
RemovePostRenderedActor(A);
}
}
defaultproperties
{
PrestigeIconScale=0.75f
PulseDuration=0.33
PulseSplit=0.25
PulseMultiplier=0.5
bDrawCrosshair=false
CrosshairAccuracyScale=(Points=((InVal=0.0001,OutVal=0.4),(InVal=0.0095,OutVal=0.5),(InVal=0.015,OutVal=0.65)))
BaseCrosshairSize=50
Text_NoClipShadowed=(bClipText=false,bEnableShadow=true)
ClassicArmorColor=(R=0, G=0, B=255, A=192)
ClassicHealthColor=(R=95, G=210, B=255, A=192)
ArmorColor=(R=0, G=100, B=210, A=192) // slightly less saturated
HealthColor=(R=0, G=192, B=0, A=192) // changed to match 'LightGreenColor'
HealthBeingRegeneratedColor=(R=211, G=211, B=211, A=192)
NonPlayerHealth=(R=0, G=184, B=97, A=192)
PlayerBarBGColor=(R=16, G=16, B=16, A=192) // changed to grey so that depleted health is more obvious. More transparent.
PlayerBarTextColor=(R=255, G=255, B=255, A=192)
PlayerBarIconColor=(R=255, G=255, B=255, A=192)
PlayerBarShadowColor=(R=0, G=0, B=0, A=255)
LightGreenColor=(R=0, G=192, B=0, A=192)
YellowColor=(R=255, G=176, B=0, A=192)
OrangeColor=(R=255, G=96, B=0, A=192)
RedHealthColor=(R=173, G=22, B=17, A=192)
// changes colors to what players generally expect from active/inactive colors
SupplierActiveColor=(R=192, G=192, B=192, A=192) // this actually INACTIVE, not an active color
SupplierUsableColor=(R=0, G=192, B=0, A=192)
SupplierHalfUsableColor=(R=160, G=192, B=0, A=192) // lime green
HumanPlayerIconInterpMult=0.007f
PlayerStatusBarBGTexture=Texture2D'EngineResources.WhiteSquareTexture'
PlayerStatusBarLengthMax = 150.0f;
PlayerStatusIconSize = 32; // 48. slightly smaller to reduce screen clutter
ZedIconColor = (R = 255, G = 255, B = 255, A = 192)
GenericHumanIconTexture = Texture2D'UI_PerkIcons_TEX.UI_Horzine_H_Logo'
GenericZedIconTexture = Texture2D'UI_PerkIcons_TEX.UI_PerkIcon_ZED'
VIPIConTexture = Texture2D'UI_PerkIcons_TEX.UI_Overscreen_vip_icon_'
OriginalVIPIconSize = 64;
IconHighLightTexture = Texture2D'UI_World_TEX.VoicCommsCircleHighlight'
VoiceCommsIconHighlightScale = 0.5f
CurrentVoiceCommsHighlightAlpha=255
MinScreenClampPos=0.1f
MaxScreenClampPos=0.4f
MaxDrawDistanceObjective=100000000.f // 100 meters | squared value for performance reasons
}