about summary refs log tree commit diff
path: root/src/game/client
diff options
context:
space:
mode:
Diffstat (limited to 'src/game/client')
-rw-r--r--src/game/client/components/camera.cpp19
-rw-r--r--src/game/client/components/camera.h13
-rw-r--r--src/game/client/components/controls.cpp17
-rw-r--r--src/game/client/components/emoticon.cpp4
-rw-r--r--src/game/client/components/hud.cpp10
-rw-r--r--src/game/client/components/menus_demo.cpp4
-rw-r--r--src/game/client/components/scoreboard.cpp13
-rw-r--r--src/game/client/components/spectator.cpp19
-rw-r--r--src/game/client/gameclient.cpp43
-rw-r--r--src/game/client/gameclient.h13
10 files changed, 106 insertions, 49 deletions
diff --git a/src/game/client/components/camera.cpp b/src/game/client/components/camera.cpp
index b4c2debb..f02b2861 100644
--- a/src/game/client/components/camera.cpp
+++ b/src/game/client/components/camera.cpp
@@ -12,7 +12,7 @@
 
 CCamera::CCamera()
 {
-	m_WasSpectator = false;
+	m_CamType = CAMTYPE_UNDEFINED;
 }
 
 void CCamera::OnRender()
@@ -21,21 +21,22 @@ void CCamera::OnRender()
 	m_Zoom = 1.0f;
 
 	// update camera center		
-	if(m_pClient->m_Snap.m_Spectate && (!m_pClient->m_Snap.m_pSpectatorInfo || m_pClient->m_Snap.m_pSpectatorInfo->m_SpectatorID == SPEC_FREEVIEW))
+	if(m_pClient->m_Snap.m_SpecInfo.m_Active && !m_pClient->m_Snap.m_SpecInfo.m_UsePosition)
 	{
-		if(!m_WasSpectator)
+		if(m_CamType != CAMTYPE_SPEC)
 		{
+			m_pClient->m_pControls->m_MousePos = m_PrevCenter;
 			m_pClient->m_pControls->ClampMousePos();
-			m_WasSpectator = true;
+			m_CamType = CAMTYPE_SPEC;
 		}
 		m_Center = m_pClient->m_pControls->m_MousePos;
 	}
 	else
 	{
-		if(m_WasSpectator)
+		if(m_CamType != CAMTYPE_PLAYER)
 		{
 			m_pClient->m_pControls->ClampMousePos();
-			m_WasSpectator = false;
+			m_CamType = CAMTYPE_PLAYER;
 		}
 
 		vec2 CameraOffset(0, 0);
@@ -50,9 +51,11 @@ void CCamera::OnRender()
 			CameraOffset = normalize(m_pClient->m_pControls->m_MousePos)*OffsetAmount;
 		}
 		
-		if(m_pClient->m_Snap.m_Spectate)
-			m_Center = m_pClient->m_Snap.m_SpectatorPos + CameraOffset;
+		if(m_pClient->m_Snap.m_SpecInfo.m_Active)
+			m_Center = m_pClient->m_Snap.m_SpecInfo.m_Position + CameraOffset;
 		else
 			m_Center = m_pClient->m_LocalCharacterPos + CameraOffset;
 	}
+
+	m_PrevCenter = m_Center;
 }
diff --git a/src/game/client/components/camera.h b/src/game/client/components/camera.h
index ba433285..75725d56 100644
--- a/src/game/client/components/camera.h
+++ b/src/game/client/components/camera.h
@@ -6,11 +6,20 @@
 #include <game/client/component.h>
 
 class CCamera : public CComponent
-{	
+{
+	enum
+	{
+		CAMTYPE_UNDEFINED=-1,
+		CAMTYPE_SPEC,
+		CAMTYPE_PLAYER,
+	};
+
+	int m_CamType;
+	vec2 m_PrevCenter;
+
 public:
 	vec2 m_Center;
 	float m_Zoom;
-	bool m_WasSpectator;
 
 	CCamera();
 	virtual void OnRender();
diff --git a/src/game/client/components/controls.cpp b/src/game/client/components/controls.cpp
index c884b394..56b6e63b 100644
--- a/src/game/client/components/controls.cpp
+++ b/src/game/client/components/controls.cpp
@@ -199,18 +199,17 @@ int CControls::SnapInput(int *pData)
 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))
+	if(m_pClient->m_Snap.m_pGameInfoObj && !(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_PAUSED || m_pClient->m_Snap.m_SpecInfo.m_Active))
 		m_TargetPos = m_pClient->m_LocalCharacterPos + m_MousePos;
