about summary refs log tree commit diff
path: root/src/game/client/components
diff options
context:
space:
mode:
authoroy <Tom_Adams@web.de>2011-03-10 10:08:14 +0100
committeroy <Tom_Adams@web.de>2011-03-10 10:08:14 +0100
commitee2f625754ca9f01be6732550f16098c5afa704a (patch)
tree9776edf90fac02d1bf03606dbc8b79fd071ed917 /src/game/client/components
parent6205583d6411e300edd1ebf2eb170fbc8e7119e8 (diff)
downloadzcatch-ee2f625754ca9f01be6732550f16098c5afa704a.tar.gz
zcatch-ee2f625754ca9f01be6732550f16098c5afa704a.zip
added extended spectator mode. Closes #28
Diffstat (limited to 'src/game/client/components')
-rw-r--r--src/game/client/components/binds.cpp1
-rw-r--r--src/game/client/components/controls.cpp3
-rw-r--r--src/game/client/components/hud.cpp49
-rw-r--r--src/game/client/components/hud.h5
-rw-r--r--src/game/client/components/menus_settings.cpp5
-rw-r--r--src/game/client/components/spectator.cpp172
-rw-r--r--src/game/client/components/spectator.h37
7 files changed, 254 insertions, 18 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