about summary refs log tree commit diff
path: root/src/game/server
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/server
parent6205583d6411e300edd1ebf2eb170fbc8e7119e8 (diff)
downloadzcatch-ee2f625754ca9f01be6732550f16098c5afa704a.tar.gz
zcatch-ee2f625754ca9f01be6732550f16098c5afa704a.zip
added extended spectator mode. Closes #28
Diffstat (limited to 'src/game/server')
-rw-r--r--src/game/server/entities/character.cpp2
-rw-r--r--src/game/server/gamecontext.cpp56
-rw-r--r--src/game/server/player.cpp39
-rw-r--r--src/game/server/player.h41
4 files changed, 95 insertions, 43 deletions
diff --git a/src/game/server/entities/character.cpp b/src/game/server/entities/character.cpp
index ddd416d1..32a9523e 100644
--- a/src/game/server/entities/character.cpp
+++ b/src/game/server/entities/character.cpp
@@ -822,7 +822,7 @@ void CCharacter::Snap(int SnappingClient)
 
 	pCharacter->m_Direction = m_Input.m_Direction;
 
-	if(m_pPlayer->GetCID() == SnappingClient)
+	if(m_pPlayer->GetCID() == SnappingClient || SnappingClient == -1 || m_pPlayer->GetCID() == GameServer()->m_apPlayers[SnappingClient]->m_SpectatorID)
 	{
 		pCharacter->m_Health = m_Health;
 		pCharacter->m_Armor = m_Armor;
diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp
index 44d9b6fc..7f8a075f 100644
--- a/src/game/server/gamecontext.cpp
+++ b/src/game/server/gamecontext.cpp
@@ -389,7 +389,10 @@ void CGameContext::OnTick()
 	for(int i = 0; i < MAX_CLIENTS; i++)
 	{
 		if(m_apPlayers[i])
+		{
 			m_apPlayers[i]->Tick();
+			m_apPlayers[i]->PostTick();
+		}
 	}
 	
 	// update voting
@@ -454,7 +457,7 @@ void CGameContext::OnTick()
 				SendChat(-1, CGameContext::CHAT_ALL, "Vote passed");
 			
 				if(m_apPlayers[m_VoteCreator])
-					m_apPlayers[m_VoteCreator]->m_Last_VoteCall = 0;
+					m_apPlayers[m_VoteCreator]->m_LastVoteCall = 0;
 			}
 			else if(m_VoteEnforce == VOTE_ENFORCE_NO || time_get() > m_VoteCloseTime)
 			{
@@ -548,6 +551,13 @@ void CGameContext::OnClientDrop(int ClientID)
 	
 	(void)m_pController->CheckTeamBalance();
 	m_VoteUpdate = true;
+
+	// update spectator modes
+	for(int i = 0; i < MAX_CLIENTS; ++i)
+	{
+		if(m_apPlayers[i] && m_apPlayers[i]->m_SpectatorID == ClientID)
+			m_apPlayers[i]->m_SpectatorID = SPEC_FREEVIEW;
+	}
 }
 
 void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
@@ -572,10 +582,10 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
 		else
 			Team = CGameContext::CHAT_ALL;
 		
-		if(g_Config.m_SvSpamprotection && pPlayer->m_Last_Chat && pPlayer->m_Last_Chat+Server()->TickSpeed() > Server()->Tick())
+		if(g_Config.m_SvSpamprotection && pPlayer->m_LastChat && pPlayer->m_LastChat+Server()->TickSpeed() > Server()->Tick())
 			return;
 		
-		pPlayer->m_Last_Chat = Server()->Tick();
+		pPlayer->m_LastChat = Server()->Tick();
 
 		// check for invalid chars
 		unsigned char *pMessage = (unsigned char *)pMsg->m_pMessage;
