I'm sorry, I haven't seen that you develop the mod, now I developed it on my own too.
From a47551c6daabd75c7eda0c3e56f697dbfe1a179e Mon Sep 17 00:00:00 2001
From: heinrich5991 <heinrich5991@gmail.com>
Date: Sat, 22 Aug 2015 17:33:27 +0200
Subject: [PATCH] Implement the 'CFT' mod, Capture The Flag without respawn
The basic idea is simple, don't respawn until either one team is dead or the
flag is captured.
Still needs some fine tuning wrt. initial joining.
---
datasrc/compile.py | 50 ++++++++++++++
datasrc/network.py | 8 +++
scripts/cmd5.py | 1 +
src/game/server/entities/character.cpp | 8 +--
src/game/server/gamecontext.cpp | 71 ++++++++++----------
src/game/server/gamecontroller.cpp | 51 ++++++++-------
src/game/server/gamecontroller.h | 1 +
src/game/server/gamemodes/ctf.cpp | 115 +++++++++++++++++++++++++++++++--
src/game/server/gamemodes/ctf.h | 6 ++
src/game/server/gamemodes/dm.cpp | 15 -----
src/game/server/gamemodes/dm.h | 13 ----
src/game/server/gamemodes/mod.cpp | 20 ------
src/game/server/gamemodes/mod.h | 16 -----
src/game/server/gamemodes/tdm.cpp | 52 ---------------
src/game/server/gamemodes/tdm.h | 16 -----
src/game/server/player.cpp | 70 ++++++++++++--------
src/game/server/player.h | 9 ++-
17 files changed, 292 insertions(+), 230 deletions(-)
delete mode 100644 src/game/server/gamemodes/dm.cpp
delete mode 100644 src/game/server/gamemodes/dm.h
delete mode 100644 src/game/server/gamemodes/mod.cpp
delete mode 100644 src/game/server/gamemodes/mod.h
delete mode 100644 src/game/server/gamemodes/tdm.cpp
delete mode 100644 src/game/server/gamemodes/tdm.h
diff --git a/datasrc/compile.py b/datasrc/compile.py
index 088e500..346e8f6 100644
--- a/datasrc/compile.py
+++ b/datasrc/compile.py
@@ -159,6 +159,56 @@ class CNetObjHandler
lines += ['#include <engine/message.h>']
lines += ['#include "protocol.h"']
+ lines += ["""
+int SnapTeam(int Team)
+{
+ switch(Team)
+ {
+ case TEAM_RED_DEAD:
+ case TEAM_BLUE_DEAD:
+ return TEAM_SPECTATORS;
+ default:
+ return Team;
+ }
+}
+
+bool IsSpectatorTeam(int Team)
+{
+ return SnapTeam(Team) == TEAM_SPECTATORS;
+}
+
+bool IsAliveTeam(int Team)
+{
+ return Team == TEAM_RED || Team == TEAM_BLUE;
+}
+
+int GameTeam(int Team)
+{
+ switch(Team)
+ {
+ case TEAM_RED_DEAD:
+ return TEAM_RED;
+ case TEAM_BLUE_DEAD:
+ return TEAM_BLUE;
+ default:
+ return Team;
+ }
+}
+
+int DeadTeam(int Team)
+{
+ switch(Team)
+ {
+ case TEAM_RED:
+ return TEAM_RED_DEAD;
+ case TEAM_BLUE:
+ return TEAM_BLUE_DEAD;
+ default:
+ return Team;
+ }
+}
+ """]
+
lines += ['CNetObjHandler::CNetObjHandler()']
lines += ['{']
lines += ['\tm_pMsgFailedOn = "";']
diff --git a/datasrc/network.py b/datasrc/network.py
index b2c42b3..8a699a8 100644
--- a/datasrc/network.py
+++ b/datasrc/network.py
@@ -23,6 +23,8 @@
TEAM_SPECTATORS=-1,
TEAM_RED,
TEAM_BLUE,
+ TEAM_RED_DEAD,
+ TEAM_BLUE_DEAD,
FLAG_MISSING=-3,
FLAG_ATSTAND,
@@ -30,6 +32,12 @@
SPEC_FREEVIEW=-1,
};
+
+int SnapTeam(int Team);
+int GameTeam(int Team);
+int DeadTeam(int Team);
+bool IsSpectatorTeam(int Team);
+bool IsAliveTeam(int Team);
'''
RawSource = '''
diff --git a/scripts/cmd5.py b/scripts/cmd5.py
index 68881d0..f347e32 100644
--- a/scripts/cmd5.py
+++ b/scripts/cmd5.py
@@ -32,4 +32,5 @@ def cstrip(lines):
#TODO 0.7: improve nethash creation
if hash == "e42d81cd67b8c7bc":
hash = "626fce9a778df4d4"
+hash = "626fce9a778df4d4"
print('#define GAME_NETVERSION_HASH "%s"' % hash)
diff --git a/src/game/server/entities/character.cpp b/src/game/server/entities/character.cpp
index f45100a..a98503e 100644
--- a/src/game/server/entities/character.cpp
+++ b/src/game/server/entities/character.cpp
@@ -526,7 +526,7 @@ void CCharacter::OnDirectInput(CNetObj_PlayerInput *pNewInput)
if(m_LatestInput.m_TargetX == 0 && m_LatestInput.m_TargetY == 0)
m_LatestInput.m_TargetY = -1;
- if(m_NumInputs > 2 && m_pPlayer->GetTeam() != TEAM_SPECTATORS)
+ if(m_NumInputs > 2 && !m_pPlayer->IsSpectator())
{
HandleWeaponSwitch();
FireWeapon();
@@ -552,7 +552,7 @@ void CCharacter::Tick()
if(m_pPlayer->m_ForceBalanced)
{
char Buf[128];
- str_format(Buf, sizeof(Buf), "You were moved to %s due to team balancing", GameServer()->m_pController->GetTeamName(m_pPlayer->GetTeam()));
+ str_format(Buf, sizeof(Buf), "You were moved to %s due to team balancing", GameServer()->m_pController->GetTeamName(m_pPlayer->GetGameTeam()));
GameServer()->SendBroadcast(Buf, m_pPlayer->GetCID());
m_pPlayer->m_ForceBalanced = false;
@@ -637,7 +637,7 @@ void CCharacter::TickDefered()
if(Events&COREEVENT_HOOK_HIT_NOHOOK) GameServer()->CreateSound(m_Pos, SOUND_HOOK_NOATTACH, Mask);
- if(m_pPlayer->GetTeam() == TEAM_SPECTATORS)
+ if(m_pPlayer->IsSpectator())
{
m_Pos.x = m_Input.m_TargetX;
m_Pos.y = m_Input.m_TargetY;
@@ -782,7 +782,7 @@ bool CCharacter::TakeDamage(vec2 Force, int Dmg, int From, int Weapon)
int Mask = CmaskOne(From);
for(int i = 0; i < MAX_CLIENTS; i++)
{
- if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->GetTeam() == TEAM_SPECTATORS && GameServer()->m_apPlayers[i]->m_SpectatorID == From)
+ if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->IsSpectator() && GameServer()->m_apPlayers[i]->m_SpectatorID == From)
Mask |= CmaskOne(i);
}
GameServer()->CreateSound(GameServer()->m_apPlayers[From]->m_ViewPos, SOUND_HIT, Mask);
diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp
index 897e348..bf3091c 100644
--- a/src/game/server/gamecontext.cpp
+++ b/src/game/server/gamecontext.cpp
@@ -9,10 +9,7 @@
#include <game/version.h>
#include <game/collision.h>
#include <game/gamecore.h>
-#include "gamemodes/dm.h"
-#include "gamemodes/tdm.h"
#include "gamemodes/ctf.h"
-#include "gamemodes/mod.h"
enum
{
@@ -257,7 +254,7 @@ void CGameContext::SendChat(int ChatterClientID, int Team, const char *pText)
// send to the clients
for(int i = 0; i < MAX_CLIENTS; i++)
{
- if(m_apPlayers[i] && m_apPlayers[i]->GetTeam() == Team)
+ if(m_apPlayers[i] && m_apPlayers[i]->GetGameTeam() == Team)
Server()->SendPackMsg(&Msg, MSGFLAG_VITAL|MSGFLAG_NORECORD, i);
}
}
@@ -397,8 +394,8 @@ void CGameContext::SwapTeams()
for(int i = 0; i < MAX_CLIENTS; ++i)
{
- if(m_apPlayers[i] && m_apPlayers[i]->GetTeam() != TEAM_SPECTATORS)
- m_apPlayers[i]->SetTeam(m_apPlayers[i]->GetTeam()^1, false);
+ if(m_apPlayers[i] && m_apPlayers[i]->GetGameTeam() != TEAM_SPECTATORS)
+ m_apPlayers[i]->SetGameTeam(m_apPlayers[i]->GetGameTeam()^1, false);
}
(void)m_pController->CheckTeamBalance();
@@ -447,7 +444,7 @@ void CGameContext::OnTick()
bool aVoteChecked[MAX_CLIENTS] = {0};
for(int i = 0; i < MAX_CLIENTS; i++)
{
- if(!m_apPlayers[i] || m_apPlayers[i]->GetTeam() == TEAM_SPECTATORS || aVoteChecked[i]) // don't count in votes by spectators
+ if(!m_apPlayers[i] || m_apPlayers[i]->GetGameTeam() == TEAM_SPECTATORS || aVoteChecked[i]) // don't count in votes by spectators
continue;
int ActVote = m_apPlayers[i]->m_Vote;
@@ -536,10 +533,10 @@ void CGameContext::OnClientEnter(int ClientID)
//world.insert_entity(&players[client_id]);
m_apPlayers[ClientID]->Respawn();
char aBuf[512];
- str_format(aBuf, sizeof(aBuf), "'%s' entered and joined the %s", Server()->ClientName(ClientID), m_pController->GetTeamName(m_apPlayers[ClientID]->GetTeam()));
+ str_format(aBuf, sizeof(aBuf), "'%s' entered and joined the %s", Server()->ClientName(ClientID), m_pController->GetTeamName(m_apPlayers[ClientID]->GetGameTeam()));
SendChat(-1, CGameContext::CHAT_ALL, aBuf);
- str_format(aBuf, sizeof(aBuf), "team_join player='%d:%s' team=%d", ClientID, Server()->ClientName(ClientID), m_apPlayers[ClientID]->GetTeam());
+ str_format(aBuf, sizeof(aBuf), "team_join player='%d:%s' team=%d", ClientID, Server()->ClientName(ClientID), m_apPlayers[ClientID]->GetGameTeam());
Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf);
m_VoteUpdate = true;
@@ -551,6 +548,7 @@ void CGameContext::OnClientConnected(int ClientID)
const int StartTeam = g_Config.m_SvTournamentMode ? TEAM_SPECTATORS : m_pController->GetAutoTeam(ClientID);
m_apPlayers[ClientID] = new(ClientID) CPlayer(this, ClientID, StartTeam);
+ m_apPlayers[ClientID]->Revive();
//players[client_id].init(client_id);
//players[client_id].client_id = client_id;
@@ -616,7 +614,7 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
return;
CNetMsg_Cl_Say *pMsg = (CNetMsg_Cl_Say *)pRawMsg;
- int Team = pMsg->m_Team ? pPlayer->GetTeam() : CGameContext::CHAT_ALL;
+ int Team = pMsg->m_Team ? pPlayer->GetGameTeam() : CGameContext::CHAT_ALL;
// trim right and set maximum length to 128 utf8-characters
int Length = 0;
@@ -661,7 +659,7 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
int64 Now = Server()->Tick();
pPlayer->m_LastVoteTry = Now;
- if(pPlayer->GetTeam() == TEAM_SPECTATORS)
+ if(pPlayer->GetGameTeam() == TEAM_SPECTATORS)
{
SendChatTarget(ClientID, "Spectators aren't allowed to start a vote.");
return;
@@ -724,7 +722,7 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
{
int PlayerNum = 0;
for(int i = 0; i < MAX_CLIENTS; ++i)
- if(m_apPlayers[i] && m_apPlayers[i]->GetTeam() != TEAM_SPECTATORS)
+ if(m_apPlayers[i] && m_apPlayers[i]->GetGameTeam() != TEAM_SPECTATORS)
++PlayerNum;
if(PlayerNum < g_Config.m_SvVoteKickMin)
@@ -775,7 +773,7 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
}
int SpectateID = str_toint(pMsg->m_Value);
- if(SpectateID < 0 || SpectateID >= MAX_CLIENTS || !m_apPlayers[SpectateID] || m_apPlayers[SpectateID]->GetTeam() == TEAM_SPECTATORS)
+ if(SpectateID < 0 || SpectateID >= MAX_CLIENTS || !m_apPlayers[SpectateID] || m_apPlayers[SpectateID]->GetGameTeam() == TEAM_SPECTATORS)
{
SendChatTarget(ClientID, "Invalid client id to move");
return;
@@ -820,8 +818,16 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
else if (MsgID == NETMSGTYPE_CL_SETTEAM && !m_World.m_Paused)
{
CNetMsg_Cl_SetTeam *pMsg = (CNetMsg_Cl_SetTeam *)pRawMsg;
+ CNetMsg_Cl_SetTeam Copy = *pMsg;
+ pMsg = &Copy;
- if(pPlayer->GetTeam() == pMsg->m_Team || (g_Config.m_SvSpamprotection && pPlayer->m_LastSetTeam && pPlayer->m_LastSetTeam+Server()->TickSpeed()*3 > Server()->Tick()))
+ // The button for joining the spectators is not
+ // available in the client when the player is dead. If
+ // you join your own team, join the spectators instead.
+ if(pPlayer->GetGameTeam() == pMsg->m_Team)
+ pMsg->m_Team = TEAM_SPECTATORS;
+
+ if(pPlayer->GetGameTeam() == pMsg->m_Team || (g_Config.m_SvSpamprotection && pPlayer->m_LastSetTeam && pPlayer->m_LastSetTeam+Server()->TickSpeed()*3 > Server()->Tick()))
return;
if(pMsg->m_Team != TEAM_SPECTATORS && m_LockTeams)
@@ -847,9 +853,9 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
if(m_pController->CanChangeTeam(pPlayer, pMsg->m_Team))
{
pPlayer->m_LastSetTeam = Server()->Tick();
- if(pPlayer->GetTeam() == TEAM_SPECTATORS || pMsg->m_Team == TEAM_SPECTATORS)
+ if(pPlayer->GetGameTeam() == TEAM_SPECTATORS || pMsg->m_Team == TEAM_SPECTATORS)
m_VoteUpdate = true;
- pPlayer->SetTeam(pMsg->m_Team);
+ pPlayer->SetGameTeam(pMsg->m_Team);
(void)m_pController->CheckTeamBalance();
pPlayer->m_TeamChangeTick = Server()->Tick();
}
@@ -867,12 +873,12 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
{
CNetMsg_Cl_SetSpectatorMode *pMsg = (CNetMsg_Cl_SetSpectatorMode *)pRawMsg;
- if(pPlayer->GetTeam() != TEAM_SPECTATORS || pPlayer->m_SpectatorID == pMsg->m_SpectatorID || ClientID == pMsg->m_SpectatorID ||
+ if(!pPlayer->IsSpectator() || 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] || m_apPlayers[pMsg->m_SpectatorID]->GetTeam() == TEAM_SPECTATORS))
+ if(pMsg->m_SpectatorID != SPEC_FREEVIEW && (!m_apPlayers[pMsg->m_SpectatorID] || m_apPlayers[pMsg->m_SpectatorID]->IsSpectator()))
SendChatTarget(ClientID, "Invalid spectator id used");
else
pPlayer->m_SpectatorID = pMsg->m_SpectatorID;
@@ -1111,7 +1117,7 @@ void CGameContext::ConSetTeam(IConsole::IResult *pResult, void *pUserData)
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
pSelf->m_apPlayers[ClientID]->m_TeamChangeTick = pSelf->Server()->Tick()+pSelf->Server()->TickSpeed()*Delay*60;
- pSelf->m_apPlayers[ClientID]->SetTeam(Team);
+ pSelf->m_apPlayers[ClientID]->SetGameTeam(Team);
(void)pSelf->m_pController->CheckTeamBalance();
}
@@ -1126,7 +1132,7 @@ void CGameContext::ConSetTeamAll(IConsole::IResult *pResult, void *pUserData)
for(int i = 0; i < MAX_CLIENTS; ++i)
if(pSelf->m_apPlayers[i])
- pSelf->m_apPlayers[i]->SetTeam(Team, false);
+ pSelf->m_apPlayers[i]->SetGameTeam(Team, false);
(void)pSelf->m_pController->CheckTeamBalance();
}
@@ -1147,7 +1153,7 @@ void CGameContext::ConShuffleTeams(IConsole::IResult *pResult, void *pUserData)
int CounterBlue = 0;
int PlayerTeam = 0;
for(int i = 0; i < MAX_CLIENTS; ++i)
- if(pSelf->m_apPlayers[i] && pSelf->m_apPlayers[i]->GetTeam() != TEAM_SPECTATORS)
+ if(pSelf->m_apPlayers[i] && pSelf->m_apPlayers[i]->GetGameTeam() != TEAM_SPECTATORS)
++PlayerTeam;
PlayerTeam = (PlayerTeam+1)/2;
@@ -1155,22 +1161,22 @@ void CGameContext::ConShuffleTeams(IConsole::IResult *pResult, void *pUserData)
for(int i = 0; i < MAX_CLIENTS; ++i)
{
- if(pSelf->m_apPlayers[i] && pSelf->m_apPlayers[i]->GetTeam() != TEAM_SPECTATORS)
+ if(pSelf->m_apPlayers[i] && pSelf->m_apPlayers[i]->GetGameTeam() != TEAM_SPECTATORS)
{
if(CounterRed == PlayerTeam)
- pSelf->m_apPlayers[i]->SetTeam(TEAM_BLUE, false);
+ pSelf->m_apPlayers[i]->SetGameTeam(TEAM_BLUE, false);
else if(CounterBlue == PlayerTeam)
- pSelf->m_apPlayers[i]->SetTeam(TEAM_RED, false);
+ pSelf->m_apPlayers[i]->SetGameTeam(TEAM_RED, false);
else
{
if(rand() % 2)
{
- pSelf->m_apPlayers[i]->SetTeam(TEAM_BLUE, false);
+ pSelf->m_apPlayers[i]->SetGameTeam(TEAM_BLUE, false);
++CounterBlue;
}
else
{
- pSelf->m_apPlayers[i]->SetTeam(TEAM_RED, false);
+ pSelf->m_apPlayers[i]->SetGameTeam(TEAM_RED, false);
++CounterRed;
}
}
@@ -1380,7 +1386,7 @@ void CGameContext::ConForceVote(IConsole::IResult *pResult, void *pUserData)
else if(str_comp_nocase(pType, "spectate") == 0)
{
int SpectateID = str_toint(pValue);
- if(SpectateID < 0 || SpectateID >= MAX_CLIENTS || !pSelf->m_apPlayers[SpectateID] || pSelf->m_apPlayers[SpectateID]->GetTeam() == TEAM_SPECTATORS)
+ if(SpectateID < 0 || SpectateID >= MAX_CLIENTS || !pSelf->m_apPlayers[SpectateID] || pSelf->m_apPlayers[SpectateID]->GetGameTeam() == TEAM_SPECTATORS)
{
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "Invalid client id to move");
return;
@@ -1489,14 +1495,7 @@ void CGameContext::OnInit(/*class IKernel *pKernel*/)
//players = new CPlayer[MAX_CLIENTS];
// select gametype
- if(str_comp(g_Config.m_SvGametype, "mod") == 0)
- m_pController = new CGameControllerMOD(this);
- else if(str_comp(g_Config.m_SvGametype, "ctf") == 0)
- m_pController = new CGameControllerCTF(this);
- else if(str_comp(g_Config.m_SvGametype, "tdm") == 0)
- m_pController = new CGameControllerTDM(this);
- else
- m_pController = new CGameControllerDM(this);
+ m_pController = new CGameControllerCTF(this);
// setup core world
//for(int i = 0; i < MAX_CLIENTS; i++)
@@ -1585,7 +1584,7 @@ bool CGameContext::IsClientReady(int ClientID)
bool CGameContext::IsClientPlayer(int ClientID)
{
- return m_apPlayers[ClientID] && m_apPlayers[ClientID]->GetTeam() == TEAM_SPECTATORS ? false : true;
+ return m_apPlayers[ClientID] && m_apPlayers[ClientID]->GetGameTeam() == TEAM_SPECTATORS ? false : true;
}
const char *CGameContext::GameType() { return m_pController && m_pController->m_pGameType ? m_pController->m_pGameType : ""; }
diff --git a/src/game/server/gamecontroller.cpp b/src/game/server/gamecontroller.cpp
index 68e5508..6bd3a5b 100644
--- a/src/game/server/gamecontroller.cpp
+++ b/src/game/server/gamecontroller.cpp
@@ -48,7 +48,7 @@ float IGameController::EvaluateSpawnPos(CSpawnEval *pEval, vec2 Pos)
{
// team mates are not as dangerous as enemies
float Scoremod = 1.0f;
- if(pEval->m_FriendlyTeam != -1 && pC->GetPlayer()->GetTeam() == pEval->m_FriendlyTeam)
+ if(pEval->m_FriendlyTeam != -1 && pC->GetPlayer()->GetGameTeam() == pEval->m_FriendlyTeam)
Scoremod = 0.5f;
float d = distance(Pos, pC->m_Pos);
@@ -326,10 +326,10 @@ void IGameController::OnPlayerInfoChange(class CPlayer *pP)
if(IsTeamplay())
{
pP->m_TeeInfos.m_UseCustomColor = 1;
- if(pP->GetTeam() >= TEAM_RED && pP->GetTeam() <= TEAM_BLUE)
+ if(pP->GetGameTeam() >= TEAM_RED && pP->GetGameTeam() <= TEAM_BLUE)
{
- pP->m_TeeInfos.m_ColorBody = aTeamColors[pP->GetTeam()];
- pP->m_TeeInfos.m_ColorFeet = aTeamColors[pP->GetTeam()];
+ pP->m_TeeInfos.m_ColorBody = aTeamColors[pP->GetGameTeam()];
+ pP->m_TeeInfos.m_ColorFeet = aTeamColors[pP->GetGameTeam()];
}
else
{
@@ -349,7 +349,7 @@ int IGameController::OnCharacterDeath(class CCharacter *pVictim, class CPlayer *
pVictim->GetPlayer()->m_Score--; // suicide
else
{
- if(IsTeamplay() && pVictim->GetPlayer()->GetTeam() == pKiller->GetTeam())
+ if(IsTeamplay() && pVictim->GetPlayer()->GetGameTeam() == pKiller->GetGameTeam())
pKiller->m_Score--; // teamkill
else
pKiller->m_Score++; // normal kill
@@ -411,7 +411,7 @@ bool IGameController::IsFriendlyFire(int ClientID1, int ClientID2)
if(!GameServer()->m_apPlayers[ClientID1] || !GameServer()->m_apPlayers[ClientID2])
return false;
- if(GameServer()->m_apPlayers[ClientID1]->GetTeam() == GameServer()->m_apPlayers[ClientID2]->GetTeam())
+ if(GameServer()->m_apPlayers[ClientID1]->GetGameTeam() == GameServer()->m_apPlayers[ClientID2]->GetGameTeam())
return true;
}
@@ -475,12 +475,12 @@ void IGameController::Tick()
float aPScore[MAX_CLIENTS] = {0.0f};
for(int i = 0; i < MAX_CLIENTS; i++)
{
- if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->GetTeam() != TEAM_SPECTATORS)
+ if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->GetGameTeam() != TEAM_SPECTATORS)
{
- aT[GameServer()->m_apPlayers[i]->GetTeam()]++;
+ aT[GameServer()->m_apPlayers[i]->GetGameTeam()]++;
aPScore[i] = GameServer()->m_apPlayers[i]->m_Score*Server()->TickSpeed()*60.0f/
(Server()->Tick()-GameServer()->m_apPlayers[i]->m_ScoreStartTick);
- aTScore[GameServer()->m_apPlayers[i]->GetTeam()] += aPScore[i];
+ aTScore[GameServer()->m_apPlayers[i]->GetGameTeam()] += aPScore[i];
}
}
@@ -499,7 +499,7 @@ void IGameController::Tick()
if(!GameServer()->m_apPlayers[i] || !CanBeMovedOnBalance(i))
continue;
// remember the player who would cause lowest score-difference
- if(GameServer()->m_apPlayers[i]->GetTeam() == M && (!pP || absolute((aTScore[M^1]+aPScore[i]) - (aTScore[M]-aPScore[i])) < PD))
+ if(GameServer()->m_apPlayers[i]->GetGameTeam() == M && (!pP || absolute((aTScore[M^1]+aPScore[i]) - (aTScore[M]-aPScore[i])) < PD))
{
pP = GameServer()->m_apPlayers[i];
PD = absolute((aTScore[M^1]+aPScore[i]) - (aTScore[M]-aPScore[i]));
@@ -508,7 +508,8 @@ void IGameController::Tick()
// move the player to the other team
int Temp = pP->m_LastActionTick;
- pP->SetTeam(M^1);
+ pP->SetGameTeam(M^1);
+ pP->Revive();
pP->m_LastActionTick = Temp;
pP->Respawn();
@@ -532,7 +533,7 @@ void IGameController::Tick()
break;
}
#endif
- if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->GetTeam() != TEAM_SPECTATORS && !Server()->IsAuthed(i))
+ if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->GetGameTeam() != TEAM_SPECTATORS && !Server()->IsAuthed(i))
{
if(Server()->Tick() > GameServer()->m_apPlayers[i]->m_LastActionTick+g_Config.m_SvInactiveKickTime*Server()->TickSpeed()*60)
{
@@ -541,7 +542,7 @@ void IGameController::Tick()
case 0:
{
// move player to spectator
- GameServer()->m_apPlayers[i]->SetTeam(TEAM_SPECTATORS);
+ GameServer()->m_apPlayers[i]->SetGameTeam(TEAM_SPECTATORS);
}
break;
case 1:
@@ -549,12 +550,12 @@ void IGameController::Tick()
// move player to spectator if the reserved slots aren't filled yet, kick him otherwise
int Spectators = 0;
for(int j = 0; j < MAX_CLIENTS; ++j)
- if(GameServer()->m_apPlayers[j] && GameServer()->m_apPlayers[j]->GetTeam() == TEAM_SPECTATORS)
+ if(GameServer()->m_apPlayers[j] && GameServer()->m_apPlayers[j]->GetGameTeam() == TEAM_SPECTATORS)
++Spectators;
if(Spectators >= g_Config.m_SvSpectatorSlots)
Server()->Kick(i, "Kicked for inactivity");
else
- GameServer()->m_apPlayers[i]->SetTeam(TEAM_SPECTATORS);
+ GameServer()->m_apPlayers[i]->SetGameTeam(TEAM_SPECTATORS);
}
break;
case 2:
@@ -612,8 +613,8 @@ int IGameController::GetAutoTeam(int NotThisID)
{
if(GameServer()->m_apPlayers[i] && i != NotThisID)
{
- if(GameServer()->m_apPlayers[i]->GetTeam() >= TEAM_RED && GameServer()->m_apPlayers[i]->GetTeam() <= TEAM_BLUE)
- aNumplayers[GameServer()->m_apPlayers[i]->GetTeam()]++;
+ if(GameServer()->m_apPlayers[i]->GetGameTeam() >= TEAM_RED && GameServer()->m_apPlayers[i]->GetGameTeam() <= TEAM_BLUE)
+ aNumplayers[GameServer()->m_apPlayers[i]->GetGameTeam()]++;
}
}
@@ -628,7 +629,7 @@ int IGameController::GetAutoTeam(int NotThisID)
bool IGameController::CanJoinTeam(int Team, int NotThisID)
{
- if(Team == TEAM_SPECTATORS || (GameServer()->m_apPlayers[NotThisID] && GameServer()->m_apPlayers[NotThisID]->GetTeam() != TEAM_SPECTATORS))
+ if(Team == TEAM_SPECTATORS || (GameServer()->m_apPlayers[NotThisID] && GameServer()->m_apPlayers[NotThisID]->GetGameTeam() != TEAM_SPECTATORS))
return true;
int aNumplayers[2] = {0,0};
@@ -636,8 +637,8 @@ bool IGameController::CanJoinTeam(int Team, int NotThisID)
{
if(GameServer()->m_apPlayers[i] && i != NotThisID)
{
- if(GameServer()->m_apPlayers[i]->GetTeam() >= TEAM_RED && GameServer()->m_apPlayers[i]->GetTeam() <= TEAM_BLUE)
- aNumplayers[GameServer()->m_apPlayers[i]->GetTeam()]++;
+ if(GameServer()->m_apPlayers[i]->GetGameTeam() >= TEAM_RED && GameServer()->m_apPlayers[i]->GetGameTeam() <= TEAM_BLUE)
+ aNumplayers[GameServer()->m_apPlayers[i]->GetGameTeam()]++;
}
}
@@ -653,8 +654,8 @@ bool IGameController::CheckTeamBalance()
for(int i = 0; i < MAX_CLIENTS; i++)
{
CPlayer *pP = GameServer()->m_apPlayers[i];
- if(pP && pP->GetTeam() != TEAM_SPECTATORS)
- aT[pP->GetTeam()]++;
+ if(pP && pP->GetGameTeam() != TEAM_SPECTATORS)
+ aT[pP->GetGameTeam()]++;
}
char aBuf[256];
@@ -685,13 +686,13 @@ bool IGameController::CanChangeTeam(CPlayer *pPlayer, int JoinTeam)
for(int i = 0; i < MAX_CLIENTS; i++)
{
CPlayer *pP = GameServer()->m_apPlayers[i];
- if(pP && pP->GetTeam() != TEAM_SPECTATORS)
- aT[pP->GetTeam()]++;
+ if(pP && pP->GetGameTeam() != TEAM_SPECTATORS)
+ aT[pP->GetGameTeam()]++;
}
// simulate what would happen if changed team
aT[JoinTeam]++;
- if (pPlayer->GetTeam() != TEAM_SPECTATORS)
+ if (pPlayer->GetGameTeam() != TEAM_SPECTATORS)
aT[JoinTeam^1]--;
// there is a player-difference of at least 2
diff --git a/src/game/server/gamecontroller.h b/src/game/server/gamecontroller.h
index 66ff1dc..c1d01c9 100644
--- a/src/game/server/gamecontroller.h
+++ b/src/game/server/gamecontroller.h
@@ -144,6 +144,7 @@ class IGameController
int ClampTeam(int Team);
virtual void PostReset();
+ virtual void ReviveCheck() = 0;
};
#endif
diff --git a/src/game/server/gamemodes/ctf.cpp b/src/game/server/gamemodes/ctf.cpp
index 140dadf..1835a6b 100644
--- a/src/game/server/gamemodes/ctf.cpp
+++ b/src/game/server/gamemodes/ctf.cpp
@@ -15,8 +15,9 @@ CGameControllerCTF::CGameControllerCTF(class CGameContext *pGameServer)
{
m_apFlags[0] = 0;
m_apFlags[1] = 0;
- m_pGameType = "CTF";
+ m_pGameType = "CFT";
m_GameFlags = GAMEFLAG_TEAMS|GAMEFLAG_FLAGS;
+ m_BothTeamsPresent = false;
}
bool CGameControllerCTF::OnEntity(int Index, vec2 Pos)
@@ -56,13 +57,38 @@ int CGameControllerCTF::OnCharacterDeath(class CCharacter *pVictim, class CPlaye
F->m_pCarryingCharacter = 0;
F->m_Vel = vec2(0,0);
- if(pKiller && pKiller->GetTeam() != pVictim->GetPlayer()->GetTeam())
+ if(pKiller && pKiller->GetGameTeam() != pVictim->GetPlayer()->GetGameTeam())
pKiller->m_Score++;
HadFlag |= 1;
}
}
+ // Don't mark the player as dead in case of team changes
+ if(WeaponID != WEAPON_GAME)
+ {
+ CPlayer *pVictimPlayer = pVictim->GetPlayer();
+ pVictimPlayer->SetTeamSimple(DeadTeam(pVictimPlayer->GetGameTeam()));
+
+ int NewSpectatorID;
+ if(pKiller && pKiller->GetCID() != pVictimPlayer->GetCID())
+ NewSpectatorID = pKiller->GetCID();
+ else
+ NewSpectatorID = SPEC_FREEVIEW;
+
+ pVictimPlayer->m_SpectatorID = NewSpectatorID;
+
+ for(int i = 0; i < MAX_CLIENTS; i++)
+ {
+ CPlayer *pPlayer = GameServer()->m_apPlayers[i];
+ if(!pPlayer)
+ continue;
+ if(pPlayer->m_SpectatorID == pVictimPlayer->GetCID())
+ pPlayer->m_SpectatorID = NewSpectatorID;
+ }
+ }
+ ReviveCheck();
+
return HadFlag;
}
@@ -197,6 +223,8 @@ void CGameControllerCTF::Tick()
m_apFlags[i]->Reset();
GameServer()->CreateSoundGlobal(SOUND_CTF_CAPTURE);
+
+ Revive();
}
}
}
@@ -206,10 +234,10 @@ void CGameControllerCTF::Tick()
int Num = GameServer()->m_World.FindEntities(F->m_Pos, CFlag::ms_PhysSize, (CEntity**)apCloseCCharacters, MAX_CLIENTS, CGameWorld::ENTTYPE_CHARACTER);
for(int i = 0; i < Num; i++)
{
- if(!apCloseCCharacters[i]->IsAlive() || apCloseCCharacters[i]->GetPlayer()->GetTeam() == TEAM_SPECTATORS || GameServer()->Collision()->IntersectLine(F->m_Pos, apCloseCCharacters[i]->m_Pos, NULL, NULL))
+ if(!apCloseCCharacters[i]->IsAlive() || apCloseCCharacters[i]->GetPlayer()->IsSpectator() || GameServer()->Collision()->IntersectLine(F->m_Pos, apCloseCCharacters[i]->m_Pos, NULL, NULL))
continue;
- if(apCloseCCharacters[i]->GetPlayer()->GetTeam() == F->m_Team)
+ if(apCloseCCharacters[i]->GetPlayer()->GetGameTeam() == F->m_Team)
{
// return the flag
if(!F->m_AtStand)
@@ -252,9 +280,9 @@ void CGameControllerCTF::Tick()
if(!pPlayer)
continue;
- if(pPlayer->GetTeam() == TEAM_SPECTATORS && pPlayer->m_SpectatorID != SPEC_FREEVIEW && GameServer()->m_apPlayers[pPlayer->m_SpectatorID] && GameServer()->m_apPlayers[pPlayer->m_SpectatorID]->GetTeam() == fi)
+ if(pPlayer->IsSpectator() && pPlayer->m_SpectatorID != SPEC_FREEVIEW && GameServer()->m_apPlayers[pPlayer->m_SpectatorID] && GameServer()->m_apPlayers[pPlayer->m_SpectatorID]->GetGameTeam() == fi)
GameServer()->CreateSoundGlobal(SOUND_CTF_GRAB_EN, c);
- else if(pPlayer->GetTeam() == fi)
+ else if(pPlayer->GetGameTeam() == fi)
GameServer()->CreateSoundGlobal(SOUND_CTF_GRAB_EN, c);
else
GameServer()->CreateSoundGlobal(SOUND_CTF_GRAB_PL, c);
@@ -280,4 +308,79 @@ void CGameControllerCTF::Tick()
}
}
}
+
+ {
+ int TeamAlive = TEAM_SPECTATORS;
+ bool OnlyOneTeamAlive = true;
+ for(int i = 0; i < MAX_CLIENTS; i++)
+ {
+ CPlayer *pPlayer = GameServer()->m_apPlayers[i];
+ if(!pPlayer || pPlayer->GetGameTeam() == TEAM_SPECTATORS)
+ continue;
+ if(!pPlayer->IsDeadTeam() && pPlayer)
+ {
+ if(TeamAlive == TEAM_SPECTATORS)
+ TeamAlive = pPlayer->GetGameTeam();
+ else if(TeamAlive != pPlayer->GetGameTeam())
+ OnlyOneTeamAlive = false;
+ }
+ }
+
+ if(OnlyOneTeamAlive)
+ {
+ if(m_BothTeamsPresent)
+ {
+ char aBuf[64];
+ str_format(aBuf, sizeof(aBuf), "The %s team eliminated all enemies", TeamAlive ? "blue" : "red");
+ GameServer()->SendChat(-1, -2, aBuf);
+
+ for(int i = 0; i < 2; i++)
+ if(m_apFlags[i])
+ m_apFlags[i]->Reset();
+
+ m_aTeamscore[TeamAlive] += 100;
+
+ GameServer()->CreateSoundGlobal(SOUND_CTF_CAPTURE);
+ }
+
+ Revive();
+ }
+
+ bool aTeamsPresent[2] = { false, false };
+ for(int i = 0; i < MAX_CLIENTS; i++)
+ {
+ CPlayer *pPlayer = GameServer()->m_apPlayers[i];
+ if(!pPlayer || pPlayer->GetGameTeam() == TEAM_SPECTATORS)
+ continue;
+ aTeamsPresent[pPlayer->GetGameTeam()] = true;
+ }
+ m_BothTeamsPresent = aTeamsPresent[TEAM_RED] && aTeamsPresent[TEAM_BLUE];
+ }
+}
+
+void CGameControllerCTF::ReviveCheck()
+{
+ bool Respawn = true;
+ for(int i = 0; i < MAX_CLIENTS && Respawn; i++)
+ {
+ CPlayer *pPlayer = GameServer()->m_apPlayers[i];
+ if(!pPlayer)
+ continue;
+ if(!pPlayer->IsDeadTeam())
+ Respawn = false;
+ }
+
+ if(Respawn)
+ Revive();
+}
+
+void CGameControllerCTF::Revive()
+{
+ for(int i = 0; i < MAX_CLIENTS; i++)
+ {
+ CPlayer *pPlayer = GameServer()->m_apPlayers[i];
+ if(!pPlayer)
+ continue;
+ pPlayer->Revive();
+ }
}
diff --git a/src/game/server/gamemodes/ctf.h b/src/game/server/gamemodes/ctf.h
index 72747ed..dfe4322 100644
--- a/src/game/server/gamemodes/ctf.h
+++ b/src/game/server/gamemodes/ctf.h
@@ -18,6 +18,12 @@ class CGameControllerCTF : public IGameController
virtual bool OnEntity(int Index, vec2 Pos);
virtual int OnCharacterDeath(class CCharacter *pVictim, class CPlayer *pKiller, int Weapon);
+
+ virtual void ReviveCheck();
+ void Revive();
+
+private:
+ bool m_BothTeamsPresent;
};
#endif
diff --git a/src/game/server/gamemodes/dm.cpp b/src/game/server/gamemodes/dm.cpp
deleted file mode 100644
index bdca4c9..0000000
--- a/src/game/server/gamemodes/dm.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-/* (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 "dm.h"
-
-
-CGameControllerDM::CGameControllerDM(class CGameContext *pGameServer)
-: IGameController(pGameServer)
-{
- m_pGameType = "DM";
-}
-
-void CGameControllerDM::Tick()
-{
- IGameController::Tick();
-}
diff --git a/src/game/server/gamemodes/dm.h b/src/game/server/gamemodes/dm.h
deleted file mode 100644
index e88fad0..0000000
--- a/src/game/server/gamemodes/dm.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/* (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_SERVER_GAMEMODES_DM_H
-#define GAME_SERVER_GAMEMODES_DM_H
-#include <game/server/gamecontroller.h>
-
-class CGameControllerDM : public IGameController
-{
-public:
- CGameControllerDM(class CGameContext *pGameServer);
- virtual void Tick();
-};
-#endif
diff --git a/src/game/server/gamemodes/mod.cpp b/src/game/server/gamemodes/mod.cpp
deleted file mode 100644
index eb8fd7c..0000000
--- a/src/game/server/gamemodes/mod.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-/* (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 "mod.h"
-
-CGameControllerMOD::CGameControllerMOD(class CGameContext *pGameServer)
-: IGameController(pGameServer)
-{
- // Exchange this to a string that identifies your game mode.
- // DM, TDM and CTF are reserved for teeworlds original modes.
- m_pGameType = "MOD";
-
- //m_GameFlags = GAMEFLAG_TEAMS; // GAMEFLAG_TEAMS makes it a two-team gamemode
-}
-
-void CGameControllerMOD::Tick()
-{
- // this is the main part of the gamemode, this function is run every tick
-
- IGameController::Tick();
-}
diff --git a/src/game/server/gamemodes/mod.h b/src/game/server/gamemodes/mod.h
deleted file mode 100644
index 847d35f..0000000
--- a/src/game/server/gamemodes/mod.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/* (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_SERVER_GAMEMODES_MOD_H
-#define GAME_SERVER_GAMEMODES_MOD_H
-#include <game/server/gamecontroller.h>
-
-// you can subclass GAMECONTROLLER_CTF, GAMECONTROLLER_TDM etc if you want
-// todo a modification with their base as well.
-class CGameControllerMOD : public IGameController
-{
-public:
- CGameControllerMOD(class CGameContext *pGameServer);
- virtual void Tick();
- // add more virtual functions here if you wish
-};
-#endif
diff --git a/src/game/server/gamemodes/tdm.cpp b/src/game/server/gamemodes/tdm.cpp
deleted file mode 100644
index 373bbd0..0000000
--- a/src/game/server/gamemodes/tdm.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/* (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/shared/config.h>
-
-#include <game/server/entities/character.h>
-#include <game/server/player.h>
-#include "tdm.h"
-
-CGameControllerTDM::CGameControllerTDM(class CGameContext *pGameServer) : IGameController(pGameServer)
-{
- m_pGameType = "TDM";
- m_GameFlags = GAMEFLAG_TEAMS;
-}
-
-int CGameControllerTDM::OnCharacterDeath(class CCharacter *pVictim, class CPlayer *pKiller, int Weapon)
-{
- IGameController::OnCharacterDeath(pVictim, pKiller, Weapon);
-
-
- if(pKiller && Weapon != WEAPON_GAME)
- {
- // do team scoring
- if(pKiller == pVictim->GetPlayer() || pKiller->GetTeam() == pVictim->GetPlayer()->GetTeam())
- m_aTeamscore[pKiller->GetTeam()&1]--; // klant arschel
- else
- m_aTeamscore[pKiller->GetTeam()&1]++; // good shit
- }
-
- pVictim->GetPlayer()->m_RespawnTick = max(pVictim->GetPlayer()->m_RespawnTick, Server()->Tick()+Server()->TickSpeed()*g_Config.m_SvRespawnDelayTDM);
-
- return 0;
-}
-
-void CGameControllerTDM::Snap(int SnappingClient)
-{
- IGameController::Snap(SnappingClient);
-
- CNetObj_GameData *pGameDataObj = (CNetObj_GameData *)Server()->SnapNewItem(NETOBJTYPE_GAMEDATA, 0, sizeof(CNetObj_GameData));
- if(!pGameDataObj)
- return;
-
- pGameDataObj->m_TeamscoreRed = m_aTeamscore[TEAM_RED];
- pGameDataObj->m_TeamscoreBlue = m_aTeamscore[TEAM_BLUE];
-
- pGameDataObj->m_FlagCarrierRed = 0;
- pGameDataObj->m_FlagCarrierBlue = 0;
-}
-
-void CGameControllerTDM::Tick()
-{
- IGameController::Tick();
-}
diff --git a/src/game/server/gamemodes/tdm.h b/src/game/server/gamemodes/tdm.h
deleted file mode 100644
index 297b48c..0000000
--- a/src/game/server/gamemodes/tdm.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/* (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_SERVER_GAMEMODES_TDM_H
-#define GAME_SERVER_GAMEMODES_TDM_H
-#include <game/server/gamecontroller.h>
-
-class CGameControllerTDM : public IGameController
-{
-public:
- CGameControllerTDM(class CGameContext *pGameServer);
-
- int OnCharacterDeath(class CCharacter *pVictim, class CPlayer *pKiller, int Weapon);
- virtual void Snap(int SnappingClient);
- virtual void Tick();
-};
-#endif
diff --git a/src/game/server/player.cpp b/src/game/server/player.cpp
index 4b37385..71219b6 100644
--- a/src/game/server/player.cpp
+++ b/src/game/server/player.cpp
@@ -17,10 +17,9 @@ CPlayer::CPlayer(CGameContext *pGameServer, int ClientID, int Team)
m_ScoreStartTick = Server()->Tick();
m_pCharacter = 0;
m_ClientID = ClientID;
- m_Team = GameServer()->m_pController->ClampTeam(Team);
- m_SpectatorID = SPEC_FREEVIEW;
m_LastActionTick = Server()->Tick();
m_TeamChangeTick = Server()->Tick();
+ SetTeamSimple(DeadTeam(Team), true);
}
CPlayer::~CPlayer()
@@ -62,7 +61,7 @@ void CPlayer::Tick()
if(!GameServer()->m_World.m_Paused)
{
- if(!m_pCharacter && m_Team == TEAM_SPECTATORS && m_SpectatorID == SPEC_FREEVIEW)
+ if(!m_pCharacter && IsSpectator() && m_SpectatorID == SPEC_FREEVIEW)
m_ViewPos -= vec2(clamp(m_ViewPos.x-m_LatestActivity.m_TargetX, -500.0f, 500.0f), clamp(m_ViewPos.y-m_LatestActivity.m_TargetY, -400.0f, 400.0f));
if(!m_pCharacter && m_DieTick+Server()->TickSpeed()*3 <= Server()->Tick())
@@ -106,7 +105,7 @@ void CPlayer::PostTick()
}
// update view pos for spectators
- if(m_Team == TEAM_SPECTATORS && m_SpectatorID != SPEC_FREEVIEW && GameServer()->m_apPlayers[m_SpectatorID])
+ if(IsSpectator() && m_SpectatorID != SPEC_FREEVIEW && GameServer()->m_apPlayers[m_SpectatorID])
m_ViewPos = GameServer()->m_apPlayers[m_SpectatorID]->m_ViewPos;
}
@@ -138,12 +137,12 @@ void CPlayer::Snap(int SnappingClient)
pPlayerInfo->m_Local = 0;
pPlayerInfo->m_ClientID = m_ClientID;
pPlayerInfo->m_Score = m_Score;
- pPlayerInfo->m_Team = m_Team;
+ pPlayerInfo->m_Team = SnapTeam(m_Team);
if(m_ClientID == SnappingClient)
pPlayerInfo->m_Local = 1;
- if(m_ClientID == SnappingClient && m_Team == TEAM_SPECTATORS)
+ if(m_ClientID == SnappingClient && IsSpectator())
{
CNetObj_SpectatorInfo *pSpectatorInfo = static_cast<CNetObj_SpectatorInfo *>(Server()->SnapNewItem(NETOBJTYPE_SPECTATORINFO, m_ClientID, sizeof(CNetObj_SpectatorInfo)));
if(!pSpectatorInfo)
@@ -204,7 +203,7 @@ void CPlayer::OnDirectInput(CNetObj_PlayerInput *NewInput)
if(m_pCharacter)
m_pCharacter->OnDirectInput(NewInput);
- if(!m_pCharacter && m_Team != TEAM_SPECTATORS && (NewInput->m_Fire&1))
+ if(!m_pCharacter && IsSpectator() && (NewInput->m_Fire&1))
m_Spawning = true;
// check for activity
@@ -237,15 +236,39 @@ void CPlayer::KillCharacter(int Weapon)
void CPlayer::Respawn()
{
- if(m_Team != TEAM_SPECTATORS)
+ if(!IsSpectator())
m_Spawning = true;
}
-void CPlayer::SetTeam(int Team, bool DoChatMsg)
+void CPlayer::Revive()
+{
+ SetTeamSimple(GetGameTeam());
+}
+
+void CPlayer::SetTeamSimple(int Team, bool Init)
+{
+ m_Team = Team;
+ m_SpectatorID = SPEC_FREEVIEW;
+ if(Init)
+ return;
+ GameServer()->m_pController->OnPlayerInfoChange(GameServer()->m_apPlayers[m_ClientID]);
+
+ if(Team == TEAM_SPECTATORS)
+ {
+ // update spectator modes
+ for(int i = 0; i < MAX_CLIENTS; ++i)
+ {
+ if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->m_SpectatorID == m_ClientID)
+ GameServer()->m_apPlayers[i]->m_SpectatorID = SPEC_FREEVIEW;
+ }
+ }
+}
+
+void CPlayer::SetGameTeam(int Team, bool DoChatMsg)
{
// clamp the team
Team = GameServer()->m_pController->ClampTeam(Team);
- if(m_Team == Team)
+ if(GetGameTeam() == Team)
return;
char aBuf[512];
@@ -257,32 +280,27 @@ void CPlayer::SetTeam(int Team, bool DoChatMsg)
KillCharacter();
- m_Team = Team;
m_LastActionTick = Server()->Tick();
- m_SpectatorID = SPEC_FREEVIEW;
// we got to wait 0.5 secs before respawning
m_RespawnTick = Server()->Tick()+Server()->TickSpeed()/2;
- str_format(aBuf, sizeof(aBuf), "team_join player='%d:%s' m_Team=%d", m_ClientID, Server()->ClientName(m_ClientID), m_Team);
+ str_format(aBuf, sizeof(aBuf), "team_join player='%d:%s' team=%d", m_ClientID, Server()->ClientName(m_ClientID), Team);
GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf);
-
- GameServer()->m_pController->OnPlayerInfoChange(GameServer()->m_apPlayers[m_ClientID]);
-
- if(Team == TEAM_SPECTATORS)
- {
- // update spectator modes
- for(int i = 0; i < MAX_CLIENTS; ++i)
- {
- if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->m_SpectatorID == m_ClientID)
- GameServer()->m_apPlayers[i]->m_SpectatorID = SPEC_FREEVIEW;
- }
- }
+ // If we're currently alive (i.e. not spectator and not dead), be alive
+ // on the new team as well.
+ if(!IsDeadTeam())
+ SetTeamSimple(Team);
+ else
+ SetTeamSimple(DeadTeam(Team));
}
void CPlayer::TryRespawn()
{
vec2 SpawnPos;
- if(!GameServer()->m_pController->CanSpawn(m_Team, &SpawnPos))
+ if(IsSpectator())
+ return;
+
+ if(!GameServer()->m_pController->CanSpawn(GetGameTeam(), &SpawnPos))
return;
m_Spawning = false;
diff --git a/src/game/server/player.h b/src/game/server/player.h
index dd804a9..64703bb 100644
--- a/src/game/server/player.h
+++ b/src/game/server/player.h
@@ -20,8 +20,15 @@ class CPlayer
void TryRespawn();
void Respawn();
- void SetTeam(int Team, bool DoChatMsg=true);
+ void SetGameTeam(int Team, bool DoChatMsg=true);
+ void SetTeamSimple(int Team, bool Init=false);
+ void Revive();
+private:
int GetTeam() const { return m_Team; };
+public:
+ int GetGameTeam() const { return GameTeam(GetTeam()); }
+ bool IsSpectator() const { return IsSpectatorTeam(GetTeam()); }
+ bool IsDeadTeam() const { return !IsAliveTeam(GetTeam()); }
int GetCID() const { return m_ClientID; };
void Tick();