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; var KFGUI_Button SpecButton; var localized string TimeText; var localized string PlayersText; var localized string PlayerText; var localized string AliveText; var localized string SpectatorsText; var localized string HeaderWaveText; var localized string HeaderPlayerText; var localized string HeaderDoshText; var localized string HeaderKillsText; var localized string HeaderAssistText; var localized string HeaderPingText; var localized string NoPerkText; var localized string RespawnText; var localized string BotText; var localized string DeadText; var localized string UnmutePlayerText; var localized string MutePlayerText; var localized string YouveMutedText; var localized string YouveUnmutedText; var localized string HealthText; var localized string RClickForOptsText; var localized string SpecButtonText; var localized string SpecButtonTooltip; var localized string SpectateThisPlayerText; var localized string ViewPlayerProfileText; var localized string MuteText; function FRowItem NewFRowItem(string Text, bool isSplitter) { local FRowItem newItem; newItem.Text=Text; newItem.bSplitter=isSplitter; return newItem; } function InitMenu() { Super.InitMenu(); HealthIcon = Texture2D(DynamicLoadObject("UI_Objective_Tex.UI_Obj_Healing_Loc",class'Texture2D')); PlayersList = KFGUI_List(FindComponentID('PlayerList')); SpecButton = KFGUI_Button(FindComponentID('Spec')); SpecButton.ButtonText=SpecButtonText; SpecButton.Tooltip=SpecButtonTooltip; PlayerContext.ItemRows.AddItem(NewFRowItem(SpectateThisPlayerText, false)); PlayerContext.ItemRows.AddItem(NewFRowItem(ViewPlayerProfileText, false)); PlayerContext.ItemRows.AddItem(NewFRowItem(MuteText, false)); PlayerContext.ItemRows.AddItem(NewFRowItem("", true)); } 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(TimeText$": "$FormatTimeSM(KFGRI.ElapsedTime)$" | "$PlayersText$": "$NumPlayer$" | "$AliveText$": "$NumAlivePlayer$" | "$SpectatorsText$": "$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(HeaderWaveText,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(HeaderPlayerText,,FontScalar,FontScalar); if (!bShowSpectatorsOnly) { Canvas.SetPos(XPos+CashXPos,Y); Canvas.DrawText(HeaderDoshText,,FontScalar,FontScalar); DrawCenteredText(HeaderKillsText,XPos+KillsXPos,Y,FontScalar); DrawCenteredText(HeaderAssistText,XPos+AssistXPos,Y,FontScalar); } DrawCenteredText(HeaderPingText,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(S,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 = RespawnText$": "$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 = PlayerText$": "$PRI.TaggedPlayerName$"|"$HealthText$": "$(PRI.PlayerHealthPercent<=0 ? "0" : string(PRI.PlayerHealth)); if (PRI.ShowAdminName()) S = S$"|"$PRI.GetAdminName(); S = S$"|"$RClickForOptsText; 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" 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 OnSelectedItem=SelectedRCItem OnBecameHidden=HidRightClickMenu End Object PlayerContext=PlayerContextMenu }