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. */
|
2010-05-29 07:25:38 +00:00
|
|
|
|
#include <engine/graphics.h>
|
2014-01-10 15:19:46 +00:00
|
|
|
|
#include <engine/serverbrowser.h>
|
2010-05-29 07:25:38 +00:00
|
|
|
|
#include <engine/shared/config.h>
|
2020-09-26 19:41:58 +00:00
|
|
|
|
#include <engine/textrender.h>
|
2010-05-29 07:25:38 +00:00
|
|
|
|
|
|
|
|
|
#include <game/client/animstate.h>
|
2013-10-07 10:13:33 +00:00
|
|
|
|
#include <game/client/components/scoreboard.h>
|
2020-09-26 19:41:58 +00:00
|
|
|
|
#include <game/client/gameclient.h>
|
|
|
|
|
#include <game/client/render.h>
|
|
|
|
|
#include <game/generated/client_data.h>
|
2022-03-21 22:55:35 +00:00
|
|
|
|
#include <game/generated/client_data7.h>
|
2020-09-26 19:41:58 +00:00
|
|
|
|
#include <game/generated/protocol.h>
|
|
|
|
|
#include <game/layers.h>
|
2010-05-29 07:25:38 +00:00
|
|
|
|
|
2018-03-13 20:56:37 +00:00
|
|
|
|
#include <cmath>
|
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
|
#include "binds.h"
|
2010-05-29 07:25:38 +00:00
|
|
|
|
#include "camera.h"
|
2020-09-26 19:41:58 +00:00
|
|
|
|
#include "controls.h"
|
2010-05-29 07:25:38 +00:00
|
|
|
|
#include "hud.h"
|
|
|
|
|
#include "voting.h"
|
|
|
|
|
|
|
|
|
|
CHud::CHud()
|
2008-08-27 15:48:50 +00:00
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
|
// won't work if zero
|
2018-01-14 16:21:50 +00:00
|
|
|
|
m_FrameTimeAvg = 0.0f;
|
2018-03-21 14:53:29 +00:00
|
|
|
|
m_FPSTextContainerIndex = -1;
|
2010-10-30 14:22:35 +00:00
|
|
|
|
OnReset();
|
2008-08-27 15:48:50 +00:00
|
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2018-03-21 14:53:29 +00:00
|
|
|
|
void CHud::ResetHudContainers()
|
2008-08-27 15:48:50 +00:00
|
|
|
|
{
|
2018-03-21 15:02:11 +00:00
|
|
|
|
if(m_aScoreInfo[0].m_OptionalNameTextContainerIndex != -1)
|
2018-03-13 20:56:37 +00:00
|
|
|
|
TextRender()->DeleteTextContainer(m_aScoreInfo[0].m_OptionalNameTextContainerIndex);
|
2018-03-21 15:02:11 +00:00
|
|
|
|
if(m_aScoreInfo[1].m_OptionalNameTextContainerIndex != -1)
|
2018-03-13 20:56:37 +00:00
|
|
|
|
TextRender()->DeleteTextContainer(m_aScoreInfo[1].m_OptionalNameTextContainerIndex);
|
|
|
|
|
|
2018-03-21 15:02:11 +00:00
|
|
|
|
if(m_aScoreInfo[0].m_TextRankContainerIndex != -1)
|
2018-03-13 20:56:37 +00:00
|
|
|
|
TextRender()->DeleteTextContainer(m_aScoreInfo[0].m_TextRankContainerIndex);
|
2018-03-21 15:02:11 +00:00
|
|
|
|
if(m_aScoreInfo[1].m_TextRankContainerIndex != -1)
|
2018-03-13 20:56:37 +00:00
|
|
|
|
TextRender()->DeleteTextContainer(m_aScoreInfo[1].m_TextRankContainerIndex);
|
|
|
|
|
|
2018-03-21 15:02:11 +00:00
|
|
|
|
if(m_aScoreInfo[0].m_TextScoreContainerIndex != -1)
|
2018-03-13 20:56:37 +00:00
|
|
|
|
TextRender()->DeleteTextContainer(m_aScoreInfo[0].m_TextScoreContainerIndex);
|
2018-03-21 15:02:11 +00:00
|
|
|
|
if(m_aScoreInfo[1].m_TextScoreContainerIndex != -1)
|
2018-03-13 20:56:37 +00:00
|
|
|
|
TextRender()->DeleteTextContainer(m_aScoreInfo[1].m_TextScoreContainerIndex);
|
|
|
|
|
|
2018-03-21 15:02:11 +00:00
|
|
|
|
if(m_aScoreInfo[0].m_RoundRectQuadContainerIndex != -1)
|
2018-03-13 20:56:37 +00:00
|
|
|
|
Graphics()->DeleteQuadContainer(m_aScoreInfo[0].m_RoundRectQuadContainerIndex);
|
2018-03-21 15:02:11 +00:00
|
|
|
|
if(m_aScoreInfo[1].m_RoundRectQuadContainerIndex != -1)
|
2018-03-13 20:56:37 +00:00
|
|
|
|
Graphics()->DeleteQuadContainer(m_aScoreInfo[1].m_RoundRectQuadContainerIndex);
|
|
|
|
|
|
|
|
|
|
m_aScoreInfo[0].Reset();
|
|
|
|
|
m_aScoreInfo[1].Reset();
|
2018-03-21 14:53:29 +00:00
|
|
|
|
|
2018-03-21 15:02:11 +00:00
|
|
|
|
if(m_FPSTextContainerIndex != -1)
|
2018-03-21 14:53:29 +00:00
|
|
|
|
TextRender()->DeleteTextContainer(m_FPSTextContainerIndex);
|
|
|
|
|
m_FPSTextContainerIndex = -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CHud::OnWindowResize()
|
|
|
|
|
{
|
|
|
|
|
ResetHudContainers();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CHud::OnReset()
|
|
|
|
|
{
|
|
|
|
|
m_CheckpointDiff = 0.0f;
|
|
|
|
|
m_DDRaceTime = 0;
|
|
|
|
|
m_LastReceivedTimeTick = 0;
|
|
|
|
|
m_CheckpointTick = 0;
|
|
|
|
|
m_FinishTime = false;
|
|
|
|
|
m_DDRaceTimeReceived = false;
|
|
|
|
|
m_ServerRecord = -1.0f;
|
2020-03-01 11:54:59 +00:00
|
|
|
|
m_PlayerRecord[0] = -1.0f;
|
|
|
|
|
m_PlayerRecord[1] = -1.0f;
|
2018-03-21 14:53:29 +00:00
|
|
|
|
|
|
|
|
|
ResetHudContainers();
|
2018-03-13 20:56:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CHud::OnInit()
|
|
|
|
|
{
|
2021-09-13 21:14:04 +00:00
|
|
|
|
m_HudQuadContainerIndex = Graphics()->CreateQuadContainer(false);
|
2022-03-18 10:11:58 +00:00
|
|
|
|
Graphics()->QuadsSetSubset(0, 0, 1, 1);
|
|
|
|
|
PrepareAmmoHealthAndArmorQuads();
|
2018-03-13 20:56:37 +00:00
|
|
|
|
|
2022-03-18 10:11:58 +00:00
|
|
|
|
// all cursors for the different weapons
|
2018-03-13 20:56:37 +00:00
|
|
|
|
for(int i = 0; i < NUM_WEAPONS; ++i)
|
|
|
|
|
{
|
2020-10-09 07:07:05 +00:00
|
|
|
|
float ScaleX, ScaleY;
|
|
|
|
|
RenderTools()->GetSpriteScale(g_pData->m_Weapons.m_aId[i].m_pSpriteCursor, ScaleX, ScaleY);
|
2022-03-18 10:11:58 +00:00
|
|
|
|
m_CursorOffset[i] = RenderTools()->QuadContainerAddSprite(m_HudQuadContainerIndex, 64.f * ScaleX, 64.f * ScaleY);
|
2018-03-13 20:56:37 +00:00
|
|
|
|
}
|
2019-04-02 23:05:38 +00:00
|
|
|
|
|
2018-03-13 20:56:37 +00:00
|
|
|
|
// the flags
|
2022-03-18 10:11:58 +00:00
|
|
|
|
m_FlagOffset = RenderTools()->QuadContainerAddSprite(m_HudQuadContainerIndex, 0.f, 0.f, 8.f, 16.f);
|
|
|
|
|
|
2022-03-20 13:18:02 +00:00
|
|
|
|
PreparePlayerStateQuads();
|
|
|
|
|
|
2021-09-13 21:14:04 +00:00
|
|
|
|
Graphics()->QuadContainerUpload(m_HudQuadContainerIndex);
|
2008-08-27 15:48:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-05-30 12:01:11 +00:00
|
|
|
|
void CHud::RenderGameTimer()
|
2008-08-27 15:48:50 +00:00
|
|
|
|
{
|
2022-04-14 11:31:00 +00:00
|
|
|
|
float Half = m_Width / 2.0f;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
|
if(!(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags & GAMESTATEFLAG_SUDDENDEATH))
|
2008-08-27 15:48:50 +00:00
|
|
|
|
{
|
2019-06-03 19:52:14 +00:00
|
|
|
|
char aBuf[32];
|
2010-05-29 07:25:38 +00:00
|
|
|
|
int Time = 0;
|
2017-01-04 13:14:10 +00:00
|
|
|
|
if(m_pClient->m_Snap.m_pGameInfoObj->m_TimeLimit && (m_pClient->m_Snap.m_pGameInfoObj->m_WarmupTimer <= 0))
|
2008-08-27 15:48:50 +00:00
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
|
Time = m_pClient->m_Snap.m_pGameInfoObj->m_TimeLimit * 60 - ((Client()->GameTick(g_Config.m_ClDummy) - m_pClient->m_Snap.m_pGameInfoObj->m_RoundStartTick) / Client()->GameTickSpeed());
|
2008-08-27 15:48:50 +00:00
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
|
if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags & GAMESTATEFLAG_GAMEOVER)
|
2011-04-13 18:37:12 +00:00
|
|
|
|
Time = 0;
|
2008-08-27 15:48:50 +00:00
|
|
|
|
}
|
2020-09-26 19:41:58 +00:00
|
|
|
|
else if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags & GAMESTATEFLAG_RACETIME)
|
2017-01-04 13:14:10 +00:00
|
|
|
|
{
|
|
|
|
|
//The Warmup timer is negative in this case to make sure that incompatible clients will not see a warmup timer
|
2020-09-26 19:41:58 +00:00
|
|
|
|
Time = (Client()->GameTick(g_Config.m_ClDummy) + m_pClient->m_Snap.m_pGameInfoObj->m_WarmupTimer) / Client()->GameTickSpeed();
|
2017-01-04 13:14:10 +00:00
|
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
|
else
|
2020-09-26 19:41:58 +00:00
|
|
|
|
Time = (Client()->GameTick(g_Config.m_ClDummy) - m_pClient->m_Snap.m_pGameInfoObj->m_RoundStartTick) / Client()->GameTickSpeed();
|
2008-08-27 15:48:50 +00:00
|
|
|
|
|
2022-03-01 20:58:10 +00:00
|
|
|
|
str_time((int64_t)Time * 100, TIME_DAYS, aBuf, sizeof(aBuf));
|
2010-05-30 12:01:11 +00:00
|
|
|
|
float FontSize = 10.0f;
|
2022-05-10 16:41:46 +00:00
|
|
|
|
static float s_TextWidthM = TextRender()->TextWidth(0, FontSize, "00:00", -1, -1.0f);
|
|
|
|
|
static float s_TextWidthH = TextRender()->TextWidth(0, FontSize, "00:00:00", -1, -1.0f);
|
|
|
|
|
static float s_TextWidth0D = TextRender()->TextWidth(0, FontSize, "0d 00:00:00", -1, -1.0f);
|
|
|
|
|
static float s_TextWidth00D = TextRender()->TextWidth(0, FontSize, "00d 00:00:00", -1, -1.0f);
|
|
|
|
|
static float s_TextWidth000D = TextRender()->TextWidth(0, FontSize, "000d 00:00:00", -1, -1.0f);
|
|
|
|
|
float w = Time >= 3600 * 24 * 100 ? s_TextWidth000D : Time >= 3600 * 24 * 10 ? s_TextWidth00D : Time >= 3600 * 24 ? s_TextWidth0D : Time >= 3600 ? s_TextWidthH : s_TextWidthM;
|
2011-01-09 23:58:03 +00:00
|
|
|
|
// last 60 sec red, last 10 sec blink
|
2017-01-04 13:14:10 +00:00
|
|
|
|
if(m_pClient->m_Snap.m_pGameInfoObj->m_TimeLimit && Time <= 60 && (m_pClient->m_Snap.m_pGameInfoObj->m_WarmupTimer <= 0))
|
2011-01-09 23:58:03 +00:00
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
|
float Alpha = Time <= 10 && (2 * time() / time_freq()) % 2 ? 0.5f : 1.0f;
|
2011-01-09 23:58:03 +00:00
|
|
|
|
TextRender()->TextColor(1.0f, 0.25f, 0.25f, Alpha);
|
|
|
|
|
}
|
2020-09-26 19:41:58 +00:00
|
|
|
|
TextRender()->Text(0, Half - w / 2, 2, FontSize, aBuf, -1.0f);
|
2011-01-09 23:58:03 +00:00
|
|
|
|
TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f);
|
2008-08-27 15:48:50 +00:00
|
|
|
|
}
|
2010-05-30 12:01:11 +00:00
|
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
|
|
2012-01-10 21:40:48 +00:00
|
|
|
|
void CHud::RenderPauseNotification()
|
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
|
if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags & GAMESTATEFLAG_PAUSED &&
|
|
|
|
|
!(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags & GAMESTATEFLAG_GAMEOVER))
|
2012-01-10 21:40:48 +00:00
|
|
|
|
{
|
|
|
|
|
const char *pText = Localize("Game paused");
|
|
|
|
|
float FontSize = 20.0f;
|
2020-09-26 19:41:58 +00:00
|
|
|
|
float w = TextRender()->TextWidth(0, FontSize, pText, -1, -1.0f);
|
|
|
|
|
TextRender()->Text(0, 150.0f * Graphics()->ScreenAspect() + -w / 2.0f, 50.0f, FontSize, pText, -1.0f);
|
2012-01-10 21:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-30 12:01:11 +00:00
|
|
|
|
void CHud::RenderSuddenDeath()
|
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
|
if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags & GAMESTATEFLAG_SUDDENDEATH)
|
2008-08-27 15:48:50 +00:00
|
|
|
|
{
|
2022-04-14 11:31:00 +00:00
|
|
|
|
float Half = m_Width / 2.0f;
|
2010-06-03 09:30:05 +00:00
|
|
|
|
const char *pText = Localize("Sudden Death");
|
2010-05-30 12:01:11 +00:00
|
|
|
|
float FontSize = 12.0f;
|
2020-07-15 19:10:13 +00:00
|
|
|
|
float w = TextRender()->TextWidth(0, FontSize, pText, -1, -1.0f);
|
2020-09-26 19:41:58 +00:00
|
|
|
|
TextRender()->Text(0, Half - w / 2, 2, FontSize, pText, -1.0f);
|
2008-08-27 15:48:50 +00:00
|
|
|
|
}
|
2010-05-30 12:01:11 +00:00
|
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
|
|
2010-05-30 12:01:11 +00:00
|
|
|
|
void CHud::RenderScoreHud()
|
2011-04-13 18:37:12 +00:00
|
|
|
|
{
|
2008-08-27 15:48:50 +00:00
|
|
|
|
// render small score hud
|
2020-09-26 19:41:58 +00:00
|
|
|
|
if(!(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags & GAMESTATEFLAG_GAMEOVER))
|
2008-08-27 15:48:50 +00:00
|
|
|
|
{
|
2011-03-04 16:08:10 +00:00
|
|
|
|
int GameFlags = m_pClient->m_Snap.m_pGameInfoObj->m_GameFlags;
|
2022-05-10 16:41:46 +00:00
|
|
|
|
float StartY = 229.0f; // the height of this display is 56, so EndY is 285
|
2011-01-12 00:01:05 +00:00
|
|
|
|
|
2021-04-09 18:11:53 +00:00
|
|
|
|
const float ScoreSingleBoxHeight = 18.0f;
|
|
|
|
|
|
2018-03-13 20:56:37 +00:00
|
|
|
|
bool ForceScoreInfoInit = !m_aScoreInfo[0].m_Initialized || !m_aScoreInfo[1].m_Initialized;
|
|
|
|
|
m_aScoreInfo[0].m_Initialized = m_aScoreInfo[1].m_Initialized = true;
|
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
|
if(GameFlags & GAMEFLAG_TEAMS && m_pClient->m_Snap.m_pGameDataObj)
|
2008-08-27 15:48:50 +00:00
|
|
|
|
{
|
2018-03-13 20:56:37 +00:00
|
|
|
|
char aScoreTeam[2][16];
|
|
|
|
|
str_format(aScoreTeam[TEAM_RED], sizeof(aScoreTeam), "%d", m_pClient->m_Snap.m_pGameDataObj->m_TeamscoreRed);
|
|
|
|
|
str_format(aScoreTeam[TEAM_BLUE], sizeof(aScoreTeam), "%d", m_pClient->m_Snap.m_pGameDataObj->m_TeamscoreBlue);
|
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
|
bool RecreateTeamScore[2] = {str_comp(aScoreTeam[0], m_aScoreInfo[0].m_aScoreText) != 0, str_comp(aScoreTeam[1], m_aScoreInfo[1].m_aScoreText) != 0};
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2019-04-02 23:05:38 +00:00
|
|
|
|
int FlagCarrier[2] = {
|
|
|
|
|
m_pClient->m_Snap.m_pGameDataObj->m_FlagCarrierRed,
|
2020-09-26 19:41:58 +00:00
|
|
|
|
m_pClient->m_Snap.m_pGameDataObj->m_FlagCarrierBlue};
|
2018-03-13 20:56:37 +00:00
|
|
|
|
|
|
|
|
|
bool RecreateRect = ForceScoreInfoInit;
|
|
|
|
|
for(int t = 0; t < 2; t++)
|
|
|
|
|
{
|
|
|
|
|
if(RecreateTeamScore[t])
|
|
|
|
|
{
|
2020-07-15 19:10:13 +00:00
|
|
|
|
m_aScoreInfo[t].m_ScoreTextWidth = TextRender()->TextWidth(0, 14.0f, aScoreTeam[t == 0 ? TEAM_RED : TEAM_BLUE], -1, -1.0f);
|
2018-03-13 20:56:37 +00:00
|
|
|
|
mem_copy(m_aScoreInfo[t].m_aScoreText, aScoreTeam[t == 0 ? TEAM_RED : TEAM_BLUE], sizeof(m_aScoreInfo[t].m_aScoreText));
|
|
|
|
|
RecreateRect = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-15 19:10:13 +00:00
|
|
|
|
static float s_TextWidth100 = TextRender()->TextWidth(0, 14.0f, "100", -1, -1.0f);
|
2019-04-26 19:36:49 +00:00
|
|
|
|
float ScoreWidthMax = maximum(maximum(m_aScoreInfo[0].m_ScoreTextWidth, m_aScoreInfo[1].m_ScoreTextWidth), s_TextWidth100);
|
2018-03-13 20:56:37 +00:00
|
|
|
|
float Split = 3.0f;
|
|
|
|
|
float ImageSize = GameFlags & GAMEFLAG_FLAGS ? 16.0f : Split;
|
2011-01-12 00:01:05 +00:00
|
|
|
|
for(int t = 0; t < 2; t++)
|
2008-08-27 15:48:50 +00:00
|
|
|
|
{
|
2011-01-12 00:01:05 +00:00
|
|
|
|
// draw box
|
2018-03-13 20:56:37 +00:00
|
|
|
|
if(RecreateRect)
|
2019-04-02 23:05:38 +00:00
|
|
|
|
{
|
2018-03-13 20:56:37 +00:00
|
|
|
|
if(m_aScoreInfo[t].m_RoundRectQuadContainerIndex != -1)
|
|
|
|
|
Graphics()->DeleteQuadContainer(m_aScoreInfo[t].m_RoundRectQuadContainerIndex);
|
|
|
|
|
|
|
|
|
|
if(t == 0)
|
|
|
|
|
Graphics()->SetColor(1.0f, 0.0f, 0.0f, 0.25f);
|
|
|
|
|
else
|
|
|
|
|
Graphics()->SetColor(0.0f, 0.0f, 1.0f, 0.25f);
|
2022-04-14 11:31:00 +00:00
|
|
|
|
m_aScoreInfo[t].m_RoundRectQuadContainerIndex = RenderTools()->CreateRoundRectQuadContainer(m_Width - ScoreWidthMax - ImageSize - 2 * Split, StartY + t * 20, ScoreWidthMax + ImageSize + 2 * Split, ScoreSingleBoxHeight, 5.0f, CUI::CORNER_L);
|
2018-03-13 20:56:37 +00:00
|
|
|
|
}
|
2012-08-12 10:41:50 +00:00
|
|
|
|
Graphics()->TextureClear();
|
2018-03-13 20:56:37 +00:00
|
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
|
|
|
|
|
if(m_aScoreInfo[t].m_RoundRectQuadContainerIndex != -1)
|
|
|
|
|
Graphics()->RenderQuadContainer(m_aScoreInfo[t].m_RoundRectQuadContainerIndex, -1);
|
2011-01-12 00:01:05 +00:00
|
|
|
|
|
|
|
|
|
// draw score
|
2018-03-13 20:56:37 +00:00
|
|
|
|
if(RecreateTeamScore[t])
|
|
|
|
|
{
|
|
|
|
|
if(m_aScoreInfo[t].m_TextScoreContainerIndex != -1)
|
|
|
|
|
TextRender()->DeleteTextContainer(m_aScoreInfo[t].m_TextScoreContainerIndex);
|
|
|
|
|
|
|
|
|
|
CTextCursor Cursor;
|
2022-04-14 11:31:00 +00:00
|
|
|
|
TextRender()->SetCursor(&Cursor, m_Width - ScoreWidthMax + (ScoreWidthMax - m_aScoreInfo[t].m_ScoreTextWidth) / 2 - Split, StartY + t * 20 + (18.f - 14.f) / 2.f, 14.0f, TEXTFLAG_RENDER);
|
2018-03-13 20:56:37 +00:00
|
|
|
|
Cursor.m_LineWidth = -1;
|
|
|
|
|
m_aScoreInfo[t].m_TextScoreContainerIndex = TextRender()->CreateTextContainer(&Cursor, aScoreTeam[t]);
|
|
|
|
|
}
|
|
|
|
|
if(m_aScoreInfo[t].m_TextScoreContainerIndex != -1)
|
|
|
|
|
{
|
|
|
|
|
STextRenderColor TColor(1.f, 1.f, 1.f, 1.f);
|
|
|
|
|
STextRenderColor TOutlineColor(0.f, 0.f, 0.f, 0.3f);
|
|
|
|
|
TextRender()->RenderTextContainer(m_aScoreInfo[t].m_TextScoreContainerIndex, &TColor, &TOutlineColor);
|
|
|
|
|
}
|
2011-01-12 00:01:05 +00:00
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
|
if(GameFlags & GAMEFLAG_FLAGS)
|
2010-06-22 19:27:58 +00:00
|
|
|
|
{
|
2011-08-11 08:59:14 +00:00
|
|
|
|
int BlinkTimer = (m_pClient->m_FlagDropTick[t] != 0 &&
|
2020-09-26 19:41:58 +00:00
|
|
|
|
(Client()->GameTick(g_Config.m_ClDummy) - m_pClient->m_FlagDropTick[t]) / Client()->GameTickSpeed() >= 25) ?
|
|
|
|
|
10 :
|
|
|
|
|
20;
|
|
|
|
|
if(FlagCarrier[t] == FLAG_ATSTAND || (FlagCarrier[t] == FLAG_TAKEN && ((Client()->GameTick(g_Config.m_ClDummy) / BlinkTimer) & 1)))
|
2011-01-12 00:01:05 +00:00
|
|
|
|
{
|
|
|
|
|
// draw flag
|
2022-03-21 22:55:35 +00:00
|
|
|
|
Graphics()->TextureSet(t == 0 ? m_pClient->m_GameSkin.m_SpriteFlagRed : m_pClient->m_GameSkin.m_SpriteFlagBlue);
|
2018-04-05 18:46:22 +00:00
|
|
|
|
Graphics()->SetColor(1.f, 1.f, 1.f, 1.f);
|
2022-04-14 11:31:00 +00:00
|
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_HudQuadContainerIndex, m_FlagOffset, m_Width - ScoreWidthMax - ImageSize, StartY + 1.0f + t * 20);
|
2011-01-12 00:01:05 +00:00
|
|
|
|
}
|
2011-03-04 16:08:10 +00:00
|
|
|
|
else if(FlagCarrier[t] >= 0)
|
2011-01-12 00:01:05 +00:00
|
|
|
|
{
|
|
|
|
|
// draw name of the flag holder
|
2020-09-26 19:41:58 +00:00
|
|
|
|
int ID = FlagCarrier[t] % MAX_CLIENTS;
|
2011-02-12 10:40:36 +00:00
|
|
|
|
const char *pName = m_pClient->m_aClients[ID].m_aName;
|
2018-03-13 20:56:37 +00:00
|
|
|
|
if(str_comp(pName, m_aScoreInfo[t].m_aPlayerNameText) != 0 || RecreateRect)
|
|
|
|
|
{
|
|
|
|
|
mem_copy(m_aScoreInfo[t].m_aPlayerNameText, pName, sizeof(m_aScoreInfo[t].m_aPlayerNameText));
|
|
|
|
|
|
|
|
|
|
if(m_aScoreInfo[t].m_OptionalNameTextContainerIndex != -1)
|
|
|
|
|
TextRender()->DeleteTextContainer(m_aScoreInfo[t].m_OptionalNameTextContainerIndex);
|
|
|
|
|
|
2020-07-15 19:10:13 +00:00
|
|
|
|
float w = TextRender()->TextWidth(0, 8.0f, pName, -1, -1.0f);
|
2019-04-02 23:05:38 +00:00
|
|
|
|
|
2018-03-13 20:56:37 +00:00
|
|
|
|
CTextCursor Cursor;
|
2022-04-14 11:31:00 +00:00
|
|
|
|
TextRender()->SetCursor(&Cursor, minimum(m_Width - w - 1.0f, m_Width - ScoreWidthMax - ImageSize - 2 * Split), StartY + (t + 1) * 20.0f - 2.0f, 8.0f, TEXTFLAG_RENDER);
|
2018-03-13 20:56:37 +00:00
|
|
|
|
Cursor.m_LineWidth = -1;
|
|
|
|
|
m_aScoreInfo[t].m_OptionalNameTextContainerIndex = TextRender()->CreateTextContainer(&Cursor, pName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(m_aScoreInfo[t].m_OptionalNameTextContainerIndex != -1)
|
|
|
|
|
{
|
|
|
|
|
STextRenderColor TColor(1.f, 1.f, 1.f, 1.f);
|
|
|
|
|
STextRenderColor TOutlineColor(0.f, 0.f, 0.f, 0.3f);
|
|
|
|
|
TextRender()->RenderTextContainer(m_aScoreInfo[t].m_OptionalNameTextContainerIndex, &TColor, &TOutlineColor);
|
|
|
|
|
}
|
2011-01-12 00:01:05 +00:00
|
|
|
|
|
|
|
|
|
// draw tee of the flag holder
|
2021-04-09 18:11:53 +00:00
|
|
|
|
CTeeRenderInfo TeeInfo = m_pClient->m_aClients[ID].m_RenderInfo;
|
|
|
|
|
TeeInfo.m_Size = ScoreSingleBoxHeight;
|
|
|
|
|
|
|
|
|
|
CAnimState *pIdleState = CAnimState::GetIdle();
|
|
|
|
|
vec2 OffsetToMid;
|
|
|
|
|
RenderTools()->GetRenderTeeOffsetToRenderedTee(pIdleState, &TeeInfo, OffsetToMid);
|
2022-04-14 11:31:00 +00:00
|
|
|
|
vec2 TeeRenderPos(m_Width - ScoreWidthMax - TeeInfo.m_Size / 2 - Split, StartY + (t * 20) + ScoreSingleBoxHeight / 2.0f + OffsetToMid.y);
|
2021-04-09 18:11:53 +00:00
|
|
|
|
|
|
|
|
|
RenderTools()->RenderTee(pIdleState, &TeeInfo, EMOTE_NORMAL, vec2(1.0f, 0.0f), TeeRenderPos);
|
2011-01-12 00:01:05 +00:00
|
|
|
|
}
|
2010-06-22 19:27:58 +00:00
|
|
|
|
}
|
2012-01-08 23:28:42 +00:00
|
|
|
|
StartY += 8.0f;
|
2011-01-12 00:01:05 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2011-01-18 16:56:09 +00:00
|
|
|
|
int Local = -1;
|
2020-09-26 19:41:58 +00:00
|
|
|
|
int aPos[2] = {1, 2};
|
|
|
|
|
const CNetObj_PlayerInfo *apPlayerInfo[2] = {0, 0};
|
2011-01-18 16:56:09 +00:00
|
|
|
|
int i = 0;
|
|
|
|
|
for(int t = 0; t < 2 && i < MAX_CLIENTS && m_pClient->m_Snap.m_paInfoByScore[i]; ++i)
|
2011-01-12 00:01:05 +00:00
|
|
|
|
{
|
2011-01-18 16:56:09 +00:00
|
|
|
|
if(m_pClient->m_Snap.m_paInfoByScore[i]->m_Team != TEAM_SPECTATORS)
|
2008-08-27 15:48:50 +00:00
|
|
|
|
{
|
2011-01-18 16:56:09 +00:00
|
|
|
|
apPlayerInfo[t] = m_pClient->m_Snap.m_paInfoByScore[i];
|
2011-02-12 10:40:36 +00:00
|
|
|
|
if(apPlayerInfo[t]->m_ClientID == m_pClient->m_Snap.m_LocalClientID)
|
2011-01-18 16:56:09 +00:00
|
|
|
|
Local = t;
|
|
|
|
|
++t;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// search local player info if not a spectator, nor within top2 scores
|
|
|
|
|
if(Local == -1 && m_pClient->m_Snap.m_pLocalInfo && m_pClient->m_Snap.m_pLocalInfo->m_Team != TEAM_SPECTATORS)
|
|
|
|
|
{
|
|
|
|
|
for(; i < MAX_CLIENTS && m_pClient->m_Snap.m_paInfoByScore[i]; ++i)
|
|
|
|
|
{
|
|
|
|
|
if(m_pClient->m_Snap.m_paInfoByScore[i]->m_Team != TEAM_SPECTATORS)
|
|
|
|
|
++aPos[1];
|
2011-02-12 10:40:36 +00:00
|
|
|
|
if(m_pClient->m_Snap.m_paInfoByScore[i]->m_ClientID == m_pClient->m_Snap.m_LocalClientID)
|
2011-01-18 16:56:09 +00:00
|
|
|
|
{
|
|
|
|
|
apPlayerInfo[1] = m_pClient->m_Snap.m_paInfoByScore[i];
|
|
|
|
|
Local = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
|
}
|
2011-01-12 00:01:05 +00:00
|
|
|
|
}
|
2018-03-13 20:56:37 +00:00
|
|
|
|
char aScore[2][16];
|
2011-01-12 00:01:05 +00:00
|
|
|
|
for(int t = 0; t < 2; ++t)
|
|
|
|
|
{
|
|
|
|
|
if(apPlayerInfo[t])
|
2014-01-10 15:19:46 +00:00
|
|
|
|
{
|
2019-06-04 22:44:59 +00:00
|
|
|
|
if(m_pClient->m_GameInfo.m_TimeScore && g_Config.m_ClDDRaceScoreBoard)
|
2014-01-10 15:19:46 +00:00
|
|
|
|
{
|
2018-03-13 20:56:37 +00:00
|
|
|
|
if(apPlayerInfo[t]->m_Score != -9999)
|
2021-06-23 05:05:49 +00:00
|
|
|
|
str_time((int64_t)abs(apPlayerInfo[t]->m_Score) * 100, TIME_HOURS, aScore[t], sizeof(aScore[t]));
|
2014-01-10 15:19:46 +00:00
|
|
|
|
else
|
|
|
|
|
aScore[t][0] = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
2020-09-26 19:41:58 +00:00
|
|
|
|
str_format(aScore[t], sizeof(aScore) / 2, "%d", apPlayerInfo[t]->m_Score);
|
2014-01-10 15:19:46 +00:00
|
|
|
|
}
|
2011-01-12 00:01:05 +00:00
|
|
|
|
else
|
|
|
|
|
aScore[t][0] = 0;
|
|
|
|
|
}
|
2018-03-13 20:56:37 +00:00
|
|
|
|
|
2022-01-09 20:53:05 +00:00
|
|
|
|
static int LocalClientID = -1;
|
|
|
|
|
bool RecreateScores = str_comp(aScore[0], m_aScoreInfo[0].m_aScoreText) != 0 || str_comp(aScore[1], m_aScoreInfo[1].m_aScoreText) != 0 || LocalClientID != m_pClient->m_Snap.m_LocalClientID;
|
|
|
|
|
LocalClientID = m_pClient->m_Snap.m_LocalClientID;
|
2018-03-13 20:56:37 +00:00
|
|
|
|
|
|
|
|
|
bool RecreateRect = ForceScoreInfoInit;
|
|
|
|
|
for(int t = 0; t < 2; t++)
|
|
|
|
|
{
|
2020-10-11 15:14:32 +00:00
|
|
|
|
if(RecreateScores)
|
2018-03-13 20:56:37 +00:00
|
|
|
|
{
|
2020-07-15 19:10:13 +00:00
|
|
|
|
m_aScoreInfo[t].m_ScoreTextWidth = TextRender()->TextWidth(0, 14.0f, aScore[t], -1, -1.0f);
|
2018-03-13 20:56:37 +00:00
|
|
|
|
mem_copy(m_aScoreInfo[t].m_aScoreText, aScore[t], sizeof(m_aScoreInfo[t].m_aScoreText));
|
|
|
|
|
RecreateRect = true;
|
|
|
|
|
}
|
2018-03-21 14:53:29 +00:00
|
|
|
|
|
2018-03-21 15:02:11 +00:00
|
|
|
|
if(apPlayerInfo[t])
|
2018-03-21 14:53:29 +00:00
|
|
|
|
{
|
|
|
|
|
int ID = apPlayerInfo[t]->m_ClientID;
|
2018-03-21 15:02:11 +00:00
|
|
|
|
if(ID >= 0 && ID < MAX_CLIENTS)
|
2018-03-21 14:53:29 +00:00
|
|
|
|
{
|
|
|
|
|
const char *pName = m_pClient->m_aClients[ID].m_aName;
|
2018-03-21 15:02:11 +00:00
|
|
|
|
if(str_comp(pName, m_aScoreInfo[t].m_aPlayerNameText) != 0)
|
2018-03-21 14:53:29 +00:00
|
|
|
|
RecreateRect = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2018-03-21 15:02:11 +00:00
|
|
|
|
if(m_aScoreInfo[t].m_aPlayerNameText[0] != 0)
|
2018-03-21 14:53:29 +00:00
|
|
|
|
RecreateRect = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char aBuf[16];
|
|
|
|
|
str_format(aBuf, sizeof(aBuf), "%d.", aPos[t]);
|
2018-03-21 15:02:11 +00:00
|
|
|
|
if(str_comp(aBuf, m_aScoreInfo[t].m_aRankText) != 0)
|
2018-03-21 14:53:29 +00:00
|
|
|
|
RecreateRect = true;
|
2018-03-13 20:56:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-07-15 19:10:13 +00:00
|
|
|
|
static float s_TextWidth10 = TextRender()->TextWidth(0, 14.0f, "10", -1, -1.0f);
|
2019-04-26 19:36:49 +00:00
|
|
|
|
float ScoreWidthMax = maximum(maximum(m_aScoreInfo[0].m_ScoreTextWidth, m_aScoreInfo[1].m_ScoreTextWidth), s_TextWidth10);
|
2011-01-12 00:01:05 +00:00
|
|
|
|
float Split = 3.0f, ImageSize = 16.0f, PosSize = 16.0f;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2011-01-12 00:01:05 +00:00
|
|
|
|
for(int t = 0; t < 2; t++)
|
|
|
|
|
{
|
|
|
|
|
// draw box
|
2018-03-13 20:56:37 +00:00
|
|
|
|
if(RecreateRect)
|
|
|
|
|
{
|
|
|
|
|
if(m_aScoreInfo[t].m_RoundRectQuadContainerIndex != -1)
|
|
|
|
|
Graphics()->DeleteQuadContainer(m_aScoreInfo[t].m_RoundRectQuadContainerIndex);
|
|
|
|
|
|
|
|
|
|
if(t == Local)
|
|
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.25f);
|
|
|
|
|
else
|
|
|
|
|
Graphics()->SetColor(0.0f, 0.0f, 0.0f, 0.25f);
|
2022-04-14 11:31:00 +00:00
|
|
|
|
m_aScoreInfo[t].m_RoundRectQuadContainerIndex = RenderTools()->CreateRoundRectQuadContainer(m_Width - ScoreWidthMax - ImageSize - 2 * Split - PosSize, StartY + t * 20, ScoreWidthMax + ImageSize + 2 * Split + PosSize, ScoreSingleBoxHeight, 5.0f, CUI::CORNER_L);
|
2018-03-13 20:56:37 +00:00
|
|
|
|
}
|
2012-08-12 10:41:50 +00:00
|
|
|
|
Graphics()->TextureClear();
|
2018-03-13 20:56:37 +00:00
|
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
|
|
|
|
|
if(m_aScoreInfo[t].m_RoundRectQuadContainerIndex != -1)
|
|
|
|
|
Graphics()->RenderQuadContainer(m_aScoreInfo[t].m_RoundRectQuadContainerIndex, -1);
|
2011-01-12 00:01:05 +00:00
|
|
|
|
|
2020-10-11 15:14:32 +00:00
|
|
|
|
if(RecreateScores)
|
2018-03-13 20:56:37 +00:00
|
|
|
|
{
|
|
|
|
|
if(m_aScoreInfo[t].m_TextScoreContainerIndex != -1)
|
|
|
|
|
TextRender()->DeleteTextContainer(m_aScoreInfo[t].m_TextScoreContainerIndex);
|
|
|
|
|
|
|
|
|
|
CTextCursor Cursor;
|
2022-04-14 11:31:00 +00:00
|
|
|
|
TextRender()->SetCursor(&Cursor, m_Width - ScoreWidthMax + (ScoreWidthMax - m_aScoreInfo[t].m_ScoreTextWidth) - Split, StartY + t * 20 + (18.f - 14.f) / 2.f, 14.0f, TEXTFLAG_RENDER);
|
2018-03-13 20:56:37 +00:00
|
|
|
|
Cursor.m_LineWidth = -1;
|
|
|
|
|
m_aScoreInfo[t].m_TextScoreContainerIndex = TextRender()->CreateTextContainer(&Cursor, aScore[t]);
|
|
|
|
|
}
|
2011-01-12 00:01:05 +00:00
|
|
|
|
// draw score
|
2018-03-13 20:56:37 +00:00
|
|
|
|
if(m_aScoreInfo[t].m_TextScoreContainerIndex != -1)
|
|
|
|
|
{
|
|
|
|
|
STextRenderColor TColor(1.f, 1.f, 1.f, 1.f);
|
|
|
|
|
STextRenderColor TOutlineColor(0.f, 0.f, 0.f, 0.3f);
|
|
|
|
|
TextRender()->RenderTextContainer(m_aScoreInfo[t].m_TextScoreContainerIndex, &TColor, &TOutlineColor);
|
|
|
|
|
}
|
2011-01-12 00:01:05 +00:00
|
|
|
|
|
|
|
|
|
if(apPlayerInfo[t])
|
2015-07-09 00:08:14 +00:00
|
|
|
|
{
|
2012-01-08 23:28:42 +00:00
|
|
|
|
// draw name
|
|
|
|
|
int ID = apPlayerInfo[t]->m_ClientID;
|
2014-07-08 00:17:08 +00:00
|
|
|
|
if(ID >= 0 && ID < MAX_CLIENTS)
|
|
|
|
|
{
|
2019-04-02 23:05:38 +00:00
|
|
|
|
const char *pName = m_pClient->m_aClients[ID].m_aName;
|
2018-03-21 14:53:29 +00:00
|
|
|
|
if(RecreateRect)
|
2018-03-13 20:56:37 +00:00
|
|
|
|
{
|
|
|
|
|
mem_copy(m_aScoreInfo[t].m_aPlayerNameText, pName, sizeof(m_aScoreInfo[t].m_aPlayerNameText));
|
|
|
|
|
|
|
|
|
|
if(m_aScoreInfo[t].m_OptionalNameTextContainerIndex != -1)
|
|
|
|
|
TextRender()->DeleteTextContainer(m_aScoreInfo[t].m_OptionalNameTextContainerIndex);
|
|
|
|
|
|
2020-07-15 19:10:13 +00:00
|
|
|
|
float w = TextRender()->TextWidth(0, 8.0f, pName, -1, -1.0f);
|
2018-03-13 20:56:37 +00:00
|
|
|
|
|
|
|
|
|
CTextCursor Cursor;
|
2022-04-14 11:31:00 +00:00
|
|
|
|
TextRender()->SetCursor(&Cursor, minimum(m_Width - w - 1.0f, m_Width - ScoreWidthMax - ImageSize - 2 * Split - PosSize), StartY + (t + 1) * 20.0f - 2.0f, 8.0f, TEXTFLAG_RENDER);
|
2018-03-13 20:56:37 +00:00
|
|
|
|
Cursor.m_LineWidth = -1;
|
|
|
|
|
m_aScoreInfo[t].m_OptionalNameTextContainerIndex = TextRender()->CreateTextContainer(&Cursor, pName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(m_aScoreInfo[t].m_OptionalNameTextContainerIndex != -1)
|
|
|
|
|
{
|
|
|
|
|
STextRenderColor TColor(1.f, 1.f, 1.f, 1.f);
|
|
|
|
|
STextRenderColor TOutlineColor(0.f, 0.f, 0.f, 0.3f);
|
|
|
|
|
TextRender()->RenderTextContainer(m_aScoreInfo[t].m_OptionalNameTextContainerIndex, &TColor, &TOutlineColor);
|
|
|
|
|
}
|
2012-01-08 23:28:42 +00:00
|
|
|
|
|
2014-07-08 00:17:08 +00:00
|
|
|
|
// draw tee
|
2021-04-09 18:11:53 +00:00
|
|
|
|
CTeeRenderInfo TeeInfo = m_pClient->m_aClients[ID].m_RenderInfo;
|
|
|
|
|
TeeInfo.m_Size = ScoreSingleBoxHeight;
|
|
|
|
|
|
|
|
|
|
CAnimState *pIdleState = CAnimState::GetIdle();
|
|
|
|
|
vec2 OffsetToMid;
|
|
|
|
|
RenderTools()->GetRenderTeeOffsetToRenderedTee(pIdleState, &TeeInfo, OffsetToMid);
|
2022-04-14 11:31:00 +00:00
|
|
|
|
vec2 TeeRenderPos(m_Width - ScoreWidthMax - TeeInfo.m_Size / 2 - Split, StartY + (t * 20) + ScoreSingleBoxHeight / 2.0f + OffsetToMid.y);
|
2021-04-09 18:11:53 +00:00
|
|
|
|
|
|
|
|
|
RenderTools()->RenderTee(pIdleState, &TeeInfo, EMOTE_NORMAL, vec2(1.0f, 0.0f), TeeRenderPos);
|
2014-07-08 00:17:08 +00:00
|
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
|
}
|
2018-03-21 14:53:29 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
m_aScoreInfo[t].m_aPlayerNameText[0] = 0;
|
|
|
|
|
}
|
2011-01-12 00:01:05 +00:00
|
|
|
|
|
|
|
|
|
// draw position
|
2018-03-13 20:56:37 +00:00
|
|
|
|
char aBuf[16];
|
2011-01-12 00:01:05 +00:00
|
|
|
|
str_format(aBuf, sizeof(aBuf), "%d.", aPos[t]);
|
2018-03-21 14:53:29 +00:00
|
|
|
|
if(RecreateRect)
|
2018-03-13 20:56:37 +00:00
|
|
|
|
{
|
|
|
|
|
mem_copy(m_aScoreInfo[t].m_aRankText, aBuf, sizeof(m_aScoreInfo[t].m_aRankText));
|
|
|
|
|
|
|
|
|
|
if(m_aScoreInfo[t].m_TextRankContainerIndex != -1)
|
|
|
|
|
TextRender()->DeleteTextContainer(m_aScoreInfo[t].m_TextRankContainerIndex);
|
2019-04-02 23:05:38 +00:00
|
|
|
|
|
2018-03-13 20:56:37 +00:00
|
|
|
|
CTextCursor Cursor;
|
2022-04-14 11:31:00 +00:00
|
|
|
|
TextRender()->SetCursor(&Cursor, m_Width - ScoreWidthMax - ImageSize - Split - PosSize, StartY + t * 20 + (18.f - 10.f) / 2.f, 10.0f, TEXTFLAG_RENDER);
|
2018-03-13 20:56:37 +00:00
|
|
|
|
Cursor.m_LineWidth = -1;
|
|
|
|
|
m_aScoreInfo[t].m_TextRankContainerIndex = TextRender()->CreateTextContainer(&Cursor, aBuf);
|
|
|
|
|
}
|
|
|
|
|
if(m_aScoreInfo[t].m_TextRankContainerIndex != -1)
|
|
|
|
|
{
|
|
|
|
|
STextRenderColor TColor(1.f, 1.f, 1.f, 1.f);
|
|
|
|
|
STextRenderColor TOutlineColor(0.f, 0.f, 0.f, 0.3f);
|
|
|
|
|
TextRender()->RenderTextContainer(m_aScoreInfo[t].m_TextRankContainerIndex, &TColor, &TOutlineColor);
|
|
|
|
|
}
|
2012-01-08 23:28:42 +00:00
|
|
|
|
|
|
|
|
|
StartY += 8.0f;
|
2008-08-27 15:48:50 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-05-30 12:01:11 +00:00
|
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
|
|
2010-05-30 12:01:11 +00:00
|
|
|
|
void CHud::RenderWarmupTimer()
|
|
|
|
|
{
|
2008-08-27 15:48:50 +00:00
|
|
|
|
// render warmup timer
|
2020-09-26 19:41:58 +00:00
|
|
|
|
if(m_pClient->m_Snap.m_pGameInfoObj->m_WarmupTimer > 0 && !(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags & GAMESTATEFLAG_RACETIME))
|
2008-08-27 15:48:50 +00:00
|
|
|
|
{
|
2021-09-13 09:47:47 +00:00
|
|
|
|
char aBuf[256];
|
2010-05-30 12:01:11 +00:00
|
|
|
|
float FontSize = 20.0f;
|
2020-07-15 19:10:13 +00:00
|
|
|
|
float w = TextRender()->TextWidth(0, FontSize, Localize("Warmup"), -1, -1.0f);
|
2020-09-26 19:41:58 +00:00
|
|
|
|
TextRender()->Text(0, 150 * Graphics()->ScreenAspect() + -w / 2, 50, FontSize, Localize("Warmup"), -1.0f);
|
2008-08-27 15:48:50 +00:00
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
|
int Seconds = m_pClient->m_Snap.m_pGameInfoObj->m_WarmupTimer / SERVER_TICK_SPEED;
|
2010-05-29 07:25:38 +00:00
|
|
|
|
if(Seconds < 5)
|
2021-09-13 09:47:47 +00:00
|
|
|
|
str_format(aBuf, sizeof(aBuf), "%d.%d", Seconds, (m_pClient->m_Snap.m_pGameInfoObj->m_WarmupTimer * 10 / SERVER_TICK_SPEED) % 10);
|
2008-08-27 15:48:50 +00:00
|
|
|
|
else
|
2021-09-13 09:47:47 +00:00
|
|
|
|
str_format(aBuf, sizeof(aBuf), "%d", Seconds);
|
|
|
|
|
w = TextRender()->TextWidth(0, FontSize, aBuf, -1, -1.0f);
|
|
|
|
|
TextRender()->Text(0, 150 * Graphics()->ScreenAspect() + -w / 2, 75, FontSize, aBuf, -1.0f);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
|
void CHud::MapscreenToGroup(float CenterX, float CenterY, CMapItemGroup *pGroup)
|
2008-08-27 15:48:50 +00:00
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
|
float Points[4];
|
2019-04-02 23:05:38 +00:00
|
|
|
|
RenderTools()->MapscreenToWorld(CenterX, CenterY, pGroup->m_ParallaxX, pGroup->m_ParallaxY,
|
2010-05-29 07:25:38 +00:00
|
|
|
|
pGroup->m_OffsetX, pGroup->m_OffsetY, Graphics()->ScreenAspect(), 1.0f, Points);
|
|
|
|
|
Graphics()->MapScreen(Points[0], Points[1], Points[2], Points[3]);
|
2008-08-27 15:48:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-05-03 14:06:10 +00:00
|
|
|
|
void CHud::RenderTextInfo()
|
2008-08-27 15:48:50 +00:00
|
|
|
|
{
|
2018-01-14 16:21:50 +00:00
|
|
|
|
if(g_Config.m_ClShowfps)
|
2008-08-27 15:48:50 +00:00
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
|
// calculate avg. fps
|
2020-09-26 19:41:58 +00:00
|
|
|
|
m_FrameTimeAvg = m_FrameTimeAvg * 0.9f + Client()->RenderFrameTime() * 0.1f;
|
2021-09-13 09:47:47 +00:00
|
|
|
|
char aBuf[64];
|
2018-03-13 20:56:37 +00:00
|
|
|
|
int FrameTime = (int)(1.0f / m_FrameTimeAvg + 0.5f);
|
2021-09-13 09:47:47 +00:00
|
|
|
|
str_format(aBuf, sizeof(aBuf), "%d", FrameTime);
|
2018-03-13 20:56:37 +00:00
|
|
|
|
|
2020-07-15 19:10:13 +00:00
|
|
|
|
static float s_TextWidth0 = TextRender()->TextWidth(0, 12.f, "0", -1, -1.0f);
|
|
|
|
|
static float s_TextWidth00 = TextRender()->TextWidth(0, 12.f, "00", -1, -1.0f);
|
|
|
|
|
static float s_TextWidth000 = TextRender()->TextWidth(0, 12.f, "000", -1, -1.0f);
|
|
|
|
|
static float s_TextWidth0000 = TextRender()->TextWidth(0, 12.f, "0000", -1, -1.0f);
|
|
|
|
|
static float s_TextWidth00000 = TextRender()->TextWidth(0, 12.f, "00000", -1, -1.0f);
|
2020-09-26 19:41:58 +00:00
|
|
|
|
static float s_TextWidth[5] = {s_TextWidth0, s_TextWidth00, s_TextWidth000, s_TextWidth0000, s_TextWidth00000};
|
2018-03-13 20:56:37 +00:00
|
|
|
|
|
2022-04-14 11:31:00 +00:00
|
|
|
|
int DigitIndex = GetDigitsIndex(FrameTime, 4);
|
2020-07-15 19:42:48 +00:00
|
|
|
|
//TextRender()->Text(0, m_Width-10-TextRender()->TextWidth(0,12,Buf,-1,-1.0f), 5, 12, Buf, -1.0f);
|
2018-03-13 20:56:37 +00:00
|
|
|
|
|
|
|
|
|
CTextCursor Cursor;
|
|
|
|
|
TextRender()->SetCursor(&Cursor, m_Width - 10 - s_TextWidth[DigitIndex], 5, 12, TEXTFLAG_RENDER);
|
|
|
|
|
Cursor.m_LineWidth = -1;
|
2022-03-20 17:03:25 +00:00
|
|
|
|
auto OldFlags = TextRender()->GetRenderFlags();
|
|
|
|
|
TextRender()->SetRenderFlags(OldFlags | TEXT_RENDER_FLAG_ONE_TIME_USE);
|
2018-03-21 14:53:29 +00:00
|
|
|
|
if(m_FPSTextContainerIndex == -1)
|
|
|
|
|
m_FPSTextContainerIndex = TextRender()->CreateTextContainer(&Cursor, "0");
|
2022-03-20 17:03:25 +00:00
|
|
|
|
else
|
|
|
|
|
TextRender()->RecreateTextContainerSoft(&Cursor, m_FPSTextContainerIndex, aBuf);
|
|
|
|
|
TextRender()->SetRenderFlags(OldFlags);
|
2018-03-13 20:56:37 +00:00
|
|
|
|
STextRenderColor TColor;
|
|
|
|
|
TColor.m_R = 1.f;
|
|
|
|
|
TColor.m_G = 1.f;
|
|
|
|
|
TColor.m_B = 1.f;
|
|
|
|
|
TColor.m_A = 1.f;
|
|
|
|
|
STextRenderColor TOutColor;
|
|
|
|
|
TOutColor.m_R = 0.f;
|
|
|
|
|
TOutColor.m_G = 0.f;
|
|
|
|
|
TOutColor.m_B = 0.f;
|
|
|
|
|
TOutColor.m_A = 0.3f;
|
2018-03-21 14:53:29 +00:00
|
|
|
|
TextRender()->RenderTextContainer(m_FPSTextContainerIndex, &TColor, &TOutColor);
|
2008-08-27 15:48:50 +00:00
|
|
|
|
}
|
2016-05-05 16:07:00 +00:00
|
|
|
|
if(g_Config.m_ClShowpred)
|
2016-05-03 14:06:10 +00:00
|
|
|
|
{
|
|
|
|
|
char aBuf[64];
|
2016-05-05 16:07:00 +00:00
|
|
|
|
str_format(aBuf, sizeof(aBuf), "%d", Client()->GetPredictionTime());
|
2020-09-26 19:41:58 +00:00
|
|
|
|
TextRender()->Text(0, m_Width - 10 - TextRender()->TextWidth(0, 12, aBuf, -1, -1.0f), g_Config.m_ClShowfps ? 20 : 5, 12, aBuf, -1.0f);
|
2016-05-03 14:06:10 +00:00
|
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
|
void CHud::RenderConnectionWarning()
|
2008-08-27 15:48:50 +00:00
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
|
if(Client()->ConnectionProblems())
|
2008-08-27 15:48:50 +00:00
|
|
|
|
{
|
2010-06-03 09:30:05 +00:00
|
|
|
|
const char *pText = Localize("Connection Problems...");
|
2020-07-15 19:10:13 +00:00
|
|
|
|
float w = TextRender()->TextWidth(0, 24, pText, -1, -1.0f);
|
2020-09-26 19:41:58 +00:00
|
|
|
|
TextRender()->Text(0, 150 * Graphics()->ScreenAspect() - w / 2, 50, 24, pText, -1.0f);
|
2008-08-27 15:48:50 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
|
void CHud::RenderTeambalanceWarning()
|
2008-09-01 18:17:01 +00:00
|
|
|
|
{
|
|
|
|
|
// render prompt about team-balance
|
2020-09-26 19:41:58 +00:00
|
|
|
|
bool Flash = time() / (time_freq() / 2) % 2 == 0;
|
|
|
|
|
if(m_pClient->m_Snap.m_pGameInfoObj->m_GameFlags & GAMEFLAG_TEAMS)
|
2011-04-13 18:37:12 +00:00
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
|
int TeamDiff = m_pClient->m_Snap.m_aTeamSize[TEAM_RED] - m_pClient->m_Snap.m_aTeamSize[TEAM_BLUE];
|
2018-03-13 20:56:37 +00:00
|
|
|
|
if(g_Config.m_ClWarningTeambalance && (TeamDiff >= 2 || TeamDiff <= -2))
|
2008-09-01 18:17:01 +00:00
|
|
|
|
{
|
2010-06-03 09:30:05 +00:00
|
|
|
|
const char *pText = Localize("Please balance teams!");
|
2010-05-29 07:25:38 +00:00
|
|
|
|
if(Flash)
|
2020-09-26 19:41:58 +00:00
|
|
|
|
TextRender()->TextColor(1, 1, 0.5f, 1);
|
2008-09-01 18:17:01 +00:00
|
|
|
|
else
|
2020-09-26 19:41:58 +00:00
|
|
|
|
TextRender()->TextColor(0.7f, 0.7f, 0.2f, 1.0f);
|
2020-07-15 19:42:48 +00:00
|
|
|
|
TextRender()->Text(0x0, 5, 50, 6, pText, -1.0f);
|
2020-09-26 19:41:58 +00:00
|
|
|
|
TextRender()->TextColor(1, 1, 1, 1);
|
2008-09-01 18:17:01 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
|
void CHud::RenderVoting()
|
2008-09-25 14:04:02 +00:00
|
|
|
|
{
|
2021-07-12 09:43:56 +00:00
|
|
|
|
if((!g_Config.m_ClShowVotesAfterVoting && !m_pClient->m_Scoreboard.Active() && m_pClient->m_Voting.TakenChoice()) || !m_pClient->m_Voting.IsVoting() || Client()->State() == IClient::STATE_DEMOPLAYBACK)
|
2008-09-25 14:04:02 +00:00
|
|
|
|
return;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2012-08-12 10:41:50 +00:00
|
|
|
|
Graphics()->TextureClear();
|
2009-10-27 14:38:53 +00:00
|
|
|
|
Graphics()->QuadsBegin();
|
2020-09-26 19:41:58 +00:00
|
|
|
|
Graphics()->SetColor(0, 0, 0, 0.40f);
|
2014-06-16 11:29:18 +00:00
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
|
RenderTools()->DrawRoundRect(-10, 60 - 2, 100 + 10 + 4 + 5, 46, 5.0f);
|
2009-10-27 14:38:53 +00:00
|
|
|
|
Graphics()->QuadsEnd();
|
2009-01-21 21:17:25 +00:00
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
|
TextRender()->TextColor(1, 1, 1, 1);
|
2009-01-21 21:17:25 +00:00
|
|
|
|
|
2010-09-12 11:18:11 +00:00
|
|
|
|
CTextCursor Cursor;
|
2011-03-25 09:26:59 +00:00
|
|
|
|
char aBuf[512];
|
2021-07-12 09:43:56 +00:00
|
|
|
|
str_format(aBuf, sizeof(aBuf), Localize("%ds left"), m_pClient->m_Voting.SecondsLeft());
|
2020-07-15 19:10:13 +00:00
|
|
|
|
float tw = TextRender()->TextWidth(0x0, 6, aBuf, -1, -1.0f);
|
2020-09-26 19:41:58 +00:00
|
|
|
|
TextRender()->SetCursor(&Cursor, 5.0f + 100.0f - tw, 60.0f, 6.0f, TEXTFLAG_RENDER);
|
2011-03-25 09:26:59 +00:00
|
|
|
|
TextRender()->TextEx(&Cursor, aBuf, -1);
|
2010-09-12 11:18:11 +00:00
|
|
|
|
|
2011-03-25 09:26:59 +00:00
|
|
|
|
TextRender()->SetCursor(&Cursor, 5.0f, 60.0f, 6.0f, TEXTFLAG_RENDER);
|
2020-09-26 19:41:58 +00:00
|
|
|
|
Cursor.m_LineWidth = 100.0f - tw;
|
2011-03-25 09:26:59 +00:00
|
|
|
|
Cursor.m_MaxLines = 3;
|
2021-07-12 09:43:56 +00:00
|
|
|
|
TextRender()->TextEx(&Cursor, m_pClient->m_Voting.VoteDescription(), -1);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2011-03-25 09:26:59 +00:00
|
|
|
|
// reason
|
2021-07-12 09:43:56 +00:00
|
|
|
|
str_format(aBuf, sizeof(aBuf), "%s %s", Localize("Reason:"), m_pClient->m_Voting.VoteReason());
|
2020-09-26 19:41:58 +00:00
|
|
|
|
TextRender()->SetCursor(&Cursor, 5.0f, 79.0f, 6.0f, TEXTFLAG_RENDER | TEXTFLAG_STOP_AT_END);
|
2011-03-25 09:26:59 +00:00
|
|
|
|
Cursor.m_LineWidth = 100.0f;
|
|
|
|
|
TextRender()->TextEx(&Cursor, aBuf, -1);
|
2009-01-21 21:17:25 +00:00
|
|
|
|
|
2011-03-25 09:26:59 +00:00
|
|
|
|
CUIRect Base = {5, 88, 100, 4};
|
2021-07-12 09:43:56 +00:00
|
|
|
|
m_pClient->m_Voting.RenderBars(Base, false);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2019-04-28 13:32:14 +00:00
|
|
|
|
char aKey[64];
|
2021-07-12 09:43:56 +00:00
|
|
|
|
m_pClient->m_Binds.GetKey("vote yes", aKey, sizeof(aKey));
|
2019-04-28 13:32:14 +00:00
|
|
|
|
|
|
|
|
|
str_format(aBuf, sizeof(aBuf), "%s - %s", aKey, Localize("Vote yes"));
|
2018-04-04 00:40:30 +00:00
|
|
|
|
Base.y += Base.h;
|
|
|
|
|
Base.h = 11.f;
|
2022-01-21 15:20:15 +00:00
|
|
|
|
UI()->DoLabel(&Base, aBuf, 6.0f, TEXTALIGN_LEFT);
|
2010-05-29 07:25:38 +00:00
|
|
|
|
|
2021-07-12 09:43:56 +00:00
|
|
|
|
m_pClient->m_Binds.GetKey("vote no", aKey, sizeof(aKey));
|
2019-04-28 13:32:14 +00:00
|
|
|
|
str_format(aBuf, sizeof(aBuf), "%s - %s", Localize("Vote no"), aKey);
|
2022-01-21 15:20:15 +00:00
|
|
|
|
UI()->DoLabel(&Base, aBuf, 6.0f, TEXTALIGN_RIGHT);
|
2008-09-25 14:04:02 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
|
void CHud::RenderCursor()
|
2008-08-27 15:48:50 +00:00
|
|
|
|
{
|
2010-09-08 00:07:36 +00:00
|
|
|
|
if(!m_pClient->m_Snap.m_pLocalCharacter || Client()->State() == IClient::STATE_DEMOPLAYBACK)
|
2008-08-31 13:36:30 +00:00
|
|
|
|
return;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2021-07-12 09:43:56 +00:00
|
|
|
|
MapscreenToGroup(m_pClient->m_Camera.m_Center.x, m_pClient->m_Camera.m_Center.y, Layers()->GameGroup());
|
2020-10-09 07:07:05 +00:00
|
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
|
// render cursor
|
2022-03-18 10:11:58 +00:00
|
|
|
|
int CurWeapon = m_pClient->m_Snap.m_pLocalCharacter->m_Weapon % NUM_WEAPONS;
|
2018-03-13 20:56:37 +00:00
|
|
|
|
Graphics()->SetColor(1.f, 1.f, 1.f, 1.f);
|
2022-03-21 22:55:35 +00:00
|
|
|
|
Graphics()->TextureSet(m_pClient->m_GameSkin.m_SpriteWeaponCursors[CurWeapon]);
|
2022-03-18 10:11:58 +00:00
|
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_HudQuadContainerIndex, m_CursorOffset[CurWeapon], m_pClient->m_Controls.m_TargetPos[g_Config.m_ClDummy].x, m_pClient->m_Controls.m_TargetPos[g_Config.m_ClDummy].y);
|
2008-08-27 15:48:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-03-18 10:11:58 +00:00
|
|
|
|
void CHud::PrepareAmmoHealthAndArmorQuads()
|
2008-08-27 15:48:50 +00:00
|
|
|
|
{
|
|
|
|
|
float x = 5;
|
|
|
|
|
float y = 5;
|
2010-05-29 07:25:38 +00:00
|
|
|
|
IGraphics::CQuadItem Array[10];
|
2008-08-27 15:48:50 +00:00
|
|
|
|
|
2022-03-18 10:11:58 +00:00
|
|
|
|
// ammo of the different weapons
|
2018-03-13 20:56:37 +00:00
|
|
|
|
for(int i = 0; i < NUM_WEAPONS; ++i)
|
|
|
|
|
{
|
2020-09-25 07:58:16 +00:00
|
|
|
|
// 0.6
|
2018-03-13 20:56:37 +00:00
|
|
|
|
for(int n = 0; n < 10; n++)
|
|
|
|
|
Array[n] = IGraphics::CQuadItem(x + n * 12, y + 24, 10, 10);
|
2020-09-25 07:58:16 +00:00
|
|
|
|
|
2022-03-18 10:11:58 +00:00
|
|
|
|
m_AmmoOffset[i] = Graphics()->QuadContainerAddQuads(m_HudQuadContainerIndex, Array, 10);
|
2020-09-25 07:58:16 +00:00
|
|
|
|
|
|
|
|
|
// 0.7
|
|
|
|
|
if(i == WEAPON_GRENADE)
|
|
|
|
|
{
|
|
|
|
|
// special case for 0.7 grenade
|
|
|
|
|
for(int n = 0; n < 10; n++)
|
|
|
|
|
Array[n] = IGraphics::CQuadItem(1 + x + n * 12, y + 24, 10, 10);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
for(int n = 0; n < 10; n++)
|
|
|
|
|
Array[n] = IGraphics::CQuadItem(x + n * 12, y + 24, 12, 12);
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-13 20:56:37 +00:00
|
|
|
|
Graphics()->QuadContainerAddQuads(m_HudQuadContainerIndex, Array, 10);
|
|
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
|
|
2018-03-13 20:56:37 +00:00
|
|
|
|
// health
|
|
|
|
|
for(int i = 0; i < 10; ++i)
|
|
|
|
|
Array[i] = IGraphics::CQuadItem(x + i * 12, y, 10, 10);
|
2022-03-18 10:11:58 +00:00
|
|
|
|
m_HealthOffset = Graphics()->QuadContainerAddQuads(m_HudQuadContainerIndex, Array, 10);
|
2008-08-27 15:48:50 +00:00
|
|
|
|
|
2020-09-25 07:58:16 +00:00
|
|
|
|
// 0.7
|
|
|
|
|
for(int i = 0; i < 10; ++i)
|
|
|
|
|
Array[i] = IGraphics::CQuadItem(x + i * 12, y, 12, 12);
|
|
|
|
|
Graphics()->QuadContainerAddQuads(m_HudQuadContainerIndex, Array, 10);
|
|
|
|
|
|
2022-03-18 10:11:58 +00:00
|
|
|
|
// empty health
|
2018-03-13 20:56:37 +00:00
|
|
|
|
for(int i = 0; i < 10; ++i)
|
|
|
|
|
Array[i] = IGraphics::CQuadItem(x + i * 12, y, 10, 10);
|
2022-03-18 10:11:58 +00:00
|
|
|
|
m_EmptyHealthOffset = Graphics()->QuadContainerAddQuads(m_HudQuadContainerIndex, Array, 10);
|
2008-08-27 15:48:50 +00:00
|
|
|
|
|
2020-09-25 07:58:16 +00:00
|
|
|
|
// 0.7
|
|
|
|
|
for(int i = 0; i < 10; ++i)
|
|
|
|
|
Array[i] = IGraphics::CQuadItem(x + i * 12, y, 12, 12);
|
|
|
|
|
Graphics()->QuadContainerAddQuads(m_HudQuadContainerIndex, Array, 10);
|
|
|
|
|
|
2018-03-13 20:56:37 +00:00
|
|
|
|
// armor meter
|
|
|
|
|
for(int i = 0; i < 10; ++i)
|
|
|
|
|
Array[i] = IGraphics::CQuadItem(x + i * 12, y + 12, 10, 10);
|
2022-03-18 10:11:58 +00:00
|
|
|
|
m_ArmorOffset = Graphics()->QuadContainerAddQuads(m_HudQuadContainerIndex, Array, 10);
|
2008-08-27 15:48:50 +00:00
|
|
|
|
|
2020-09-25 07:58:16 +00:00
|
|
|
|
// 0.7
|
|
|
|
|
for(int i = 0; i < 10; ++i)
|
|
|
|
|
Array[i] = IGraphics::CQuadItem(x + i * 12, y + 12, 12, 12);
|
|
|
|
|
Graphics()->QuadContainerAddQuads(m_HudQuadContainerIndex, Array, 10);
|
|
|
|
|
|
2022-03-18 10:11:58 +00:00
|
|
|
|
// empty armor meter
|
2018-03-13 20:56:37 +00:00
|
|
|
|
for(int i = 0; i < 10; ++i)
|
|
|
|
|
Array[i] = IGraphics::CQuadItem(x + i * 12, y + 12, 10, 10);
|
2022-03-18 10:11:58 +00:00
|
|
|
|
m_EmptyArmorOffset = Graphics()->QuadContainerAddQuads(m_HudQuadContainerIndex, Array, 10);
|
2020-09-25 07:58:16 +00:00
|
|
|
|
|
|
|
|
|
// 0.7
|
|
|
|
|
for(int i = 0; i < 10; ++i)
|
|
|
|
|
Array[i] = IGraphics::CQuadItem(x + i * 12, y + 12, 12, 12);
|
|
|
|
|
Graphics()->QuadContainerAddQuads(m_HudQuadContainerIndex, Array, 10);
|
2018-03-13 20:56:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-03-18 10:11:58 +00:00
|
|
|
|
void CHud::RenderAmmoHealthAndArmor(const CNetObj_Character *pCharacter)
|
2018-03-13 20:56:37 +00:00
|
|
|
|
{
|
|
|
|
|
if(!pCharacter)
|
|
|
|
|
return;
|
|
|
|
|
|
2022-03-21 22:55:35 +00:00
|
|
|
|
bool IsSixupGameSkin = m_pClient->m_GameSkin.IsSixup();
|
2020-09-25 07:58:16 +00:00
|
|
|
|
int QuadOffsetSixup = (IsSixupGameSkin ? 10 : 0);
|
|
|
|
|
|
2022-03-18 10:11:58 +00:00
|
|
|
|
// ammo display
|
2020-10-09 07:07:05 +00:00
|
|
|
|
int CurWeapon = pCharacter->m_Weapon % NUM_WEAPONS;
|
2022-03-21 22:55:35 +00:00
|
|
|
|
if(m_pClient->m_GameSkin.m_SpriteWeaponProjectiles[CurWeapon].IsValid())
|
2020-10-09 07:07:05 +00:00
|
|
|
|
{
|
2022-03-21 22:55:35 +00:00
|
|
|
|
Graphics()->TextureSet(m_pClient->m_GameSkin.m_SpriteWeaponProjectiles[CurWeapon]);
|
2022-03-18 10:11:58 +00:00
|
|
|
|
Graphics()->RenderQuadContainer(m_HudQuadContainerIndex, m_AmmoOffset[CurWeapon] + QuadOffsetSixup, minimum(pCharacter->m_AmmoCount, 10));
|
2020-10-09 07:07:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-03-18 10:11:58 +00:00
|
|
|
|
// health display
|
2022-03-21 22:55:35 +00:00
|
|
|
|
Graphics()->TextureSet(m_pClient->m_GameSkin.m_SpriteHealthFull);
|
2022-03-18 10:11:58 +00:00
|
|
|
|
Graphics()->RenderQuadContainer(m_HudQuadContainerIndex, m_HealthOffset + QuadOffsetSixup, minimum(pCharacter->m_Health, 10));
|
2022-03-21 22:55:35 +00:00
|
|
|
|
Graphics()->TextureSet(m_pClient->m_GameSkin.m_SpriteHealthEmpty);
|
2022-03-18 10:11:58 +00:00
|
|
|
|
Graphics()->RenderQuadContainer(m_HudQuadContainerIndex, m_EmptyHealthOffset + QuadOffsetSixup + minimum(pCharacter->m_Health, 10), 10 - minimum(pCharacter->m_Health, 10));
|
2020-10-09 07:07:05 +00:00
|
|
|
|
|
2022-03-18 10:11:58 +00:00
|
|
|
|
// armor display
|
2022-03-21 22:55:35 +00:00
|
|
|
|
Graphics()->TextureSet(m_pClient->m_GameSkin.m_SpriteArmorFull);
|
2022-03-18 10:11:58 +00:00
|
|
|
|
Graphics()->RenderQuadContainer(m_HudQuadContainerIndex, m_ArmorOffset + QuadOffsetSixup, minimum(pCharacter->m_Armor, 10));
|
2022-03-21 22:55:35 +00:00
|
|
|
|
Graphics()->TextureSet(m_pClient->m_GameSkin.m_SpriteArmorEmpty);
|
2022-03-18 10:11:58 +00:00
|
|
|
|
Graphics()->RenderQuadContainer(m_HudQuadContainerIndex, m_ArmorOffset + QuadOffsetSixup + minimum(pCharacter->m_Armor, 10), 10 - minimum(pCharacter->m_Armor, 10));
|
2008-08-27 15:48:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-03-20 13:18:02 +00:00
|
|
|
|
void CHud::PreparePlayerStateQuads()
|
|
|
|
|
{
|
|
|
|
|
float x = 5;
|
2022-03-30 22:41:11 +00:00
|
|
|
|
float y = 5 + 24;
|
2022-03-20 13:18:02 +00:00
|
|
|
|
IGraphics::CQuadItem Array[10];
|
|
|
|
|
|
|
|
|
|
// Quads for displaying the available and used jumps
|
|
|
|
|
for(int i = 0; i < 10; ++i)
|
|
|
|
|
Array[i] = IGraphics::CQuadItem(x + i * 12, y, 12, 12);
|
|
|
|
|
m_AirjumpOffset = Graphics()->QuadContainerAddQuads(m_HudQuadContainerIndex, Array, 10);
|
|
|
|
|
|
|
|
|
|
for(int i = 0; i < 10; ++i)
|
|
|
|
|
Array[i] = IGraphics::CQuadItem(x + i * 12, y, 12, 12);
|
|
|
|
|
m_AirjumpEmptyOffset = Graphics()->QuadContainerAddQuads(m_HudQuadContainerIndex, Array, 10);
|
|
|
|
|
|
2022-03-21 22:55:35 +00:00
|
|
|
|
// Quads for displaying weapons
|
|
|
|
|
float ScaleX, ScaleY;
|
2022-03-30 22:41:11 +00:00
|
|
|
|
const float HudWeaponScale = 0.25f;
|
|
|
|
|
RenderTools()->GetSpriteScale(g_pData->m_Weapons.m_aId[WEAPON_HAMMER].m_pSpriteBody, ScaleX, ScaleY);
|
|
|
|
|
m_WeaponHammerOffset = RenderTools()->QuadContainerAddSprite(m_HudQuadContainerIndex, g_pData->m_Weapons.m_aId[WEAPON_HAMMER].m_VisualSize * ScaleX * HudWeaponScale, g_pData->m_Weapons.m_aId[WEAPON_HAMMER].m_VisualSize * ScaleY * HudWeaponScale);
|
|
|
|
|
RenderTools()->GetSpriteScale(g_pData->m_Weapons.m_aId[WEAPON_GUN].m_pSpriteBody, ScaleX, ScaleY);
|
|
|
|
|
m_WeaponGunOffset = RenderTools()->QuadContainerAddSprite(m_HudQuadContainerIndex, g_pData->m_Weapons.m_aId[WEAPON_GUN].m_VisualSize * ScaleX * HudWeaponScale, g_pData->m_Weapons.m_aId[WEAPON_GUN].m_VisualSize * ScaleY * HudWeaponScale);
|
|
|
|
|
RenderTools()->GetSpriteScale(g_pData->m_Weapons.m_aId[WEAPON_SHOTGUN].m_pSpriteBody, ScaleX, ScaleY);
|
|
|
|
|
m_WeaponShotgunOffset = RenderTools()->QuadContainerAddSprite(m_HudQuadContainerIndex, g_pData->m_Weapons.m_aId[WEAPON_SHOTGUN].m_VisualSize * ScaleX * HudWeaponScale, g_pData->m_Weapons.m_aId[WEAPON_SHOTGUN].m_VisualSize * ScaleY * HudWeaponScale);
|
|
|
|
|
RenderTools()->GetSpriteScale(g_pData->m_Weapons.m_aId[WEAPON_GRENADE].m_pSpriteBody, ScaleX, ScaleY);
|
|
|
|
|
m_WeaponGrenadeOffset = RenderTools()->QuadContainerAddSprite(m_HudQuadContainerIndex, g_pData->m_Weapons.m_aId[WEAPON_GRENADE].m_VisualSize * ScaleX * HudWeaponScale, g_pData->m_Weapons.m_aId[WEAPON_GRENADE].m_VisualSize * ScaleY * HudWeaponScale);
|
|
|
|
|
RenderTools()->GetSpriteScale(g_pData->m_Weapons.m_aId[WEAPON_LASER].m_pSpriteBody, ScaleX, ScaleY);
|
|
|
|
|
m_WeaponLaserOffset = RenderTools()->QuadContainerAddSprite(m_HudQuadContainerIndex, g_pData->m_Weapons.m_aId[WEAPON_LASER].m_VisualSize * ScaleX * HudWeaponScale, g_pData->m_Weapons.m_aId[WEAPON_LASER].m_VisualSize * ScaleY * HudWeaponScale);
|
|
|
|
|
RenderTools()->GetSpriteScale(g_pData->m_Weapons.m_aId[WEAPON_NINJA].m_pSpriteBody, ScaleX, ScaleY);
|
|
|
|
|
m_WeaponNinjaOffset = RenderTools()->QuadContainerAddSprite(m_HudQuadContainerIndex, g_pData->m_Weapons.m_aId[WEAPON_NINJA].m_VisualSize * ScaleX * HudWeaponScale, g_pData->m_Weapons.m_aId[WEAPON_NINJA].m_VisualSize * ScaleY * HudWeaponScale);
|
2022-03-21 22:55:35 +00:00
|
|
|
|
|
|
|
|
|
// Quads for displaying capabilities
|
2022-03-20 13:18:02 +00:00
|
|
|
|
m_EndlessJumpOffset = RenderTools()->QuadContainerAddSprite(m_HudQuadContainerIndex, 0.f, 0.f, 12.f, 12.f);
|
|
|
|
|
m_EndlessHookOffset = RenderTools()->QuadContainerAddSprite(m_HudQuadContainerIndex, 0.f, 0.f, 12.f, 12.f);
|
|
|
|
|
m_JetpackOffset = RenderTools()->QuadContainerAddSprite(m_HudQuadContainerIndex, 0.f, 0.f, 12.f, 12.f);
|
2022-03-21 22:55:35 +00:00
|
|
|
|
m_TeleportGrenadeOffset = RenderTools()->QuadContainerAddSprite(m_HudQuadContainerIndex, 0.f, 0.f, 12.f, 12.f);
|
|
|
|
|
m_TeleportGunOffset = RenderTools()->QuadContainerAddSprite(m_HudQuadContainerIndex, 0.f, 0.f, 12.f, 12.f);
|
|
|
|
|
m_TeleportLaserOffset = RenderTools()->QuadContainerAddSprite(m_HudQuadContainerIndex, 0.f, 0.f, 12.f, 12.f);
|
|
|
|
|
|
|
|
|
|
// Quads for displaying prohibited capabilities
|
|
|
|
|
m_SoloOffset = RenderTools()->QuadContainerAddSprite(m_HudQuadContainerIndex, 0.f, 0.f, 12.f, 12.f);
|
|
|
|
|
m_NoCollisionOffset = RenderTools()->QuadContainerAddSprite(m_HudQuadContainerIndex, 0.f, 0.f, 12.f, 12.f);
|
2022-03-20 13:18:02 +00:00
|
|
|
|
m_NoHookHitOffset = RenderTools()->QuadContainerAddSprite(m_HudQuadContainerIndex, 0.f, 0.f, 12.f, 12.f);
|
|
|
|
|
m_NoHammerHitOffset = RenderTools()->QuadContainerAddSprite(m_HudQuadContainerIndex, 0.f, 0.f, 12.f, 12.f);
|
|
|
|
|
m_NoShotgunHitOffset = RenderTools()->QuadContainerAddSprite(m_HudQuadContainerIndex, 0.f, 0.f, 12.f, 12.f);
|
|
|
|
|
m_NoGrenadeHitOffset = RenderTools()->QuadContainerAddSprite(m_HudQuadContainerIndex, 0.f, 0.f, 12.f, 12.f);
|
|
|
|
|
m_NoLaserHitOffset = RenderTools()->QuadContainerAddSprite(m_HudQuadContainerIndex, 0.f, 0.f, 12.f, 12.f);
|
2022-03-21 22:55:35 +00:00
|
|
|
|
|
2022-03-31 16:05:16 +00:00
|
|
|
|
// Quads for displaying freeze status
|
2022-03-25 09:09:13 +00:00
|
|
|
|
m_DeepFrozenOffset = RenderTools()->QuadContainerAddSprite(m_HudQuadContainerIndex, 0.f, 0.f, 12.f, 12.f);
|
|
|
|
|
m_LiveFrozenOffset = RenderTools()->QuadContainerAddSprite(m_HudQuadContainerIndex, 0.f, 0.f, 12.f, 12.f);
|
2022-03-31 16:05:16 +00:00
|
|
|
|
|
|
|
|
|
// Quads for displaying dummy actions
|
2022-03-20 13:18:02 +00:00
|
|
|
|
m_DummyHammerOffset = RenderTools()->QuadContainerAddSprite(m_HudQuadContainerIndex, 0.f, 0.f, 12.f, 12.f);
|
|
|
|
|
m_DummyCopyOffset = RenderTools()->QuadContainerAddSprite(m_HudQuadContainerIndex, 0.f, 0.f, 12.f, 12.f);
|
2022-03-31 16:05:16 +00:00
|
|
|
|
|
|
|
|
|
// Quad for displaying practice mode
|
2022-04-01 19:48:06 +00:00
|
|
|
|
m_PracticeModeOffset = RenderTools()->QuadContainerAddSprite(m_HudQuadContainerIndex, 0.f, 0.f, 12.f, 12.f);
|
2022-03-20 13:18:02 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-03-21 22:55:35 +00:00
|
|
|
|
void CHud::RenderPlayerState(const int ClientID)
|
2022-03-20 13:18:02 +00:00
|
|
|
|
{
|
|
|
|
|
Graphics()->SetColor(1.f, 1.f, 1.f, 1.f);
|
|
|
|
|
|
2022-03-27 16:18:53 +00:00
|
|
|
|
// pCharacter contains the predicted character for local players or the last snap for players who are spectated
|
2022-03-21 22:55:35 +00:00
|
|
|
|
CCharacterCore *pCharacter = &m_pClient->m_aClients[ClientID].m_Predicted;
|
2022-03-20 13:18:02 +00:00
|
|
|
|
|
|
|
|
|
int TotalJumpsToDisplay, AvailableJumpsToDisplay;
|
2022-03-27 16:18:53 +00:00
|
|
|
|
if(m_pClient->m_Snap.m_aCharacters[ClientID].m_HasExtendedDisplayInfo)
|
2022-03-20 13:18:02 +00:00
|
|
|
|
{
|
|
|
|
|
bool Grounded = false;
|
2022-05-16 21:17:19 +00:00
|
|
|
|
if(Collision()->CheckPoint(pCharacter->m_Pos.x + CCharacter::ms_PhysSize / 2,
|
|
|
|
|
pCharacter->m_Pos.y + CCharacter::ms_PhysSize / 2 + 5))
|
|
|
|
|
{
|
2022-03-20 13:18:02 +00:00
|
|
|
|
Grounded = true;
|
2022-05-16 21:17:19 +00:00
|
|
|
|
}
|
|
|
|
|
if(Collision()->CheckPoint(pCharacter->m_Pos.x - CCharacter::ms_PhysSize / 2,
|
|
|
|
|
pCharacter->m_Pos.y + CCharacter::ms_PhysSize / 2 + 5))
|
|
|
|
|
{
|
2022-03-20 13:18:02 +00:00
|
|
|
|
Grounded = true;
|
2022-05-16 21:17:19 +00:00
|
|
|
|
}
|
2022-03-20 13:18:02 +00:00
|
|
|
|
|
2022-03-21 22:55:35 +00:00
|
|
|
|
int UsedJumps = pCharacter->m_JumpedTotal;
|
2022-05-16 21:17:19 +00:00
|
|
|
|
if(pCharacter->m_Jumps > 1)
|
2022-03-20 13:18:02 +00:00
|
|
|
|
{
|
2022-05-16 21:17:19 +00:00
|
|
|
|
UsedJumps += !Grounded;
|
2022-03-20 13:18:02 +00:00
|
|
|
|
}
|
2022-05-16 21:17:19 +00:00
|
|
|
|
else if(pCharacter->m_Jumps == 1)
|
2022-03-20 13:18:02 +00:00
|
|
|
|
{
|
2022-05-16 21:17:19 +00:00
|
|
|
|
// If the player has only one jump, each jump is the last one
|
|
|
|
|
UsedJumps = pCharacter->m_Jumped & 2;
|
|
|
|
|
}
|
|
|
|
|
else if(pCharacter->m_Jumps == -1)
|
|
|
|
|
{
|
|
|
|
|
// The player has only one ground jump
|
2022-03-20 13:18:02 +00:00
|
|
|
|
UsedJumps = !Grounded;
|
|
|
|
|
}
|
2022-05-16 21:17:19 +00:00
|
|
|
|
|
|
|
|
|
if(pCharacter->m_EndlessJump && UsedJumps >= abs(pCharacter->m_Jumps))
|
2022-03-21 22:55:35 +00:00
|
|
|
|
{
|
2022-05-16 21:17:19 +00:00
|
|
|
|
UsedJumps = abs(pCharacter->m_Jumps) - 1;
|
2022-03-21 22:55:35 +00:00
|
|
|
|
}
|
2022-03-20 13:18:02 +00:00
|
|
|
|
|
2022-03-21 22:55:35 +00:00
|
|
|
|
int UnusedJumps = abs(pCharacter->m_Jumps) - UsedJumps;
|
2022-05-16 21:17:19 +00:00
|
|
|
|
if(!(pCharacter->m_Jumped & 2) && UnusedJumps <= 0)
|
2022-03-20 13:18:02 +00:00
|
|
|
|
{
|
2022-05-16 21:17:19 +00:00
|
|
|
|
// In some edge cases when the player just got another number of jumps, UnusedJumps is not correct
|
|
|
|
|
UnusedJumps = 1;
|
2022-03-20 13:18:02 +00:00
|
|
|
|
}
|
2022-03-21 22:55:35 +00:00
|
|
|
|
TotalJumpsToDisplay = maximum(minimum(abs(pCharacter->m_Jumps), 10), 0);
|
2022-03-20 13:18:02 +00:00
|
|
|
|
AvailableJumpsToDisplay = maximum(minimum(UnusedJumps, TotalJumpsToDisplay), 0);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2022-03-24 09:17:35 +00:00
|
|
|
|
TotalJumpsToDisplay = AvailableJumpsToDisplay = abs(m_pClient->m_Snap.m_aCharacters[ClientID].m_ExtendedData.m_Jumps);
|
2022-03-20 13:18:02 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// render available and used jumps
|
2022-03-21 22:55:35 +00:00
|
|
|
|
Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudAirjump);
|
2022-03-20 13:18:02 +00:00
|
|
|
|
Graphics()->RenderQuadContainer(m_HudQuadContainerIndex, m_AirjumpOffset, AvailableJumpsToDisplay);
|
2022-03-21 22:55:35 +00:00
|
|
|
|
Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudAirjumpEmpty);
|
2022-03-20 13:18:02 +00:00
|
|
|
|
Graphics()->RenderQuadContainer(m_HudQuadContainerIndex, m_AirjumpEmptyOffset + AvailableJumpsToDisplay, TotalJumpsToDisplay - AvailableJumpsToDisplay);
|
2022-03-21 22:55:35 +00:00
|
|
|
|
|
|
|
|
|
float x = 5 + 12;
|
2022-03-30 22:41:11 +00:00
|
|
|
|
float y = 5 + 12;
|
2022-03-21 22:55:35 +00:00
|
|
|
|
|
|
|
|
|
// render weapons
|
2022-03-24 00:06:13 +00:00
|
|
|
|
if(pCharacter->m_aWeapons[WEAPON_HAMMER].m_Got)
|
|
|
|
|
{
|
|
|
|
|
if(pCharacter->m_ActiveWeapon != WEAPON_HAMMER)
|
|
|
|
|
{
|
|
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.4f);
|
|
|
|
|
}
|
2022-03-29 21:24:39 +00:00
|
|
|
|
x -= 3;
|
2022-03-24 00:06:13 +00:00
|
|
|
|
Graphics()->QuadsSetRotation(pi * 7 / 4);
|
|
|
|
|
Graphics()->TextureSet(m_pClient->m_GameSkin.m_SpritePickupHammer);
|
2022-03-30 22:41:11 +00:00
|
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_HudQuadContainerIndex, m_WeaponHammerOffset, x, y);
|
2022-03-24 00:06:13 +00:00
|
|
|
|
Graphics()->QuadsSetRotation(0);
|
|
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
|
|
|
|
|
x += 16;
|
|
|
|
|
}
|
|
|
|
|
if(pCharacter->m_aWeapons[WEAPON_GUN].m_Got)
|
|
|
|
|
{
|
|
|
|
|
if(pCharacter->m_ActiveWeapon != WEAPON_GUN)
|
|
|
|
|
{
|
|
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.4f);
|
|
|
|
|
}
|
|
|
|
|
Graphics()->QuadsSetRotation(pi * 7 / 4);
|
|
|
|
|
Graphics()->TextureSet(m_pClient->m_GameSkin.m_SpritePickupGun);
|
2022-03-30 22:41:11 +00:00
|
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_HudQuadContainerIndex, m_WeaponGunOffset, x, y);
|
2022-03-24 00:06:13 +00:00
|
|
|
|
Graphics()->QuadsSetRotation(0);
|
|
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
|
|
|
|
|
x += 12;
|
|
|
|
|
}
|
2022-03-21 22:55:35 +00:00
|
|
|
|
if(pCharacter->m_aWeapons[WEAPON_SHOTGUN].m_Got)
|
|
|
|
|
{
|
|
|
|
|
if(pCharacter->m_ActiveWeapon != WEAPON_SHOTGUN)
|
|
|
|
|
{
|
|
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.4f);
|
|
|
|
|
}
|
|
|
|
|
Graphics()->QuadsSetRotation(pi * 7 / 4);
|
|
|
|
|
Graphics()->TextureSet(m_pClient->m_GameSkin.m_SpritePickupShotgun);
|
|
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_HudQuadContainerIndex, m_WeaponShotgunOffset, x, y);
|
|
|
|
|
Graphics()->QuadsSetRotation(0);
|
|
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
|
|
|
|
|
x += 12;
|
|
|
|
|
}
|
|
|
|
|
if(pCharacter->m_aWeapons[WEAPON_GRENADE].m_Got)
|
|
|
|
|
{
|
|
|
|
|
if(pCharacter->m_ActiveWeapon != WEAPON_GRENADE)
|
|
|
|
|
{
|
|
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.4f);
|
|
|
|
|
}
|
|
|
|
|
Graphics()->QuadsSetRotation(pi * 7 / 4);
|
|
|
|
|
Graphics()->TextureSet(m_pClient->m_GameSkin.m_SpritePickupGrenade);
|
|
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_HudQuadContainerIndex, m_WeaponGrenadeOffset, x, y);
|
|
|
|
|
Graphics()->QuadsSetRotation(0);
|
|
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
|
|
|
|
|
x += 12;
|
|
|
|
|
}
|
|
|
|
|
if(pCharacter->m_aWeapons[WEAPON_LASER].m_Got)
|
|
|
|
|
{
|
|
|
|
|
if(pCharacter->m_ActiveWeapon != WEAPON_LASER)
|
|
|
|
|
{
|
|
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.4f);
|
|
|
|
|
}
|
|
|
|
|
Graphics()->QuadsSetRotation(pi * 7 / 4);
|
|
|
|
|
Graphics()->TextureSet(m_pClient->m_GameSkin.m_SpritePickupLaser);
|
2022-03-30 22:41:11 +00:00
|
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_HudQuadContainerIndex, m_WeaponLaserOffset, x, y);
|
2022-03-21 22:55:35 +00:00
|
|
|
|
Graphics()->QuadsSetRotation(0);
|
|
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
|
2022-03-24 00:06:13 +00:00
|
|
|
|
x += 12;
|
|
|
|
|
}
|
|
|
|
|
if(pCharacter->m_aWeapons[WEAPON_NINJA].m_Got)
|
|
|
|
|
{
|
|
|
|
|
if(pCharacter->m_ActiveWeapon != WEAPON_NINJA)
|
|
|
|
|
{
|
|
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.4f);
|
|
|
|
|
}
|
|
|
|
|
Graphics()->QuadsSetRotation(pi * 7 / 4);
|
|
|
|
|
Graphics()->TextureSet(m_pClient->m_GameSkin.m_SpritePickupNinja);
|
2022-03-30 22:41:11 +00:00
|
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_HudQuadContainerIndex, m_WeaponNinjaOffset, x, y);
|
2022-03-24 00:06:13 +00:00
|
|
|
|
Graphics()->QuadsSetRotation(0);
|
|
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
|
|
|
|
|
|
2022-03-27 16:18:53 +00:00
|
|
|
|
const int Max = g_pData->m_Weapons.m_Ninja.m_Duration * Client()->GameTickSpeed() / 1000;
|
|
|
|
|
float NinjaProgress = clamp(pCharacter->m_Ninja.m_ActivationTick + g_pData->m_Weapons.m_Ninja.m_Duration * Client()->GameTickSpeed() / 1000 - Client()->GameTick(g_Config.m_ClDummy), 0, Max) / (float)Max;
|
|
|
|
|
if(NinjaProgress > 0.0f && m_pClient->m_Snap.m_aCharacters[ClientID].m_HasExtendedDisplayInfo)
|
2022-03-24 00:06:13 +00:00
|
|
|
|
{
|
2022-03-29 21:24:39 +00:00
|
|
|
|
x += 12;
|
2022-03-30 22:41:11 +00:00
|
|
|
|
RenderNinjaBarPos(x, y - 12, 6.f, 24.f, NinjaProgress);
|
2022-03-24 00:06:13 +00:00
|
|
|
|
}
|
2022-03-21 22:55:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// render capabilities
|
|
|
|
|
x = 5;
|
|
|
|
|
y += 12;
|
2022-03-30 22:41:11 +00:00
|
|
|
|
if(TotalJumpsToDisplay > 0)
|
|
|
|
|
{
|
|
|
|
|
y += 12;
|
|
|
|
|
}
|
2022-03-24 09:17:35 +00:00
|
|
|
|
bool HasCapabilities = false;
|
2022-03-21 22:55:35 +00:00
|
|
|
|
if(pCharacter->m_EndlessJump)
|
|
|
|
|
{
|
2022-03-24 09:17:35 +00:00
|
|
|
|
HasCapabilities = true;
|
2022-03-21 22:55:35 +00:00
|
|
|
|
Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudEndlessJump);
|
|
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_HudQuadContainerIndex, m_EndlessJumpOffset, x, y);
|
|
|
|
|
x += 12;
|
|
|
|
|
}
|
|
|
|
|
if(pCharacter->m_EndlessHook)
|
|
|
|
|
{
|
2022-03-24 09:17:35 +00:00
|
|
|
|
HasCapabilities = true;
|
2022-03-21 22:55:35 +00:00
|
|
|
|
Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudEndlessHook);
|
|
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_HudQuadContainerIndex, m_EndlessHookOffset, x, y);
|
|
|
|
|
x += 12;
|
|
|
|
|
}
|
|
|
|
|
if(pCharacter->m_Jetpack)
|
|
|
|
|
{
|
2022-03-24 09:17:35 +00:00
|
|
|
|
HasCapabilities = true;
|
2022-03-21 22:55:35 +00:00
|
|
|
|
Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudJetpack);
|
|
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_HudQuadContainerIndex, m_JetpackOffset, x, y);
|
|
|
|
|
x += 12;
|
|
|
|
|
}
|
2022-03-29 21:24:39 +00:00
|
|
|
|
if(pCharacter->m_HasTelegunGun && pCharacter->m_aWeapons[WEAPON_GUN].m_Got)
|
2022-03-21 22:55:35 +00:00
|
|
|
|
{
|
2022-03-24 09:17:35 +00:00
|
|
|
|
HasCapabilities = true;
|
2022-03-21 22:55:35 +00:00
|
|
|
|
Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudTeleportGun);
|
|
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_HudQuadContainerIndex, m_TeleportGunOffset, x, y);
|
|
|
|
|
x += 12;
|
|
|
|
|
}
|
2022-03-29 21:24:39 +00:00
|
|
|
|
if(pCharacter->m_HasTelegunGrenade && pCharacter->m_aWeapons[WEAPON_GRENADE].m_Got)
|
2022-03-21 22:55:35 +00:00
|
|
|
|
{
|
2022-03-24 09:17:35 +00:00
|
|
|
|
HasCapabilities = true;
|
2022-03-21 22:55:35 +00:00
|
|
|
|
Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudTeleportGrenade);
|
|
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_HudQuadContainerIndex, m_TeleportGrenadeOffset, x, y);
|
|
|
|
|
x += 12;
|
|
|
|
|
}
|
2022-03-29 21:24:39 +00:00
|
|
|
|
if(pCharacter->m_HasTelegunLaser && pCharacter->m_aWeapons[WEAPON_LASER].m_Got)
|
2022-03-21 22:55:35 +00:00
|
|
|
|
{
|
2022-03-24 09:17:35 +00:00
|
|
|
|
HasCapabilities = true;
|
2022-03-21 22:55:35 +00:00
|
|
|
|
Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudTeleportLaser);
|
|
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_HudQuadContainerIndex, m_TeleportLaserOffset, x, y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// render prohibited capabilities
|
|
|
|
|
x = 5;
|
2022-03-24 09:17:35 +00:00
|
|
|
|
if(HasCapabilities)
|
|
|
|
|
{
|
|
|
|
|
y += 12;
|
|
|
|
|
}
|
|
|
|
|
bool HasProhibitedCapabilities = false;
|
2022-03-21 22:55:35 +00:00
|
|
|
|
if(pCharacter->m_Solo)
|
|
|
|
|
{
|
2022-03-24 09:17:35 +00:00
|
|
|
|
HasProhibitedCapabilities = true;
|
2022-03-21 22:55:35 +00:00
|
|
|
|
Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudSolo);
|
|
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_HudQuadContainerIndex, m_SoloOffset, x, y);
|
|
|
|
|
x += 12;
|
|
|
|
|
}
|
|
|
|
|
if(pCharacter->m_NoCollision)
|
|
|
|
|
{
|
2022-03-24 09:17:35 +00:00
|
|
|
|
HasProhibitedCapabilities = true;
|
2022-03-21 22:55:35 +00:00
|
|
|
|
Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudNoCollision);
|
|
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_HudQuadContainerIndex, m_NoCollisionOffset, x, y);
|
|
|
|
|
x += 12;
|
|
|
|
|
}
|
|
|
|
|
if(pCharacter->m_NoHookHit)
|
|
|
|
|
{
|
2022-03-24 09:17:35 +00:00
|
|
|
|
HasProhibitedCapabilities = true;
|
2022-03-21 22:55:35 +00:00
|
|
|
|
Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudNoHookHit);
|
|
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_HudQuadContainerIndex, m_NoHookHitOffset, x, y);
|
|
|
|
|
x += 12;
|
|
|
|
|
}
|
|
|
|
|
if(pCharacter->m_NoHammerHit)
|
|
|
|
|
{
|
2022-03-24 09:17:35 +00:00
|
|
|
|
HasProhibitedCapabilities = true;
|
2022-03-21 22:55:35 +00:00
|
|
|
|
Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudNoHammerHit);
|
|
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_HudQuadContainerIndex, m_NoHammerHitOffset, x, y);
|
|
|
|
|
x += 12;
|
|
|
|
|
}
|
2022-03-24 09:17:35 +00:00
|
|
|
|
if((pCharacter->m_NoShotgunHit && pCharacter->m_aWeapons[WEAPON_SHOTGUN].m_Got))
|
2022-03-21 22:55:35 +00:00
|
|
|
|
{
|
2022-03-24 09:17:35 +00:00
|
|
|
|
HasProhibitedCapabilities = true;
|
2022-03-21 22:55:35 +00:00
|
|
|
|
Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudNoShotgunHit);
|
|
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_HudQuadContainerIndex, m_NoShotgunHitOffset, x, y);
|
|
|
|
|
x += 12;
|
|
|
|
|
}
|
2022-03-24 09:17:35 +00:00
|
|
|
|
if((pCharacter->m_NoGrenadeHit && pCharacter->m_aWeapons[WEAPON_GRENADE].m_Got))
|
2022-03-21 22:55:35 +00:00
|
|
|
|
{
|
2022-03-24 09:17:35 +00:00
|
|
|
|
HasProhibitedCapabilities = true;
|
2022-03-21 22:55:35 +00:00
|
|
|
|
Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudNoGrenadeHit);
|
|
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_HudQuadContainerIndex, m_NoGrenadeHitOffset, x, y);
|
|
|
|
|
x += 12;
|
|
|
|
|
}
|
2022-03-24 09:17:35 +00:00
|
|
|
|
if((pCharacter->m_NoLaserHit && pCharacter->m_aWeapons[WEAPON_LASER].m_Got))
|
2022-03-21 22:55:35 +00:00
|
|
|
|
{
|
2022-03-24 09:17:35 +00:00
|
|
|
|
HasProhibitedCapabilities = true;
|
2022-03-21 22:55:35 +00:00
|
|
|
|
Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudNoLaserHit);
|
|
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_HudQuadContainerIndex, m_NoLaserHitOffset, x, y);
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-25 09:09:13 +00:00
|
|
|
|
// render dummy actions and freeze state
|
2022-03-21 22:55:35 +00:00
|
|
|
|
x = 5;
|
2022-03-24 09:17:35 +00:00
|
|
|
|
if(HasProhibitedCapabilities)
|
|
|
|
|
{
|
|
|
|
|
y += 12;
|
|
|
|
|
}
|
2022-04-01 19:48:06 +00:00
|
|
|
|
if(m_pClient->m_Snap.m_aCharacters[ClientID].m_HasExtendedDisplayInfo && m_pClient->m_Snap.m_aCharacters[ClientID].m_ExtendedDisplayInfo.m_IsInPracticeMode)
|
|
|
|
|
{
|
|
|
|
|
Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudPracticeMode);
|
|
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_HudQuadContainerIndex, m_PracticeModeOffset, x, y);
|
|
|
|
|
x += 12;
|
|
|
|
|
}
|
2022-03-25 09:09:13 +00:00
|
|
|
|
if(pCharacter->m_DeepFrozen)
|
|
|
|
|
{
|
|
|
|
|
Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudDeepFrozen);
|
|
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_HudQuadContainerIndex, m_DeepFrozenOffset, x, y);
|
|
|
|
|
x += 12;
|
|
|
|
|
}
|
|
|
|
|
if(pCharacter->m_LiveFrozen)
|
|
|
|
|
{
|
|
|
|
|
Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudLiveFrozen);
|
|
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_HudQuadContainerIndex, m_LiveFrozenOffset, x, y);
|
2022-03-21 22:55:35 +00:00
|
|
|
|
}
|
2022-03-20 13:18:02 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-03-29 21:24:39 +00:00
|
|
|
|
void CHud::RenderNinjaBarPos(const float x, float y, const float width, const float height, float Progress, const float Alpha)
|
2022-03-24 00:06:13 +00:00
|
|
|
|
{
|
|
|
|
|
Progress = clamp(Progress, 0.0f, 1.0f);
|
2022-03-30 09:12:48 +00:00
|
|
|
|
|
|
|
|
|
// what percentage of the end pieces is used for the progress indicator and how much is the rest
|
|
|
|
|
// half of the ends are used for the progress display
|
|
|
|
|
const float RestPct = 0.5f;
|
|
|
|
|
const float ProgPct = 0.5f;
|
|
|
|
|
|
2022-03-29 21:24:39 +00:00
|
|
|
|
const float EndHeight = width; // to keep the correct scale - the width of the sprite is as long as the height
|
|
|
|
|
const float BarWidth = width;
|
2022-03-30 09:12:48 +00:00
|
|
|
|
const float WholeBarHeight = height;
|
2022-03-29 21:24:39 +00:00
|
|
|
|
const float MiddleBarHeight = WholeBarHeight - (EndHeight * 2.0f);
|
2022-03-30 09:12:48 +00:00
|
|
|
|
const float EndProgressHeight = EndHeight * ProgPct;
|
|
|
|
|
const float EndRestHeight = EndHeight * RestPct;
|
2022-03-29 21:24:39 +00:00
|
|
|
|
const float ProgressBarHeight = WholeBarHeight - (EndProgressHeight * 2.0f);
|
|
|
|
|
const float EndProgressProportion = EndProgressHeight / ProgressBarHeight;
|
|
|
|
|
const float MiddleProgressProportion = MiddleBarHeight / ProgressBarHeight;
|
|
|
|
|
|
2022-03-30 09:12:48 +00:00
|
|
|
|
// we cut 2% of all sides of all sprites so we don't get edge bleeding
|
|
|
|
|
const float CutL = 0.02f;
|
|
|
|
|
const float CutR = 0.98f;
|
|
|
|
|
const float CutT = 0.02f;
|
|
|
|
|
const float CutB = 0.98f;
|
2022-03-29 21:24:39 +00:00
|
|
|
|
const float Slice = 0.02f;
|
2022-03-27 16:18:53 +00:00
|
|
|
|
|
2022-03-24 20:31:27 +00:00
|
|
|
|
// beginning piece
|
|
|
|
|
float BeginningPieceProgress = 1;
|
2022-03-29 21:24:39 +00:00
|
|
|
|
if(Progress <= 1)
|
2022-03-24 20:31:27 +00:00
|
|
|
|
{
|
2022-03-29 21:24:39 +00:00
|
|
|
|
if(Progress <= (EndProgressProportion + MiddleProgressProportion))
|
|
|
|
|
{
|
|
|
|
|
BeginningPieceProgress = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
BeginningPieceProgress = (Progress - EndProgressProportion - MiddleProgressProportion) / EndProgressProportion;
|
|
|
|
|
}
|
2022-03-24 20:31:27 +00:00
|
|
|
|
}
|
2022-03-29 21:24:39 +00:00
|
|
|
|
// empty
|
|
|
|
|
Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudNinjaBarEmptyRight);
|
2022-03-24 20:31:27 +00:00
|
|
|
|
Graphics()->QuadsBegin();
|
2022-03-25 11:54:11 +00:00
|
|
|
|
Graphics()->SetColor(1.f, 1.f, 1.f, Alpha);
|
2022-03-29 21:24:39 +00:00
|
|
|
|
// Subset: btm_r, top_r, top_m, btm_m | it is mirrored on the horizontal axe and rotated 90 degrees counterclockwise
|
2022-03-30 09:12:48 +00:00
|
|
|
|
Graphics()->QuadsSetSubsetFree(CutR, CutB, CutR, CutT, ProgPct - (ProgPct - CutL) * (1.0f - BeginningPieceProgress), CutT, ProgPct - (ProgPct - CutL) * (1.0f - BeginningPieceProgress), CutB);
|
|
|
|
|
IGraphics::CQuadItem QuadEmptyBeginning(x, y, BarWidth, EndRestHeight + EndProgressHeight * (1.0f - BeginningPieceProgress));
|
2022-03-29 21:24:39 +00:00
|
|
|
|
Graphics()->QuadsDrawTL(&QuadEmptyBeginning, 1);
|
2022-03-24 20:31:27 +00:00
|
|
|
|
Graphics()->QuadsEnd();
|
2022-03-29 21:24:39 +00:00
|
|
|
|
// full
|
|
|
|
|
if(BeginningPieceProgress > 0.0f)
|
2022-03-24 20:31:27 +00:00
|
|
|
|
{
|
2022-03-29 21:24:39 +00:00
|
|
|
|
Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudNinjaBarFullLeft);
|
2022-03-24 20:31:27 +00:00
|
|
|
|
Graphics()->QuadsBegin();
|
2022-03-25 11:54:11 +00:00
|
|
|
|
Graphics()->SetColor(1.f, 1.f, 1.f, Alpha);
|
2022-03-29 21:24:39 +00:00
|
|
|
|
// Subset: btm_m, top_m, top_r, btm_r | it is rotated 90 degrees clockwise
|
2022-03-30 09:12:48 +00:00
|
|
|
|
Graphics()->QuadsSetSubsetFree(RestPct + (ProgPct - CutL) * (1.0f - BeginningPieceProgress), CutB, RestPct + (ProgPct - CutL) * (1.0f - BeginningPieceProgress), CutT, CutR, CutT, CutR, CutB);
|
|
|
|
|
IGraphics::CQuadItem QuadFullBeginning(x, y + (EndRestHeight + EndProgressHeight * (1.0f - BeginningPieceProgress)), BarWidth, EndProgressHeight * BeginningPieceProgress);
|
2022-03-29 21:24:39 +00:00
|
|
|
|
Graphics()->QuadsDrawTL(&QuadFullBeginning, 1);
|
2022-03-24 20:31:27 +00:00
|
|
|
|
Graphics()->QuadsEnd();
|
|
|
|
|
}
|
2022-03-24 00:06:13 +00:00
|
|
|
|
|
2022-03-24 20:31:27 +00:00
|
|
|
|
// middle piece
|
2022-03-29 21:24:39 +00:00
|
|
|
|
y += EndHeight;
|
2022-03-24 00:06:13 +00:00
|
|
|
|
|
2022-03-24 20:31:27 +00:00
|
|
|
|
float MiddlePieceProgress = 1;
|
|
|
|
|
if(Progress <= EndProgressProportion + MiddleProgressProportion)
|
|
|
|
|
{
|
|
|
|
|
if(Progress <= EndProgressProportion)
|
|
|
|
|
{
|
|
|
|
|
MiddlePieceProgress = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
MiddlePieceProgress = (Progress - EndProgressProportion) / MiddleProgressProportion;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-03-24 00:06:13 +00:00
|
|
|
|
|
2022-03-29 21:24:39 +00:00
|
|
|
|
const float FullMiddleBarHeight = MiddleBarHeight * MiddlePieceProgress;
|
|
|
|
|
const float EmptyMiddleBarHeight = MiddleBarHeight - FullMiddleBarHeight;
|
2022-03-24 20:31:27 +00:00
|
|
|
|
|
2022-03-29 21:24:39 +00:00
|
|
|
|
// empty ninja bar
|
|
|
|
|
if(EmptyMiddleBarHeight > 0.0f)
|
2022-03-24 20:31:27 +00:00
|
|
|
|
{
|
2022-03-29 21:24:39 +00:00
|
|
|
|
Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudNinjaBarEmpty);
|
|
|
|
|
Graphics()->QuadsBegin();
|
|
|
|
|
Graphics()->SetColor(1.f, 1.f, 1.f, Alpha);
|
|
|
|
|
// select the middle portion of the sprite so we don't get edge bleeding
|
|
|
|
|
if(EmptyMiddleBarHeight <= EndHeight)
|
|
|
|
|
{
|
|
|
|
|
// prevent pixel puree, select only a small slice
|
|
|
|
|
// Subset: btm_r, top_r, top_m, btm_m | it is mirrored on the horizontal axe and rotated 90 degrees counterclockwise
|
|
|
|
|
Graphics()->QuadsSetSubsetFree(CutR, CutB, CutR, CutT, CutR - Slice, CutT, CutR - Slice, CutB);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Subset: btm_r, top_r, top_l, btm_l | it is mirrored on the horizontal axe and rotated 90 degrees counterclockwise
|
|
|
|
|
Graphics()->QuadsSetSubsetFree(CutR, CutB, CutR, CutT, CutL, CutT, CutL, CutB);
|
|
|
|
|
}
|
|
|
|
|
IGraphics::CQuadItem QuadEmpty(x, y, BarWidth, EmptyMiddleBarHeight);
|
|
|
|
|
Graphics()->QuadsDrawTL(&QuadEmpty, 1);
|
|
|
|
|
Graphics()->QuadsEnd();
|
2022-03-24 00:06:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-03-29 21:24:39 +00:00
|
|
|
|
// full ninja bar
|
|
|
|
|
Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudNinjaBarFull);
|
2022-03-24 00:06:13 +00:00
|
|
|
|
Graphics()->QuadsBegin();
|
2022-03-25 11:54:11 +00:00
|
|
|
|
Graphics()->SetColor(1.f, 1.f, 1.f, Alpha);
|
2022-03-24 20:31:27 +00:00
|
|
|
|
// select the middle portion of the sprite so we don't get edge bleeding
|
2022-03-29 21:24:39 +00:00
|
|
|
|
if(FullMiddleBarHeight <= EndHeight)
|
2022-03-24 20:31:27 +00:00
|
|
|
|
{
|
|
|
|
|
// prevent pixel puree, select only a small slice
|
2022-03-29 21:24:39 +00:00
|
|
|
|
// Subset: btm_m, top_m, top_r, btm_r | it is rotated 90 degrees clockwise
|
|
|
|
|
Graphics()->QuadsSetSubsetFree(CutR - Slice, CutB, CutR - Slice, CutT, CutR, CutT, CutR, CutB);
|
2022-03-24 20:31:27 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2022-03-29 21:24:39 +00:00
|
|
|
|
// Subset: btm_l, top_l, top_r, btm_r | it is rotated 90 degrees clockwise
|
|
|
|
|
Graphics()->QuadsSetSubsetFree(CutL, CutB, CutL, CutT, CutR, CutT, CutR, CutB);
|
2022-03-24 20:31:27 +00:00
|
|
|
|
}
|
2022-03-29 21:24:39 +00:00
|
|
|
|
IGraphics::CQuadItem QuadFull(x, y + EmptyMiddleBarHeight, BarWidth, FullMiddleBarHeight);
|
|
|
|
|
Graphics()->QuadsDrawTL(&QuadFull, 1);
|
2022-03-24 00:06:13 +00:00
|
|
|
|
Graphics()->QuadsEnd();
|
|
|
|
|
|
2022-03-29 21:24:39 +00:00
|
|
|
|
// ending piece
|
|
|
|
|
y += MiddleBarHeight;
|
2022-03-24 20:31:27 +00:00
|
|
|
|
float EndingPieceProgress = 1;
|
2022-03-29 21:24:39 +00:00
|
|
|
|
if(Progress <= EndProgressProportion)
|
2022-03-24 00:06:13 +00:00
|
|
|
|
{
|
2022-03-29 21:24:39 +00:00
|
|
|
|
EndingPieceProgress = Progress / EndProgressProportion;
|
2022-03-24 00:06:13 +00:00
|
|
|
|
}
|
2022-03-29 21:24:39 +00:00
|
|
|
|
// empty
|
|
|
|
|
if(EndingPieceProgress < 1.0f)
|
2022-03-24 00:06:13 +00:00
|
|
|
|
{
|
2022-03-29 21:24:39 +00:00
|
|
|
|
Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudNinjaBarEmptyRight);
|
2022-03-24 20:31:27 +00:00
|
|
|
|
Graphics()->QuadsBegin();
|
2022-03-25 11:54:11 +00:00
|
|
|
|
Graphics()->SetColor(1.f, 1.f, 1.f, Alpha);
|
2022-03-29 21:24:39 +00:00
|
|
|
|
// Subset: btm_l, top_l, top_m, btm_m | it is rotated 90 degrees clockwise
|
2022-03-30 09:12:48 +00:00
|
|
|
|
Graphics()->QuadsSetSubsetFree(CutL, CutB, CutL, CutT, ProgPct - (ProgPct - CutL) * EndingPieceProgress, CutT, ProgPct - (ProgPct - CutL) * EndingPieceProgress, CutB);
|
2022-04-14 12:07:01 +00:00
|
|
|
|
IGraphics::CQuadItem QuadEmptyEnding(x, y, BarWidth, EndProgressHeight * (1.0f - EndingPieceProgress));
|
|
|
|
|
Graphics()->QuadsDrawTL(&QuadEmptyEnding, 1);
|
2022-03-24 20:31:27 +00:00
|
|
|
|
Graphics()->QuadsEnd();
|
2022-03-24 00:06:13 +00:00
|
|
|
|
}
|
2022-03-29 21:24:39 +00:00
|
|
|
|
// full
|
|
|
|
|
Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudNinjaBarFullLeft);
|
2022-03-24 20:31:27 +00:00
|
|
|
|
Graphics()->QuadsBegin();
|
2022-03-25 11:54:11 +00:00
|
|
|
|
Graphics()->SetColor(1.f, 1.f, 1.f, Alpha);
|
2022-03-29 21:24:39 +00:00
|
|
|
|
// Subset: btm_m, top_m, top_l, btm_l | it is mirrored on the horizontal axe and rotated 90 degrees counterclockwise
|
2022-03-30 09:12:48 +00:00
|
|
|
|
Graphics()->QuadsSetSubsetFree(RestPct + (ProgPct - CutL) * EndingPieceProgress, CutB, RestPct + (ProgPct - CutL) * EndingPieceProgress, CutT, CutL, CutT, CutL, CutB);
|
2022-04-14 12:07:01 +00:00
|
|
|
|
IGraphics::CQuadItem QuadFullEnding(x, y + (EndProgressHeight * (1.0f - EndingPieceProgress)), BarWidth, EndRestHeight + EndProgressHeight * EndingPieceProgress);
|
|
|
|
|
Graphics()->QuadsDrawTL(&QuadFullEnding, 1);
|
2022-03-24 20:31:27 +00:00
|
|
|
|
Graphics()->QuadsEnd();
|
2022-03-30 09:12:48 +00:00
|
|
|
|
|
|
|
|
|
Graphics()->QuadsSetSubset(0, 0, 1, 1);
|
|
|
|
|
Graphics()->SetColor(1.f, 1.f, 1.f, 1.f);
|
2022-03-24 00:06:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-04-01 19:48:06 +00:00
|
|
|
|
void CHud::RenderDummyActions()
|
|
|
|
|
{
|
2022-04-14 11:31:00 +00:00
|
|
|
|
if(!g_Config.m_ClShowhudDummyActions || (m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags & GAMESTATEFLAG_GAMEOVER) || !Client()->DummyConnected())
|
2022-04-01 19:48:06 +00:00
|
|
|
|
{
|
2022-04-14 11:31:00 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// render small dummy actions hud
|
|
|
|
|
const float BoxHeight = 27.0f;
|
|
|
|
|
const float BoxWidth = 14.0f;
|
2022-04-01 19:48:06 +00:00
|
|
|
|
|
2022-04-14 11:31:00 +00:00
|
|
|
|
float StartX = m_Width - BoxWidth;
|
|
|
|
|
float StartY = 285.0f - BoxHeight - 4; // 4 units distance to the next display;
|
|
|
|
|
if(g_Config.m_ClShowhudPlayerPosition || g_Config.m_ClShowhudPlayerSpeed || g_Config.m_ClShowhudPlayerAngle)
|
|
|
|
|
{
|
|
|
|
|
StartY -= 4;
|
|
|
|
|
}
|
2022-05-10 16:41:46 +00:00
|
|
|
|
StartY -= GetMovementInformationBoxHeight();
|
2022-04-01 19:48:06 +00:00
|
|
|
|
|
2022-04-14 11:31:00 +00:00
|
|
|
|
if(g_Config.m_ClShowhudScore)
|
|
|
|
|
{
|
|
|
|
|
StartY -= 56;
|
|
|
|
|
}
|
2022-04-01 19:48:06 +00:00
|
|
|
|
|
2022-04-14 11:31:00 +00:00
|
|
|
|
Graphics()->TextureClear();
|
|
|
|
|
Graphics()->QuadsBegin();
|
|
|
|
|
Graphics()->SetColor(0.0f, 0.0f, 0.0f, 0.4f);
|
|
|
|
|
RenderTools()->DrawRoundRectExt(StartX, StartY, BoxWidth, BoxHeight, 5.0f, CUI::CORNER_L);
|
|
|
|
|
Graphics()->QuadsEnd();
|
|
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
|
2022-04-01 19:48:06 +00:00
|
|
|
|
|
2022-04-14 11:31:00 +00:00
|
|
|
|
float y = StartY + 1;
|
|
|
|
|
float x = StartX + 1;
|
|
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.4f);
|
|
|
|
|
if(g_Config.m_ClDummyHammer)
|
|
|
|
|
{
|
2022-04-01 19:48:06 +00:00
|
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
|
2022-04-14 11:31:00 +00:00
|
|
|
|
}
|
|
|
|
|
Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudDummyHammer);
|
|
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_HudQuadContainerIndex, m_DummyHammerOffset, x, y);
|
|
|
|
|
y += 13;
|
|
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.4f);
|
|
|
|
|
if(g_Config.m_ClDummyCopyMoves)
|
|
|
|
|
{
|
|
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
|
|
|
|
|
}
|
|
|
|
|
Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudDummyCopy);
|
|
|
|
|
Graphics()->RenderQuadContainerAsSprite(m_HudQuadContainerIndex, m_DummyCopyOffset, x, y);
|
|
|
|
|
}
|
2022-04-01 19:48:06 +00:00
|
|
|
|
|
2022-04-14 12:07:01 +00:00
|
|
|
|
inline int CHud::GetDigitsIndex(int Value, int Max)
|
2022-04-14 11:31:00 +00:00
|
|
|
|
{
|
|
|
|
|
if(Value < 0)
|
|
|
|
|
{
|
|
|
|
|
Value *= -1;
|
|
|
|
|
}
|
|
|
|
|
int DigitsIndex = (int)log10((Value ? Value : 1));
|
|
|
|
|
if(DigitsIndex > Max)
|
|
|
|
|
{
|
|
|
|
|
DigitsIndex = Max;
|
|
|
|
|
}
|
|
|
|
|
if(DigitsIndex < 0)
|
|
|
|
|
{
|
|
|
|
|
DigitsIndex = 0;
|
|
|
|
|
}
|
|
|
|
|
return DigitsIndex;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-10 16:41:46 +00:00
|
|
|
|
inline float CHud::GetMovementInformationBoxHeight()
|
|
|
|
|
{
|
|
|
|
|
float BoxHeight = 3 * MOVEMENT_INFORMATION_LINE_HEIGHT * (g_Config.m_ClShowhudPlayerPosition + g_Config.m_ClShowhudPlayerSpeed) + 2 * MOVEMENT_INFORMATION_LINE_HEIGHT * g_Config.m_ClShowhudPlayerAngle;
|
|
|
|
|
if(g_Config.m_ClShowhudPlayerPosition || g_Config.m_ClShowhudPlayerSpeed || g_Config.m_ClShowhudPlayerAngle)
|
|
|
|
|
{
|
|
|
|
|
BoxHeight += 2;
|
|
|
|
|
}
|
|
|
|
|
return BoxHeight;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-14 11:31:00 +00:00
|
|
|
|
void CHud::RenderMovementInformation(const int ClientID)
|
|
|
|
|
{
|
|
|
|
|
// Draw the infomations depending on settings: Position, speed and target angle
|
|
|
|
|
// This display is only to present the available information from the last snapshot, not to interpolate or predict
|
|
|
|
|
if(!g_Config.m_ClShowhudPlayerPosition && !g_Config.m_ClShowhudPlayerSpeed && !g_Config.m_ClShowhudPlayerAngle)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const float LineSpacer = 1.0f; // above and below each entry
|
2022-05-10 16:41:46 +00:00
|
|
|
|
const float Fontsize = 6.0f;
|
2022-04-14 11:31:00 +00:00
|
|
|
|
|
2022-05-10 16:41:46 +00:00
|
|
|
|
float BoxHeight = GetMovementInformationBoxHeight();
|
2022-04-14 11:31:00 +00:00
|
|
|
|
const float BoxWidth = 62.0f;
|
|
|
|
|
|
|
|
|
|
float StartX = m_Width - BoxWidth;
|
|
|
|
|
float StartY = 285.0f - BoxHeight - 4; // 4 units distance to the next display;
|
|
|
|
|
if(g_Config.m_ClShowhudScore)
|
|
|
|
|
{
|
|
|
|
|
StartY -= 56;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Graphics()->TextureClear();
|
|
|
|
|
Graphics()->QuadsBegin();
|
|
|
|
|
Graphics()->SetColor(0.0f, 0.0f, 0.0f, 0.4f);
|
|
|
|
|
RenderTools()->DrawRoundRectExt(StartX, StartY, BoxWidth, BoxHeight, 5.0f, CUI::CORNER_L);
|
|
|
|
|
Graphics()->QuadsEnd();
|
|
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
|
|
|
|
|
|
|
|
|
|
CNetObj_Character *Character = &m_pClient->m_Snap.m_aCharacters[ClientID].m_Cur;
|
|
|
|
|
const float TicksPerSecond = 50.0f;
|
|
|
|
|
|
|
|
|
|
// To make the player position relative to blocks we need to divide by the block size
|
|
|
|
|
float PosX = Character->m_X / 32.0f;
|
|
|
|
|
float PosY = Character->m_Y / 32.0f;
|
|
|
|
|
|
|
|
|
|
float VelspeedX = Character->m_VelX / 256.0f * TicksPerSecond;
|
|
|
|
|
if(Character->m_VelX >= -1 && Character->m_VelX <= 1)
|
|
|
|
|
{
|
|
|
|
|
VelspeedX = 0;
|
|
|
|
|
}
|
|
|
|
|
float VelspeedY = Character->m_VelY / 256.0f * TicksPerSecond;
|
|
|
|
|
if(Character->m_VelY >= -128 && Character->m_VelY <= 128)
|
|
|
|
|
{
|
|
|
|
|
VelspeedY = 0;
|
|
|
|
|
}
|
|
|
|
|
// We show the speed in Blocks per Second (Bps) and therefore have to divide by the block size
|
|
|
|
|
float DisplaySpeedX = VelspeedX / 32;
|
|
|
|
|
float DisplaySpeedY = VelspeedY / 32;
|
|
|
|
|
if(m_pClient->m_Snap.m_aCharacters[ClientID].m_HasExtendedDisplayInfo)
|
|
|
|
|
{
|
|
|
|
|
// On DDNet servers the actual speed on X axis is displayed, i.e. VelspeedX * Ramp
|
|
|
|
|
DisplaySpeedX *= (m_pClient->m_Snap.m_aCharacters[ClientID].m_ExtendedDisplayInfo.m_RampValue / 1000.0f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float Angle = Character->m_Angle / 256.0f;
|
|
|
|
|
if(Angle > pi)
|
|
|
|
|
{
|
|
|
|
|
Angle -= 2.0f * pi;
|
|
|
|
|
}
|
|
|
|
|
if(m_pClient->m_Snap.m_aCharacters[ClientID].m_HasExtendedDisplayInfo)
|
|
|
|
|
{
|
|
|
|
|
// On DDNet servers the more accurate angle is displayed, calculated from the target coordinates
|
|
|
|
|
CNetObj_DDNetCharacterDisplayInfo *CharacterDisplayInfo = &m_pClient->m_Snap.m_aCharacters[ClientID].m_ExtendedDisplayInfo;
|
|
|
|
|
Angle = atan2f(CharacterDisplayInfo->m_TargetY, CharacterDisplayInfo->m_TargetX);
|
|
|
|
|
}
|
|
|
|
|
float DisplayAngle = Angle * 180.0f / pi;
|
|
|
|
|
|
|
|
|
|
char aBuf[128];
|
|
|
|
|
float w;
|
|
|
|
|
|
2022-05-10 16:41:46 +00:00
|
|
|
|
float y = StartY + LineSpacer * 2;
|
|
|
|
|
float xl = StartX + 2;
|
|
|
|
|
float xr = m_Width - 2;
|
2022-04-14 11:31:00 +00:00
|
|
|
|
int DigitsIndex = 0;
|
|
|
|
|
|
|
|
|
|
static float s_TextWidth0 = TextRender()->TextWidth(0, Fontsize, "0.00", -1, -1.0f);
|
|
|
|
|
static float s_TextWidth00 = TextRender()->TextWidth(0, Fontsize, "00.00", -1, -1.0f);
|
|
|
|
|
static float s_TextWidth000 = TextRender()->TextWidth(0, Fontsize, "000.00", -1, -1.0f);
|
|
|
|
|
static float s_TextWidth0000 = TextRender()->TextWidth(0, Fontsize, "0000.00", -1, -1.0f);
|
|
|
|
|
static float s_TextWidth00000 = TextRender()->TextWidth(0, Fontsize, "00000.00", -1, -1.0f);
|
|
|
|
|
static float s_TextWidth000000 = TextRender()->TextWidth(0, Fontsize, "000000.00", -1, -1.0f);
|
|
|
|
|
static float s_TextWidth[6] = {s_TextWidth0, s_TextWidth00, s_TextWidth000, s_TextWidth0000, s_TextWidth00000, s_TextWidth000000};
|
|
|
|
|
static float s_TextWidthMinus0 = TextRender()->TextWidth(0, Fontsize, "-0.00", -1, -1.0f);
|
|
|
|
|
static float s_TextWidthMinus00 = TextRender()->TextWidth(0, Fontsize, "-00.00", -1, -1.0f);
|
|
|
|
|
static float s_TextWidthMinus000 = TextRender()->TextWidth(0, Fontsize, "-000.00", -1, -1.0f);
|
|
|
|
|
static float s_TextWidthMinus0000 = TextRender()->TextWidth(0, Fontsize, "-0000.00", -1, -1.0f);
|
|
|
|
|
static float s_TextWidthMinus00000 = TextRender()->TextWidth(0, Fontsize, "-00000.00", -1, -1.0f);
|
|
|
|
|
static float s_TextWidthMinus000000 = TextRender()->TextWidth(0, Fontsize, "-000000.00", -1, -1.0f);
|
|
|
|
|
static float s_TextWidthMinus[6] = {s_TextWidthMinus0, s_TextWidthMinus00, s_TextWidthMinus000, s_TextWidthMinus0000, s_TextWidthMinus00000, s_TextWidthMinus000000};
|
|
|
|
|
|
|
|
|
|
if(g_Config.m_ClShowhudPlayerPosition)
|
|
|
|
|
{
|
2022-05-10 16:41:46 +00:00
|
|
|
|
TextRender()->Text(0, xl, y, Fontsize, Localize("Position:"), -1.0f);
|
|
|
|
|
y += MOVEMENT_INFORMATION_LINE_HEIGHT;
|
2022-04-14 11:31:00 +00:00
|
|
|
|
|
|
|
|
|
TextRender()->Text(0, xl, y, Fontsize, "X:", -1.0f);
|
|
|
|
|
str_format(aBuf, sizeof(aBuf), "%.2f", PosX);
|
|
|
|
|
DigitsIndex = GetDigitsIndex(PosX, 5);
|
|
|
|
|
w = (PosX < 0) ? s_TextWidthMinus[DigitsIndex] : s_TextWidth[DigitsIndex];
|
|
|
|
|
TextRender()->Text(0, xr - w, y, Fontsize, aBuf, -1.0f);
|
2022-05-10 16:41:46 +00:00
|
|
|
|
y += MOVEMENT_INFORMATION_LINE_HEIGHT;
|
2022-04-14 11:31:00 +00:00
|
|
|
|
|
|
|
|
|
TextRender()->Text(0, xl, y, Fontsize, "Y:", -1.0f);
|
|
|
|
|
str_format(aBuf, sizeof(aBuf), "%.2f", PosY);
|
|
|
|
|
DigitsIndex = GetDigitsIndex(PosY, 5);
|
|
|
|
|
w = (PosY < 0) ? s_TextWidthMinus[DigitsIndex] : s_TextWidth[DigitsIndex];
|
|
|
|
|
TextRender()->Text(0, xr - w, y, Fontsize, aBuf, -1.0f);
|
2022-05-10 16:41:46 +00:00
|
|
|
|
y += MOVEMENT_INFORMATION_LINE_HEIGHT;
|
2022-04-14 11:31:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(g_Config.m_ClShowhudPlayerSpeed)
|
|
|
|
|
{
|
2022-05-10 16:41:46 +00:00
|
|
|
|
TextRender()->Text(0, xl, y, Fontsize, Localize("Speed:"), -1.0f);
|
|
|
|
|
y += MOVEMENT_INFORMATION_LINE_HEIGHT;
|
2022-04-14 11:31:00 +00:00
|
|
|
|
|
|
|
|
|
TextRender()->Text(0, xl, y, Fontsize, "X:", -1.0f);
|
|
|
|
|
str_format(aBuf, sizeof(aBuf), "%.2f", DisplaySpeedX);
|
|
|
|
|
DigitsIndex = GetDigitsIndex(DisplaySpeedX, 5);
|
|
|
|
|
w = (DisplaySpeedX < 0) ? s_TextWidthMinus[DigitsIndex] : s_TextWidth[DigitsIndex];
|
|
|
|
|
TextRender()->Text(0, xr - w, y, Fontsize, aBuf, -1.0f);
|
2022-05-10 16:41:46 +00:00
|
|
|
|
y += MOVEMENT_INFORMATION_LINE_HEIGHT;
|
2022-04-14 11:31:00 +00:00
|
|
|
|
|
|
|
|
|
TextRender()->Text(0, xl, y, Fontsize, "Y:", -1.0f);
|
|
|
|
|
str_format(aBuf, sizeof(aBuf), "%.2f", DisplaySpeedY);
|
|
|
|
|
DigitsIndex = GetDigitsIndex(DisplaySpeedY, 5);
|
|
|
|
|
w = (DisplaySpeedY < 0) ? s_TextWidthMinus[DigitsIndex] : s_TextWidth[DigitsIndex];
|
|
|
|
|
TextRender()->Text(0, xr - w, y, Fontsize, aBuf, -1.0f);
|
2022-05-10 16:41:46 +00:00
|
|
|
|
y += MOVEMENT_INFORMATION_LINE_HEIGHT;
|
2022-04-14 11:31:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(g_Config.m_ClShowhudPlayerAngle)
|
|
|
|
|
{
|
2022-05-10 16:41:46 +00:00
|
|
|
|
TextRender()->Text(0, xl, y, Fontsize, Localize("Angle:"), -1.0f);
|
|
|
|
|
y += MOVEMENT_INFORMATION_LINE_HEIGHT;
|
2022-04-14 11:31:00 +00:00
|
|
|
|
str_format(aBuf, sizeof(aBuf), "%.2f", DisplayAngle);
|
|
|
|
|
DigitsIndex = GetDigitsIndex(DisplayAngle, 5);
|
|
|
|
|
w = (DisplayAngle < 0) ? s_TextWidthMinus[DigitsIndex] : s_TextWidth[DigitsIndex];
|
|
|
|
|
TextRender()->Text(0, xr - w, y, Fontsize, aBuf, -1.0f);
|
2022-04-01 19:48:06 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-04-14 11:31:00 +00:00
|
|
|
|
|
2011-03-10 09:08:14 +00:00
|
|
|
|
void CHud::RenderSpectatorHud()
|
|
|
|
|
{
|
|
|
|
|
// draw the box
|
2012-08-12 10:41:50 +00:00
|
|
|
|
Graphics()->TextureClear();
|
2011-03-10 09:08:14 +00:00
|
|
|
|
Graphics()->QuadsBegin();
|
|
|
|
|
Graphics()->SetColor(0.0f, 0.0f, 0.0f, 0.4f);
|
2020-09-26 19:41:58 +00:00
|
|
|
|
RenderTools()->DrawRoundRectExt(m_Width - 180.0f, m_Height - 15.0f, 180.0f, 15.0f, 5.0f, CUI::CORNER_TL);
|
2011-03-10 09:08:14 +00:00
|
|
|
|
Graphics()->QuadsEnd();
|
|
|
|
|
|
|
|
|
|
// draw the text
|
|
|
|
|
char aBuf[128];
|
2020-09-26 19:41:58 +00:00
|
|
|
|
str_format(aBuf, sizeof(aBuf), "%s: %s", Localize("Spectate"), m_pClient->m_Snap.m_SpecInfo.m_SpectatorID != SPEC_FREEVIEW ? m_pClient->m_aClients[m_pClient->m_Snap.m_SpecInfo.m_SpectatorID].m_aName : Localize("Free-View"));
|
|
|
|
|
TextRender()->Text(0, m_Width - 174.0f, m_Height - 15.0f + (15.f - 8.f) / 2.f, 8.0f, aBuf, -1.0f);
|
2011-03-10 09:08:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-04-27 17:22:55 +00:00
|
|
|
|
void CHud::RenderLocalTime(float x)
|
|
|
|
|
{
|
2021-07-12 09:43:56 +00:00
|
|
|
|
if(!g_Config.m_ClShowLocalTimeAlways && !m_pClient->m_Scoreboard.Active())
|
2016-04-27 17:22:55 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
//draw the box
|
|
|
|
|
Graphics()->BlendNormal();
|
2012-08-12 10:41:50 +00:00
|
|
|
|
Graphics()->TextureClear();
|
2016-04-27 17:22:55 +00:00
|
|
|
|
Graphics()->QuadsBegin();
|
|
|
|
|
Graphics()->SetColor(0.0f, 0.0f, 0.0f, 0.4f);
|
2020-09-26 19:41:58 +00:00
|
|
|
|
RenderTools()->DrawRoundRectExt(x - 30.0f, 0.0f, 25.0f, 12.5f, 3.75f, CUI::CORNER_B);
|
2016-04-27 17:22:55 +00:00
|
|
|
|
Graphics()->QuadsEnd();
|
|
|
|
|
|
|
|
|
|
//draw the text
|
2017-09-03 06:53:54 +00:00
|
|
|
|
char aTimeStr[6];
|
|
|
|
|
str_timestamp_format(aTimeStr, sizeof(aTimeStr), "%H:%M");
|
2020-09-26 19:41:58 +00:00
|
|
|
|
TextRender()->Text(0, x - 25.0f, (12.5f - 5.f) / 2.f, 5.0f, aTimeStr, -1.0f);
|
2016-04-27 17:22:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-01-06 03:46:10 +00:00
|
|
|
|
void CHud::OnRender()
|
|
|
|
|
{
|
2011-03-04 16:08:10 +00:00
|
|
|
|
if(!m_pClient->m_Snap.m_pGameInfoObj)
|
2011-01-06 03:46:10 +00:00
|
|
|
|
return;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
|
m_Width = 300.0f * Graphics()->ScreenAspect();
|
2011-03-10 09:08:14 +00:00
|
|
|
|
m_Height = 300.0f;
|
|
|
|
|
Graphics()->MapScreen(0.0f, 0.0f, m_Width, m_Height);
|
2011-01-06 03:46:10 +00:00
|
|
|
|
|
2019-10-02 05:11:58 +00:00
|
|
|
|
#if defined(CONF_VIDEORECORDER)
|
2020-09-26 19:41:58 +00:00
|
|
|
|
if((IVideo::Current() && g_Config.m_ClVideoShowhud) || (!IVideo::Current() && g_Config.m_ClShowhud))
|
2019-10-02 05:11:58 +00:00
|
|
|
|
#else
|
2011-03-27 12:40:15 +00:00
|
|
|
|
if(g_Config.m_ClShowhud)
|
2019-10-02 05:11:58 +00:00
|
|
|
|
#endif
|
2011-03-10 09:08:14 +00:00
|
|
|
|
{
|
2022-03-20 13:18:02 +00:00
|
|
|
|
if(m_pClient->m_Snap.m_pLocalCharacter && !m_pClient->m_Snap.m_SpecInfo.m_Active && !(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags & GAMESTATEFLAG_GAMEOVER))
|
2011-12-26 11:56:24 +00:00
|
|
|
|
{
|
2022-05-10 16:41:46 +00:00
|
|
|
|
if(g_Config.m_ClShowhudHealthAmmo && (!m_pClient->m_Snap.m_aCharacters[m_pClient->m_Snap.m_LocalClientID].m_HasExtendedData || !g_Config.m_ClDDRaceHud))
|
2022-03-20 13:18:02 +00:00
|
|
|
|
{
|
2022-03-18 10:11:58 +00:00
|
|
|
|
RenderAmmoHealthAndArmor(m_pClient->m_Snap.m_pLocalCharacter);
|
2022-03-20 13:18:02 +00:00
|
|
|
|
}
|
2022-05-10 16:41:46 +00:00
|
|
|
|
if(m_pClient->m_Snap.m_aCharacters[m_pClient->m_Snap.m_LocalClientID].m_HasExtendedData && g_Config.m_ClDDRaceHud)
|
2022-03-20 13:18:02 +00:00
|
|
|
|
{
|
2022-03-21 22:55:35 +00:00
|
|
|
|
RenderPlayerState(m_pClient->m_Snap.m_LocalClientID);
|
2022-03-20 13:18:02 +00:00
|
|
|
|
}
|
2022-04-14 11:31:00 +00:00
|
|
|
|
RenderMovementInformation(m_pClient->m_Snap.m_LocalClientID);
|
2011-12-26 11:56:24 +00:00
|
|
|
|
RenderDDRaceEffects();
|
|
|
|
|
}
|
2011-03-27 12:40:15 +00:00
|
|
|
|
else if(m_pClient->m_Snap.m_SpecInfo.m_Active)
|
|
|
|
|
{
|
2022-03-20 13:18:02 +00:00
|
|
|
|
int SpectatorID = m_pClient->m_Snap.m_SpecInfo.m_SpectatorID;
|
2022-05-10 16:41:46 +00:00
|
|
|
|
if(SpectatorID != SPEC_FREEVIEW && g_Config.m_ClShowhudHealthAmmo && (!m_pClient->m_Snap.m_aCharacters[SpectatorID].m_HasExtendedData || !g_Config.m_ClDDRaceHud))
|
2022-03-20 13:18:02 +00:00
|
|
|
|
{
|
|
|
|
|
RenderAmmoHealthAndArmor(&m_pClient->m_Snap.m_aCharacters[SpectatorID].m_Cur);
|
|
|
|
|
}
|
2022-05-10 16:41:46 +00:00
|
|
|
|
if(SpectatorID != SPEC_FREEVIEW && m_pClient->m_Snap.m_aCharacters[SpectatorID].m_HasExtendedData && g_Config.m_ClDDRaceHud)
|
2022-03-20 13:18:02 +00:00
|
|
|
|
{
|
2022-03-21 22:55:35 +00:00
|
|
|
|
RenderPlayerState(SpectatorID);
|
2022-03-20 13:18:02 +00:00
|
|
|
|
}
|
2022-04-14 11:31:00 +00:00
|
|
|
|
if(SpectatorID != SPEC_FREEVIEW)
|
|
|
|
|
{
|
|
|
|
|
RenderMovementInformation(SpectatorID);
|
|
|
|
|
}
|
2011-03-27 12:40:15 +00:00
|
|
|
|
RenderSpectatorHud();
|
|
|
|
|
}
|
2011-01-06 03:46:10 +00:00
|
|
|
|
|
2020-11-06 08:25:21 +00:00
|
|
|
|
if(g_Config.m_ClShowhudTimer)
|
|
|
|
|
RenderGameTimer();
|
2012-01-10 21:40:48 +00:00
|
|
|
|
RenderPauseNotification();
|
2011-03-27 12:40:15 +00:00
|
|
|
|
RenderSuddenDeath();
|
2018-03-13 20:56:37 +00:00
|
|
|
|
if(g_Config.m_ClShowhudScore)
|
2013-11-02 02:09:56 +00:00
|
|
|
|
RenderScoreHud();
|
2022-04-01 19:48:06 +00:00
|
|
|
|
RenderDummyActions();
|
2011-03-27 12:40:15 +00:00
|
|
|
|
RenderWarmupTimer();
|
2016-05-03 14:06:10 +00:00
|
|
|
|
RenderTextInfo();
|
2020-09-26 19:41:58 +00:00
|
|
|
|
RenderLocalTime((m_Width / 7) * 3);
|
2011-03-27 12:40:15 +00:00
|
|
|
|
if(Client()->State() != IClient::STATE_DEMOPLAYBACK)
|
|
|
|
|
RenderConnectionWarning();
|
|
|
|
|
RenderTeambalanceWarning();
|
|
|
|
|
RenderVoting();
|
2018-03-13 20:56:37 +00:00
|
|
|
|
if(g_Config.m_ClShowRecord)
|
2014-02-06 22:49:25 +00:00
|
|
|
|
RenderRecord();
|
2011-03-27 12:40:15 +00:00
|
|
|
|
}
|
2011-01-06 03:46:10 +00:00
|
|
|
|
RenderCursor();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CHud::OnMessage(int MsgType, void *pRawMsg)
|
|
|
|
|
{
|
2021-01-10 16:41:06 +00:00
|
|
|
|
if(MsgType == NETMSGTYPE_SV_DDRACETIME || MsgType == NETMSGTYPE_SV_DDRACETIMELEGACY)
|
2011-01-06 03:46:10 +00:00
|
|
|
|
{
|
|
|
|
|
m_DDRaceTimeReceived = true;
|
2011-04-09 06:41:31 +00:00
|
|
|
|
|
2011-01-06 03:46:10 +00:00
|
|
|
|
CNetMsg_Sv_DDRaceTime *pMsg = (CNetMsg_Sv_DDRaceTime *)pRawMsg;
|
|
|
|
|
|
|
|
|
|
m_DDRaceTime = pMsg->m_Time;
|
2011-04-09 06:41:31 +00:00
|
|
|
|
|
2020-02-19 10:24:58 +00:00
|
|
|
|
m_LastReceivedTimeTick = Client()->GameTick(g_Config.m_ClDummy);
|
2011-04-09 06:41:31 +00:00
|
|
|
|
|
2022-01-22 16:34:23 +00:00
|
|
|
|
m_FinishTime = pMsg->m_Finish != 0;
|
2011-04-09 06:41:31 +00:00
|
|
|
|
|
2011-01-06 03:46:10 +00:00
|
|
|
|
if(pMsg->m_Check)
|
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
|
m_CheckpointDiff = (float)pMsg->m_Check / 100;
|
2020-02-19 10:24:58 +00:00
|
|
|
|
m_CheckpointTick = Client()->GameTick(g_Config.m_ClDummy);
|
2011-01-06 03:46:10 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2021-01-10 16:41:06 +00:00
|
|
|
|
else if(MsgType == NETMSGTYPE_SV_RECORD || MsgType == NETMSGTYPE_SV_RECORDLEGACY)
|
2016-05-21 23:26:15 +00:00
|
|
|
|
{
|
2016-05-22 10:12:02 +00:00
|
|
|
|
CNetMsg_Sv_Record *pMsg = (CNetMsg_Sv_Record *)pRawMsg;
|
|
|
|
|
|
|
|
|
|
// NETMSGTYPE_SV_RACETIME on old race servers
|
2022-03-21 22:55:35 +00:00
|
|
|
|
if(MsgType == NETMSGTYPE_SV_RECORDLEGACY && m_pClient->m_GameInfo.m_DDRaceRecordMessage)
|
2016-05-21 23:26:15 +00:00
|
|
|
|
{
|
|
|
|
|
m_DDRaceTimeReceived = true;
|
|
|
|
|
|
|
|
|
|
m_DDRaceTime = pMsg->m_ServerTimeBest; // First value: m_Time
|
|
|
|
|
|
2020-02-19 10:24:58 +00:00
|
|
|
|
m_LastReceivedTimeTick = Client()->GameTick(g_Config.m_ClDummy);
|
2016-05-21 23:26:15 +00:00
|
|
|
|
|
|
|
|
|
if(pMsg->m_PlayerTimeBest) // Second value: m_Check
|
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
|
m_CheckpointDiff = (float)pMsg->m_PlayerTimeBest / 100;
|
2020-02-19 10:24:58 +00:00
|
|
|
|
m_CheckpointTick = Client()->GameTick(g_Config.m_ClDummy);
|
2016-05-21 23:26:15 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-03-21 22:55:35 +00:00
|
|
|
|
else if(MsgType == NETMSGTYPE_SV_RECORD || m_pClient->m_GameInfo.m_RaceRecordMessage)
|
2011-01-06 03:46:10 +00:00
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
|
m_ServerRecord = (float)pMsg->m_ServerTimeBest / 100;
|
|
|
|
|
m_PlayerRecord[g_Config.m_ClDummy] = (float)pMsg->m_PlayerTimeBest / 100;
|
2011-01-06 03:46:10 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-11-30 02:24:15 +00:00
|
|
|
|
void CHud::RenderDDRaceEffects()
|
2010-10-30 14:22:35 +00:00
|
|
|
|
{
|
|
|
|
|
// check racestate
|
2020-09-26 19:41:58 +00:00
|
|
|
|
if(m_FinishTime && m_LastReceivedTimeTick + Client()->GameTickSpeed() * 2 < Client()->GameTick(g_Config.m_ClDummy))
|
2010-10-30 14:22:35 +00:00
|
|
|
|
{
|
|
|
|
|
m_FinishTime = false;
|
|
|
|
|
m_DDRaceTimeReceived = false;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2011-04-09 06:41:31 +00:00
|
|
|
|
|
2010-10-30 14:22:35 +00:00
|
|
|
|
if(m_DDRaceTime)
|
|
|
|
|
{
|
|
|
|
|
char aBuf[64];
|
2020-10-18 20:44:02 +00:00
|
|
|
|
char aTime[32];
|
2010-10-30 14:22:35 +00:00
|
|
|
|
if(m_FinishTime)
|
|
|
|
|
{
|
2020-10-18 20:44:02 +00:00
|
|
|
|
str_time(m_DDRaceTime, TIME_HOURS_CENTISECS, aTime, sizeof(aTime));
|
|
|
|
|
str_format(aBuf, sizeof(aBuf), "Finish time: %s", aTime);
|
2020-09-26 19:41:58 +00:00
|
|
|
|
TextRender()->Text(0, 150 * Graphics()->ScreenAspect() - TextRender()->TextWidth(0, 12, aBuf, -1, -1.0f) / 2, 20, 12, aBuf, -1.0f);
|
2010-10-30 14:22:35 +00:00
|
|
|
|
}
|
2020-09-26 19:41:58 +00:00
|
|
|
|
else if(m_CheckpointTick + Client()->GameTickSpeed() * 6 > Client()->GameTick(g_Config.m_ClDummy))
|
2010-10-30 14:22:35 +00:00
|
|
|
|
{
|
|
|
|
|
str_format(aBuf, sizeof(aBuf), "%+5.2f", m_CheckpointDiff);
|
2011-04-09 06:41:31 +00:00
|
|
|
|
|
2010-10-30 14:22:35 +00:00
|
|
|
|
// calculate alpha (4 sec 1 than get lower the next 2 sec)
|
|
|
|
|
float a = 1.0f;
|
2020-09-26 19:41:58 +00:00
|
|
|
|
if(m_CheckpointTick + Client()->GameTickSpeed() * 4 < Client()->GameTick(g_Config.m_ClDummy) && m_CheckpointTick + Client()->GameTickSpeed() * 6 > Client()->GameTick(g_Config.m_ClDummy))
|
2010-10-30 14:22:35 +00:00
|
|
|
|
{
|
|
|
|
|
// lower the alpha slowly to blend text out
|
2020-09-26 19:41:58 +00:00
|
|
|
|
a = ((float)(m_CheckpointTick + Client()->GameTickSpeed() * 6) - (float)Client()->GameTick(g_Config.m_ClDummy)) / (float)(Client()->GameTickSpeed() * 2);
|
2010-10-30 14:22:35 +00:00
|
|
|
|
}
|
2011-04-09 06:41:31 +00:00
|
|
|
|
|
2010-10-30 14:22:35 +00:00
|
|
|
|
if(m_CheckpointDiff > 0)
|
2020-09-26 19:41:58 +00:00
|
|
|
|
TextRender()->TextColor(1.0f, 0.5f, 0.5f, a); // red
|
2010-10-30 14:22:35 +00:00
|
|
|
|
else if(m_CheckpointDiff < 0)
|
2020-09-26 19:41:58 +00:00
|
|
|
|
TextRender()->TextColor(0.5f, 1.0f, 0.5f, a); // green
|
2010-10-30 14:22:35 +00:00
|
|
|
|
else if(!m_CheckpointDiff)
|
2020-09-26 19:41:58 +00:00
|
|
|
|
TextRender()->TextColor(1, 1, 1, a); // white
|
|
|
|
|
TextRender()->Text(0, 150 * Graphics()->ScreenAspect() - TextRender()->TextWidth(0, 10, aBuf, -1, -1.0f) / 2, 20, 10, aBuf, -1.0f);
|
2011-04-09 06:41:31 +00:00
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
|
TextRender()->TextColor(1, 1, 1, 1);
|
2010-10-30 14:22:35 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-02-06 22:49:25 +00:00
|
|
|
|
|
|
|
|
|
void CHud::RenderRecord()
|
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
|
if(m_ServerRecord > 0)
|
2014-02-06 22:49:25 +00:00
|
|
|
|
{
|
|
|
|
|
char aBuf[64];
|
2020-03-01 11:54:59 +00:00
|
|
|
|
str_format(aBuf, sizeof(aBuf), Localize("Server best:"));
|
2020-07-15 19:42:48 +00:00
|
|
|
|
TextRender()->Text(0, 5, 40, 6, aBuf, -1.0f);
|
2020-10-18 20:44:02 +00:00
|
|
|
|
char aTime[32];
|
|
|
|
|
str_time_float(m_ServerRecord, TIME_HOURS_CENTISECS, aTime, sizeof(aTime));
|
|
|
|
|
str_format(aBuf, sizeof(aBuf), "%s%s", m_ServerRecord > 3600 ? "" : " ", aTime);
|
2020-07-15 19:42:48 +00:00
|
|
|
|
TextRender()->Text(0, 53, 40, 6, aBuf, -1.0f);
|
2014-02-06 22:49:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-01 11:54:59 +00:00
|
|
|
|
const float PlayerRecord = m_PlayerRecord[g_Config.m_ClDummy];
|
2020-09-26 19:41:58 +00:00
|
|
|
|
if(PlayerRecord > 0)
|
2014-02-06 22:49:25 +00:00
|
|
|
|
{
|
|
|
|
|
char aBuf[64];
|
2020-03-01 11:54:59 +00:00
|
|
|
|
str_format(aBuf, sizeof(aBuf), Localize("Personal best:"));
|
2020-07-15 19:42:48 +00:00
|
|
|
|
TextRender()->Text(0, 5, 47, 6, aBuf, -1.0f);
|
2020-10-18 20:44:02 +00:00
|
|
|
|
char aTime[32];
|
|
|
|
|
str_time_float(PlayerRecord, TIME_HOURS_CENTISECS, aTime, sizeof(aTime));
|
|
|
|
|
str_format(aBuf, sizeof(aBuf), "%s%s", PlayerRecord > 3600 ? "" : " ", aTime);
|
2020-07-15 19:42:48 +00:00
|
|
|
|
TextRender()->Text(0, 53, 47, 6, aBuf, -1.0f);
|
2014-02-06 22:49:25 +00:00
|
|
|
|
}
|
|
|
|
|
}
|