Class UI_Scoreboard extends KFGUI_Page; var editinline export KFGUI_RightClickMenu PlayerContext; var KFGUI_List PlayersList; var() float ScoreboardSpacing; var color SBTextColor; var Texture2D HealthIcon; var KFGameReplicationInfo KFGRI; var array PRIList; var ExtPlayerReplicationInfo RightClickPlayer; var int PlayerIndex; var Font SBFont; var transient float SBFontSize,CashXPos,KillsXPos,AssistXPos,PingXPos,SBFontHeight; var transient int InitAdminSize; var KFGUI_Tooltip ToolTipItem; var transient bool bHasSelectedPlayer,bMeAdmin,bShowSpectatorsOnly; function InitMenu() { Super.InitMenu(); HealthIcon = Texture2D(DynamicLoadObject("UI_Objective_Tex.UI_Obj_Healing_Loc",class'Texture2D')); PlayersList = KFGUI_List(FindComponentID('PlayerList')); } function ShowMenu() { local ExtPlayerController PC; local int i; local bool bAdmin; Owner.bAbsorbInput = false; PC = ExtPlayerController(GetPlayer()); bAdmin = PC!=None && (PC.WorldInfo.NetMode!=NM_Client || (PC.PlayerReplicationInfo!=None && PC.PlayerReplicationInfo.bAdmin)); if( PC!=None && (InitAdminSize!=PC.AdminCommands.Length || !bAdmin) ) { InitAdminSize = (bAdmin ? PC.AdminCommands.Length : 0); PlayerContext.ItemRows.Length = 4+InitAdminSize; for( i=0; i0; --i ) { for( j=i-1; j>=0; --j ) if( !InOrder(KFGRI.PRIArray[i],KFGRI.PRIArray[j]) ) { PRI = KFGRI.PRIArray[i]; KFGRI.PRIArray[i] = KFGRI.PRIArray[j]; KFGRI.PRIArray[j] = PRI; } } // Check players. PlayerIndex = -1; NumPlayer = 0; for( i=(KFGRI.PRIArray.Length-1); i>=0; --i ) { KPRI = ExtPlayerReplicationInfo(KFGRI.PRIArray[i]); if( KPRI==None || KPRI.bHiddenUser ) continue; if( KPRI.bOnlySpectator ) { ++NumSpec; continue; } if( KPRI.PlayerHealth>0 && KPRI.PlayerHealthPercent>0 && KPRI.GetTeamNum()==0 ) ++NumAlivePlayer; ++NumPlayer; } PRIList.Length = (bShowSpectatorsOnly ? NumSpec : NumPlayer); j = PRIList.Length; for( i=(KFGRI.PRIArray.Length-1); i>=0; --i ) { KPRI = ExtPlayerReplicationInfo(KFGRI.PRIArray[i]); if( KPRI!=None && bShowSpectatorsOnly==KPRI.bOnlySpectator ) { PRIList[--j] = KPRI; if( KPRI==PC.PlayerReplicationInfo ) PlayerIndex = j; } } // Header font info. DefFont = Owner.CurrentStyle.DefaultFontSize; Canvas.Font = Owner.CurrentStyle.PickFont(DefFont,FontScalar); YL = Owner.CurrentStyle.DefaultHeight; YHeight = YL*5.f; // Draw header. if( Canvas.ClipX<1000 ) { XPos = Canvas.ClipX*0.2; XScale = Canvas.ClipX*0.6; } else { XPos = Canvas.ClipX*0.3; XScale = Canvas.ClipX*0.4; } YPos = Canvas.ClipY*0.05; Canvas.SetDrawColor(128,32,32,FrameOpacity); Owner.CurrentStyle.DrawRectBox(XPos,YPos,XScale*0.75,YHeight,26,1); Canvas.DrawColor = SBTextColor; Y = YPos+10; Canvas.SetPos(XPos+26,Y); Canvas.DrawText(PC.WorldInfo.Title,,FontScalar,FontScalar); Y+=YL; Canvas.SetPos(XPos+26,Y); Canvas.DrawText(KFGRI.ServerName,,FontScalar,FontScalar); if( KFGRI.GameClass!=None ) { Y+=YL; Canvas.SetPos(XPos+26,Y); Canvas.DrawText(KFGRI.GameClass.Default.GameName$" - "$Class'KFCommon_LocalizedStrings'.Static.GetDifficultyString(KFGRI.GameDifficulty),,FontScalar,FontScalar); } Y+=YL; Canvas.SetPos(XPos+26,Y); Canvas.DrawText("Time: "$FormatTimeSM(KFGRI.ElapsedTime)$" | Players: "$NumPlayer$" | Alive: "$NumAlivePlayer$" | Spectators: "$NumSpec,,FontScalar,FontScalar); XPos += XScale*0.75-1; XScale *= 0.25; Canvas.SetDrawColor(18,8,8,FrameOpacity); Owner.CurrentStyle.DrawRectBox(XPos,YPos,XScale,YHeight,26); Canvas.DrawColor = SBTextColor; Canvas.Font = Owner.CurrentStyle.PickFont(DefFont+3,FontScalar); Canvas.TextSize("A",XL,YL,FontScalar,FontScalar); Y = YPos+4; DrawCenteredText("WAVE",XPos+XScale*0.5,Y,FontScalar); Y += YL; DrawCenteredText(KFGRI.WaveNum$"/"$(KFGRI.WaveMax-1),XPos+XScale*0.5,Y,FontScalar*1.1); // Scoreboard title line. Canvas.Font = Owner.CurrentStyle.PickFont(DefFont,FontScalar); YL = Owner.CurrentStyle.DefaultHeight; if( Canvas.ClipX<1000 ) { XPos = Canvas.ClipX*0.175; XScale = Canvas.ClipX*0.65; } else { XPos = Canvas.ClipX*0.25; XScale = Canvas.ClipX*0.5; } YPos += YHeight*1.05; YHeight = YL; if( bShowSpectatorsOnly ) Canvas.SetDrawColor(32,32,128,FrameOpacity); else Canvas.SetDrawColor(128,32,32,FrameOpacity); Owner.CurrentStyle.DrawRectBox(XPos,YPos,XScale,YHeight,16,2); // Calc X offsets CashXPos = XScale*0.5; KillsXPos = XScale*0.7; AssistXPos = XScale*0.8; PingXPos = XScale*0.9; // Header texts Canvas.DrawColor = SBTextColor; Y = YPos+4; Canvas.SetPos(XPos+18,Y); Canvas.DrawText("PLAYER",,FontScalar,FontScalar); if( !bShowSpectatorsOnly ) { Canvas.SetPos(XPos+CashXPos,Y); Canvas.DrawText("DOSH",,FontScalar,FontScalar); DrawCenteredText("KILLS",XPos+KillsXPos,Y,FontScalar); DrawCenteredText("ASSISTS",XPos+AssistXPos,Y,FontScalar); } DrawCenteredText("PING",XPos+PingXPos,Y,FontScalar); // Check how many players to draw. YPos+=(YHeight-1); YHeight = (Canvas.ClipY*0.95) - YPos; i = DefFont+2; while( i>0 ) { Canvas.Font = Owner.CurrentStyle.PickFont(i,SBFontSize); Canvas.TextSize("A",XL,SBFontHeight,SBFontSize,SBFontSize); BoxHeight = SBFontHeight*2.f+ScoreboardSpacing; if( (BoxHeight*PRIList.Length)<=YHeight ) break; --i; } // Scoreboard background. Canvas.SetDrawColor(18,8,8,FrameOpacity); Owner.CurrentStyle.DrawRectBox(XPos,YPos,XScale,YHeight,16); // Setup listing. PlayersList.XPosition = (XPos+8.f) / InputPos[2]; PlayersList.YPosition = (YPos+8.f) / InputPos[3]; PlayersList.XSize = (XScale-16.f) / InputPos[2]; PlayersList.YSize = (YHeight-16.f) / InputPos[3]; PlayersList.ListItemsPerPage = YHeight/BoxHeight; PlayersList.ChangeListSize(PRIList.Length); SBFont = Canvas.Font; } final function Texture2D FindAvatar( UniqueNetId ClientID ) { local string S; S = KFPlayerController(GetPlayer()).GetSteamAvatar(ClientID); if( S=="" ) return None; return Texture2D(FindObject(Mid(S,6),class'Texture2D')); } final function DrawCenteredText( string S, float X, float Y, optional float Scale=1.f ) { local float XL,YL; Canvas.TextSize(S,XL,YL); Canvas.SetPos(X-(XL*Scale*0.5),Y); Canvas.DrawText(S,,Scale,Scale); } static final function string FormatTimeSM( float Sec ) { local int Seconds,Minutes; Sec = Abs(Sec); Seconds = int(Sec); Minutes = Seconds/60; Seconds-=Minutes*60; return Minutes$":"$(Seconds<10 ? "0"$Seconds : string(Seconds)); } function DrawPlayerEntry( Canvas C, int Index, float YOffset, float Height, float Width, bool bFocus ) { local ExtPlayerReplicationInfo PRI; local float XPos,YPos,XL,YL; local string S; if( Index==0 ) { // Setup font info. C.Font = SBFont; } PRI = PRIList[Index]; bFocus = bFocus || (bHasSelectedPlayer && RightClickPlayer==PRI); // Draw name entry background. if( PRI.bOnlySpectator ) // Spectator - blue. { if( bFocus ) C.SetDrawColor(86,86,212,FrameOpacity); else C.SetDrawColor(48,48,164,FrameOpacity); } else if( PRI.Team==None ) // Unteamed - Grey. { if( bFocus ) C.SetDrawColor(86,86,86,FrameOpacity); else C.SetDrawColor(48,48,48,FrameOpacity); } else { switch( PRI.Team.TeamIndex ) { case 0: // Humans - Red. if( bFocus ) C.SetDrawColor(160,48,48,FrameOpacity); else C.SetDrawColor(128,32,32,FrameOpacity); break; default: // Rest - Green. if( bFocus ) C.SetDrawColor(48,160,48,FrameOpacity); else C.SetDrawColor(32,128,32,FrameOpacity); } } if( PRI.PlayerHealth<=0 || PRI.PlayerHealthPercent<=0 ) C.DrawColor = C.DrawColor*0.6; Owner.CurrentStyle.DrawRectBox(0.f,YOffset,Width,Height-ScoreboardSpacing,10); Height-=ScoreboardSpacing; // Draw health bg. if( !bShowSpectatorsOnly ) { if( PRI.PlayerHealth<30 || PRI.PlayerHealthPercent<=0 ) // Chose color based on health. C.SetDrawColor(220,32,32,255); else if( PRI.PlayerHealth<70 ) C.SetDrawColor(220,220,32,255); else C.SetDrawColor(32,225,32,255); Owner.CurrentStyle.DrawRectBox(6.f,YOffset+6,Height-12,Height-12,5); } // Avatar if( PRI.Avatar!=None ) { C.SetDrawColor(255,255,255,255); C.SetPos(Height+4,YOffset+4); C.DrawTile(PRI.Avatar,Height-8,Height-8,0,0,PRI.Avatar.SizeX,PRI.Avatar.SizeY); XPos = Height*2+8; } else { XPos = Height+4; // Try to obtain avatar. if( !PRI.bBot ) PRI.Avatar = FindAvatar(PRI.UniqueId); } // Name C.SetPos(XPos,YOffset+2); if( PlayerIndex==Index ) C.SetDrawColor(128,255,128,255); else C.DrawColor = SBTextColor; YPos = SBFontSize; S = PRI.TaggedPlayerName; if( PRI.ShowAdminName() ) { S = S$" ("$PRI.GetAdminNameAbr()$")"; C.DrawColor = PRI.GetAdminColorC(); } else if( PRI.bIsDev ) { S = S$" (D)"; C.DrawColor = MakeColor(130,255,235,255); } if( bMeAdmin && PRI.FixedData>0 ) { C.DrawColor = MakeColor(255,0,0,255); S = S$" -"$PRI.GetDesc(); } while( true ) // Make sure too long name doesn't overleap. { C.TextSize(S,XL,YL,YPos,YPos); if( (C.CurX+XL)=0 ) { C.DrawColor = SBTextColor; S = "Respawn: "$FormatTimeSM(PRI.RespawnCounter); } while( true ) // Make sure too long name doesn't overleap. { C.TextSize(S,XL,YL,YPos,YPos); if( (C.CurX+XL)=4 ) PC.ConsoleCommand("Admin "$ExtPlayerController(PC).AdminCommands[Index-4].Cmd@RightClickPlayer.PlayerID); } } function ShowPlayerTooltip( int Index ) { local ExtPlayerReplicationInfo PRI; local string S; PRI = PRIList[Index]; if( PRI!=None ) { if( ToolTipItem==None ) { ToolTipItem = New(None)Class'KFGUI_Tooltip'; ToolTipItem.Owner = Owner; ToolTipItem.ParentComponent = Self; ToolTipItem.InitMenu(); } S = "Player: "$PRI.TaggedPlayerName$"|Health: "$(PRI.PlayerHealthPercent<=0 ? "0" : string(PRI.PlayerHealth)); if( PRI.ShowAdminName() ) S = S$"|"$PRI.GetAdminName(); S = S$"|(Right click for options)"; ToolTipItem.SetText(S); ToolTipItem.ShowMenu(); ToolTipItem.CompPos[0] = Owner.MousePosition.X; ToolTipItem.CompPos[1] = Owner.MousePosition.Y; ToolTipItem.GetInputFocus(); } } function ButtonClicked( KFGUI_Button Sender ) { switch( Sender.ID ) { case 'Spec': bShowSpectatorsOnly = !bShowSpectatorsOnly; break; } } defaultproperties { bAlwaysTop=true SBTextColor=(R=250,G=250,B=250,A=255) ScoreboardSpacing=4 Begin Object Class=KFGUI_List Name=PlayerList bDrawBackground=false OnDrawItem=DrawPlayerEntry OnClickedItem=ClickedPlayer ID="PlayerList" bClickable=true OnMouseRest=ShowPlayerTooltip End Object Begin Object Class=KFGUI_Button Name=B_ShowSpecs ID="Spec" ButtonText="Show Spectators" Tooltip="Toggle show server spectators" XPosition=0.67 YPosition=0.95 XSize=0.09 YSize=0.03 OnClickLeft=ButtonClicked OnClickRight=ButtonClicked End Object Components.Add(PlayerList) Components.Add(B_ShowSpecs) Begin Object Class=KFGUI_RightClickMenu Name=PlayerContextMenu ItemRows.Add((Text="Spectate this player")) ItemRows.Add((Text="View player Steam profile")) ItemRows.Add((Text="Mute")) ItemRows.Add((bSplitter=true)) OnSelectedItem=SelectedRCItem OnBecameHidden=HidRightClickMenu End Object PlayerContext=PlayerContextMenu }