ddnet/src/game/client/components/scoreboard.cpp

706 lines
21 KiB
C++
Raw Normal View History

2010-11-20 10:37:14 +00:00
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
#include <engine/demo.h>
2010-05-29 07:25:38 +00:00
#include <engine/graphics.h>
#include <engine/textrender.h>
#include <engine/shared/config.h>
2010-05-29 07:25:38 +00:00
#include <game/generated/client_data.h>
#include <game/generated/protocol.h>
#include <game/localization.h>
2010-05-29 07:25:38 +00:00
#include <game/client/animstate.h>
#include <game/client/gameclient.h>
2010-05-29 07:25:38 +00:00
#include <game/client/render.h>
#include <game/client/components/countryflags.h>
2010-05-29 07:25:38 +00:00
#include <game/client/components/motd.h>
#include <game/client/components/statboard.h>
#include <game/client/components/skins.h>
2010-05-29 07:25:38 +00:00
#include "scoreboard.h"
2011-08-31 11:56:04 +00:00
#include <base/tl/string.h>
#include <engine/serverbrowser.h>
2010-05-29 07:25:38 +00:00
CScoreboard::CScoreboard()
2008-08-27 19:50:33 +00:00
{
2010-05-29 07:25:38 +00:00
OnReset();
2008-08-27 19:50:33 +00:00
}
void CScoreboard::ConKeyScoreboard(IConsole::IResult *pResult, void *pUserData)
2008-08-27 19:50:33 +00:00
{
CScoreboard *pSelf = (CScoreboard *)pUserData;
CServerInfo Info;
pSelf->Client()->GetServerInfo(&Info);
2014-12-10 02:39:15 +00:00
pSelf->m_IsGameTypeRace = IsRace(&Info);
pSelf->m_Active = pResult->GetInteger(0) != 0;
2008-08-27 19:50:33 +00:00
}
2010-05-29 07:25:38 +00:00
void CScoreboard::OnReset()
2008-08-27 19:50:33 +00:00
{
2010-05-29 07:25:38 +00:00
m_Active = false;
2014-01-10 15:19:46 +00:00
m_ServerRecord = -1.0f;
2008-08-27 19:50:33 +00:00
}
void CScoreboard::OnRelease()
{
m_Active = false;
}
2014-01-10 15:19:46 +00:00
void CScoreboard::OnMessage(int MsgType, void *pRawMsg)
{
if(MsgType == NETMSGTYPE_SV_RECORD)
{
CNetMsg_Sv_Record *pMsg = (CNetMsg_Sv_Record *)pRawMsg;
m_ServerRecord = (float)pMsg->m_ServerTimeBest/100;
//m_PlayerRecord = (float)pMsg->m_PlayerTimeBest/100;
}
}
2010-05-29 07:25:38 +00:00
void CScoreboard::OnConsoleInit()
2008-08-27 19:50:33 +00:00
{
Console()->Register("+scoreboard", "", CFGFLAG_CLIENT, ConKeyScoreboard, this, "Show scoreboard");
2008-08-27 19:50:33 +00:00
}
2010-05-29 07:25:38 +00:00
void CScoreboard::RenderGoals(float x, float y, float w)
{
float h = 50.0f;
2009-10-27 14:38:53 +00:00
Graphics()->BlendNormal();
Graphics()->TextureSet(-1);
Graphics()->QuadsBegin();
Graphics()->SetColor(0,0,0,0.5f);
RenderTools()->DrawRoundRect(x, y, w, h, 10.0f);
2009-10-27 14:38:53 +00:00
Graphics()->QuadsEnd();
// render goals
2011-03-04 16:08:10 +00:00
if(m_pClient->m_Snap.m_pGameInfoObj)
2008-09-07 15:07:08 +00:00
{
2011-03-04 16:08:10 +00:00
if(m_pClient->m_Snap.m_pGameInfoObj->m_ScoreLimit)
2010-05-29 07:25:38 +00:00
{
char aBuf[64];
2011-03-04 16:08:10 +00:00
str_format(aBuf, sizeof(aBuf), "%s: %d", Localize("Score limit"), m_pClient->m_Snap.m_pGameInfoObj->m_ScoreLimit);
2018-04-04 00:40:30 +00:00
TextRender()->Text(0, x+10.0f, y + (h - 20.f) / 2.f, 20.0f, aBuf, -1);
2010-05-29 07:25:38 +00:00
}
2011-03-04 16:08:10 +00:00
if(m_pClient->m_Snap.m_pGameInfoObj->m_TimeLimit)
2010-05-29 07:25:38 +00:00
{
char aBuf[64];
2011-03-04 16:08:10 +00:00
str_format(aBuf, sizeof(aBuf), Localize("Time limit: %d min"), m_pClient->m_Snap.m_pGameInfoObj->m_TimeLimit);
2018-04-04 00:40:30 +00:00
TextRender()->Text(0, x+230.0f, y + (h - 20.f) / 2.f, 20.0f, aBuf, -1);
2010-05-29 07:25:38 +00:00
}
2011-03-04 16:08:10 +00:00
if(m_pClient->m_Snap.m_pGameInfoObj->m_RoundNum && m_pClient->m_Snap.m_pGameInfoObj->m_RoundCurrent)
2010-05-29 07:25:38 +00:00
{
char aBuf[64];
2011-03-04 16:08:10 +00:00
str_format(aBuf, sizeof(aBuf), "%s %d/%d", Localize("Round"), m_pClient->m_Snap.m_pGameInfoObj->m_RoundCurrent, m_pClient->m_Snap.m_pGameInfoObj->m_RoundNum);
float tw = TextRender()->TextWidth(0, 20.0f, aBuf, -1);
2018-04-04 00:40:30 +00:00
TextRender()->Text(0, x+w-tw-10.0f, y + (h - 20.f) / 2.f, 20.0f, aBuf, -1);
2010-05-29 07:25:38 +00:00
}
}
}
2010-05-29 07:25:38 +00:00
void CScoreboard::RenderSpectators(float x, float y, float w)
{
float h = 140.0f;
// background
2009-10-27 14:38:53 +00:00
Graphics()->BlendNormal();
Graphics()->TextureSet(-1);
Graphics()->QuadsBegin();
Graphics()->SetColor(0,0,0,0.5f);
RenderTools()->DrawRoundRect(x, y, w, h, 10.0f);
2009-10-27 14:38:53 +00:00
Graphics()->QuadsEnd();
// Headline
y += 10.0f;
2018-04-11 10:19:30 +00:00
TextRender()->Text(0, x+10.0f, y + (30.f - 28.f) / 2.f, 28.0f, Localize("Spectators"), w-20.0f);
// spectator names
y += 30.0f;
bool Multiple = false;
CTextCursor Cursor;
TextRender()->SetCursor(&Cursor, x+10.0f, y, 22.0f, TEXTFLAG_RENDER);
Cursor.m_LineWidth = w-20.0f;
Cursor.m_MaxLines = 4;
for(int i = 0; i < MAX_CLIENTS; ++i)
{
2015-07-28 21:30:23 +00:00
const CNetObj_PlayerInfo *pInfo = m_pClient->m_Snap.m_paInfoByName[i];
if(!pInfo || pInfo->m_Team != TEAM_SPECTATORS)
continue;
if(Multiple)
TextRender()->TextEx(&Cursor, ", ", 2);
if(m_pClient->m_aClients[pInfo->m_ClientID].m_AuthLevel)
{
2019-04-26 12:06:32 +00:00
ColorRGBA Color = color_cast<ColorRGBA>(ColorHSLA(g_Config.m_ClAuthedPlayerColor));
2019-04-26 22:34:20 +00:00
TextRender()->TextColor(Color);
}
if(g_Config.m_ClShowIDs)
{
2019-03-20 17:27:08 +00:00
char aBuffer[5];
int size = str_format(aBuffer, sizeof(aBuffer), "%d: ", pInfo->m_ClientID);
TextRender()->TextEx(&Cursor, aBuffer, size);
}
TextRender()->TextEx(&Cursor, m_pClient->m_aClients[pInfo->m_ClientID].m_aName, -1);
TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f);
Multiple = true;
}
}
2010-05-29 07:25:38 +00:00
void CScoreboard::RenderScoreboard(float x, float y, float w, int Team, const char *pTitle)
{
if(Team == TEAM_SPECTATORS)
return;
2014-01-10 17:15:26 +00:00
bool lower16 = false;
2013-12-31 05:13:57 +00:00
bool upper16 = false;
bool lower24 = false;
bool upper24 = false;
2014-01-10 14:45:32 +00:00
bool lower32 = false;
bool upper32 = false;
2014-01-10 17:15:26 +00:00
if(Team == -3)
2013-12-31 05:13:57 +00:00
upper16 = true;
2014-01-10 17:15:26 +00:00
else if(Team == -4)
2014-01-08 03:11:50 +00:00
lower32 = true;
2014-01-10 17:15:26 +00:00
else if(Team == -5)
2014-01-08 03:11:50 +00:00
upper32 = true;
2014-01-10 17:15:26 +00:00
else if(Team == -6)
lower16 = true;
else if(Team == -7)
lower24 = true;
else if(Team == -8)
upper24 = true;
if(Team < -1)
2014-01-10 17:15:26 +00:00
Team = 0;
2013-12-31 05:13:57 +00:00
float h = 760.0f;
// background
2009-10-27 14:38:53 +00:00
Graphics()->BlendNormal();
Graphics()->TextureSet(-1);
Graphics()->QuadsBegin();
Graphics()->SetColor(0.0f, 0.0f, 0.0f, 0.5f);
if(upper16 || upper32 || upper24)
2014-01-10 17:15:26 +00:00
RenderTools()->DrawRoundRectExt(x, y, w, h, 17.0f, 10);
else if(lower16 || lower32 || lower24)
2014-01-10 17:15:26 +00:00
RenderTools()->DrawRoundRectExt(x, y, w, h, 17.0f, 5);
else
RenderTools()->DrawRoundRect(x, y, w, h, 17.0f);
2009-10-27 14:38:53 +00:00
Graphics()->QuadsEnd();
// render title
float TitleFontsize = 40.0f;
2010-05-29 07:25:38 +00:00
if(!pTitle)
{
2011-03-04 16:08:10 +00:00
if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER)
2010-05-29 07:25:38 +00:00
pTitle = Localize("Game over");
else
pTitle = Localize("Scoreboard");
}
2018-04-11 10:19:30 +00:00
TextRender()->Text(0, x+20.0f, y + (50.f - TitleFontsize) / 2.f, TitleFontsize, pTitle, -1);
char aBuf[128] = {0};
2014-01-10 14:45:32 +00:00
2011-03-04 16:08:10 +00:00
if(m_pClient->m_Snap.m_pGameInfoObj->m_GameFlags&GAMEFLAG_TEAMS)
{
if(m_pClient->m_Snap.m_pGameDataObj)
{
2011-03-04 16:08:10 +00:00
int Score = Team == TEAM_RED ? m_pClient->m_Snap.m_pGameDataObj->m_TeamscoreRed : m_pClient->m_Snap.m_pGameDataObj->m_TeamscoreBlue;
str_format(aBuf, sizeof(aBuf), "%d", Score);
}
}
else
{
if(m_pClient->m_Snap.m_SpecInfo.m_Active && m_pClient->m_Snap.m_SpecInfo.m_SpectatorID != SPEC_FREEVIEW &&
m_pClient->m_Snap.m_paPlayerInfos[m_pClient->m_Snap.m_SpecInfo.m_SpectatorID])
{
int Score = m_pClient->m_Snap.m_paPlayerInfos[m_pClient->m_Snap.m_SpecInfo.m_SpectatorID]->m_Score;
str_format(aBuf, sizeof(aBuf), "%d", Score);
}
else if(m_pClient->m_Snap.m_pLocalInfo)
{
int Score = m_pClient->m_Snap.m_pLocalInfo->m_Score;
str_format(aBuf, sizeof(aBuf), "%d", Score);
}
}
2014-01-10 15:19:46 +00:00
2019-01-11 14:08:40 +00:00
if(m_IsGameTypeRace && g_Config.m_ClDDRaceScoreBoard && m_pClient->m_AllowTimeScore[g_Config.m_ClDummy])
2014-01-10 15:19:46 +00:00
{
if (m_ServerRecord > 0)
{
2017-03-21 10:24:44 +00:00
str_format(aBuf, sizeof(aBuf), "%02d:%02d", ((int)m_ServerRecord)/60, ((int)m_ServerRecord)%60);
2014-01-10 15:19:46 +00:00
}
else
aBuf[0] = 0;
}
2014-01-10 17:15:26 +00:00
float tw;
if (!lower16 && !lower32 && !lower24)
2014-01-10 17:15:26 +00:00
{
tw = TextRender()->TextWidth(0, TitleFontsize, aBuf, -1);
2018-04-11 10:19:30 +00:00
TextRender()->Text(0, x+w-tw-20.0f, y + (50.f - TitleFontsize) / 2.f, TitleFontsize, aBuf, -1);
2014-01-10 17:15:26 +00:00
}
// calculate measurements
x += 10.0f;
float LineHeight = 60.0f;
2010-05-29 07:25:38 +00:00
float TeeSizeMod = 1.0f;
float Spacing = 16.0f;
2014-01-22 00:39:18 +00:00
float RoundRadius = 15.0f;
if(m_pClient->m_Snap.m_aTeamSize[Team] > 48)
2014-01-08 03:11:50 +00:00
{
LineHeight = 20.0f;
TeeSizeMod = 0.4f;
Spacing = 0.0f;
2014-01-22 00:39:18 +00:00
RoundRadius = 5.0f;
2014-01-08 03:11:50 +00:00
}
else if(m_pClient->m_Snap.m_aTeamSize[Team] > 32)
{
LineHeight = 27.0f;
TeeSizeMod = 0.6f;
Spacing = 0.0f;
2014-01-22 00:39:18 +00:00
RoundRadius = 5.0f;
}
2014-01-11 13:09:55 +00:00
else if(m_pClient->m_Snap.m_aTeamSize[Team] > 12)
2009-05-31 09:44:20 +00:00
{
2010-05-29 07:25:38 +00:00
LineHeight = 40.0f;
TeeSizeMod = 0.8f;
Spacing = 0.0f;
2014-01-22 00:39:18 +00:00
RoundRadius = 15.0f;
2009-05-31 09:44:20 +00:00
}
else if(m_pClient->m_Snap.m_aTeamSize[Team] > 8)
{
LineHeight = 50.0f;
TeeSizeMod = 0.9f;
2014-02-02 22:23:10 +00:00
Spacing = 5.0f;
2014-01-22 00:39:18 +00:00
RoundRadius = 15.0f;
2009-05-31 09:44:20 +00:00
}
float ScoreOffset = x+10.0f, ScoreLength = TextRender()->TextWidth(0, 22.0f/*HeadlineFontsize*/, "00:00:0", -1);
float TeeOffset = ScoreOffset+ScoreLength, TeeLength = 60*TeeSizeMod;
float NameOffset = TeeOffset+TeeLength, NameLength = 300.0f-TeeLength;
2011-04-02 13:10:51 +00:00
float PingOffset = x+610.0f, PingLength = 65.0f;
float CountryOffset = PingOffset-(LineHeight-Spacing-TeeSizeMod*5.0f)*2.0f, CountryLength = (LineHeight-Spacing-TeeSizeMod*5.0f)*2.0f;
float ClanOffset = x+360.0f, ClanLength = 240.0f-CountryLength;
// render headlines
y += 50.0f;
float HeadlineFontsize = 22.0f;
const char* pScore = (m_IsGameTypeRace && g_Config.m_ClDDRaceScoreBoard && m_pClient->m_AllowTimeScore[g_Config.m_ClDummy]) ? Localize("Time") : Localize("Score");
float ScoreWidth = TextRender()->TextWidth(0, HeadlineFontsize, pScore, -1);
2011-12-26 11:45:41 +00:00
tw = ScoreLength > ScoreWidth ? ScoreLength : ScoreWidth;
TextRender()->Text(0, ScoreOffset+ScoreLength-tw, y + (HeadlineFontsize * 2.f - HeadlineFontsize) / 2.f, HeadlineFontsize, pScore, -1);
2018-04-11 10:19:30 +00:00
TextRender()->Text(0, NameOffset, y + (HeadlineFontsize * 2.f - HeadlineFontsize) / 2.f, HeadlineFontsize, Localize("Name"), -1);
2011-04-02 13:10:51 +00:00
tw = TextRender()->TextWidth(0, HeadlineFontsize, Localize("Clan"), -1);
2018-04-11 10:19:30 +00:00
TextRender()->Text(0, ClanOffset+ClanLength/2-tw/2, y + (HeadlineFontsize * 2.f - HeadlineFontsize) / 2.f, HeadlineFontsize, Localize("Clan"), -1);
2011-04-02 13:10:51 +00:00
tw = TextRender()->TextWidth(0, HeadlineFontsize, Localize("Ping"), -1);
2018-04-11 10:19:30 +00:00
TextRender()->Text(0, PingOffset+PingLength-tw, y + (HeadlineFontsize * 2.f - HeadlineFontsize) / 2.f, HeadlineFontsize, Localize("Ping"), -1);
// render player entries
y += HeadlineFontsize*2.0f;
float FontSize = 24.0f;
if(m_pClient->m_Snap.m_aTeamSize[Team] > 48)
2014-01-08 03:11:50 +00:00
FontSize = 16.0f;
else if(m_pClient->m_Snap.m_aTeamSize[Team] > 32)
FontSize = 20.0f;
CTextCursor Cursor;
2014-01-08 03:11:50 +00:00
int rendered = 0;
if (upper16)
rendered = -16;
if (upper32)
rendered = -32;
if (upper24)
rendered = -24;
2014-01-22 00:39:18 +00:00
2014-01-22 14:38:05 +00:00
int OldDDTeam = -1;
2014-01-22 00:39:18 +00:00
for(int i = 0; i < MAX_CLIENTS; i++)
{
// make sure that we render the correct team
2014-01-22 00:39:18 +00:00
const CNetObj_PlayerInfo *pInfo = m_pClient->m_Snap.m_paInfoByDDTeam[i];
if(!pInfo || pInfo->m_Team != Team)
continue;
2013-12-31 05:13:57 +00:00
if (rendered++ < 0) continue;
int DDTeam = m_pClient->m_Teams.Team(pInfo->m_ClientID);
2014-01-22 00:39:18 +00:00
int NextDDTeam = 0;
for(int j = i + 1; j < MAX_CLIENTS; j++)
{
const CNetObj_PlayerInfo *pInfo2 = m_pClient->m_Snap.m_paInfoByDDTeam[j];
if(!pInfo2 || pInfo2->m_Team != Team)
continue;
NextDDTeam = m_pClient->m_Teams.Team(pInfo2->m_ClientID);
2014-01-22 00:39:18 +00:00
break;
}
2014-01-22 14:38:05 +00:00
if (OldDDTeam == -1)
{
for (int j = i - 1; j >= 0; j--)
{
const CNetObj_PlayerInfo *pInfo2 = m_pClient->m_Snap.m_paInfoByDDTeam[j];
if(!pInfo2 || pInfo2->m_Team != Team)
continue;
OldDDTeam = m_pClient->m_Teams.Team(pInfo2->m_ClientID);
2014-01-22 14:38:05 +00:00
break;
}
}
2014-01-22 00:39:18 +00:00
if (DDTeam != TEAM_FLOCK)
{
Graphics()->TextureSet(-1);
Graphics()->QuadsBegin();
2019-04-26 22:11:15 +00:00
ColorRGBA rgb = color_cast<ColorRGBA>(ColorHSLA(DDTeam / 64.0f, 1.0f, 0.5f, 0.5f));
Graphics()->SetColor(rgb);
2014-01-22 00:39:18 +00:00
int Corners = 0;
if (OldDDTeam != DDTeam)
Corners |= CUI::CORNER_TL | CUI::CORNER_TR;
if (NextDDTeam != DDTeam)
Corners |= CUI::CORNER_BL | CUI::CORNER_BR;
RenderTools()->DrawRoundRectExt(x - 10.0f, y, w, LineHeight + Spacing, RoundRadius, Corners);
Graphics()->QuadsEnd();
if (NextDDTeam != DDTeam)
{
char aBuf[64];
2014-01-22 13:04:15 +00:00
if(m_pClient->m_Snap.m_aTeamSize[0] > 8)
2014-01-22 00:39:18 +00:00
{
str_format(aBuf, sizeof(aBuf),"%d", DDTeam);
TextRender()->SetCursor(&Cursor, x - 10.0f, y + Spacing + FontSize - (FontSize/1.5f), FontSize/1.5f, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END);
Cursor.m_LineWidth = NameLength+3;
}
else
{
str_format(aBuf, sizeof(aBuf),"Team %d", DDTeam);
tw = TextRender()->TextWidth(0, FontSize, aBuf, -1);
2018-03-15 02:59:57 +00:00
TextRender()->SetCursor(&Cursor, ScoreOffset+w/2.0f-tw/2.0f, y + LineHeight, FontSize/1.5f, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END);
2014-01-22 00:39:18 +00:00
Cursor.m_LineWidth = NameLength+3;
}
TextRender()->TextEx(&Cursor, aBuf, -1);
}
}
OldDDTeam = DDTeam;
// background so it's easy to find the local player or the followed one in spectator mode
if(pInfo->m_Local || (m_pClient->m_Snap.m_SpecInfo.m_Active && pInfo->m_ClientID == m_pClient->m_Snap.m_SpecInfo.m_SpectatorID))
{
2009-10-27 14:38:53 +00:00
Graphics()->TextureSet(-1);
Graphics()->QuadsBegin();
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.25f);
2014-01-22 00:39:18 +00:00
RenderTools()->DrawRoundRect(x, y, w-20.0f, LineHeight, RoundRadius);
2009-10-27 14:38:53 +00:00
Graphics()->QuadsEnd();
}
// score
2019-01-11 14:08:40 +00:00
if(m_IsGameTypeRace && g_Config.m_ClDDRaceScoreBoard && m_pClient->m_AllowTimeScore[g_Config.m_ClDummy])
2011-12-26 11:45:41 +00:00
{
2014-01-12 15:16:09 +00:00
if (pInfo->m_Score == -9999)
aBuf[0] = 0;
else
{
int Time = abs(pInfo->m_Score);
str_format(aBuf, sizeof(aBuf), "%02d:%02d", Time/60, Time%60);
}
2011-12-26 11:45:41 +00:00
}
else
str_format(aBuf, sizeof(aBuf), "%d", clamp(pInfo->m_Score, -999, 99999));
tw = TextRender()->TextWidth(0, FontSize, aBuf, -1);
2018-04-03 15:41:11 +00:00
TextRender()->SetCursor(&Cursor, ScoreOffset+ScoreLength-tw, y + (LineHeight - FontSize) / 2.f, FontSize, TEXTFLAG_RENDER);
TextRender()->TextEx(&Cursor, aBuf, -1);
// flag
if(m_pClient->m_Snap.m_pGameInfoObj->m_GameFlags&GAMEFLAG_FLAGS &&
2011-03-04 16:08:10 +00:00
m_pClient->m_Snap.m_pGameDataObj && (m_pClient->m_Snap.m_pGameDataObj->m_FlagCarrierRed == pInfo->m_ClientID ||
m_pClient->m_Snap.m_pGameDataObj->m_FlagCarrierBlue == pInfo->m_ClientID))
{
2009-10-27 14:38:53 +00:00
Graphics()->BlendNormal();
2010-05-29 07:25:38 +00:00
Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GAME].m_Id);
2009-10-27 14:38:53 +00:00
Graphics()->QuadsBegin();
2011-03-04 16:08:10 +00:00
RenderTools()->SelectSprite(pInfo->m_Team==TEAM_RED ? SPRITE_FLAG_BLUE : SPRITE_FLAG_RED, SPRITE_FLAG_FLIP_X);
float Size = LineHeight;
IGraphics::CQuadItem QuadItem(TeeOffset+0.0f, y-5.0f-Spacing/2.0f, Size/2.0f, Size);
2010-05-29 07:25:38 +00:00
Graphics()->QuadsDrawTL(&QuadItem, 1);
2009-10-27 14:38:53 +00:00
Graphics()->QuadsEnd();
}
// avatar
CTeeRenderInfo TeeInfo = m_pClient->m_aClients[pInfo->m_ClientID].m_RenderInfo;
2010-05-29 07:25:38 +00:00
TeeInfo.m_Size *= TeeSizeMod;
RenderTools()->RenderTee(CAnimState::GetIdle(), &TeeInfo, EMOTE_NORMAL, vec2(1.0f, 0.0f), vec2(TeeOffset+TeeLength/2, y+LineHeight/2));
// name
2018-04-03 15:41:11 +00:00
TextRender()->SetCursor(&Cursor, NameOffset, y + (LineHeight - FontSize) / 2.f, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END);
2019-03-05 08:48:06 +00:00
if(m_pClient->m_aClients[pInfo->m_ClientID].m_AuthLevel)
{
2019-04-26 12:06:32 +00:00
ColorRGBA Color = color_cast<ColorRGBA>(ColorHSLA(g_Config.m_ClAuthedPlayerColor));
2019-04-26 22:34:20 +00:00
TextRender()->TextColor(Color);
}
if(g_Config.m_ClShowIDs)
{
char aId[64] = "";
str_format(aId, sizeof(aId),"%2d: ", pInfo->m_ClientID);
str_append(aId, m_pClient->m_aClients[pInfo->m_ClientID].m_aName,sizeof(aId));
Cursor.m_LineWidth = NameLength+8;
TextRender()->TextEx(&Cursor, aId, -1);
}
else
{
Cursor.m_LineWidth = NameLength;
TextRender()->TextEx(&Cursor, m_pClient->m_aClients[pInfo->m_ClientID].m_aName, -1);
}
// clan
if(str_comp(m_pClient->m_aClients[pInfo->m_ClientID].m_aClan,
m_pClient->m_aClients[GameClient()->m_LocalIDs[0]].m_aClan) == 0)
{
2019-04-26 12:06:32 +00:00
ColorRGBA Color = color_cast<ColorRGBA>(ColorHSLA(g_Config.m_ClSameClanColor));
2019-04-26 22:34:20 +00:00
TextRender()->TextColor(Color);
}
else
TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f);
tw = TextRender()->TextWidth(nullptr, FontSize, m_pClient->m_aClients[pInfo->m_ClientID].m_aClan, -1);
TextRender()->SetCursor(&Cursor, ClanOffset + ClanLength / 2 - tw / 2, y + (LineHeight - FontSize) / 2.f, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END);
Cursor.m_LineWidth = ClanLength;
TextRender()->TextEx(&Cursor, m_pClient->m_aClients[pInfo->m_ClientID].m_aClan, -1);
TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f);
// country flag
ColorRGBA Color(1.0f, 1.0f, 1.0f, 0.5f);
m_pClient->m_pCountryFlags->Render(m_pClient->m_aClients[pInfo->m_ClientID].m_Country, &Color,
CountryOffset, y+(Spacing+TeeSizeMod*5.0f)/2.0f, CountryLength, LineHeight-Spacing-TeeSizeMod*5.0f);
// ping
2019-04-05 11:25:17 +00:00
if(g_Config.m_ClEnablePingColor)
{
2019-04-26 12:06:32 +00:00
ColorRGBA rgb = color_cast<ColorRGBA>(ColorHSLA((300.0f - clamp(pInfo->m_Latency, 0, 300)) / 1000.0f, 1.0f, 0.5f));
2019-04-26 22:34:20 +00:00
TextRender()->TextColor(rgb);
2019-04-05 11:12:08 +00:00
}
str_format(aBuf, sizeof(aBuf), "%d", clamp(pInfo->m_Latency, 0, 1000));
2019-04-05 11:12:08 +00:00
tw = TextRender()->TextWidth(nullptr, FontSize, aBuf, -1);
2018-04-03 15:41:11 +00:00
TextRender()->SetCursor(&Cursor, PingOffset+PingLength-tw, y + (LineHeight - FontSize) / 2.f, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END);
Cursor.m_LineWidth = PingLength;
TextRender()->TextEx(&Cursor, aBuf, -1);
2019-04-05 11:12:08 +00:00
TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f);
y += LineHeight+Spacing;
2014-01-08 03:11:50 +00:00
if (lower32 || upper32) {
if (rendered == 32) break;
} else if (lower24 || upper24) {
if (rendered == 24) break;
} else {
2014-01-08 03:11:50 +00:00
if (rendered == 16) break;
}
}
}
void CScoreboard::RenderRecordingNotification(float x)
{
if(!m_pClient->DemoRecorder(RECORDER_MANUAL)->IsRecording() &&
!m_pClient->DemoRecorder(RECORDER_AUTO)->IsRecording() &&
!m_pClient->DemoRecorder(RECORDER_RACE)->IsRecording())
{
return;
}
//draw the text
char aBuf[64] = "\0";
char aBuf2[64];
int Seconds;
if(m_pClient->DemoRecorder(RECORDER_MANUAL)->IsRecording())
{
Seconds = m_pClient->DemoRecorder(RECORDER_MANUAL)->Length();
str_format(aBuf2, sizeof(aBuf2), Localize("Manual %3d:%02d "), Seconds/60, Seconds%60);
str_append(aBuf, aBuf2, sizeof(aBuf));
}
if(m_pClient->DemoRecorder(RECORDER_RACE)->IsRecording())
{
Seconds = m_pClient->DemoRecorder(RECORDER_RACE)->Length();
str_format(aBuf2, sizeof(aBuf2), Localize("Race %3d:%02d "), Seconds/60, Seconds%60);
str_append(aBuf, aBuf2, sizeof(aBuf));
}
if(m_pClient->DemoRecorder(RECORDER_AUTO)->IsRecording())
{
Seconds = m_pClient->DemoRecorder(RECORDER_AUTO)->Length();
str_format(aBuf2, sizeof(aBuf2), Localize("Auto %3d:%02d "), Seconds/60, Seconds%60);
str_append(aBuf, aBuf2, sizeof(aBuf));
}
float w = TextRender()->TextWidth(0, 20.0f, aBuf, -1);
//draw the box
Graphics()->BlendNormal();
Graphics()->TextureSet(-1);
Graphics()->QuadsBegin();
Graphics()->SetColor(0.0f, 0.0f, 0.0f, 0.4f);
RenderTools()->DrawRoundRectExt(x, 0.0f, w+60.0f, 50.0f, 15.0f, CUI::CORNER_B);
Graphics()->QuadsEnd();
//draw the red dot
Graphics()->QuadsBegin();
Graphics()->SetColor(1.0f, 0.0f, 0.0f, 1.0f);
RenderTools()->DrawRoundRect(x+20, 15.0f, 20.0f, 20.0f, 10.0f);
Graphics()->QuadsEnd();
2018-04-03 15:41:11 +00:00
TextRender()->Text(0, x+50.0f, (50.f - 20.f) / 2.f, 20.0f, aBuf, -1);
}
2010-05-29 07:25:38 +00:00
void CScoreboard::OnRender()
{
if(!Active())
return;
2018-02-04 15:00:47 +00:00
// if the score board is active, then we should clear the motd message as well
if(m_pClient->m_pMotd->IsActive())
2010-05-29 07:25:38 +00:00
m_pClient->m_pMotd->Clear();
2010-05-29 07:25:38 +00:00
float Width = 400*3.0f*Graphics()->ScreenAspect();
float Height = 400*3.0f;
2010-05-29 07:25:38 +00:00
Graphics()->MapScreen(0, 0, Width, Height);
float w = 700.0f;
2011-03-04 16:08:10 +00:00
if(m_pClient->m_Snap.m_pGameInfoObj)
{
2011-03-04 16:08:10 +00:00
if(!(m_pClient->m_Snap.m_pGameInfoObj->m_GameFlags&GAMEFLAG_TEAMS))
2013-12-31 05:13:57 +00:00
{
if(m_pClient->m_Snap.m_aTeamSize[0] > 48)
2014-01-08 03:11:50 +00:00
{
2014-01-10 17:15:26 +00:00
RenderScoreboard(Width/2-w, 150.0f, w, -4, 0);
RenderScoreboard(Width/2, 150.0f, w, -5, "");
} else if(m_pClient->m_Snap.m_aTeamSize[0] > 32)
{
RenderScoreboard(Width/2-w, 150.0f, w, -7, 0);
RenderScoreboard(Width/2, 150.0f, w, -8, "");
2014-01-08 03:11:50 +00:00
} else if(m_pClient->m_Snap.m_aTeamSize[0] > 16)
2013-12-31 05:13:57 +00:00
{
2014-01-10 17:15:26 +00:00
RenderScoreboard(Width/2-w, 150.0f, w, -6, 0);
RenderScoreboard(Width/2, 150.0f, w, -3, "");
2013-12-31 05:13:57 +00:00
} else
{
RenderScoreboard(Width/2-w/2, 150.0f, w, 0, 0);
}
}
2011-03-04 16:08:10 +00:00
else
{
const char *pRedClanName = GetClanName(TEAM_RED);
const char *pBlueClanName = GetClanName(TEAM_BLUE);
2011-03-04 16:08:10 +00:00
if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER && m_pClient->m_Snap.m_pGameDataObj)
{
char aText[256];
str_copy(aText, Localize("Draw!"), sizeof(aText));
2011-03-04 16:08:10 +00:00
if(m_pClient->m_Snap.m_pGameDataObj->m_TeamscoreRed > m_pClient->m_Snap.m_pGameDataObj->m_TeamscoreBlue)
{
if(pRedClanName)
str_format(aText, sizeof(aText), Localize("%s wins!"), pRedClanName);
else
str_copy(aText, Localize("Red team wins!"), sizeof(aText));
}
2011-03-04 16:08:10 +00:00
else if(m_pClient->m_Snap.m_pGameDataObj->m_TeamscoreBlue > m_pClient->m_Snap.m_pGameDataObj->m_TeamscoreRed)
{
if(pBlueClanName)
str_format(aText, sizeof(aText), Localize("%s wins!"), pBlueClanName);
else
str_copy(aText, Localize("Blue team wins!"), sizeof(aText));
}
float w = TextRender()->TextWidth(0, 86.0f, aText, -1);
TextRender()->Text(0, Width/2-w/2, 39, 86.0f, aText, -1);
2011-03-04 16:08:10 +00:00
}
RenderScoreboard(Width/2-w-5.0f, 150.0f, w, TEAM_RED, pRedClanName ? pRedClanName : Localize("Red team"));
RenderScoreboard(Width/2+5.0f, 150.0f, w, TEAM_BLUE, pBlueClanName ? pBlueClanName : Localize("Blue team"));
}
}
RenderGoals(Width/2-w/2, 150+760+10, w);
RenderSpectators(Width/2-w/2, 150+760+10+50+10, w);
RenderRecordingNotification((Width/7)*4);
}
bool CScoreboard::Active()
{
2018-02-04 15:00:47 +00:00
// if statboard is active don't show scoreboard
if(m_pClient->m_pStatboard->IsActive())
return false;
if(m_Active)
return true;
if(m_pClient->m_Snap.m_pLocalInfo && m_pClient->m_Snap.m_pLocalInfo->m_Team != TEAM_SPECTATORS)
{
// we are not a spectator, check if we are dead
if(!m_pClient->m_Snap.m_pLocalCharacter && g_Config.m_ClScoreboardOnDeath)
return true;
}
// if the game is over
2011-03-04 16:08:10 +00:00
if(m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER)
return true;
return false;
}
const char *CScoreboard::GetClanName(int Team)
{
int ClanPlayers = 0;
const char *pClanName = 0;
for(int i = 0; i < MAX_CLIENTS; i++)
{
const CNetObj_PlayerInfo *pInfo = m_pClient->m_Snap.m_paInfoByScore[i];
if(!pInfo || pInfo->m_Team != Team)
continue;
if(!pClanName)
{
pClanName = m_pClient->m_aClients[pInfo->m_ClientID].m_aClan;
ClanPlayers++;
}
else
{
if(str_comp(m_pClient->m_aClients[pInfo->m_ClientID].m_aClan, pClanName) == 0)
ClanPlayers++;
else
return 0;
}
}
if(ClanPlayers > 1 && pClanName[0])
return pClanName;
else
return 0;
}