-
-	if(m_pClient->m_Snap.m_Spectate && m_pClient->m_Snap.m_pSpectatorInfo && m_pClient->m_Snap.m_pSpectatorInfo->m_SpectatorID != SPEC_FREEVIEW)
-		m_TargetPos = m_pClient->m_Snap.m_SpectatorPos + m_MousePos;
+	else if(m_pClient->m_Snap.m_SpecInfo.m_Active && m_pClient->m_Snap.m_SpecInfo.m_UsePosition)
+		m_TargetPos = m_pClient->m_Snap.m_SpecInfo.m_Position + m_MousePos;
+	else
+		m_TargetPos = m_MousePos;
 }
 
 bool CControls::OnMouseMove(float x, float y)
 {
-	if((m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_PAUSED) ||
-		(m_pClient->m_Snap.m_Spectate  && (!m_pClient->m_Snap.m_pSpectatorInfo || m_pClient->m_Snap.m_pSpectatorInfo->m_SpectatorID == SPEC_FREEVIEW) &&
-		m_pClient->m_pChat->IsActive()))
+	if(m_pClient->m_Snap.m_pGameInfoObj && m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_PAUSED)
 		return false;
 	
 	m_MousePos += vec2(x, y); // TODO: ugly
@@ -221,11 +220,11 @@ bool CControls::OnMouseMove(float x, float y)
 
 void CControls::ClampMousePos()
 {
-	if(m_pClient->m_Snap.m_Spectate && (!m_pClient->m_Snap.m_pSpectatorInfo || m_pClient->m_Snap.m_pSpectatorInfo->m_SpectatorID == SPEC_FREEVIEW))
+	if(m_pClient->m_Snap.m_SpecInfo.m_Active && !m_pClient->m_Snap.m_SpecInfo.m_UsePosition)
 	{
 		m_MousePos.x = clamp(m_MousePos.x, 200.0f, Collision()->GetWidth()*32-200.0f);
 		m_MousePos.y = clamp(m_MousePos.y, 200.0f, Collision()->GetHeight()*32-200.0f);
-		m_TargetPos = m_MousePos;
+		
 	}
 	else
 	{
diff --git a/src/game/client/components/emoticon.cpp b/src/game/client/components/emoticon.cpp
index 1fa72a7f..64b47b74 100644
--- a/src/game/client/components/emoticon.cpp
+++ b/src/game/client/components/emoticon.cpp
@@ -18,8 +18,8 @@ CEmoticon::CEmoticon()
 void CEmoticon::ConKeyEmoticon(IConsole::IResult *pResult, void *pUserData)
 {
 	CEmoticon *pSelf = (CEmoticon *)pUserData;
-	if(!pSelf->m_pClient->m_Snap.m_Spectate && pSelf->Client()->State() != IClient::STATE_DEMOPLAYBACK)
-		((CEmoticon *)pUserData)->m_Active = pResult->GetInteger(0) != 0;
+	if(!pSelf->m_pClient->m_Snap.m_SpecInfo.m_Active && pSelf->Client()->State() != IClient::STATE_DEMOPLAYBACK)
+		pSelf->m_Active = pResult->GetInteger(0) != 0;
 }
 
 void CEmoticon::ConEmote(IConsole::IResult *pResult, void *pUserData)
diff --git a/src/game/client/components/hud.cpp b/src/game/client/components/hud.cpp
index aff76bc8..a9869bb3 100644
--- a/src/game/client/components/hud.cpp
+++ b/src/game/client/components/hud.cpp
@@ -406,8 +406,8 @@ void CHud::RenderSpectatorHud()
 
 	// 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"));
+	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-13.0f, 8.0f, aBuf, -1);
 }
 
@@ -422,10 +422,10 @@ void CHud::OnRender()
 
 	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)
+	else if(m_pClient->m_Snap.m_SpecInfo.m_Active)
 	{
-		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);
+		if(m_pClient->m_Snap.m_SpecInfo.m_SpectatorID != SPEC_FREEVIEW)
+			RenderHealthAndAmmo(&m_pClient->m_Snap.m_aCharacters[m_pClient->m_Snap.m_SpecInfo.m_SpectatorID].m_Cur);
 		RenderSpectatorHud();
 	}
 
diff --git a/src/game/client/components/menus_demo.cpp b/src/game/client/components/menus_demo.cpp
index 92dd381d..068d9c32 100644
--- a/src/game/client/components/menus_demo.cpp
+++ b/src/game/client/components/menus_demo.cpp
@@ -55,8 +55,8 @@ void CMenus::RenderDemoPlayer(CUIRect MainView)
 		TotalHeight = SeekBarHeight+Margins*2;
 	
 	MainView.HSplitBottom(TotalHeight, 0, &MainView);