@@ -590,11 +600,11 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
 	}
 	else if(MsgID == NETMSGTYPE_CL_CALLVOTE)
 	{
-		if(g_Config.m_SvSpamprotection && pPlayer->m_Last_VoteTry && pPlayer->m_Last_VoteTry+Server()->TickSpeed()*3 > Server()->Tick())
+		if(g_Config.m_SvSpamprotection && pPlayer->m_LastVoteTry && pPlayer->m_LastVoteTry+Server()->TickSpeed()*3 > Server()->Tick())
 			return;
 
 		int64 Now = Server()->Tick();
-		pPlayer->m_Last_VoteTry = Now;
+		pPlayer->m_LastVoteTry = Now;
 		if(pPlayer->GetTeam() == TEAM_SPECTATORS)
 		{
 			SendChatTarget(ClientID, "Spectators aren't allowed to start a vote.");
@@ -607,8 +617,8 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
 			return;
 		}
 		
-		int Timeleft = pPlayer->m_Last_VoteCall + Server()->TickSpeed()*60 - Now;
-		if(pPlayer->m_Last_VoteCall && Timeleft > 0)
+		int Timeleft = pPlayer->m_LastVoteCall + Server()->TickSpeed()*60 - Now;
+		if(pPlayer->m_LastVoteCall && Timeleft > 0)
 		{
 			char aChatmsg[512] = {0};
 			str_format(aChatmsg, sizeof(aChatmsg), "You must wait %d seconds before making another vote", (Timeleft/Server()->TickSpeed())+1);
@@ -715,7 +725,7 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
 			pPlayer->m_Vote = 1;
 			pPlayer->m_VotePos = m_VotePos = 1;
 			m_VoteCreator = ClientID;
-			pPlayer->m_Last_VoteCall = Now;
+			pPlayer->m_LastVoteCall = Now;
 		}
 	}
 	else if(MsgID == NETMSGTYPE_CL_VOTE)
