made client scoreboard and hud survival ready

This commit is contained in:
oy 2012-02-15 01:40:04 +01:00
parent 495dc849ba
commit 7e78740478
7 changed files with 131 additions and 81 deletions

View file

@ -235,6 +235,7 @@ image_guiicons = Image("guiicons", "gui_icons.png")
container.images.Add(image_null)
container.images.Add(image_game)
container.images.Add(Image("deadtee", "deadtee.png"))
container.images.Add(image_particles)
container.images.Add(Image("cursor", "gui_cursor.png"))
container.images.Add(Image("banner", "gui_logo.png"))

View file

@ -3,7 +3,7 @@ from datatypes import *
Emotes = ["NORMAL", "PAIN", "HAPPY", "SURPRISE", "ANGRY", "BLINK"]
PlayerFlags = ["PLAYING", "IN_MENU", "CHATTING", "SCOREBOARD", "READY", "DEAD"]
GameFlags = ["TEAMS", "FLAGS", "SURVIVAL"]
GameStateFlags = ["WARMUP", "SUDDENDEATH", "GAMEOVER", "PAUSED", "STARTCOUNTDOWN"]
GameStateFlags = ["WARMUP", "SUDDENDEATH", "ROUNDOVER", "GAMEOVER", "PAUSED", "STARTCOUNTDOWN"]
Emoticons = ["OOP", "EXCLAMATION", "HEARTS", "DROP", "DOTDOT", "MUSIC", "SORRY", "GHOST", "SUSHI", "SPLATTEE", "DEVILTEE", "ZOMG", "ZZZ", "WTF", "EYES", "QUESTION"]

View file

