rott/kf_sources/ServerPerks/Classes/SRScoreBoard.uc
2026-07-14 20:27:09 +07:00

506 lines
15 KiB
Ucode

class SRScoreBoard extends KFScoreBoard;
#exec TEXTURE IMPORT FILE="Textures\Shield.pcx" NAME="I_AdminShield" GROUP="Icons" MIPS=0 MASKED=1
var bool bDrawLevelDigits;
var byte FrameCounter;
var localized string NotShownInfo,PlayerCountText,SpectatorCountText,AliveCountText,BotText;
simulated static final function Material GetCountryFlag( PlayerReplicationInfo PRI )
{
if( PRI.Skins.Length!=1 )
{
PRI.Skins.Length = 1;
if( Mid(PRI.PlayerName,4,1)=="]" )
PRI.Skins[0] = Material(DynamicLoadObject("CountryFlagsTex."$Mid(PRI.PlayerName,1,3),Class'Material',true));
else PRI.Skins[0] = Material(DynamicLoadObject("CountryFlagsTex."$Mid(PRI.PlayerName,1,2),Class'Material',true));
}
return PRI.Skins[0];
}
simulated static final function float DrawCountryName( Canvas C, PlayerReplicationInfo PRI, float X, float Y, optional byte MaxLen )
{
local float XL,YL,Result;
local Color Cl;
local Material M;
local string S;
if( MaxLen>0 )
S = Left(PRI.PlayerName,MaxLen);
else S = PRI.PlayerName;
if( Mid(S,0,1)=="[" )
{
if( Mid(S,4,1)=="]" )
{
M = GetCountryFlag(PRI);
if( M!=None )
{
C.TextSize("ABC",XL,YL);
Cl = C.DrawColor;
C.DrawColor = Class'HudBase'.Default.WhiteColor;
C.SetPos(X, Y+(YL*0.2));
C.DrawTile(M, YL, YL, 0, 0, M.MaterialUSize(), M.MaterialVSize());
X+=YL;
S = Mid(S,5);
C.DrawColor = Cl;
}
}
else if( Mid(S,3,1)=="]" )
{
M = GetCountryFlag(PRI);
if( M!=None )
{
C.TextSize("ABC",XL,YL);
Cl = C.DrawColor;
C.DrawColor = Class'HudBase'.Default.WhiteColor;
C.SetPos(X, Y+(YL*0.2));
C.DrawTile(M, YL, YL, 0, 0, M.MaterialUSize(), M.MaterialVSize());
X+=YL;
S = Mid(S,4);
C.DrawColor = Cl;
}
}
}
C.SetPos(X, Y);
C.DrawTextClipped(S,false);
C.TextSize(S,Result,XL);
return Result + YL;
}
simulated static final function TextSizeCountry( Canvas C, PlayerReplicationInfo PRI, out float XL, out float YL )
{
local float XS;
local Material M;
local string S;
XL = 0;
S = PRI.PlayerName;
if( Mid(S,0,1)=="[" )
{
if( Mid(S,4,1)=="]" )
{
M = GetCountryFlag(PRI);
if( M!=None )
{
C.TextSize("ABC",XS,YL);
XL = YL;
S = Mid(S,5);
}
}
else if( Mid(S,3,1)=="]" )
{
M = GetCountryFlag(PRI);
if( M!=None )
{
C.TextSize("ABC",XS,YL);
XL = YL;
S = Mid(S,4);
}
}
}
C.TextSize(S,XS,YL);
XL+=XS;
}
simulated static final function DrawProgressBar( Canvas C, float X, float Y, float XS, float YS, float Value )
{
C.DrawColor.A = 64;
C.SetPos(X, Y);
C.DrawTileStretched(Texture'thinpipe_b',XS,YS);
if( Value>0.f )
{
C.DrawColor.A = 150;
C.SetPos(X,Y);
C.DrawTileStretched(Texture'thinpipe_f',XS*Value,YS);
}
}
simulated event UpdateScoreBoard(Canvas Canvas)
{
local PlayerReplicationInfo PRI, OwnerPRI;
local KFPlayerReplicationInfo KFPRI;
local KF_StoryPRI StoryPRI;
local int i, FontReduction, NetXPos, PlayerCount, HeaderOffsetY, HeadFoot, MessageFoot, PlayerBoxSizeY, BoxSpaceY, NameXPos, BoxTextOffsetY, OwnerOffset, HealthXPos, BoxXPos,KillsXPos, TitleYPos, BoxWidth, VetXPos, NotShownCount;
local float XL,YL;
local float deathsXL, KillsXL, NetXL, HealthXL, MaxNamePos, KillWidthX, CashXPos, TimeXPos, PProgressXS, StoryIconXPos;
local Material VeterancyBox,StarBox;
local string S;
local byte Stars;
local KF_StoryObjective CurrentObj;
local Font LvlFont,OrgFont;
if( ++FrameCounter>250 )
{
FrameCounter = 0;
bDrawLevelDigits = !bDrawLevelDigits;
}
OwnerPRI = KFPlayerController(Owner).PlayerReplicationInfo;
OwnerOffset = -1;
for ( i = 0; i < GRI.PRIArray.Length; i++)
{
PRI = GRI.PRIArray[i];
if ( !PRI.bOnlySpectator )
{
if( !PRI.bOutOfLives && KFPlayerReplicationInfo(PRI).PlayerHealth>0 )
++HeadFoot;
if ( PRI == OwnerPRI )
OwnerOffset = i;
PlayerCount++;
}
else ++NetXPos;
}
// First, draw title.
if(KF_StoryGRI(GRI) != none)
{
CurrentObj = KF_StoryGRI(GRI).GetCurrentObjective();
if(CurrentObj != none)
S = CurrentObj.HUD_Header.Header_Text;
}
else S = WaveString @ (InvasionGameReplicationInfo(GRI).WaveNumber + 1);
S = SkillLevel[Clamp(InvasionGameReplicationInfo(GRI).BaseDifficulty, 0, 7)] $ " | " $ S $ " | " $ Level.Title $ " | " $ FormatTime(GRI.ElapsedTime);
Canvas.Font = class'ROHud'.static.GetSmallMenuFont(Canvas);
Canvas.TextSize(S, XL,YL);
Canvas.DrawColor = HUDClass.default.RedColor;
Canvas.Style = ERenderStyle.STY_Normal;
HeaderOffsetY = Canvas.ClipY * 0.11;
Canvas.SetPos(0.5 * (Canvas.ClipX - XL), HeaderOffsetY);
Canvas.DrawTextClipped(S);
// Second title line
S = PlayerCountText@PlayerCount@SpectatorCountText@NetXPos@AliveCountText@HeadFoot;
Canvas.TextSize(S, XL,YL);
HeaderOffsetY+=YL;
Canvas.SetPos(0.5 * (Canvas.ClipX - XL), HeaderOffsetY);
Canvas.DrawTextClipped(S);
HeaderOffsetY+=(YL*3.f);
// Select best font size and box size to fit as many players as possible on screen
if ( Canvas.ClipX < 600 )
i = 4;
else if ( Canvas.ClipX < 800 )
i = 3;
else if ( Canvas.ClipX < 1000 )
i = 2;
else if ( Canvas.ClipX < 1200 )
i = 1;
else i = 0;
Canvas.Font = class'ROHud'.static.LoadMenuFontStatic(i);
Canvas.TextSize("Test", XL, YL);
PlayerBoxSizeY = 1.2 * YL;
BoxSpaceY = 0.25 * YL;
while( ((PlayerBoxSizeY+BoxSpaceY)*PlayerCount)>(Canvas.ClipY-HeaderOffsetY) )
{
if( ++i>=5 || ++FontReduction>=3 ) // Shrink font, if too small then break loop.
{
// We need to remove some player names here to make it fit.
NotShownCount = PlayerCount-int((Canvas.ClipY-HeaderOffsetY)/(PlayerBoxSizeY+BoxSpaceY))+1;
PlayerCount-=NotShownCount;
break;
}
Canvas.Font = class'ROHud'.static.LoadMenuFontStatic(i);
Canvas.TextSize("Test", XL, YL);
PlayerBoxSizeY = 1.2 * YL;
BoxSpaceY = 0.25 * YL;
}
if( bDrawLevelDigits )
{
LvlFont = class'ROHud'.static.LoadMenuFontStatic(i+2);
OrgFont = Canvas.Font;
}
HeadFoot = 7 * YL;
MessageFoot = 1.5 * HeadFoot;
BoxWidth = 0.9 * Canvas.ClipX;
BoxXPos = 0.5 * (Canvas.ClipX - BoxWidth);
BoxWidth = Canvas.ClipX - 2 * BoxXPos;
VetXPos = BoxXPos + 0.0001 * BoxWidth;
NameXPos = VetXPos + PlayerBoxSizeY*1.75f;
StoryIconXPos = BoxXPos + 0.48 * BoxWidth;
KillsXPos = BoxXPos + 0.55 * BoxWidth;
CashXPos = BoxXPos + 0.65 * BoxWidth;
HealthXpos = BoxXPos + 0.75 * BoxWidth;
TimeXPos = BoxXPos + 0.87 * BoxWidth;
NetXPos = BoxXPos + 0.996 * BoxWidth;
PProgressXS = BoxWidth * 0.1f;
// draw background boxes
Canvas.Style = ERenderStyle.STY_Alpha;
Canvas.DrawColor = HUDClass.default.WhiteColor;
Canvas.DrawColor.A = 128;
for ( i = 0; i < PlayerCount; i++ )
{
Canvas.SetPos(BoxXPos, HeaderOffsetY + (PlayerBoxSizeY + BoxSpaceY) * i);
Canvas.DrawTileStretched( BoxMaterial, BoxWidth, PlayerBoxSizeY);
}
if( NotShownCount>0 ) // Add box for not shown players.
{
Canvas.DrawColor = HUDClass.default.RedColor;
Canvas.SetPos(BoxXPos, HeaderOffsetY + (PlayerBoxSizeY + BoxSpaceY) * PlayerCount);
Canvas.DrawTileStretched( BoxMaterial, BoxWidth, PlayerBoxSizeY);
Canvas.DrawColor = HUDClass.default.WhiteColor;
}
// Draw headers
TitleYPos = HeaderOffsetY - 1.1 * YL;
Canvas.TextSize(HealthText, HealthXL, YL);
Canvas.TextSize(DeathsText, DeathsXL, YL);
Canvas.TextSize(KillsText, KillsXL, YL);
Canvas.TextSize(NetText, NetXL, YL);
Canvas.DrawColor = HUDClass.default.WhiteColor;
Canvas.SetPos(NameXPos, TitleYPos);
Canvas.DrawTextClipped(PlayerText);
Canvas.SetPos(KillsXPos - 0.5 * KillsXL, TitleYPos);
Canvas.DrawTextClipped(KillsText);
Canvas.TextSize(PointsText, XL, YL);
Canvas.SetPos(CashXPos - 0.5 * XL, TitleYPos);
Canvas.DrawTextClipped(PointsText);
Canvas.TextSize(TimeText, XL, YL);
Canvas.SetPos(TimeXPos - 0.5 * XL, TitleYPos);
Canvas.DrawTextClipped(TimeText);
Canvas.SetPos(HealthXPos - 0.5 * HealthXL, TitleYPos);
Canvas.DrawTextClipped(HealthText);
Canvas.Style = ERenderStyle.STY_Normal;
Canvas.DrawColor = HUDClass.default.WhiteColor;
Canvas.SetPos(0.5 * Canvas.ClipX, HeaderOffsetY + 4);
Canvas.DrawColor = HUDClass.default.WhiteColor;
Canvas.SetPos(NetXPos - NetXL, TitleYPos);
Canvas.DrawTextClipped(NetText);
BoxTextOffsetY = HeaderOffsetY + 0.5 * (PlayerBoxSizeY - YL);
Canvas.DrawColor = HUDClass.default.WhiteColor;
MaxNamePos = Canvas.ClipX;
Canvas.ClipX = KillsXPos - 4.f;
for ( i = 0; i < PlayerCount; i++ )
{
if( i == OwnerOffset )
{
Canvas.DrawColor.G = 0;
Canvas.DrawColor.B = 0;
}
else
{
Canvas.DrawColor.G = 255;
Canvas.DrawColor.B = 255;
}
DrawCountryName(Canvas,GRI.PRIArray[i],NameXPos,(PlayerBoxSizeY + BoxSpaceY)*i + BoxTextOffsetY);
}
if( NotShownCount>0 ) // Draw not shown info
{
Canvas.DrawColor.G = 255;
Canvas.DrawColor.B = 0;
Canvas.SetPos(NameXPos, (PlayerBoxSizeY + BoxSpaceY)*PlayerCount + BoxTextOffsetY);
Canvas.DrawText(NotShownCount@NotShownInfo,true);
}
Canvas.ClipX = MaxNamePos;
Canvas.DrawColor = HUDClass.default.WhiteColor;
Canvas.Style = ERenderStyle.STY_Normal;
// Draw the player informations.
for ( i = 0; i < PlayerCount; i++ )
{
PRI = GRI.PRIArray[i];
KFPRI = KFPlayerReplicationInfo(PRI);
StoryPRI = KF_StoryPRI(PRI);
Canvas.DrawColor = HUDClass.default.WhiteColor;
// Display admin.
if( PRI.bAdmin && !bDrawLevelDigits )
{
Canvas.SetPos(BoxXPos - PlayerBoxSizeY, (PlayerBoxSizeY + BoxSpaceY) * i + HeaderOffsetY + PlayerBoxSizeY*0.25);
XL = PlayerBoxSizeY*0.5;
Canvas.DrawTile(Texture'I_AdminShield', XL, XL, 0, 0, Texture'I_AdminShield'.USize, Texture'I_AdminShield'.VSize);
}
// display Story Icon
if ( StoryPRI != none )
{
StarBox = StoryPRI.GetFloatingIconMat();
if ( StarBox != none )
{
Canvas.SetPos(StoryIconXPos, (PlayerBoxSizeY + BoxSpaceY) * i + HeaderOffsetY + 1 );
Canvas.DrawTile(StarBox, PlayerBoxSizeY*0.8, PlayerBoxSizeY*0.8, 0, 0, StarBox.MaterialUSize(), StarBox.MaterialVSize());
}
}
// Display perks.
if ( KFPRI!=None && Class<SRVeterancyTypes>(KFPRI.ClientVeteranSkill)!=none )
{
Stars = Class<SRVeterancyTypes>(KFPRI.ClientVeteranSkill).Static.PreDrawPerk(Canvas
,KFPRI.ClientVeteranSkillLevel,VeterancyBox,StarBox);
if ( VeterancyBox != None )
{
YL = HeaderOffsetY+(PlayerBoxSizeY+BoxSpaceY)*i;
DrawPerkWithStars(Canvas,VetXPos,YL,PlayerBoxSizeY,Stars,VeterancyBox,StarBox);
if( bDrawLevelDigits )
{
Canvas.SetPos(BoxXPos,YL);
Canvas.Font = LvlFont;
Canvas.DrawColor = HUDClass.default.GoldColor;
S = "Lv"$string(KFPRI.ClientVeteranSkillLevel);
Canvas.TextSize(S,XL,YL);
Canvas.CurX-=(XL*1.025);
Canvas.CurY+=(PlayerBoxSizeY-YL)*0.5;
Canvas.DrawTextClipped(S);
Canvas.Font = OrgFont;
}
}
Canvas.DrawColor = HUDClass.default.WhiteColor;
// Draw perk progress
if( !PRI.bBot && KFPRI.ThreeSecondScore>=0 )
{
YL = float(KFPRI.ThreeSecondScore) / 10000.f;
DrawProgressBar(Canvas,KillsXPos-PProgressXS*1.5,HeaderOffsetY + (PlayerBoxSizeY + BoxSpaceY) * i + PlayerBoxSizeY*0.4,PProgressXS,PlayerBoxSizeY*0.2,FClamp(YL,0.f,1.f));
Canvas.DrawColor.A = 255;
}
}
// draw kills
if( KFPRI!=None )
{
Canvas.TextSize(KFPRI.Kills, KillWidthX, YL);
Canvas.SetPos(KillsXPos - 0.5 * KillWidthX, (PlayerBoxSizeY + BoxSpaceY) * i + BoxTextOffsetY);
Canvas.DrawTextClipped(KFPRI.Kills);
}
// draw cash
S = string(int(PRI.Score));
Canvas.TextSize(S, XL, YL);
Canvas.SetPos(CashXPos-XL*0.5f, (PlayerBoxSizeY + BoxSpaceY)*i + BoxTextOffsetY);
Canvas.DrawText(S,true);
// draw time
if( GRI.ElapsedTime<PRI.StartTime ) // Login timer error, fix it.
GRI.ElapsedTime = PRI.StartTime;
S = FormatTime(GRI.ElapsedTime-PRI.StartTime);
Canvas.TextSize(S, XL, YL);
Canvas.SetPos(TimeXPos-XL*0.5f, (PlayerBoxSizeY + BoxSpaceY)*i + BoxTextOffsetY);
Canvas.DrawText(S,true);
// Draw ping
if ( !GRI.bMatchHasBegun )
{
if ( PRI.bReadyToPlay )
S = ReadyText;
else S = NotReadyText;
}
else if( !PRI.bBot )
S = string(PRI.Ping*4);
else S = BotText;
Canvas.TextSize(S, XL, YL);
Canvas.SetPos(NetXPos-XL, (PlayerBoxSizeY + BoxSpaceY) * i + BoxTextOffsetY);
Canvas.DrawTextClipped(S);
// draw healths
if ( PRI.bOutOfLives || KFPRI==None || KFPRI.PlayerHealth<=0 )
{
Canvas.DrawColor = HUDClass.default.RedColor;
S = OutText;
}
else
{
if( KFPRI.PlayerHealth>=90 )
Canvas.DrawColor = HUDClass.default.GreenColor;
else if( KFPRI.PlayerHealth>=50 )
Canvas.DrawColor = HUDClass.default.GoldColor;
else Canvas.DrawColor = HUDClass.default.RedColor;
S = KFPlayerReplicationInfo(PRI).PlayerHealth@HealthyString;
}
Canvas.TextSize(S, XL, YL);
Canvas.SetPos(HealthXpos - 0.5 * XL, (PlayerBoxSizeY + BoxSpaceY) * i + BoxTextOffsetY);
Canvas.DrawTextClipped(S);
}
}
simulated final function DrawPerkWithStars( Canvas C, float X, float Y, float Scale, int Stars, Material PerkIcon, Material StarIcon )
{
local byte i;
C.SetPos(X,Y);
C.DrawTile(PerkIcon, Scale, Scale, 0, 0, PerkIcon.MaterialUSize(), PerkIcon.MaterialVSize());
if( Stars==0 || StarIcon==None )
return;
Y+=Scale*0.9f;
X+=Scale*0.8f;
Scale*=0.2f;
while( Stars>0 )
{
for( i=1; i<=Min(5,Stars); ++i )
{
C.SetPos(X,Y-(i*Scale*0.8f));
C.DrawTile(StarIcon, Scale, Scale, 0, 0, StarIcon.MaterialUSize(), StarIcon.MaterialVSize());
}
X+=Scale;
Stars-=5;
}
}
simulated function bool InOrder( PlayerReplicationInfo P1, PlayerReplicationInfo P2 )
{
local KFPlayerReplicationInfo P11,P22;
if( P1.bOnlySpectator )
return P2.bOnlySpectator;
else if ( P2.bOnlySpectator )
return true;
if( P1.Kills < P2.Kills )
return false;
else if( P1.Kills==P2.Kills )
{
P11 = KFPlayerReplicationInfo(P1);
P22 = KFPlayerReplicationInfo(P2);
if( P11==None || P22==None )
{
// Go for dosh
if( P1.Score < P2.Score )
return false;
else if( P1.Score == P2.Score)
return (P1.PlayerName<P2.PlayerName); // Go for name.
}
else
{
// Kills is equal, go for assists.
if( P11.KillAssists < P22.KillAssists )
return false;
else if( P11.KillAssists==P22.KillAssists )
{
// Go for dosh
if( P1.Score < P2.Score )
return false;
else if( P1.Score == P2.Score)
return (P1.PlayerName<P2.PlayerName); // Go for name.
}
}
}
return true;
}
defaultproperties
{
NotShownInfo="player names not shown"
PlayerCountText="Players:"
SpectatorCountText="| Spectators:"
AliveCountText="| Alive players:"
BotText="BOT"
HealthyString="HP"
}