@@ -738,7 +748,7 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
 	{
 		CNetMsg_Cl_SetTeam *pMsg = (CNetMsg_Cl_SetTeam *)pRawMsg;
 		
-		if(pPlayer->GetTeam() == pMsg->m_Team || (g_Config.m_SvSpamprotection && pPlayer->m_Last_SetTeam && pPlayer->m_Last_SetTeam+Server()->TickSpeed()*3 > Server()->Tick()))
+		if(pPlayer->GetTeam() == pMsg->m_Team || (g_Config.m_SvSpamprotection && pPlayer->m_LastSetTeam && pPlayer->m_LastSetTeam+Server()->TickSpeed()*3 > Server()->Tick()))
 			return;
 
 		// Switch team on given client and kill/respawn him
@@ -746,7 +756,7 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
 		{
 			if(m_pController->CanChangeTeam(pPlayer, pMsg->m_Team))
 			{
-				pPlayer->m_Last_SetTeam = Server()->Tick();
+				pPlayer->m_LastSetTeam = Server()->Tick();
 				if(pPlayer->GetTeam() == TEAM_SPECTATORS || pMsg->m_Team == TEAM_SPECTATORS)
 					m_VoteUpdate = true;
 				pPlayer->SetTeam(pMsg->m_Team);
@@ -762,14 +772,28 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
 			SendBroadcast(aBuf, ClientID);
 		}
 	}
+	else if (MsgID == NETMSGTYPE_CL_SETSPECTATORMODE && !m_World.m_Paused)
+	{
+		CNetMsg_Cl_SetSpectatorMode *pMsg = (CNetMsg_Cl_SetSpectatorMode *)pRawMsg;
+		
+		if(pPlayer->GetTeam() != TEAM_SPECTATORS || pPlayer->m_SpectatorID == pMsg->m_SpectatorID || ClientID == pMsg->m_SpectatorID ||
+			(g_Config.m_SvSpamprotection && pPlayer->m_LastSetSpectatorMode && pPlayer->m_LastSetSpectatorMode+Server()->TickSpeed()*3 > Server()->Tick()))
+			return;
+
+		pPlayer->m_LastSetSpectatorMode = Server()->Tick();
+		if(pMsg->m_SpectatorID != SPEC_FREEVIEW && !m_apPlayers[pMsg->m_SpectatorID])
+			SendChatTarget(ClientID, "Invalid spectator id used");
+		else
+			pPlayer->m_SpectatorID = pMsg->m_SpectatorID;
+	}
 	else if (MsgID == NETMSGTYPE_CL_CHANGEINFO || MsgID == NETMSGTYPE_CL_STARTINFO)
 	{
 		CNetMsg_Cl_ChangeInfo *pMsg = (CNetMsg_Cl_ChangeInfo *)pRawMsg;
 		
-		if(g_Config.m_SvSpamprotection && pPlayer->m_Last_ChangeInfo && pPlayer->m_Last_ChangeInfo+Server()->TickSpeed()*5 > Server()->Tick())
+		if(g_Config.m_SvSpamprotection && pPlayer->m_LastChangeInfo && pPlayer->m_LastChangeInfo+Server()->TickSpeed()*5 > Server()->Tick())
 			return;
 			
-		pPlayer->m_Last_ChangeInfo = Server()->Tick();
+		pPlayer->m_LastChangeInfo = Server()->Tick();
 		
 		pPlayer->m_TeeInfos.m_UseCustomColor = pMsg->m_UseCustomColor;
 		pPlayer->m_TeeInfos.m_ColorBody = pMsg->m_ColorBody;
@@ -818,19 +842,19 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
 	{
 		CNetMsg_Cl_Emoticon *pMsg = (CNetMsg_Cl_Emoticon *)pRawMsg;
 		
-		if(g_Config.m_SvSpamprotection && pPlayer->m_Last_Emote && pPlayer->m_Last_Emote+Server()->TickSpeed()*3 > Server()->Tick())
+		if(g_Config.m_SvSpamprotection && pPlayer->m_LastEmote && pPlayer->m_LastEmote+Server()->TickSpeed()*3 > Server()->Tick())
 			return;
 			
-		pPlayer->m_Last_Emote = Server()->Tick();
+		pPlayer->m_LastEmote = Server()->Tick();
 		
 		SendEmoticon(ClientID, pMsg->m_Emoticon);
 	}
 	else if (MsgID == NETMSGTYPE_CL_KILL && !m_World.m_Paused)
 	{
-		if(pPlayer->m_Last_Kill && pPlayer->m_Last_Kill+Server()->TickSpeed()*3 > Server()->Tick())
+		if(pPlayer->m_LastKill && pPlayer->m_LastKill+Server()->TickSpeed()*3 > Server()->Tick())
 			return;
 		
-		pPlayer->m_Last_Kill = Server()->Tick();
+		pPlayer->m_LastKill = Server()->Tick();
 		pPlayer->KillCharacter(WEAPON_SELF);
 		pPlayer->m_RespawnTick = Server()->Tick()+Server()->TickSpeed()*3;
 	}
diff --git a/src/game/server/player.cpp b/src/game/server/player.cpp
index 573d996d..7d2f4ad9 100644
--- a/src/game/server/player.cpp
+++ b/src/game/server/player.cpp
@@ -18,6 +18,7 @@ CPlayer::CPlayer(CGameContext *pGameServer, int ClientID, int Team)
 	Character = 0;
 	this->m_ClientID = ClientID;
 	m_Team = GameServer()->m_pController->ClampTeam(Team);
+	m_SpectatorID = SPEC_FREEVIEW;
 	m_LastActionTick = Server()->Tick();
 }
 
@@ -77,6 +78,23 @@ void CPlayer::Tick()
 		TryRespawn();
 }
 
