2011-03-10 09:08: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. */
|
2011-03-12 17:07:57 +00:00
|
|
|
#include <engine/demo.h>
|
2011-03-10 09:08:14 +00:00
|
|
|
#include <engine/graphics.h>
|
|
|
|
#include <engine/textrender.h>
|
|
|
|
#include <engine/shared/config.h>
|
|
|
|
|
|
|
|
#include <game/generated/client_data.h>
|
|
|
|
#include <game/generated/protocol.h>
|
|
|
|
|
|
|
|
#include <game/client/animstate.h>
|
|
|
|
#include <game/client/render.h>
|
|
|
|
|
|
|
|
#include "spectator.h"
|
|
|
|
|
|
|
|
|
|
|
|
void CSpectator::ConKeySpectator(IConsole::IResult *pResult, void *pUserData)
|
|
|
|
{
|
|
|
|
CSpectator *pSelf = (CSpectator *)pUserData;
|
2011-03-12 17:07:57 +00:00
|
|
|
if(pSelf->m_pClient->m_Snap.m_SpecInfo.m_Active &&
|
|
|
|
(pSelf->Client()->State() != IClient::STATE_DEMOPLAYBACK || pSelf->DemoPlayer()->GetDemoType() == IDemoPlayer::DEMOTYPE_SERVER))
|
2011-03-10 09:08:14 +00:00
|
|
|
pSelf->m_Active = pResult->GetInteger(0) != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CSpectator::ConSpectate(IConsole::IResult *pResult, void *pUserData)
|
|
|
|
{
|
|
|
|
((CSpectator *)pUserData)->Spectate(pResult->GetInteger(0));
|
|
|
|
}
|
|
|
|
|
2011-04-03 23:27:23 +00:00
|
|
|
void CSpectator::ConSpectateNext(IConsole::IResult *pResult, void *pUserData)
|
|
|
|
{
|
|
|
|
CSpectator *pSelf = (CSpectator *)pUserData;
|
2011-04-04 08:42:36 +00:00
|
|
|
int NewSpectatorID;
|
|
|
|
bool GotNewSpectatorID = false;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2011-04-03 23:27:23 +00:00
|
|
|
if(pSelf->m_pClient->m_Snap.m_SpecInfo.m_SpectatorID == SPEC_FREEVIEW)
|
|
|
|
{
|
|
|
|
for(int i = 0; i < MAX_CLIENTS; i++)
|
|
|
|
{
|
|
|
|
if(!pSelf->m_pClient->m_Snap.m_paPlayerInfos[i] || pSelf->m_pClient->m_Snap.m_paPlayerInfos[i]->m_Team == TEAM_SPECTATORS)
|
|
|
|
continue;
|
|
|
|
|
2011-04-04 08:42:36 +00:00
|
|
|
NewSpectatorID = i;
|
|
|
|
GotNewSpectatorID = true;
|
2011-04-03 23:27:23 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for(int i = pSelf->m_pClient->m_Snap.m_SpecInfo.m_SpectatorID + 1; i < MAX_CLIENTS; i++)
|
|
|
|
{
|
|
|
|
if(!pSelf->m_pClient->m_Snap.m_paPlayerInfos[i] || pSelf->m_pClient->m_Snap.m_paPlayerInfos[i]->m_Team == TEAM_SPECTATORS)
|
|
|
|
continue;
|
|
|
|
|
2011-04-04 08:42:36 +00:00
|
|
|
NewSpectatorID = i;
|
|
|
|
GotNewSpectatorID = true;
|
2011-04-03 23:27:23 +00:00
|
|
|
break;
|
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2011-04-04 08:42:36 +00:00
|
|
|
if(!GotNewSpectatorID)
|
2011-04-03 23:27:23 +00:00
|
|
|
{
|
|
|
|
for(int i = 0; i < pSelf->m_pClient->m_Snap.m_SpecInfo.m_SpectatorID; i++)
|
|
|
|
{
|
|
|
|
if(!pSelf->m_pClient->m_Snap.m_paPlayerInfos[i] || pSelf->m_pClient->m_Snap.m_paPlayerInfos[i]->m_Team == TEAM_SPECTATORS)
|
|
|
|
continue;
|
|
|
|
|
2011-04-19 14:10:50 +00:00
|
|
|
NewSpectatorID = i;
|
|
|
|
GotNewSpectatorID = true;
|
2011-04-03 23:27:23 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-04-04 08:42:36 +00:00
|
|
|
if(GotNewSpectatorID)
|
|
|
|
pSelf->Spectate(NewSpectatorID);
|
2011-04-03 23:27:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CSpectator::ConSpectatePrevious(IConsole::IResult *pResult, void *pUserData)
|
|
|
|
{
|
|
|
|
CSpectator *pSelf = (CSpectator *)pUserData;
|
2011-04-04 08:42:36 +00:00
|
|
|
int NewSpectatorID;
|
|
|
|
bool GotNewSpectatorID = false;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2011-04-03 23:27:23 +00:00
|
|
|
if(pSelf->m_pClient->m_Snap.m_SpecInfo.m_SpectatorID == SPEC_FREEVIEW)
|
|
|
|
{
|
|
|
|
for(int i = MAX_CLIENTS -1; i > -1; i--)
|
|
|
|
{
|
|
|
|
if(!pSelf->m_pClient->m_Snap.m_paPlayerInfos[i] || pSelf->m_pClient->m_Snap.m_paPlayerInfos[i]->m_Team == TEAM_SPECTATORS)
|
|
|
|
continue;
|
|
|
|
|
2011-04-04 08:42:36 +00:00
|
|
|
NewSpectatorID = i;
|
|
|
|
GotNewSpectatorID = true;
|
2011-04-03 23:27:23 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for(int i = pSelf->m_pClient->m_Snap.m_SpecInfo.m_SpectatorID - 1; i > -1; i--)
|
|
|
|
{
|
|
|
|
if(!pSelf->m_pClient->m_Snap.m_paPlayerInfos[i] || pSelf->m_pClient->m_Snap.m_paPlayerInfos[i]->m_Team == TEAM_SPECTATORS)
|
|
|
|
continue;
|
|
|
|
|
2011-04-04 08:42:36 +00:00
|
|
|
NewSpectatorID = i;
|
|
|
|
GotNewSpectatorID = true;
|
2011-04-03 23:27:23 +00:00
|
|
|
break;
|
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2011-04-04 08:42:36 +00:00
|
|
|
if(!GotNewSpectatorID)
|
2011-04-03 23:27:23 +00:00
|
|
|
{
|
|
|
|
for(int i = MAX_CLIENTS - 1; i > pSelf->m_pClient->m_Snap.m_SpecInfo.m_SpectatorID; i--)
|
|
|
|
{
|
|
|
|
if(!pSelf->m_pClient->m_Snap.m_paPlayerInfos[i] || pSelf->m_pClient->m_Snap.m_paPlayerInfos[i]->m_Team == TEAM_SPECTATORS)
|
|
|
|
continue;
|
|
|
|
|
2011-04-04 08:42:36 +00:00
|
|
|
NewSpectatorID = i;
|
|
|
|
GotNewSpectatorID = true;
|
2011-04-03 23:27:23 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-04-04 08:42:36 +00:00
|
|
|
if(GotNewSpectatorID)
|
|
|
|
pSelf->Spectate(NewSpectatorID);
|
2011-04-03 23:27:23 +00:00
|
|
|
}
|
|
|
|
|
2011-03-10 09:08:14 +00:00
|
|
|
CSpectator::CSpectator()
|
|
|
|
{
|
|
|
|
OnReset();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CSpectator::OnConsoleInit()
|
|
|
|
{
|
|
|
|
Console()->Register("+spectate", "", CFGFLAG_CLIENT, ConKeySpectator, this, "Open spectator mode selector");
|
|
|
|
Console()->Register("spectate", "i", CFGFLAG_CLIENT, ConSpectate, this, "Switch spectator mode");
|
2011-04-03 23:27:23 +00:00
|
|
|
Console()->Register("spectate_next", "", CFGFLAG_CLIENT, ConSpectateNext, this, "Spectate the next player");
|
|
|
|
Console()->Register("spectate_previous", "", CFGFLAG_CLIENT, ConSpectatePrevious, this, "Spectate the previous player");
|
2011-03-10 09:08:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool CSpectator::OnMouseMove(float x, float y)
|
|
|
|
{
|
|
|
|
if(!m_Active)
|
|
|
|
return false;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2011-03-10 09:08:14 +00:00
|
|
|
m_SelectorMouse += vec2(x,y);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CSpectator::OnRelease()
|
|
|
|
{
|
|
|
|
OnReset();
|
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2011-03-10 09:08:14 +00:00
|
|
|
void CSpectator::OnRender()
|
|
|
|
{
|
|
|
|
if(!m_Active)
|
|
|
|
{
|
|
|
|
if(m_WasActive)
|
|
|
|
{
|
|
|
|
if(m_SelectedSpectatorID != NO_SELECTION)
|
|
|
|
Spectate(m_SelectedSpectatorID);
|
2011-03-12 17:07:57 +00:00
|
|
|
m_WasActive = false;
|
2011-03-10 09:08:14 +00:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2011-03-10 09:08:14 +00:00
|
|
|
m_WasActive = true;
|
|
|
|
m_SelectedSpectatorID = NO_SELECTION;
|
|
|
|
|
|
|
|
// draw background
|
|
|
|
float Width = 400*3.0f*Graphics()->ScreenAspect();
|
|
|
|
float Height = 400*3.0f;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2011-03-10 09:08:14 +00:00
|
|
|
Graphics()->MapScreen(0, 0, Width, Height);
|
|
|
|
|
|
|
|
Graphics()->BlendNormal();
|
|
|
|
Graphics()->TextureSet(-1);
|
|
|
|
Graphics()->QuadsBegin();
|
|
|
|
Graphics()->SetColor(0.0f, 0.0f, 0.0f, 0.3f);
|
|
|
|
RenderTools()->DrawRoundRect(Width/2.0f-300.0f, Height/2.0f-300.0f, 600.0f, 600.0f, 20.0f);
|
|
|
|
Graphics()->QuadsEnd();
|
|
|
|
|
|
|
|
// clamp mouse position to selector area
|
|
|
|
m_SelectorMouse.x = clamp(m_SelectorMouse.x, -280.0f, 280.0f);
|
|
|
|
m_SelectorMouse.y = clamp(m_SelectorMouse.y, -280.0f, 280.0f);
|
|
|
|
|
|
|
|
// draw selections
|
|
|
|
float FontSize = 20.0f;
|
|
|
|
float StartY = -190.0f;
|
|
|
|
float LineHeight = 60.0f;
|
2011-04-13 18:37:12 +00:00
|
|
|
bool Selected = false;
|
2011-03-10 09:08:14 +00:00
|
|
|
|
2011-03-12 17:07:57 +00:00
|
|
|
if(m_pClient->m_Snap.m_SpecInfo.m_SpectatorID == SPEC_FREEVIEW)
|
2011-03-10 09:08:14 +00:00
|
|
|
{
|
|
|
|
Graphics()->TextureSet(-1);
|
|
|
|
Graphics()->QuadsBegin();
|
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.25f);
|
|
|
|
RenderTools()->DrawRoundRect(Width/2.0f-280.0f, Height/2.0f-280.0f, 270.0f, 60.0f, 20.0f);
|
|
|
|
Graphics()->QuadsEnd();
|
|
|
|
}
|
|
|
|
|
|
|
|
if(m_SelectorMouse.x >= -280.0f && m_SelectorMouse.x <= -10.0f &&
|
|
|
|
m_SelectorMouse.y >= -280.0f && m_SelectorMouse.y <= -220.0f)
|
|
|
|
{
|
|
|
|
m_SelectedSpectatorID = SPEC_FREEVIEW;
|
|
|
|
Selected = true;
|
|
|
|
}
|
|
|
|
TextRender()->TextColor(1.0f, 1.0f, 1.0f, Selected?1.0f:0.5f);
|
|
|
|
TextRender()->Text(0, Width/2.0f-240.0f, Height/2.0f-265.0f, FontSize, Localize("Free-View"), -1);
|
|
|
|
|
|
|
|
float x = -270.0f, y = StartY;
|
|
|
|
for(int i = 0, Count = 0; i < MAX_CLIENTS; ++i)
|
|
|
|
{
|
|
|
|
if(!m_pClient->m_Snap.m_paPlayerInfos[i] || m_pClient->m_Snap.m_paPlayerInfos[i]->m_Team == TEAM_SPECTATORS)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if(++Count%9 == 0)
|
|
|
|
{
|
|
|
|
x += 290.0f;
|
|
|
|
y = StartY;
|
|
|
|
}
|
|
|
|
|
2011-03-12 17:07:57 +00:00
|
|
|
if(m_pClient->m_Snap.m_SpecInfo.m_SpectatorID == i)
|
2011-03-10 09:08:14 +00:00
|
|
|
{
|
|
|
|
Graphics()->TextureSet(-1);
|
|
|
|
Graphics()->QuadsBegin();
|
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.25f);
|
|
|
|
RenderTools()->DrawRoundRect(Width/2.0f+x-10.0f, Height/2.0f+y-10.0f, 270.0f, 60.0f, 20.0f);
|
|
|
|
Graphics()->QuadsEnd();
|
|
|
|
}
|
|
|
|
|
|
|
|
Selected = false;
|
|
|
|
if(m_SelectorMouse.x >= x-10.0f && m_SelectorMouse.x <= x+260.0f &&
|
|
|
|
m_SelectorMouse.y >= y-10.0f && m_SelectorMouse.y <= y+50.0f)
|
|
|
|
{
|
|
|
|
m_SelectedSpectatorID = i;
|
|
|
|
Selected = true;
|
|
|
|
}
|
|
|
|
TextRender()->TextColor(1.0f, 1.0f, 1.0f, Selected?1.0f:0.5f);
|
|
|
|
TextRender()->Text(0, Width/2.0f+x+50.0f, Height/2.0f+y+5.0f, FontSize, m_pClient->m_aClients[i].m_aName, 220.0f);
|
|
|
|
|
2011-05-05 00:00:43 +00:00
|
|
|
// 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 == m_pClient->m_Snap.m_paPlayerInfos[i]->m_ClientID ||
|
|
|
|
m_pClient->m_Snap.m_pGameDataObj->m_FlagCarrierBlue == m_pClient->m_Snap.m_paPlayerInfos[i]->m_ClientID))
|
|
|
|
{
|
|
|
|
Graphics()->BlendNormal();
|
|
|
|
Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GAME].m_Id);
|
|
|
|
Graphics()->QuadsBegin();
|
|
|
|
|
|
|
|
RenderTools()->SelectSprite(m_pClient->m_Snap.m_paPlayerInfos[i]->m_Team==TEAM_RED ? SPRITE_FLAG_BLUE : SPRITE_FLAG_RED, SPRITE_FLAG_FLIP_X);
|
|
|
|
|
|
|
|
float Size = LineHeight;
|
|
|
|
IGraphics::CQuadItem QuadItem(Width/2.0f+x-LineHeight/5.0f, Height/2.0f+y-LineHeight/3.0f, Size/2.0f, Size);
|
|
|
|
Graphics()->QuadsDrawTL(&QuadItem, 1);
|
|
|
|
Graphics()->QuadsEnd();
|
|
|
|
}
|
|
|
|
|
2011-03-10 09:08:14 +00:00
|
|
|
CTeeRenderInfo TeeInfo = m_pClient->m_aClients[i].m_RenderInfo;
|
|
|
|
RenderTools()->RenderTee(CAnimState::GetIdle(), &TeeInfo, EMOTE_NORMAL, vec2(1.0f, 0.0f), vec2(Width/2.0f+x+20.0f, Height/2.0f+y+20.0f));
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2011-03-10 09:08:14 +00:00
|
|
|
y += LineHeight;
|
|
|
|
}
|
2011-03-18 17:03:50 +00:00
|
|
|
TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f);
|
2011-03-10 09:08:14 +00:00
|
|
|
|
|
|
|
// draw cursor
|
|
|
|
Graphics()->TextureSet(g_pData->m_aImages[IMAGE_CURSOR].m_Id);
|
|
|
|
Graphics()->QuadsBegin();
|
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
|
|
|
|
IGraphics::CQuadItem QuadItem(m_SelectorMouse.x+Width/2.0f, m_SelectorMouse.y+Height/2.0f, 48.0f, 48.0f);
|
|
|
|
Graphics()->QuadsDrawTL(&QuadItem, 1);
|
|
|
|
Graphics()->QuadsEnd();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CSpectator::OnReset()
|
|
|
|
{
|
|
|
|
m_WasActive = false;
|
|
|
|
m_Active = false;
|
|
|
|
m_SelectedSpectatorID = NO_SELECTION;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CSpectator::Spectate(int SpectatorID)
|
|
|
|
{
|
2011-03-12 17:07:57 +00:00
|
|
|
if(Client()->State() == IClient::STATE_DEMOPLAYBACK)
|
|
|
|
{
|
|
|
|
m_pClient->m_DemoSpecID = clamp(SpectatorID, (int)SPEC_FREEVIEW, MAX_CLIENTS-1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(m_pClient->m_Snap.m_SpecInfo.m_SpectatorID == SpectatorID)
|
2011-03-10 09:08:14 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
CNetMsg_Cl_SetSpectatorMode Msg;
|
|
|
|
Msg.m_SpectatorID = SpectatorID;
|
|
|
|
Client()->SendPackMsg(&Msg, MSGFLAG_VITAL);
|
|
|
|
}
|