-	MainView.VSplitLeft(250.0f, 0, &MainView);
-	MainView.VSplitRight(250.0f, &MainView, 0);
+	MainView.VSplitLeft(50.0f, 0, &MainView);
+	MainView.VSplitRight(450.0f, &MainView, 0);
 	
 	RenderTools()->DrawUIRect(&MainView, ms_ColorTabbarActive, CUI::CORNER_T, 10.0f);
 		
diff --git a/src/game/client/components/scoreboard.cpp b/src/game/client/components/scoreboard.cpp
index a9b249ed..0d355456 100644
--- a/src/game/client/components/scoreboard.cpp
+++ b/src/game/client/components/scoreboard.cpp
@@ -151,11 +151,14 @@ void CScoreboard::RenderScoreboard(float x, float y, float w, int Team, const ch
 	}
 	else
 	{
-		char aBuf[128];
-		int Score = m_pClient->m_Snap.m_pLocalInfo->m_Score;
-		str_format(aBuf, sizeof(aBuf), "%d", Score);
-		tw = TextRender()->TextWidth(0, 48, aBuf, -1);
-		TextRender()->Text(0, x+w-tw-30, y, 48, aBuf, -1);
+		if(m_pClient->m_Snap.m_pLocalInfo)
+		{
+			char aBuf[128];
+			int Score = m_pClient->m_Snap.m_pLocalInfo->m_Score;
+			str_format(aBuf, sizeof(aBuf), "%d", Score);
+			tw = TextRender()->TextWidth(0, 48, aBuf, -1);
+			TextRender()->Text(0, x+w-tw-30, y, 48, aBuf, -1);
+		}
 	}
 
 	y += 54.0f;