+void CPlayer::PostTick()
+{
+	// update latency value
+	if(m_PlayerFlags&PLAYERFLAG_SCOREBOARD)
+	{
+		for(int i = 0; i < MAX_CLIENTS; ++i)
+		{
+			if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->GetTeam() != TEAM_SPECTATORS)
+				m_aActLatency[i] = GameServer()->m_apPlayers[i]->m_Latency.m_Min;
+		}
+	}
+
+	// update view pos for spectators
+	if(m_Team == TEAM_SPECTATORS && m_SpectatorID != SPEC_FREEVIEW && GameServer()->m_apPlayers[m_SpectatorID])
+		m_ViewPos = GameServer()->m_apPlayers[m_SpectatorID]->m_ViewPos;
+}
+
 void CPlayer::Snap(int SnappingClient)
 {
 #ifdef CONF_DEBUG
@@ -99,12 +117,6 @@ void CPlayer::Snap(int SnappingClient)
 	if(!pPlayerInfo)
 		return;
 
-	// update latency value
-	if(SnappingClient != -1 && m_Team != -1 && GameServer()->m_apPlayers[SnappingClient]->m_PlayerFlags&PLAYERFLAG_SCOREBOARD)
-	{
-		GameServer()->m_apPlayers[SnappingClient]->m_aActLatency[m_ClientID] = m_Latency.m_Min;
-	}
-
 	pPlayerInfo->m_Latency = SnappingClient == -1 ? m_Latency.m_Min : GameServer()->m_apPlayers[SnappingClient]->m_aActLatency[m_ClientID];
 	pPlayerInfo->m_Local = 0;
 	pPlayerInfo->m_ClientID = m_ClientID;
@@ -112,7 +124,18 @@ void CPlayer::Snap(int SnappingClient)
 	pPlayerInfo->m_Team = m_Team;
 
 	if(m_ClientID == SnappingClient)
-		pPlayerInfo->m_Local = 1;	
+		pPlayerInfo->m_Local = 1;
+
+	if(m_ClientID == SnappingClient && m_Team == TEAM_SPECTATORS && m_SpectatorID != SPEC_FREEVIEW)
+	{
+		CNetObj_SpectatorInfo *pSpectatorInfo = static_cast<CNetObj_SpectatorInfo *>(Server()->SnapNewItem(NETOBJTYPE_SPECTATORINFO, m_ClientID, sizeof(CNetObj_SpectatorInfo)));
+		if(!pSpectatorInfo)
+			return;
+
+		pSpectatorInfo->m_SpectatorID = m_SpectatorID;
+		pSpectatorInfo->m_X = m_ViewPos.x;
+		pSpectatorInfo->m_Y = m_ViewPos.y;
+	}
 }
 
 void CPlayer::OnDisconnect()
@@ -146,7 +169,7 @@ void CPlayer::OnDirectInput(CNetObj_PlayerInput *NewInput)
 	if(!Character && m_Team != TEAM_SPECTATORS && (NewInput->m_Fire&1))
 		m_Spawning = true;
 	
-	if(!Character && m_Team == TEAM_SPECTATORS)
+	if(!Character && m_Team == TEAM_SPECTATORS && m_SpectatorID == SPEC_FREEVIEW)
 		m_ViewPos = vec2(NewInput->m_TargetX, NewInput->m_TargetY);
 
 	// check for activity
diff --git a/src/game/server/player.h b/src/game/server/player.h
index f4d82d24..c638fae8 100644
--- a/src/game/server/player.h
+++ b/src/game/server/player.h
@@ -25,6 +25,7 @@ public:
 	int GetCID() const { return m_ClientID; };
 	
 	void Tick();
+	void PostTick();
 	void Snap(int SnappingClient);
 
 	void OnDirectInput(CNetObj_PlayerInput *NewInput);
@@ -43,18 +44,22 @@ public:
 
 	// used for snapping to just update latency if the scoreboard is active
 	int m_aActLatency[MAX_CLIENTS];
+
+	// used for spectator mode
+	int m_SpectatorID;
 	
 	//
 	int m_Vote;
 	int m_VotePos;
 	//
-	int m_Last_VoteCall;
-	int m_Last_VoteTry;
-	int m_Last_Chat;
-	int m_Last_SetTeam;
-	int m_Last_ChangeInfo;
-	int m_Last_Emote;
-	int m_Last_Kill;
+	int m_LastVoteCall;
+	int m_LastVoteTry;
+	int m_LastChat;
+	int m_LastSetTeam;
+	int m_LastSetSpectatorMode;
+	int m_LastChangeInfo;
+	int m_LastEmote;
+	int m_LastKill;
 	
 	// TODO: clean this up
 	struct 
@@ -76,6 +81,17 @@ public:
 		int m_TargetX;
 		int m_TargetY;
 	} m_LatestActivity;
+
+	// network latency calculations	
+	struct
+	{
+		int m_Accum;
+		int m_AccumMin;
+		int m_AccumMax;
+		int m_Avg;
+		int m_Min;
+		int m_Max;	
+	} m_Latency;
 	
 private:
 	CCharacter *Character;
@@ -88,17 +104,6 @@ private:
 	bool m_Spawning;
 	int m_ClientID;
 	int m_Team;
-
-	// network latency calculations	
-	struct
-	{
-		int m_Accum;
-		int m_AccumMin;
-		int m_AccumMax;
-		int m_Avg;
-		int m_Min;
-		int m_Max;	
-	} m_Latency;
 };
 
 #endif