@ -39,10 +39,10 @@ void CHud::RenderGameTimer()
{
Time = m_pClient->m_Snap.m_pGameInfoObj->m_TimeLimit*60 - ((Client()->GameTick()-m_pClient->m_Snap.m_pGameInfoObj->m_GameStartTick)/Client()->GameTickSpeed());
if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER)
if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&(GAMESTATEFLAG_ROUNDOVER|GAMESTATEFLAG_GAMEOVER))
Time = 0;
}
else if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER)
else if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&(GAMESTATEFLAG_ROUNDOVER|GAMESTATEFLAG_GAMEOVER))
Time = m_pClient->m_Snap.m_pGameInfoObj->m_GameStateTimer/Client()->GameTickSpeed();
else
Time = (Client()->GameTick()-m_pClient->m_Snap.m_pGameInfoObj->m_GameStartTick)/Client()->GameTickSpeed();
@ -137,7 +137,7 @@ void CHud::RenderSuddenDeath()
void CHud::RenderScoreHud()
{
// render small score hud
if(!(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER))
if(!(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&(GAMESTATEFLAG_ROUNDOVER|GAMESTATEFLAG_GAMEOVER)))
{
int GameFlags = m_pClient->m_Snap.m_pGameInfoObj->m_GameFlags;
float Whole = 300*Graphics()->ScreenAspect();
@ -200,6 +200,22 @@ void CHud::RenderScoreHud()
vec2(Whole-ScoreWidthMax-Info.m_Size/2-Split, StartY+1.0f+Info.m_Size/2+t*20));
}
}
if(GameFlags&GAMEFLAG_SURVIVAL)
{
// draw number of alive players
int Count = 0;
for(int i = 0; i < MAX_CLIENTS; ++i)
{
if(m_pClient->m_Snap.m_paPlayerInfos[i] && !(m_pClient->m_Snap.m_paPlayerInfos[i]->m_PlayerFlags&PLAYERFLAG_DEAD) &&
m_pClient->m_Snap.m_paPlayerInfos[i]->m_Team == t)
++Count;
}
char aBuf[32];
str_format(aBuf, sizeof(aBuf), Count==1?Localize("%d player left"):Localize("%d players left"), Count);
float w = TextRender()->TextWidth(0, 8.0f, aBuf, -1);
TextRender()->Text(0, min(Whole-w-1.0f, Whole-ScoreWidthMax-ImageSize-2*Split), StartY+(t+1)*20.0f-3.0f, 8.0f, aBuf, -1);
}
StartY += 8.0f;
}
}
@ -523,7 +539,7 @@ void CHud::OnRender()
if(g_Config.m_ClShowhud)
{
if(m_pClient->m_Snap.m_pLocalCharacter && !(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER))
if(m_pClient->m_Snap.m_pLocalCharacter && !(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&(GAMESTATEFLAG_ROUNDOVER|GAMESTATEFLAG_GAMEOVER)))
RenderHealthAndAmmo(m_pClient->m_Snap.m_pLocalCharacter);
else if(m_pClient->m_Snap.m_SpecInfo.m_Active)
{

View file

@ -107,7 +107,7 @@ void CPlayers::RenderHook(
if(pInfo.m_Local && g_Config.m_ClPredict && Client()->State() != IClient::STATE_DEMOPLAYBACK)
{
if(!m_pClient->m_Snap.m_pLocalCharacter ||
(m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&(GAMESTATEFLAG_PAUSED|GAMESTATEFLAG_GAMEOVER)))
(m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&(GAMESTATEFLAG_PAUSED|GAMESTATEFLAG_ROUNDOVER|GAMESTATEFLAG_GAMEOVER)))
{
}
else
@ -241,7 +241,7 @@ void CPlayers::RenderPlayer(
if(pInfo.m_Local && g_Config.m_ClPredict && Client()->State() != IClient::STATE_DEMOPLAYBACK)
{
if(!m_pClient->m_Snap.m_pLocalCharacter ||
(m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&(GAMESTATEFLAG_PAUSED|GAMESTATEFLAG_GAMEOVER)))
(m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&(GAMESTATEFLAG_PAUSED|GAMESTATEFLAG_ROUNDOVER|GAMESTATEFLAG_GAMEOVER)))
{
}
else

View file

@ -140,6 +140,8 @@ void CScoreboard::RenderScoreboard(float x, float y, float w, int Team, const ch
{
if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER)
pTitle = Localize("Game over");
else if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_ROUNDOVER)
pTitle = Localize("Round over");
else
pTitle = Localize("Score board");
}
@ -215,81 +217,99 @@ void CScoreboard::RenderScoreboard(float x, float y, float w, int Team, const ch
float FontSize = 24.0f;
CTextCursor Cursor;
for(int i = 0; i < MAX_CLIENTS; i++)
for(int RenderDead = 0; RenderDead < 2; ++RenderDead)
{
// make sure that we render the correct team
const CNetObj_PlayerInfo *pInfo = m_pClient->m_Snap.m_paInfoByScore[i];
if(!pInfo || pInfo->m_Team != Team)
continue;
// background so it's easy to find the local player or the followed one in spectator mode
if(pInfo->m_Local || (m_pClient->m_Snap.m_SpecInfo.m_Active && pInfo->m_ClientID == m_pClient->m_Snap.m_SpecInfo.m_SpectatorID))
float ColorAlpha = RenderDead ? 0.5f : 1.0f;
TextRender()->TextColor(1.0f, 1.0f, 1.0f, ColorAlpha);
for(int i = 0; i < MAX_CLIENTS; i++)
{
Graphics()->TextureSet(-1);
Graphics()->QuadsBegin();
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.25f);
RenderTools()->DrawRoundRect(x, y, w-20.0f, LineHeight, 15.0f);
Graphics()->QuadsEnd();
// make sure that we render the correct team
const CNetObj_PlayerInfo *pInfo = m_pClient->m_Snap.m_paInfoByScore[i];
if(!pInfo || pInfo->m_Team != Team || (!RenderDead && (pInfo->m_PlayerFlags&PLAYERFLAG_DEAD)) || (RenderDead && !(pInfo->m_PlayerFlags&PLAYERFLAG_DEAD)))
continue;
// background so it's easy to find the local player or the followed one in spectator mode
if(pInfo->m_Local || (m_pClient->m_Snap.m_SpecInfo.m_Active && pInfo->m_ClientID == m_pClient->m_Snap.m_SpecInfo.m_SpectatorID))
{
Graphics()->TextureSet(-1);
Graphics()->QuadsBegin();
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.25f);
RenderTools()->DrawRoundRect(x, y, w-20.0f, LineHeight, 15.0f);
Graphics()->QuadsEnd();
}
// score
str_format(aBuf, sizeof(aBuf), "%d", clamp(pInfo->m_Score, -999, 999));
tw = TextRender()->TextWidth(0, FontSize, aBuf, -1);
TextRender()->SetCursor(&Cursor, ScoreOffset+ScoreLength-tw, y+Spacing, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END);
Cursor.m_LineWidth = ScoreLength;
TextRender()->TextEx(&Cursor, aBuf, -1);
// flag
if(m_pClient->m_Snap.m_pGameInfoObj->m_GameFlags&GAMEFLAG_FLAGS &&
m_pClient->m_Snap.m_pGameDataObj && (m_pClient->m_Snap.m_pGameDataObj->m_FlagCarrierRed == pInfo->m_ClientID ||
m_pClient->m_Snap.m_pGameDataObj->m_FlagCarrierBlue == pInfo->m_ClientID))
{
Graphics()->BlendNormal();
Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GAME].m_Id);
Graphics()->QuadsBegin();
RenderTools()->SelectSprite(pInfo->m_Team==TEAM_RED ? SPRITE_FLAG_BLUE : SPRITE_FLAG_RED, SPRITE_FLAG_FLIP_X);
float Size = LineHeight;
IGraphics::CQuadItem QuadItem(TeeOffset+0.0f, y-5.0f-Spacing/2.0f, Size/2.0f, Size);
Graphics()->QuadsDrawTL(&QuadItem, 1);
Graphics()->QuadsEnd();
}
// avatar
if(RenderDead)
{
Graphics()->BlendNormal();
Graphics()->TextureSet(g_pData->m_aImages[IMAGE_DEADTEE].m_Id);
Graphics()->QuadsBegin();
IGraphics::CQuadItem QuadItem(TeeOffset, y, 64*TeeSizeMod, 64*TeeSizeMod);
Graphics()->QuadsDrawTL(&QuadItem, 1);
Graphics()->QuadsEnd();
}
else
{
CTeeRenderInfo TeeInfo = m_pClient->m_aClients[pInfo->m_ClientID].m_RenderInfo;
TeeInfo.m_Size *= TeeSizeMod;
RenderTools()->RenderTee(CAnimState::GetIdle(), &TeeInfo, EMOTE_NORMAL, vec2(1.0f, 0.0f), vec2(TeeOffset+TeeLength/2, y+LineHeight/2));
}
// name
// todo: improve visual player ready state
if(!(pInfo->m_PlayerFlags&PLAYERFLAG_READY))
TextRender()->TextColor(1.0f, 0.5f, 0.5f,ColorAlpha);
TextRender()->SetCursor(&Cursor, NameOffset, y+Spacing, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END);
Cursor.m_LineWidth = NameLength;
TextRender()->TextEx(&Cursor, m_pClient->m_aClients[pInfo->m_ClientID].m_aName, -1);
TextRender()->TextColor(1.0f, 1.0f, 1.0f, ColorAlpha);
// clan
tw = TextRender()->TextWidth(0, FontSize, m_pClient->m_aClients[pInfo->m_ClientID].m_aClan, -1);
TextRender()->SetCursor(&Cursor, ClanOffset+ClanLength/2-tw/2, y+Spacing, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END);
Cursor.m_LineWidth = ClanLength;
TextRender()->TextEx(&Cursor, m_pClient->m_aClients[pInfo->m_ClientID].m_aClan, -1);
// country flag
vec4 Color(1.0f, 1.0f, 1.0f, 0.5f*ColorAlpha);
m_pClient->m_pCountryFlags->Render(m_pClient->m_aClients[pInfo->m_ClientID].m_Country, &Color,
CountryOffset, y+(Spacing+TeeSizeMod*5.0f)/2.0f, CountryLength, LineHeight-Spacing-TeeSizeMod*5.0f);
// ping
str_format(aBuf, sizeof(aBuf), "%d", clamp(pInfo->m_Latency, 0, 1000));
tw = TextRender()->TextWidth(0, FontSize, aBuf, -1);
TextRender()->SetCursor(&Cursor, PingOffset+PingLength-tw, y+Spacing, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END);
Cursor.m_LineWidth = PingLength;
TextRender()->TextEx(&Cursor, aBuf, -1);
y += LineHeight+Spacing;
}
// score
str_format(aBuf, sizeof(aBuf), "%d", clamp(pInfo->m_Score, -999, 999));
tw = TextRender()->TextWidth(0, FontSize, aBuf, -1);
TextRender()->SetCursor(&Cursor, ScoreOffset+ScoreLength-tw, y+Spacing, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END);
Cursor.m_LineWidth = ScoreLength;
TextRender()->TextEx(&Cursor, aBuf, -1);
// flag
if(m_pClient->m_Snap.m_pGameInfoObj->m_GameFlags&GAMEFLAG_FLAGS &&
m_pClient->m_Snap.m_pGameDataObj && (m_pClient->m_Snap.m_pGameDataObj->m_FlagCarrierRed == pInfo->m_ClientID ||
m_pClient->m_Snap.m_pGameDataObj->m_FlagCarrierBlue == pInfo->m_ClientID))
{
Graphics()->BlendNormal();
Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GAME].m_Id);
Graphics()->QuadsBegin();
RenderTools()->SelectSprite(pInfo->m_Team==TEAM_RED ? SPRITE_FLAG_BLUE : SPRITE_FLAG_RED, SPRITE_FLAG_FLIP_X);
float Size = LineHeight;
IGraphics::CQuadItem QuadItem(TeeOffset+0.0f, y-5.0f-Spacing/2.0f, Size/2.0f, Size);
Graphics()->QuadsDrawTL(&QuadItem, 1);
Graphics()->QuadsEnd();
}
// avatar
CTeeRenderInfo TeeInfo = m_pClient->m_aClients[pInfo->m_ClientID].m_RenderInfo;
TeeInfo.m_Size *= TeeSizeMod;
RenderTools()->RenderTee(CAnimState::GetIdle(), &TeeInfo, EMOTE_NORMAL, vec2(1.0f, 0.0f), vec2(TeeOffset+TeeLength/2, y+LineHeight/2));
// name
// todo: improve visual player ready state
if(!(pInfo->m_PlayerFlags&PLAYERFLAG_READY))
TextRender()->TextColor(1.0f, 0.5f, 0.5f, 1.0f);
TextRender()->SetCursor(&Cursor, NameOffset, y+Spacing, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END);
Cursor.m_LineWidth = NameLength;
TextRender()->TextEx(&Cursor, m_pClient->m_aClients[pInfo->m_ClientID].m_aName, -1);
TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f);
// clan
tw = TextRender()->TextWidth(0, FontSize, m_pClient->m_aClients[pInfo->m_ClientID].m_aClan, -1);
TextRender()->SetCursor(&Cursor, ClanOffset+ClanLength/2-tw/2, y+Spacing, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END);
Cursor.m_LineWidth = ClanLength;
TextRender()->TextEx(&Cursor, m_pClient->m_aClients[pInfo->m_ClientID].m_aClan, -1);
// country flag
vec4 Color(1.0f, 1.0f, 1.0f, 0.5f);
m_pClient->m_pCountryFlags->Render(m_pClient->m_aClients[pInfo->m_ClientID].m_Country, &Color,
CountryOffset, y+(Spacing+TeeSizeMod*5.0f)/2.0f, CountryLength, LineHeight-Spacing-TeeSizeMod*5.0f);
// ping
str_format(aBuf, sizeof(aBuf), "%d", clamp(pInfo->m_Latency, 0, 1000));
tw = TextRender()->TextWidth(0, FontSize, aBuf, -1);
TextRender()->SetCursor(&Cursor, PingOffset+PingLength-tw, y+Spacing, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END);
Cursor.m_LineWidth = PingLength;
TextRender()->TextEx(&Cursor, aBuf, -1);
y += LineHeight+Spacing;
}
TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f);
}
void CScoreboard::RenderRecordingNotification(float x)
@ -344,7 +364,7 @@ void CScoreboard::OnRender()
const char *pRedClanName = GetClanName(TEAM_RED);
const char *pBlueClanName = GetClanName(TEAM_BLUE);
if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER && m_pClient->m_Snap.m_pGameDataObj)
if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER)
{
char aText[256];
str_copy(aText, Localize("Draw!"), sizeof(aText));
@ -367,6 +387,14 @@ void CScoreboard::OnRender()
float w = TextRender()->TextWidth(0, 86.0f, aText, -1);
TextRender()->Text(0, Width/2-w/2, 39, 86.0f, aText, -1);
}
else if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_ROUNDOVER)
{
char aText[256];
str_copy(aText, Localize("Round over!"), sizeof(aText));
float w = TextRender()->TextWidth(0, 86.0f, aText, -1);
TextRender()->Text(0, Width/2-w/2, 39, 86.0f, aText, -1);
}
RenderScoreboard(Width/2-w-5.0f, 150.0f, w, TEAM_RED, pRedClanName ? pRedClanName : Localize("Red team"));
RenderScoreboard(Width/2+5.0f, 150.0f, w, TEAM_BLUE, pBlueClanName ? pBlueClanName : Localize("Blue team"));
@ -392,7 +420,7 @@ bool CScoreboard::Active()
}
// if the game is over
if(m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER)
if(m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&(GAMESTATEFLAG_ROUNDOVER|GAMESTATEFLAG_GAMEOVER))
return true;
return false;