diff --git a/src/game/client/components/spectator.cpp b/src/game/client/components/spectator.cpp
index 18035248..706dbc63 100644
--- a/src/game/client/components/spectator.cpp
+++ b/src/game/client/components/spectator.cpp
@@ -1,5 +1,6 @@
 /* (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/demo.h>
 #include <engine/graphics.h>
 #include <engine/textrender.h>
 #include <engine/shared/config.h>
@@ -16,7 +17,8 @@
 void CSpectator::ConKeySpectator(IConsole::IResult *pResult, void *pUserData)
 {
 	CSpectator *pSelf = (CSpectator *)pUserData;
-	if(pSelf->m_pClient->m_Snap.m_Spectate)
+	if(pSelf->m_pClient->m_Snap.m_SpecInfo.m_Active &&
+		(pSelf->Client()->State() != IClient::STATE_DEMOPLAYBACK || pSelf->DemoPlayer()->GetDemoType() == IDemoPlayer::DEMOTYPE_SERVER))
 		pSelf->m_Active = pResult->GetInteger(0) != 0;
 }
 
@@ -58,7 +60,7 @@ void CSpectator::OnRender()
 		{
 			if(m_SelectedSpectatorID != NO_SELECTION)
 				Spectate(m_SelectedSpectatorID);
-			OnReset();
+			m_WasActive = false;
 		}
 		return;
 	}
@@ -89,8 +91,7 @@ void CSpectator::OnRender()
 	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)
+	if(m_pClient->m_Snap.m_SpecInfo.m_SpectatorID == SPEC_FREEVIEW)
 	{
 		Graphics()->TextureSet(-1);
 		Graphics()->QuadsBegin();
@@ -120,7 +121,7 @@ void CSpectator::OnRender()
 			y = StartY;
 		}
 
-		if(SpectatorID == i)
+		if(m_pClient->m_Snap.m_SpecInfo.m_SpectatorID == i)
 		{
 			Graphics()->TextureSet(-1);
 			Graphics()->QuadsBegin();
@@ -163,7 +164,13 @@ void CSpectator::OnReset()
 
 void CSpectator::Spectate(int SpectatorID)
 {
-	if(m_pClient->m_Snap.m_pSpectatorInfo && m_pClient->m_Snap.m_pSpectatorInfo->m_SpectatorID == SpectatorID)
+	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)
 		return;
 
 	CNetMsg_Cl_SetSpectatorMode Msg;
diff --git a/src/game/client/gameclient.cpp b/src/game/client/gameclient.cpp
index 0d847162..0e2e8056 100644
--- a/src/game/client/gameclient.cpp
+++ b/src/game/client/gameclient.cpp
@@ -337,6 +337,8 @@ void CGameClient::OnReset()
 	
 	for(int i = 0; i < m_All.m_Num; i++)
 		m_All.m_paComponents[i]->OnReset();
+
+	m_DemoSpecID = SPEC_FREEVIEW;
 }
 
 
@@ -360,13 +362,26 @@ void CGameClient::UpdatePositions()
 	}
 
 	// spectator position
-	if(m_Snap.m_Spectate && m_Snap.m_pSpectatorInfo)
+	if(m_Snap.m_SpecInfo.m_Active)
 	{
-		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);
+		if(Client()->State() == IClient::STATE_DEMOPLAYBACK && DemoPlayer()->GetDemoType() == IDemoPlayer::DEMOTYPE_SERVER &&
+			m_Snap.m_SpecInfo.m_SpectatorID != SPEC_FREEVIEW)
+		{
+			m_Snap.m_SpecInfo.m_Position = mix(
+				vec2(m_Snap.m_aCharacters[m_Snap.m_SpecInfo.m_SpectatorID].m_Prev.m_X, m_Snap.m_aCharacters[m_Snap.m_SpecInfo.m_SpectatorID].m_Prev.m_Y),
+				vec2(m_Snap.m_aCharacters[m_Snap.m_SpecInfo.m_SpectatorID].m_Cur.m_X, m_Snap.m_aCharacters[m_Snap.m_SpecInfo.m_SpectatorID].m_Cur.m_Y),
+				Client()->IntraGameTick());
+			m_Snap.m_SpecInfo.m_UsePosition = true;
+		}
+		else if(m_Snap.m_pSpectatorInfo && (Client()->State() == IClient::STATE_DEMOPLAYBACK || m_Snap.m_SpecInfo.m_SpectatorID != SPEC_FREEVIEW))
+		{
+			if(m_Snap.m_pPrevSpectatorInfo)
+				m_Snap.m_SpecInfo.m_Position = 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_SpecInfo.m_Position = vec2(m_Snap.m_pSpectatorInfo->m_X, m_Snap.m_pSpectatorInfo->m_Y);
+			m_Snap.m_SpecInfo.m_UsePosition = true;
+		}
 	}
 }
 
@@ -720,7 +735,10 @@ void CGameClient::OnNewSnapshot()
 					m_Snap.m_pLocalInfo = pInfo;
 					
 					if(pInfo->m_Team == TEAM_SPECTATORS)
-						m_Snap.m_Spectate = true;
+					{
+						m_Snap.m_SpecInfo.m_Active = true;
+						m_Snap.m_SpecInfo.m_SpectatorID = SPEC_FREEVIEW;
+					}
 				}
 				
 				// calculate team-balance
@@ -747,6 +765,8 @@ void CGameClient::OnNewSnapshot()
 			{
 				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);
+
+				m_Snap.m_SpecInfo.m_SpectatorID = m_Snap.m_pSpectatorInfo->m_SpectatorID;
 			}
 			else if(Item.m_Type == NETOBJTYPE_GAMEINFO)
 			{
@@ -785,7 +805,14 @@ void CGameClient::OnNewSnapshot()
 		}
 	}
 	else
-		m_Snap.m_Spectate = true;
+	{
+		m_Snap.m_SpecInfo.m_Active = true;
+		if(Client()->State() == IClient::STATE_DEMOPLAYBACK && DemoPlayer()->GetDemoType() == IDemoPlayer::DEMOTYPE_SERVER &&
+			m_DemoSpecID != SPEC_FREEVIEW && m_Snap.m_aCharacters[m_DemoSpecID].m_Active)
+			m_Snap.m_SpecInfo.m_SpectatorID = m_DemoSpecID;
+		else
+			m_Snap.m_SpecInfo.m_SpectatorID = SPEC_FREEVIEW;
+	}
 
 	// sort player infos by score
 	mem_copy(m_Snap.m_paInfoByScore, m_Snap.m_paPlayerInfos, sizeof(m_Snap.m_paInfoByScore));
diff --git a/src/game/client/gameclient.h b/src/game/client/gameclient.h
index 5e8b9391..831cae24 100644
--- a/src/game/client/gameclient.h
+++ b/src/game/client/gameclient.h
@@ -97,6 +97,8 @@ public:
 	};
 	int m_ServerMode;
 
+	int m_DemoSpecID;
+
 	vec2 m_LocalCharacterPos;
 
 	// predicted players
@@ -122,8 +124,15 @@ public:
 		int m_LocalClientID;
 		int m_NumPlayers;
 		int m_aTeamSize[2];
-		bool m_Spectate;
-		vec2 m_SpectatorPos;
+		
+		// spectate data
+		struct CSpectateInfo
+		{
+			bool m_Active;
+			int m_SpectatorID;
+			bool m_UsePosition;
+			vec2 m_Position;
+		} m_SpecInfo;
 		
 		//
 		struct CCharacterInfo