Esempio n. 1
0
////////////////////////////////////////////////////////////
/// Create a new shape made of a single rectangle
////////////////////////////////////////////////////////////
sfShape* sfShape_CreateRectangle(float P1X, float P1Y, float P2X, float P2Y, sfColor Col, float Outline, sfColor OutlineCol)
{
    sf::Color Color(Col.r, Col.g, Col.b, Col.a);
    sf::Color OutlineColor(OutlineCol.r, OutlineCol.g, OutlineCol.b, OutlineCol.a);

    sfShape* Shape = new sfShape;
    Shape->This = sf::Shape::Rectangle(P1X, P1Y, P2X, P2Y, Color, Outline, OutlineColor);
    return Shape;
}
Esempio n. 2
0
////////////////////////////////////////////////////////////
/// Create a new shape made of a single circle
////////////////////////////////////////////////////////////
sfShape* sfShape_CreateCircle(float X, float Y, float Radius, sfColor Col, float Outline, sfColor OutlineCol)
{
    sf::Color Color(Col.r, Col.g, Col.b, Col.a);
    sf::Color OutlineColor(OutlineCol.r, OutlineCol.g, OutlineCol.b, OutlineCol.a);

    sfShape* Shape = new sfShape;
    Shape->This = sf::Shape::Circle(X, Y, Radius, Color, Outline, OutlineColor);
    return Shape;
}
Esempio n. 3
0
float CScoreboard::RenderScoreboard(float x, float y, float w, int Team, const char *pTitle, int Align)
{
	if(Team == TEAM_SPECTATORS)
		return 0.0f;

	// ready mode
	const CGameClient::CSnapState& Snap = m_pClient->m_Snap;
	const bool ReadyMode = Snap.m_pGameData && (Snap.m_pGameData->m_GameStateFlags&(GAMESTATEFLAG_STARTCOUNTDOWN|GAMESTATEFLAG_PAUSED|GAMESTATEFLAG_WARMUP)) && Snap.m_pGameData->m_GameStateEndTick == 0;

	float HeadlineHeight = 40.0f;
	float TitleFontsize = 20.0f;
	float HeadlineFontsize = 12.0f;
	float LineHeight = 20.0f;
	float TeeSizeMod = 1.0f;
	float Spacing = 2.0f;
	float PingOffset = x+Spacing, PingLength = 35.0f;
	float CountryFlagOffset = PingOffset+PingLength, CountryFlagLength = 20.f;
	float IdSize = g_Config.m_ClShowUserId ? LineHeight : 0.0f;
	float ReadyLength = ReadyMode ? 10.f : 0.f;
	float TeeOffset = CountryFlagOffset+CountryFlagLength+4.0f, TeeLength = 25*TeeSizeMod;
	float NameOffset = CountryFlagOffset+CountryFlagLength+IdSize, NameLength = 128.0f-IdSize/2-ReadyLength;
	float ClanOffset = NameOffset+NameLength+ReadyLength, ClanLength = 88.0f-IdSize/2;
	float KillOffset = ClanOffset+ClanLength, KillLength = 24.0f;
	float DeathOffset = KillOffset+KillLength, DeathLength = 24.0f;
	float ScoreOffset = DeathOffset+DeathLength, ScoreLength = 35.0f;
	float tw = 0.0f;

	bool NoTitle = pTitle? false : true;

	// count players
	dbg_assert(Team == TEAM_RED || Team == TEAM_BLUE, "Unknown team id");
	int NumPlayers = m_pClient->m_GameInfo.m_aTeamSize[Team];
	m_PlayerLines = max(m_PlayerLines, NumPlayers);

	// clamp to 16
	if(m_PlayerLines > 16)
		m_PlayerLines = 16;

	char aBuf[128] = {0};

	// background
	Graphics()->BlendNormal();
	vec4 Color;
	if(Team == TEAM_RED && m_pClient->m_GameInfo.m_GameFlags&GAMEFLAG_TEAMS)
		Color = vec4(0.975f, 0.17f, 0.17f, 0.75f);
	else if(Team == TEAM_BLUE)
		Color = vec4(0.17f, 0.46f, 0.975f, 0.75f);
	else
		Color = vec4(0.0f, 0.0f, 0.0f, 0.5f);
	CUIRect Rect = {x, y, w, HeadlineHeight};
	RenderTools()->DrawRoundRect(&Rect, Color, 5.0f);

	// render title
	if(NoTitle)
	{
		if(m_pClient->m_Snap.m_pGameData->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER)
			pTitle = Localize("Game over");
		else if(m_pClient->m_Snap.m_pGameData->m_GameStateFlags&GAMESTATEFLAG_ROUNDOVER)
		{
			pTitle = Localize("Round over");
			m_SkipPlayerStatsReset = true;
		}
		else
			pTitle = Localize("Scoreboard");
	}
	else
	{
		if(Team == TEAM_BLUE)
			str_format(aBuf, sizeof(aBuf), "(%d) %s", NumPlayers, pTitle);
		else
			str_format(aBuf, sizeof(aBuf), "%s (%d)", pTitle, NumPlayers);
	}

	if(Align == -1)
	{
		tw = TextRender()->TextWidth(0, TitleFontsize, pTitle, -1, -1.0f);
		TextRender()->Text(0, x+20.0f, y+5.0f, TitleFontsize, pTitle, -1.0f);
		if(!NoTitle)
		{
			str_format(aBuf, sizeof(aBuf), " (%d)", NumPlayers);
			TextRender()->TextColor(1.0f, 1.0f, 1.0f, 0.5f);
			TextRender()->Text(0, x+20.0f+tw, y+5.0f, TitleFontsize, aBuf, -1.0f);
			TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f);
		}
	}
	else
	{
		tw = TextRender()->TextWidth(0, TitleFontsize, pTitle, -1, -1.0f);
		if(!NoTitle)
		{
			str_format(aBuf, sizeof(aBuf), "(%d) ", NumPlayers);
			float PlayersTextWidth = TextRender()->TextWidth(0, TitleFontsize, aBuf, -1, -1.0f);
			TextRender()->TextColor(1.0f, 1.0f, 1.0f, 0.5f);
			TextRender()->Text(0, x+w-tw-PlayersTextWidth-20.0f, y+5.0f, TitleFontsize, aBuf, -1.0f);
			TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f);
		}
		tw = TextRender()->TextWidth(0, TitleFontsize, pTitle, -1, -1.0f);
		TextRender()->Text(0, x+w-tw-20.0f, y+5.0f, TitleFontsize, pTitle, -1.0f);
	}

	if(m_pClient->m_GameInfo.m_GameFlags&GAMEFLAG_TEAMS)
	{
		int Score = Team == TEAM_RED ? m_pClient->m_Snap.m_pGameDataTeam->m_TeamscoreRed : m_pClient->m_Snap.m_pGameDataTeam->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 >= 0 &&
			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);
		}
	}
	if(Align == -1)
	{
		tw = TextRender()->TextWidth(0, TitleFontsize, aBuf, -1, -1.0f);
		TextRender()->Text(0, x+w-tw-20.0f, y+5.0f, TitleFontsize, aBuf, -1.0f);
	}
	else
		TextRender()->Text(0, x+20.0f, y+5.0f, TitleFontsize, aBuf, -1.0f);

	// render headlines
	y += HeadlineHeight;

	Graphics()->BlendNormal();
	{
		CUIRect Rect = {x, y, w, LineHeight*(m_PlayerLines+1)};
		RenderTools()->DrawRoundRect(&Rect, vec4(0.0f, 0.0f, 0.0f, 0.25f), 5.0f);
	}
	if(m_PlayerLines)
	{
		CUIRect Rect = {x, y+LineHeight, w, LineHeight*(m_PlayerLines)};
		RenderTools()->DrawRoundRect(&Rect, vec4(0.0f, 0.0f, 0.0f, 0.25f), 5.0f);
	}

	TextRender()->TextColor(1.0f, 1.0f, 1.0f, 0.5f);
	tw = TextRender()->TextWidth(0, HeadlineFontsize, Localize("Ping"), -1, -1.0f);
	TextRender()->Text(0, PingOffset+PingLength-tw, y+Spacing, HeadlineFontsize, Localize("Ping"), -1.0f);

	TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f);
	TextRender()->Text(0, NameOffset+ TeeLength, y+Spacing, HeadlineFontsize, Localize("Name"), -1.0f);

	tw = TextRender()->TextWidth(0, HeadlineFontsize, Localize("Clan"), -1, -1.0f);
	TextRender()->Text(0, ClanOffset+ClanLength/2-tw/2, y+Spacing, HeadlineFontsize, Localize("Clan"), -1.0f);

	TextRender()->TextColor(1.0f, 1.0f, 1.0f, 0.5f);
	tw = TextRender()->TextWidth(0, HeadlineFontsize, "K", -1, -1.0f);
	TextRender()->Text(0, KillOffset+KillLength/2-tw/2, y+Spacing, HeadlineFontsize, "K", -1.0f);

	tw = TextRender()->TextWidth(0, HeadlineFontsize, "D", -1, -1.0f);
	TextRender()->Text(0, DeathOffset+DeathLength/2-tw/2, y+Spacing, HeadlineFontsize, "D", -1.0f);

	TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f);
	tw = TextRender()->TextWidth(0, HeadlineFontsize, Localize("Score"), -1, -1.0f);
	TextRender()->Text(0, ScoreOffset+ScoreLength/2-tw/2, y+Spacing, HeadlineFontsize, Localize("Score"), -1.0f);

	TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f);

	// render player entries
	y += LineHeight;
	float FontSize = HeadlineFontsize;
	CTextCursor Cursor;

	const int MAX_IDS = 16;
	int RenderScoreIDs[MAX_IDS];
	int NumRenderScoreIDs = 0;
	int HoleSizes[2];
	for(int i = 0; i < MAX_IDS; ++i)
		RenderScoreIDs[i] = -1;

	// Non vanilla scoreboard, for now, some parts of the scoreboard are omitted
	if(NumPlayers > MAX_IDS)
	{
		for(int RenderDead = 0; RenderDead < 2 && NumRenderScoreIDs < MAX_IDS-1; ++RenderDead)
		{
			for(int i = 0; i < MAX_CLIENTS && NumRenderScoreIDs < MAX_IDS-1; i++)
			{
				// make sure that we render the correct team
				const CGameClient::CPlayerInfoItem *pInfo = &m_pClient->m_Snap.m_aInfoByScore[i];
				if(!pInfo->m_pPlayerInfo || m_pClient->m_aClients[pInfo->m_ClientID].m_Team != Team || (!RenderDead && (pInfo->m_pPlayerInfo->m_PlayerFlags&PLAYERFLAG_DEAD)) ||
					(RenderDead && !(pInfo->m_pPlayerInfo->m_PlayerFlags&PLAYERFLAG_DEAD)))
					continue;

				RenderScoreIDs[NumRenderScoreIDs] = i;
				NumRenderScoreIDs++;
			}
		}
		NumRenderScoreIDs = MAX_IDS;
		RenderScoreIDs[MAX_IDS-1] = -1;
		HoleSizes[0] = m_pClient->m_GameInfo.m_aTeamSize[Team] - (MAX_IDS-1);

		if(m_pClient->m_LocalClientID != -1 && (m_pClient->m_aClients[m_pClient->m_LocalClientID].m_Team == Team || m_pClient->m_Snap.m_SpecInfo.m_Active))
		{
			int Classment = -1;
			int TeamScoreIDs[MAX_CLIENTS];
			for(int RenderDead = 0, j = 0; RenderDead < 2; ++RenderDead)
			{
				for(int i = 0; i < MAX_CLIENTS; i++)
				{
					// make sure that we render the correct team
					const CGameClient::CPlayerInfoItem *pInfo = &m_pClient->m_Snap.m_aInfoByScore[i];
					if(!pInfo->m_pPlayerInfo || m_pClient->m_aClients[pInfo->m_ClientID].m_Team != Team || (!RenderDead && (pInfo->m_pPlayerInfo->m_PlayerFlags&PLAYERFLAG_DEAD)) ||
						(RenderDead && !(pInfo->m_pPlayerInfo->m_PlayerFlags&PLAYERFLAG_DEAD)))
						continue;

					if(m_pClient->m_LocalClientID == pInfo->m_ClientID || (m_pClient->m_Snap.m_SpecInfo.m_Active && pInfo->m_ClientID == m_pClient->m_Snap.m_SpecInfo.m_SpectatorID))
						Classment = j;

					TeamScoreIDs[j] = i;
					j++;
				}
			}

			if(Classment < MAX_IDS-1) {}
			else if(Classment == m_pClient->m_GameInfo.m_aTeamSize[Team] - 1)
			{
				HoleSizes[0] = Classment - MAX_IDS-2;
				RenderScoreIDs[MAX_IDS-3] = -1;
				RenderScoreIDs[MAX_IDS-2] = TeamScoreIDs[Classment-1];
				RenderScoreIDs[MAX_IDS-1] = TeamScoreIDs[Classment];
			}
			else if(Classment == m_pClient->m_GameInfo.m_aTeamSize[Team] - 2)
			{
				HoleSizes[0] = Classment - MAX_IDS-3;
				RenderScoreIDs[MAX_IDS-4] = -1;
				RenderScoreIDs[MAX_IDS-3] = TeamScoreIDs[Classment-1];
				RenderScoreIDs[MAX_IDS-2] = TeamScoreIDs[Classment];
				RenderScoreIDs[MAX_IDS-1] = TeamScoreIDs[Classment+1];
			}
			else if(Classment == m_pClient->m_GameInfo.m_aTeamSize[Team] - 3)
			{
				HoleSizes[0] = Classment - MAX_IDS-4;
				RenderScoreIDs[MAX_IDS-5] = -1;
				RenderScoreIDs[MAX_IDS-4] = TeamScoreIDs[Classment-1];
				RenderScoreIDs[MAX_IDS-3] = TeamScoreIDs[Classment];
				RenderScoreIDs[MAX_IDS-2] = TeamScoreIDs[Classment+1];
				RenderScoreIDs[MAX_IDS-1] = TeamScoreIDs[Classment+2];
			}
			else if(Classment < m_pClient->m_GameInfo.m_aTeamSize[Team] - 3)
			{
				HoleSizes[0] = Classment - MAX_IDS-4;
				RenderScoreIDs[MAX_IDS-5] = -1;
				RenderScoreIDs[MAX_IDS-4] = TeamScoreIDs[Classment-1];
				RenderScoreIDs[MAX_IDS-3] = TeamScoreIDs[Classment];
				RenderScoreIDs[MAX_IDS-2] = TeamScoreIDs[Classment+1];
				HoleSizes[1] = m_pClient->m_GameInfo.m_aTeamSize[Team] - Classment - 2;
				RenderScoreIDs[MAX_IDS-1] = -2;
			}
		}
	}
	else // Normal scoreboard
	{
		for(int RenderDead = 0; RenderDead < 2; ++RenderDead)
		{
			for(int i = 0; i < MAX_CLIENTS && NumRenderScoreIDs < MAX_IDS; i++)
			{
				// make sure that we render the correct team
				const CGameClient::CPlayerInfoItem *pInfo = &m_pClient->m_Snap.m_aInfoByScore[i];
				if(!pInfo->m_pPlayerInfo || m_pClient->m_aClients[pInfo->m_ClientID].m_Team != Team || (!RenderDead && (pInfo->m_pPlayerInfo->m_PlayerFlags&PLAYERFLAG_DEAD)) ||
					(RenderDead && !(pInfo->m_pPlayerInfo->m_PlayerFlags&PLAYERFLAG_DEAD)))
					continue;

				RenderScoreIDs[NumRenderScoreIDs] = i;
				NumRenderScoreIDs++;
			}
		}
	}

	for(int i = 0 ; i < NumRenderScoreIDs ; i++)
	{
		if(RenderScoreIDs[i] >= 0)
		{
			const CGameClient::CPlayerInfoItem *pInfo = &m_pClient->m_Snap.m_aInfoByScore[RenderScoreIDs[i]];
			bool RenderDead = pInfo->m_pPlayerInfo->m_PlayerFlags&PLAYERFLAG_DEAD;
			float ColorAlpha = RenderDead ? 0.5f : 1.0f;
			TextRender()->TextColor(1.0f, 1.0f, 1.0f, ColorAlpha);

			// color for text
			vec3 TextColor = vec3(1.0f, 1.0f, 1.0f);
			vec4 OutlineColor(0.0f, 0.0f, 0.0f, 0.3f);
			const bool HighlightedLine = m_pClient->m_LocalClientID == pInfo->m_ClientID || (Snap.m_SpecInfo.m_Active && pInfo->m_ClientID == Snap.m_SpecInfo.m_SpectatorID);

			// background so it's easy to find the local player or the followed one in spectator mode
			if(HighlightedLine)
			{
				CUIRect Rect = {x, y, w, LineHeight};
				RenderTools()->DrawRoundRect(&Rect, vec4(1.0f, 1.0f, 1.0f, 0.75f*ColorAlpha), 5.0f);

				// make color for own entry black
				TextColor = vec3(0.0f, 0.0f, 0.0f);
				OutlineColor = vec4(1.0f, 1.0f, 1.0f, 0.25f);
			}
			else
				OutlineColor = vec4(0.0f, 0.0f, 0.0f, 0.3f);

			// set text color
			TextRender()->TextColor(TextColor.r, TextColor.g, TextColor.b, ColorAlpha);
			TextRender()->TextOutlineColor(OutlineColor.r, OutlineColor.g, OutlineColor.b, OutlineColor.a);

			// ping
			TextRender()->TextColor(TextColor.r, TextColor.g, TextColor.b, 0.5f*ColorAlpha);
			str_format(aBuf, sizeof(aBuf), "%d", clamp(pInfo->m_pPlayerInfo->m_Latency, 0, 999));
			tw = TextRender()->TextWidth(0, FontSize, aBuf, -1, -1.0f);
			TextRender()->SetCursor(&Cursor, PingOffset+PingLength-tw, y+Spacing, FontSize, TEXTFLAG_RENDER);
			Cursor.m_LineWidth = PingLength;
			TextRender()->TextEx(&Cursor, aBuf, -1);
			TextRender()->TextColor(TextColor.r, TextColor.g, TextColor.b, ColorAlpha);

			// country flag
			const vec4 CFColor(1, 1, 1, 0.75f * ColorAlpha);
			m_pClient->m_pCountryFlags->Render(m_pClient->m_aClients[pInfo->m_ClientID].m_Country, &CFColor,
				CountryFlagOffset, y + 3.0f, 30.0f, LineHeight-5.0f);

			// flag
			if(m_pClient->m_GameInfo.m_GameFlags&GAMEFLAG_FLAGS && m_pClient->m_Snap.m_pGameDataFlag &&
				(m_pClient->m_Snap.m_pGameDataFlag->m_FlagCarrierRed == pInfo->m_ClientID ||
				m_pClient->m_Snap.m_pGameDataFlag->m_FlagCarrierBlue == pInfo->m_ClientID))
			{
				Graphics()->BlendNormal();
				Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GAME].m_Id);
				Graphics()->QuadsBegin();

				RenderTools()->SelectSprite(m_pClient->m_aClients[pInfo->m_ClientID].m_Team==TEAM_RED ? SPRITE_FLAG_BLUE : SPRITE_FLAG_RED, SPRITE_FLAG_FLIP_X);

				float Size = LineHeight;
				IGraphics::CQuadItem QuadItem(TeeOffset+4.0f, y-2.0f-Spacing/2.0f, Size/2.0f, Size);
				Graphics()->QuadsDrawTL(&QuadItem, 1);
				Graphics()->QuadsEnd();
			}

			// avatar
			if(RenderDead)
			{
				Graphics()->BlendNormal();
				Graphics()->TextureSet(g_pData->m_aImages[IMAGE_DEADTEE].m_Id);
				Graphics()->QuadsBegin();
				if(m_pClient->m_GameInfo.m_GameFlags&GAMEFLAG_TEAMS)
				{
					vec4 Color = m_pClient->m_pSkins->GetColorV4(m_pClient->m_pSkins->GetTeamColor(true, 0, m_pClient->m_aClients[pInfo->m_ClientID].m_Team, SKINPART_BODY), false);
					Graphics()->SetColor(Color.r, Color.g, Color.b, Color.a);
				}
				IGraphics::CQuadItem QuadItem(TeeOffset+TeeLength/2 - 10*TeeSizeMod, y-2.0f+Spacing, 20*TeeSizeMod, 20*TeeSizeMod);
				Graphics()->QuadsDrawTL(&QuadItem, 1);
				Graphics()->QuadsEnd();
			}
			else
			{
				CTeeRenderInfo TeeInfo = m_pClient->m_aClients[pInfo->m_ClientID].m_RenderInfo;
				TeeInfo.m_Size = 20*TeeSizeMod;
				RenderTools()->RenderTee(CAnimState::GetIdle(), &TeeInfo, EMOTE_NORMAL, vec2(1.0f, 0.0f), vec2(TeeOffset+TeeLength/2, y+LineHeight/2+Spacing));
			}

			// TODO: make an eye icon or something
			if(RenderDead && pInfo->m_pPlayerInfo->m_PlayerFlags&PLAYERFLAG_WATCHING)
				TextRender()->TextColor(1.0f, 1.0f, 0.0f, ColorAlpha);

			// id
			if(g_Config.m_ClShowUserId)
			{
				TextRender()->SetCursor(&Cursor, NameOffset+TeeLength-IdSize+Spacing, y+Spacing, FontSize, TEXTFLAG_RENDER);
				RenderTools()->DrawClientID(TextRender(), &Cursor, pInfo->m_ClientID);
			}

			// name
			TextRender()->SetCursor(&Cursor, NameOffset+TeeLength, y+Spacing, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END);
			Cursor.m_LineWidth = NameLength-TeeLength;
			TextRender()->TextEx(&Cursor, m_pClient->m_aClients[pInfo->m_ClientID].m_aName, str_length(m_pClient->m_aClients[pInfo->m_ClientID].m_aName));
			// ready / watching
			if(ReadyMode && (pInfo->m_pPlayerInfo->m_PlayerFlags&PLAYERFLAG_READY))
			{
				if(HighlightedLine)
					TextRender()->TextOutlineColor(0.0f, 0.1f, 0.0f, 0.5f);
				TextRender()->TextColor(0.1f, 1.0f, 0.1f, ColorAlpha);
				TextRender()->SetCursor(&Cursor, Cursor.m_X, y+Spacing, FontSize, TEXTFLAG_RENDER);
				TextRender()->TextEx(&Cursor, "\xE2\x9C\x93", str_length("\xE2\x9C\x93"));
			}
			TextRender()->TextColor(TextColor.r, TextColor.g, TextColor.b, ColorAlpha);
			TextRender()->TextOutlineColor(OutlineColor.r, OutlineColor.g, OutlineColor.b, OutlineColor.a);

			// clan
			tw = TextRender()->TextWidth(0, FontSize, m_pClient->m_aClients[pInfo->m_ClientID].m_aClan, -1, -1.0f);
			TextRender()->SetCursor(&Cursor, ClanOffset+ClanLength/2-tw/2, y+Spacing, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END);
			Cursor.m_LineWidth = ClanLength;
			TextRender()->TextEx(&Cursor, m_pClient->m_aClients[pInfo->m_ClientID].m_aClan, -1);

			// K
			TextRender()->TextColor(TextColor.r, TextColor.g, TextColor.b, 0.5f*ColorAlpha);
			str_format(aBuf, sizeof(aBuf), "%d", clamp(m_aPlayerStats[pInfo->m_ClientID].m_Kills, 0, 999));
			tw = TextRender()->TextWidth(0, FontSize, aBuf, -1, -1.0f);
			TextRender()->SetCursor(&Cursor, KillOffset+KillLength/2-tw/2, y+Spacing, FontSize, TEXTFLAG_RENDER);
			Cursor.m_LineWidth = KillLength;
			TextRender()->TextEx(&Cursor, aBuf, -1);

			// D
			str_format(aBuf, sizeof(aBuf), "%d", clamp(m_aPlayerStats[pInfo->m_ClientID].m_Deaths, 0, 999));
			tw = TextRender()->TextWidth(0, FontSize, aBuf, -1, -1.0f);
			TextRender()->SetCursor(&Cursor, DeathOffset+DeathLength/2-tw/2, y+Spacing, FontSize, TEXTFLAG_RENDER);
			Cursor.m_LineWidth = DeathLength;
			TextRender()->TextEx(&Cursor, aBuf, -1);

			// score
			TextRender()->TextColor(TextColor.r, TextColor.g, TextColor.b, ColorAlpha);
			str_format(aBuf, sizeof(aBuf), "%d", clamp(pInfo->m_pPlayerInfo->m_Score, -999, 999));
			tw = TextRender()->TextWidth(0, FontSize, aBuf, -1, -1.0f);
			TextRender()->SetCursor(&Cursor, ScoreOffset+ScoreLength/2-tw/2, y+Spacing, FontSize, TEXTFLAG_RENDER);
			Cursor.m_LineWidth = ScoreLength;
			TextRender()->TextEx(&Cursor, aBuf, -1);

			y += LineHeight;
		}
		else
		{
			int HoleSize = HoleSizes[-1-RenderScoreIDs[i]];

			TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f);

			TextRender()->SetCursor(&Cursor, NameOffset+TeeLength, y+Spacing, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END);
			Cursor.m_LineWidth = NameLength;
			char aBuf[64], aBuf2[64];
			str_format(aBuf, sizeof(aBuf), Localize("%d other players"), HoleSize);
			str_format(aBuf2, sizeof(aBuf2), "\xe2\x8b\x85\xe2\x8b\x85\xe2\x8b\x85 %s", aBuf);
			TextRender()->TextEx(&Cursor, aBuf2, -1);
			y += LineHeight;
		}
	}
	TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f);
	TextRender()->TextOutlineColor(0.0f, 0.0f, 0.0f, 0.3f);

	return HeadlineHeight+LineHeight*(m_PlayerLines+1);
}