diff options
| author | oy <Tom_Adams@web.de> | 2011-03-10 10:08:14 +0100 |
|---|---|---|
| committer | oy <Tom_Adams@web.de> | 2011-03-10 10:08:14 +0100 |
| commit | ee2f625754ca9f01be6732550f16098c5afa704a (patch) | |
| tree | 9776edf90fac02d1bf03606dbc8b79fd071ed917 /src/game/client | |
| parent | 6205583d6411e300edd1ebf2eb170fbc8e7119e8 (diff) | |
| download | zcatch-ee2f625754ca9f01be6732550f16098c5afa704a.tar.gz zcatch-ee2f625754ca9f01be6732550f16098c5afa704a.zip | |
added extended spectator mode. Closes #28
Diffstat (limited to 'src/game/client')
| -rw-r--r-- | src/game/client/components/binds.cpp | 1 | ||||
| -rw-r--r-- | src/game/client/components/controls.cpp | 3 | ||||
| -rw-r--r-- | src/game/client/components/hud.cpp | 49 | ||||
| -rw-r--r-- | src/game/client/components/hud.h | 5 | ||||
| -rw-r--r-- | src/game/client/components/menus_settings.cpp | 5 | ||||
| -rw-r--r-- | src/game/client/components/spectator.cpp | 172 | ||||
| -rw-r--r-- | src/game/client/components/spectator.h | 37 | ||||
| -rw-r--r-- | src/game/client/gameclient.cpp | 28 | ||||
| -rw-r--r-- | src/game/client/gameclient.h | 5 |
9 files changed, 282 insertions, 23 deletions
diff --git a/src/game/client/components/binds.cpp b/src/game/client/components/binds.cpp index 7f473ef4..746389bd 100644 --- a/src/game/client/components/binds.cpp +++ b/src/game/client/components/binds.cpp @@ -99,6 +99,7 @@ void CBinds::SetDefaults() Bind(KEY_MOUSE_1, "+fire"); Bind(KEY_MOUSE_2, "+hook"); Bind(KEY_LSHIFT, "+emote"); + Bind(KEY_RSHIFT, "+spectate"); Bind('1', "+weapon1"); Bind('2', "+weapon2"); diff --git a/src/game/client/components/controls.cpp b/src/game/client/components/controls.cpp index df9a6bf0..f67caa8e 100644 --- a/src/game/client/components/controls.cpp +++ b/src/game/client/components/controls.cpp @@ -201,6 +201,9 @@ void CControls::OnRender() // update target pos if(m_pClient->m_Snap.m_pGameInfoObj && !(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_PAUSED || m_pClient->m_Snap.m_Spectate)) m_TargetPos = m_pClient->m_LocalCharacterPos + m_MousePos; + + if(m_pClient->m_Snap.m_Spectate && m_pClient->m_Snap.m_pSpectatorInfo) + m_MousePos = m_pClient->m_Snap.m_SpectatorPos; } bool CControls::OnMouseMove(float x, float y) diff --git a/src/game/client/components/hud.cpp b/src/game/client/components/hud.cpp index ca100f9d..aff76bc8 100644 --- a/src/game/client/components/hud.cpp +++ b/src/game/client/components/hud.cpp @@ -30,7 +30,6 @@ void CHud::OnReset() void CHud::RenderGameTimer() { float Half = 300.0f*Graphics()->ScreenAspect()/2.0f; - Graphics()->MapScreen(0, 0, 300.0f*Graphics()->ScreenAspect(), 300.0f); if(!(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_SUDDENDEATH)) { @@ -340,8 +339,11 @@ void CHud::RenderCursor() Graphics()->QuadsEnd(); } -void CHud::RenderHealthAndAmmo() +void CHud::RenderHealthAndAmmo(const CNetObj_Character *pCharacter) { + if(!pCharacter) + return; + //mapscreen_to_group(gacenter_x, center_y, layers_game_group()); float x = 5; @@ -351,15 +353,14 @@ void CHud::RenderHealthAndAmmo() // render gui stuff Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GAME].m_Id); - Graphics()->MapScreen(0,0,m_Width,300); Graphics()->QuadsBegin(); // if weaponstage is active, put a "glow" around the stage ammo - RenderTools()->SelectSprite(g_pData->m_Weapons.m_aId[m_pClient->m_Snap.m_pLocalCharacter->m_Weapon%NUM_WEAPONS].m_pSpriteProj); + RenderTools()->SelectSprite(g_pData->m_Weapons.m_aId[pCharacter->m_Weapon%NUM_WEAPONS].m_pSpriteProj); IGraphics::CQuadItem Array[10]; int i; - for (i = 0; i < min(m_pClient->m_Snap.m_pLocalCharacter->m_AmmoCount, 10); i++) + for (i = 0; i < min(pCharacter->m_AmmoCount, 10); i++) Array[i] = IGraphics::CQuadItem(x+i*12,y+24,10,10); Graphics()->QuadsDrawTL(Array, i); Graphics()->QuadsEnd(); @@ -369,7 +370,7 @@ void CHud::RenderHealthAndAmmo() // render health RenderTools()->SelectSprite(SPRITE_HEALTH_FULL); - for(; h < min(m_pClient->m_Snap.m_pLocalCharacter->m_Health, 10); h++) + for(; h < min(pCharacter->m_Health, 10); h++) Array[h] = IGraphics::CQuadItem(x+h*12,y,10,10); Graphics()->QuadsDrawTL(Array, h); @@ -382,7 +383,7 @@ void CHud::RenderHealthAndAmmo() // render armor meter h = 0; RenderTools()->SelectSprite(SPRITE_ARMOR_FULL); - for(; h < min(m_pClient->m_Snap.m_pLocalCharacter->m_Armor, 10); h++) + for(; h < min(pCharacter->m_Armor, 10); h++) Array[h] = IGraphics::CQuadItem(x+h*12,y+12,10,10); Graphics()->QuadsDrawTL(Array, h); @@ -394,19 +395,39 @@ void CHud::RenderHealthAndAmmo() Graphics()->QuadsEnd(); } +void CHud::RenderSpectatorHud() +{ + // draw the box + Graphics()->TextureSet(-1); + Graphics()->QuadsBegin(); + Graphics()->SetColor(0.0f, 0.0f, 0.0f, 0.4f); + RenderTools()->DrawRoundRectExt(m_Width-180.0f, m_Height-15.0f, 180.0f, 15.0f, 5.0f, CUI::CORNER_TL); + Graphics()->QuadsEnd(); + + // draw the text + char aBuf[128]; + str_format(aBuf, sizeof(aBuf), "%s: %s", Localize("Spectate"), m_pClient->m_Snap.m_pSpectatorInfo && m_pClient->m_Snap.m_pSpectatorInfo->m_SpectatorID != SPEC_FREEVIEW ? + m_pClient->m_aClients[m_pClient->m_Snap.m_pSpectatorInfo->m_SpectatorID].m_aName : Localize("Free-View")); + TextRender()->Text(0, m_Width-174.0f, m_Height-13.0f, 8.0f, aBuf, -1); +} + void CHud::OnRender() { if(!m_pClient->m_Snap.m_pGameInfoObj) return; - m_Width = 300*Graphics()->ScreenAspect(); + m_Width = 300.0f*Graphics()->ScreenAspect(); + m_Height = 300.0f; + Graphics()->MapScreen(0.0f, 0.0f, m_Width, m_Height); - bool Spectate = false; - if(m_pClient->m_Snap.m_pLocalInfo && m_pClient->m_Snap.m_pLocalInfo->m_Team == TEAM_SPECTATORS) - Spectate = true; - - if(m_pClient->m_Snap.m_pLocalCharacter && !Spectate && !(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER)) - RenderHealthAndAmmo(); + if(m_pClient->m_Snap.m_pLocalCharacter && !(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER)) + RenderHealthAndAmmo(m_pClient->m_Snap.m_pLocalCharacter); + else if(m_pClient->m_Snap.m_Spectate) + { + if(m_pClient->m_Snap.m_pSpectatorInfo && m_pClient->m_Snap.m_pSpectatorInfo->m_SpectatorID != SPEC_FREEVIEW) + RenderHealthAndAmmo(&m_pClient->m_Snap.m_aCharacters[m_pClient->m_Snap.m_pSpectatorInfo->m_SpectatorID].m_Cur); + RenderSpectatorHud(); + } RenderGameTimer(); RenderSuddenDeath(); diff --git a/src/game/client/components/hud.h b/src/game/client/components/hud.h index f1f3dc0a..75702d51 100644 --- a/src/game/client/components/hud.h +++ b/src/game/client/components/hud.h @@ -6,7 +6,7 @@ class CHud : public CComponent { - float m_Width; + float m_Width, m_Height; float m_AverageFPS; void RenderCursor(); @@ -15,10 +15,11 @@ class CHud : public CComponent void RenderConnectionWarning(); void RenderTeambalanceWarning(); void RenderVoting(); - void RenderHealthAndAmmo(); + void RenderHealthAndAmmo(const CNetObj_Character *pCharacter); void RenderGameTimer(); void RenderSuddenDeath(); void RenderScoreHud(); + void RenderSpectatorHud(); void RenderWarmupTimer(); void MapscreenToGroup(float CenterX, float CenterY, struct CMapItemGroup *PGroup); diff --git a/src/game/client/components/menus_settings.cpp b/src/game/client/components/menus_settings.cpp index 9accd6af..4bdf0fd3 100644 --- a/src/game/client/components/menus_settings.cpp +++ b/src/game/client/components/menus_settings.cpp @@ -322,6 +322,7 @@ static CKeyInfo gs_aKeys[] = { "Team chat", "chat team", 0 }, { "Show chat", "+show_chat", 0 }, { "Emoticon", "+emote", 0 }, + { "Spectator mode", "+spectate", 0 }, { "Console", "toggle_local_console", 0 }, { "Remote console", "toggle_remote_console", 0 }, { "Screenshot", "screenshot", 0 }, @@ -331,7 +332,7 @@ static CKeyInfo gs_aKeys[] = Localize("Move left");Localize("Move right");Localize("Jump");Localize("Fire");Localize("Hook");Localize("Hammer"); Localize("Pistol");Localize("Shotgun");Localize("Grenade");Localize("Rifle");Localize("Next weapon");Localize("Prev. weapon"); Localize("Vote yes");Localize("Vote no");Localize("Chat");Localize("Team chat");Localize("Show chat");Localize("Emoticon"); - Localize("Console");Localize("Remote console");Localize("Screenshot");Localize("Scoreboard"); + Localize("Spectate");Localize("Console");Localize("Remote console");Localize("Screenshot");Localize("Scoreboard"); */ const int g_KeyCount = sizeof(gs_aKeys) / sizeof(CKeyInfo); @@ -458,7 +459,7 @@ void CMenus::RenderSettingsControls(CUIRect MainView) TextRender()->Text(0, MiscSettings.x, MiscSettings.y, 14.0f*UI()->Scale(), Localize("Miscellaneous"), -1); MiscSettings.HSplitTop(14.0f+5.0f+10.0f, 0, &MiscSettings); - UiDoGetButtons(17, 22, MiscSettings); + UiDoGetButtons(17, 23, MiscSettings); } // defaults diff --git a/src/game/client/components/spectator.cpp b/src/game/client/components/spectator.cpp new file mode 100644 index 00000000..18035248 --- /dev/null +++ b/src/game/client/components/spectator.cpp @@ -0,0 +1,172 @@ +/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ +/* If you are missing that file, acquire a complete release at teeworlds.com. */ +#include <engine/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; + if(pSelf->m_pClient->m_Snap.m_Spectate) + pSelf->m_Active = pResult->GetInteger(0) != 0; +} + +void CSpectator::ConSpectate(IConsole::IResult *pResult, void *pUserData) +{ + ((CSpectator *)pUserData)->Spectate(pResult->GetInteger(0)); +} + +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"); +} + +bool CSpectator::OnMouseMove(float x, float y) +{ + if(!m_Active) + return false; + + m_SelectorMouse += vec2(x,y); + return true; +} + +void CSpectator::OnRelease() +{ + OnReset(); +} + +void CSpectator::OnRender() +{ + if(!m_Active) + { + if(m_WasActive) + { + if(m_SelectedSpectatorID != NO_SELECTION) + Spectate(m_SelectedSpectatorID); + OnReset(); + } + return; + } + + m_WasActive = true; + m_SelectedSpectatorID = NO_SELECTION; + + // draw background + float Width = 400*3.0f*Graphics()->ScreenAspect(); + float Height = 400*3.0f; + + 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; + bool Selected = false; + + int SpectatorID = m_pClient->m_Snap.m_pSpectatorInfo ? m_pClient->m_Snap.m_pSpectatorInfo->m_SpectatorID : SPEC_FREEVIEW; + if(SpectatorID == SPEC_FREEVIEW) + { + 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; + } + + if(SpectatorID == i) + { + 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); + + 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)); + + y += LineHeight; + } + + // 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) +{ + if(m_pClient->m_Snap.m_pSpectatorInfo && m_pClient->m_Snap.m_pSpectatorInfo->m_SpectatorID == SpectatorID) + return; + + CNetMsg_Cl_SetSpectatorMode Msg; + Msg.m_SpectatorID = SpectatorID; + Client()->SendPackMsg(&Msg, MSGFLAG_VITAL); +} diff --git a/src/game/client/components/spectator.h b/src/game/client/components/spectator.h new file mode 100644 index 00000000..607780f5 --- /dev/null +++ b/src/game/client/components/spectator.h @@ -0,0 +1,37 @@ +/* (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. */ +#ifndef GAME_CLIENT_COMPONENTS_SPECTATOR_H +#define GAME_CLIENT_COMPONENTS_SPECTATOR_H +#include <base/vmath.h> + +#include <game/client/component.h> + +class CSpectator : public CComponent +{ + enum + { + NO_SELECTION=-2, + }; + + bool m_Active; + bool m_WasActive; + + int m_SelectedSpectatorID; + vec2 m_SelectorMouse; + + static void ConKeySpectator(IConsole::IResult *pResult, void *pUserData); + static void ConSpectate(IConsole::IResult *pResult, void *pUserData); + +public: + CSpectator(); + + virtual void OnConsoleInit(); + virtual bool OnMouseMove(float x, float y); + virtual void OnRender(); + virtual void OnRelease(); + virtual void OnReset(); + + void Spectate(int SpectatorID); +}; + +#endif diff --git a/src/game/client/gameclient.cpp b/src/game/client/gameclient.cpp index f80d0266..0d847162 100644 --- a/src/game/client/gameclient.cpp +++ b/src/game/client/gameclient.cpp @@ -44,6 +44,7 @@ #include "components/scoreboard.h" #include "components/skins.h" #include "components/sounds.h" +#include "components/spectator.h" #include "components/voting.h" CGameClient g_GameClient; @@ -69,6 +70,7 @@ static CSounds gs_Sounds; static CEmoticon gs_Emoticon; static CDamageInd gsDamageInd; static CVoting gs_Voting; +static CSpectator gs_Spectator; static CPlayers gs_Players; static CNamePlates gs_NamePlates; @@ -139,6 +141,7 @@ void CGameClient::OnConsoleInit() m_All.Add(&m_pParticles->m_RenderGeneral); m_All.Add(m_pDamageind); m_All.Add(&gs_Hud); + m_All.Add(&gs_Spectator); m_All.Add(&gs_Emoticon); m_All.Add(&gs_KillMessages); m_All.Add(m_pChat); @@ -156,6 +159,7 @@ void CGameClient::OnConsoleInit() m_Input.Add(m_pChat); // chat has higher prio due to tha you can quit it by pressing esc m_Input.Add(m_pMotd); // for pressing esc to remove it m_Input.Add(m_pMenus); + m_Input.Add(&gs_Spectator); m_Input.Add(&gs_Emoticon); m_Input.Add(m_pControls); m_Input.Add(m_pBinds); @@ -336,8 +340,9 @@ void CGameClient::OnReset() } -void CGameClient::UpdateLocalCharacterPos() +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_GAMEOVER)) @@ -353,6 +358,16 @@ void CGameClient::UpdateLocalCharacterPos() vec2(m_Snap.m_pLocalPrevCharacter->m_X, m_Snap.m_pLocalPrevCharacter->m_Y), vec2(m_Snap.m_pLocalCharacter->m_X, m_Snap.m_pLocalCharacter->m_Y), Client()->IntraGameTick()); } + + // spectator position + if(m_Snap.m_Spectate && m_Snap.m_pSpectatorInfo) + { + if(m_Snap.m_pPrevSpectatorInfo) + m_Snap.m_SpectatorPos = mix(vec2(m_Snap.m_pPrevSpectatorInfo->m_X, m_Snap.m_pPrevSpectatorInfo->m_Y), + vec2(m_Snap.m_pSpectatorInfo->m_X, m_Snap.m_pSpectatorInfo->m_Y), Client()->IntraGameTick()); + else + m_Snap.m_SpectatorPos = vec2(m_Snap.m_pSpectatorInfo->m_X, m_Snap.m_pSpectatorInfo->m_Y); + } } @@ -393,8 +408,8 @@ void CGameClient::OnRender() return;*/ - // update the local character position - UpdateLocalCharacterPos(); + // update the local character and spectate position + UpdatePositions(); // dispatch all input to systems DispatchInput(); @@ -716,11 +731,11 @@ void CGameClient::OnNewSnapshot() else if(Item.m_Type == NETOBJTYPE_CHARACTER) { const void *pOld = Client()->SnapFindItem(IClient::SNAP_PREV, NETOBJTYPE_CHARACTER, Item.m_ID); + m_Snap.m_aCharacters[Item.m_ID].m_Cur = *((const CNetObj_Character *)pData); if(pOld) { m_Snap.m_aCharacters[Item.m_ID].m_Active = true; m_Snap.m_aCharacters[Item.m_ID].m_Prev = *((const CNetObj_Character *)pOld); - m_Snap.m_aCharacters[Item.m_ID].m_Cur = *((const CNetObj_Character *)pData); if(m_Snap.m_aCharacters[Item.m_ID].m_Prev.m_Tick) Evolve(&m_Snap.m_aCharacters[Item.m_ID].m_Prev, Client()->PrevGameTick()); @@ -728,6 +743,11 @@ void CGameClient::OnNewSnapshot() Evolve(&m_Snap.m_aCharacters[Item.m_ID].m_Cur, Client()->GameTick()); } } + else if(Item.m_Type == NETOBJTYPE_SPECTATORINFO) + { + m_Snap.m_pSpectatorInfo = (const CNetObj_SpectatorInfo *)pData; + m_Snap.m_pPrevSpectatorInfo = (const CNetObj_SpectatorInfo *)Client()->SnapFindItem(IClient::SNAP_PREV, NETOBJTYPE_SPECTATORINFO, Item.m_ID); + } else if(Item.m_Type == NETOBJTYPE_GAMEINFO) { static bool s_GameOver = 0; diff --git a/src/game/client/gameclient.h b/src/game/client/gameclient.h index 3681b301..5e8b9391 100644 --- a/src/game/client/gameclient.h +++ b/src/game/client/gameclient.h @@ -49,7 +49,7 @@ class CGameClient : public IGameClient void DispatchInput(); void ProcessEvents(); - void UpdateLocalCharacterPos(); + void UpdatePositions(); int m_PredictedTick; int m_LastNewPredictedTick; @@ -109,6 +109,8 @@ public: const CNetObj_Character *m_pLocalCharacter; const CNetObj_Character *m_pLocalPrevCharacter; const CNetObj_PlayerInfo *m_pLocalInfo; + const CNetObj_SpectatorInfo *m_pSpectatorInfo; + const CNetObj_SpectatorInfo *m_pPrevSpectatorInfo; const CNetObj_Flag *m_paFlags[2]; const CNetObj_GameInfo *m_pGameInfoObj; const CNetObj_GameData *m_pGameDataObj; @@ -121,6 +123,7 @@ public: int m_NumPlayers; int m_aTeamSize[2]; bool m_Spectate; + vec2 m_SpectatorPos; // struct CCharacterInfo |