View file

@ -359,7 +359,8 @@ void CGameClient::UpdatePositions()
// local character position
if(g_Config.m_ClPredict && Client()->State() != IClient::STATE_DEMOPLAYBACK)
{
if(!m_Snap.m_pLocalCharacter || (m_Snap.m_pGameInfoObj && m_Snap.m_pGameInfoObj->m_GameStateFlags&(GAMESTATEFLAG_PAUSED|GAMESTATEFLAG_GAMEOVER)))
if(!m_Snap.m_pLocalCharacter ||
(m_Snap.m_pGameInfoObj && m_Snap.m_pGameInfoObj->m_GameStateFlags&(GAMESTATEFLAG_PAUSED|GAMESTATEFLAG_ROUNDOVER|GAMESTATEFLAG_GAMEOVER)))
{
// don't use predicted
}

View file

@ -570,6 +570,10 @@ void IGameController::Snap(int SnappingClient)
pGameInfoObj->m_GameStateFlags |= GAMESTATEFLAG_PAUSED;
pGameInfoObj->m_GameStateTimer = m_GameStateTimer;
break;
case GS_ROUNDOVER:
pGameInfoObj->m_GameStateFlags |= GAMESTATEFLAG_ROUNDOVER;
pGameInfoObj->m_GameStateTimer = Server()->Tick()-m_GameStartTick-10*Server()->TickSpeed()+m_GameStateTimer;
break;
case GS_GAMEOVER:
pGameInfoObj->m_GameStateFlags |= GAMESTATEFLAG_GAMEOVER;
pGameInfoObj->m_GameStateTimer = Server()->Tick()-m_GameStartTick-10*Server()->TickSpeed()+m_GameStateTimer;