2011-12-25 13:33:05 +00:00
|
|
|
/* (c) Shereef Marzouk. See "licence DDRace.txt" and the readme.txt in the root of the distribution for more information. */
|
2010-08-28 13:47:52 +00:00
|
|
|
#include "teams.h"
|
2010-11-06 22:54:35 +00:00
|
|
|
#include <engine/shared/config.h>
|
2014-01-21 23:08:30 +00:00
|
|
|
#include <engine/server/server.h>
|
2010-08-28 13:47:52 +00:00
|
|
|
|
2011-12-25 13:51:04 +00:00
|
|
|
CGameTeams::CGameTeams(CGameContext *pGameContext) :
|
|
|
|
m_pGameContext(pGameContext)
|
2011-01-06 05:30:19 +00:00
|
|
|
{
|
2010-09-24 13:37:13 +00:00
|
|
|
Reset();
|
|
|
|
}
|
|
|
|
|
2011-01-06 05:30:19 +00:00
|
|
|
void CGameTeams::Reset()
|
|
|
|
{
|
2010-09-24 13:37:13 +00:00
|
|
|
m_Core.Reset();
|
2013-12-28 15:09:03 +00:00
|
|
|
for (int i = 0; i < MAX_CLIENTS; ++i)
|
2011-01-06 05:30:19 +00:00
|
|
|
{
|
2011-02-02 10:49:19 +00:00
|
|
|
m_TeamState[i] = TEAMSTATE_EMPTY;
|
2010-08-28 13:47:52 +00:00
|
|
|
m_TeeFinished[i] = false;
|
2010-11-06 22:54:35 +00:00
|
|
|
m_MembersCount[i] = 0;
|
2010-12-19 03:48:16 +00:00
|
|
|
m_LastChat[i] = 0;
|
2013-11-15 23:44:49 +00:00
|
|
|
m_TeamLocked[i] = false;
|
2010-08-28 13:47:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-02 10:49:19 +00:00
|
|
|
void CGameTeams::OnCharacterStart(int ClientID)
|
|
|
|
{
|
2010-08-28 20:53:42 +00:00
|
|
|
int Tick = Server()->Tick();
|
2011-03-16 13:14:25 +00:00
|
|
|
CCharacter* pStartingChar = Character(ClientID);
|
2011-12-25 13:51:04 +00:00
|
|
|
if (!pStartingChar)
|
2010-12-19 03:48:16 +00:00
|
|
|
return;
|
2013-08-14 18:12:53 +00:00
|
|
|
if (m_Core.Team(ClientID) != TEAM_FLOCK && pStartingChar->m_DDRaceState == DDRACE_FINISHED)
|
|
|
|
return;
|
2011-12-25 13:51:04 +00:00
|
|
|
if (m_Core.Team(ClientID) == TEAM_FLOCK
|
|
|
|
|| m_Core.Team(ClientID) == TEAM_SUPER)
|
2010-12-19 03:48:16 +00:00
|
|
|
{
|
2011-03-16 13:14:25 +00:00
|
|
|
pStartingChar->m_DDRaceState = DDRACE_STARTED;
|
|
|
|
pStartingChar->m_StartTime = Tick;
|
2011-02-14 21:34:46 +00:00
|
|
|
}
|
2010-12-19 03:48:16 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
bool Waiting = false;
|
2011-12-25 13:51:04 +00:00
|
|
|
for (int i = 0; i < MAX_CLIENTS; ++i)
|
2011-03-16 13:14:25 +00:00
|
|
|
{
|
2011-12-25 13:51:04 +00:00
|
|
|
if (m_Core.Team(ClientID) == m_Core.Team(i))
|
2010-12-19 03:48:16 +00:00
|
|
|
{
|
2011-06-06 19:24:27 +00:00
|
|
|
CPlayer* pPlayer = GetPlayer(i);
|
2011-12-25 13:51:04 +00:00
|
|
|
if (pPlayer && pPlayer->IsPlaying()
|
|
|
|
&& GetDDRaceState(pPlayer) == DDRACE_FINISHED)
|
2010-12-19 03:48:16 +00:00
|
|
|
{
|
2011-03-16 13:14:25 +00:00
|
|
|
Waiting = true;
|
2011-11-08 13:21:03 +00:00
|
|
|
pStartingChar->m_DDRaceState = DDRACE_NONE;
|
2013-11-15 23:44:49 +00:00
|
|
|
|
2011-12-25 13:51:04 +00:00
|
|
|
if (m_LastChat[ClientID] + Server()->TickSpeed()
|
|
|
|
+ g_Config.m_SvChatDelay < Tick)
|
2010-12-19 03:48:16 +00:00
|
|
|
{
|
2011-03-16 13:14:25 +00:00
|
|
|
char aBuf[128];
|
2011-12-25 13:51:04 +00:00
|
|
|
str_format(
|
|
|
|
aBuf,
|
|
|
|
sizeof(aBuf),
|
|
|
|
"%s has finished and didn't go through start yet, wait for him or join another team.",
|
|
|
|
Server()->ClientName(i));
|
2011-03-16 13:14:25 +00:00
|
|
|
GameServer()->SendChatTarget(ClientID, aBuf);
|
|
|
|
m_LastChat[ClientID] = Tick;
|
2010-12-19 03:48:16 +00:00
|
|
|
}
|
2011-12-25 13:51:04 +00:00
|
|
|
if (m_LastChat[i] + Server()->TickSpeed()
|
|
|
|
+ g_Config.m_SvChatDelay < Tick)
|
2010-12-19 03:48:16 +00:00
|
|
|
{
|
2011-03-16 13:14:25 +00:00
|
|
|
char aBuf[128];
|
2011-12-25 13:51:04 +00:00
|
|
|
str_format(
|
|
|
|
aBuf,
|
|
|
|
sizeof(aBuf),
|
|
|
|
"%s wants to start a new round, kill or walk to start.",
|
|
|
|
Server()->ClientName(ClientID));
|
2011-03-16 13:14:25 +00:00
|
|
|
GameServer()->SendChatTarget(i, aBuf);
|
|
|
|
m_LastChat[i] = Tick;
|
2010-12-19 03:48:16 +00:00
|
|
|
}
|
|
|
|
}
|
2011-03-16 13:14:25 +00:00
|
|
|
}
|
2010-12-19 03:48:16 +00:00
|
|
|
}
|
|
|
|
|
2011-12-25 13:51:04 +00:00
|
|
|
if (m_TeamState[m_Core.Team(ClientID)] < TEAMSTATE_STARTED && !Waiting)
|
2010-12-19 03:48:16 +00:00
|
|
|
{
|
2011-03-16 13:14:25 +00:00
|
|
|
ChangeTeamState(m_Core.Team(ClientID), TEAMSTATE_STARTED);
|
2011-12-25 13:51:04 +00:00
|
|
|
for (int i = 0; i < MAX_CLIENTS; ++i)
|
2010-12-19 03:48:16 +00:00
|
|
|
{
|
2011-12-25 13:51:04 +00:00
|
|
|
if (m_Core.Team(ClientID) == m_Core.Team(i))
|
2010-12-19 03:48:16 +00:00
|
|
|
{
|
2011-06-06 19:24:27 +00:00
|
|
|
CPlayer* pPlayer = GetPlayer(i);
|
2013-11-15 23:44:49 +00:00
|
|
|
// TODO: THE PROBLEM IS THAT THERE IS NO CHARACTER SO START TIME CAN'T BE SET!
|
|
|
|
if (pPlayer && (pPlayer->IsPlaying() || TeamLocked(m_Core.Team(ClientID))))
|
2010-12-19 03:48:16 +00:00
|
|
|
{
|
2011-06-06 19:24:27 +00:00
|
|
|
SetDDRaceState(pPlayer, DDRACE_STARTED);
|
|
|
|
SetStartTime(pPlayer, Tick);
|
2010-12-19 03:48:16 +00:00
|
|
|
}
|
2010-08-28 20:53:42 +00:00
|
|
|
}
|
2010-08-28 13:47:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-02 10:49:19 +00:00
|
|
|
void CGameTeams::OnCharacterFinish(int ClientID)
|
2011-01-06 05:30:19 +00:00
|
|
|
{
|
2011-12-25 13:51:04 +00:00
|
|
|
if (m_Core.Team(ClientID) == TEAM_FLOCK
|
|
|
|
|| m_Core.Team(ClientID) == TEAM_SUPER)
|
2010-12-19 03:48:16 +00:00
|
|
|
{
|
2011-06-06 19:24:27 +00:00
|
|
|
CPlayer* pPlayer = GetPlayer(ClientID);
|
2011-12-25 13:51:04 +00:00
|
|
|
if (pPlayer && pPlayer->IsPlaying())
|
2011-06-06 19:24:27 +00:00
|
|
|
OnFinish(pPlayer);
|
2010-12-19 03:48:16 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-02-02 10:49:19 +00:00
|
|
|
m_TeeFinished[ClientID] = true;
|
2013-07-21 06:46:52 +00:00
|
|
|
|
2014-09-26 01:42:49 +00:00
|
|
|
CheckTeamFinished(m_Core.Team(ClientID));
|
|
|
|
}
|
|
|
|
}
|
2013-07-21 06:46:52 +00:00
|
|
|
|
2014-09-26 01:42:49 +00:00
|
|
|
void CGameTeams::CheckTeamFinished(int Team)
|
|
|
|
{
|
|
|
|
if (TeamFinished(Team))
|
|
|
|
{
|
|
|
|
CPlayer *TeamPlayers[MAX_CLIENTS];
|
|
|
|
unsigned int PlayersCount = 0;
|
|
|
|
|
|
|
|
for (int i = 0; i < MAX_CLIENTS; ++i)
|
|
|
|
{
|
|
|
|
if (Team == m_Core.Team(i))
|
2010-12-19 03:48:16 +00:00
|
|
|
{
|
2014-09-26 01:42:49 +00:00
|
|
|
CPlayer* pPlayer = GetPlayer(i);
|
|
|
|
if (pPlayer && pPlayer->IsPlaying())
|
2010-12-19 03:48:16 +00:00
|
|
|
{
|
2014-09-26 01:42:49 +00:00
|
|
|
OnFinish(pPlayer);
|
|
|
|
m_TeeFinished[i] = false;
|
2013-07-21 06:46:52 +00:00
|
|
|
|
2014-09-26 01:42:49 +00:00
|
|
|
TeamPlayers[PlayersCount++] = pPlayer;
|
2010-08-28 20:53:42 +00:00
|
|
|
}
|
|
|
|
}
|
2010-08-28 13:47:52 +00:00
|
|
|
}
|
2014-09-26 01:42:49 +00:00
|
|
|
|
2014-09-26 10:43:56 +00:00
|
|
|
if (PlayersCount > 0)
|
2014-09-26 11:03:01 +00:00
|
|
|
{
|
|
|
|
ChangeTeamState(Team, TEAMSTATE_FINISHED); //TODO: Make it better
|
|
|
|
//ChangeTeamState(Team, TEAMSTATE_OPEN);
|
2014-09-26 10:43:56 +00:00
|
|
|
OnTeamFinish(TeamPlayers, PlayersCount);
|
2014-09-26 11:03:01 +00:00
|
|
|
}
|
2010-08-28 13:47:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-16 13:14:25 +00:00
|
|
|
bool CGameTeams::SetCharacterTeam(int ClientID, int Team)
|
2011-02-14 18:36:30 +00:00
|
|
|
{
|
2011-03-16 13:14:25 +00:00
|
|
|
//Check on wrong parameters. +1 for TEAM_SUPER
|
2011-12-25 13:51:04 +00:00
|
|
|
if (ClientID < 0 || ClientID >= MAX_CLIENTS || Team < 0
|
|
|
|
|| Team >= MAX_CLIENTS + 1)
|
2011-03-16 13:14:25 +00:00
|
|
|
return false;
|
|
|
|
//You can join to TEAM_SUPER at any time, but any other group you cannot if it started
|
2011-12-25 13:51:04 +00:00
|
|
|
if (Team != TEAM_SUPER && m_TeamState[Team] > TEAMSTATE_OPEN)
|
2011-03-16 13:14:25 +00:00
|
|
|
return false;
|
|
|
|
//No need to switch team if you there
|
2011-12-25 13:51:04 +00:00
|
|
|
if (m_Core.Team(ClientID) == Team)
|
2011-03-16 13:14:25 +00:00
|
|
|
return false;
|
2014-01-10 23:13:35 +00:00
|
|
|
if (!Character(ClientID))
|
|
|
|
return false;
|
2011-03-16 13:14:25 +00:00
|
|
|
//You cannot be in TEAM_SUPER if you not super
|
2011-12-25 13:51:04 +00:00
|
|
|
if (Team == TEAM_SUPER && !Character(ClientID)->m_Super)
|
|
|
|
return false;
|
2011-03-16 13:14:25 +00:00
|
|
|
//if you begin race
|
2013-10-07 12:09:30 +00:00
|
|
|
if (Character(ClientID)->m_DDRaceState != DDRACE_NONE && Team != TEAM_SUPER)
|
|
|
|
return false;
|
|
|
|
|
2011-02-02 10:49:19 +00:00
|
|
|
SetForceCharacterTeam(ClientID, Team);
|
2011-12-25 13:51:04 +00:00
|
|
|
|
2011-03-16 13:14:25 +00:00
|
|
|
//GameServer()->CreatePlayerSpawn(Character(id)->m_Core.m_Pos, TeamMask());
|
|
|
|
return true;
|
2010-09-22 10:43:59 +00:00
|
|
|
}
|
|
|
|
|
2011-02-02 10:49:19 +00:00
|
|
|
void CGameTeams::SetForceCharacterTeam(int ClientID, int Team)
|
2014-01-11 14:19:34 +00:00
|
|
|
{
|
2014-01-24 14:12:46 +00:00
|
|
|
int OldTeam = m_Core.Team(ClientID);
|
|
|
|
|
2014-09-26 21:47:25 +00:00
|
|
|
if (Team != m_Core.Team(ClientID))
|
|
|
|
ForceLeaveTeam(ClientID);
|
2014-09-29 17:32:43 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
m_TeeFinished[ClientID] = false;
|
|
|
|
if (Count(m_Core.Team(ClientID)) > 0)
|
|
|
|
m_MembersCount[m_Core.Team(ClientID)]--;
|
|
|
|
}
|
2014-01-11 14:19:34 +00:00
|
|
|
|
|
|
|
m_Core.Team(ClientID, Team);
|
|
|
|
|
2014-09-29 17:32:43 +00:00
|
|
|
if (m_Core.Team(ClientID) != TEAM_SUPER)
|
2014-01-11 14:19:34 +00:00
|
|
|
m_MembersCount[m_Core.Team(ClientID)]++;
|
2014-03-10 12:39:50 +00:00
|
|
|
if (Team != TEAM_SUPER && (m_TeamState[Team] == TEAMSTATE_EMPTY || m_TeamLocked[Team]))
|
2014-01-11 14:19:34 +00:00
|
|
|
{
|
2014-03-12 18:36:25 +00:00
|
|
|
if (!m_TeamLocked[Team])
|
|
|
|
ChangeTeamState(Team, TEAMSTATE_OPEN);
|
2014-01-11 14:19:34 +00:00
|
|
|
|
|
|
|
if (GameServer()->Collision()->m_NumSwitchers > 0) {
|
|
|
|
for (int i = 0; i < GameServer()->Collision()->m_NumSwitchers+1; ++i)
|
|
|
|
{
|
|
|
|
GameServer()->Collision()->m_pSwitchers[i].m_Status[Team] = true;
|
|
|
|
GameServer()->Collision()->m_pSwitchers[i].m_EndTick[Team] = 0;
|
|
|
|
GameServer()->Collision()->m_pSwitchers[i].m_Type[Team] = TILE_SWITCHOPEN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-24 14:12:46 +00:00
|
|
|
if (OldTeam != Team)
|
|
|
|
for (int LoopClientID = 0; LoopClientID < MAX_CLIENTS; ++LoopClientID)
|
|
|
|
if (GetPlayer(LoopClientID))
|
|
|
|
SendTeamsState(LoopClientID);
|
2014-01-11 14:19:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CGameTeams::ForceLeaveTeam(int ClientID)
|
2011-01-06 05:30:19 +00:00
|
|
|
{
|
2011-02-02 10:49:19 +00:00
|
|
|
m_TeeFinished[ClientID] = false;
|
2014-01-11 14:19:34 +00:00
|
|
|
|
2011-12-25 13:51:04 +00:00
|
|
|
if (m_Core.Team(ClientID) != TEAM_FLOCK
|
|
|
|
&& m_Core.Team(ClientID) != TEAM_SUPER
|
|
|
|
&& m_TeamState[m_Core.Team(ClientID)] != TEAMSTATE_EMPTY)
|
2011-01-06 05:30:19 +00:00
|
|
|
{
|
2010-08-28 20:53:42 +00:00
|
|
|
bool NoOneInOldTeam = true;
|
2011-12-25 13:51:04 +00:00
|
|
|
for (int i = 0; i < MAX_CLIENTS; ++i)
|
|
|
|
if (i != ClientID && m_Core.Team(ClientID) == m_Core.Team(i))
|
2011-01-06 05:30:19 +00:00
|
|
|
{
|
2011-12-25 13:51:04 +00:00
|
|
|
NoOneInOldTeam = false; //all good exists someone in old team
|
2010-08-28 20:53:42 +00:00
|
|
|
break;
|
2011-06-06 19:24:27 +00:00
|
|
|
}
|
2011-12-25 13:51:04 +00:00
|
|
|
if (NoOneInOldTeam)
|
2013-11-15 23:44:49 +00:00
|
|
|
{
|
2011-03-16 13:14:25 +00:00
|
|
|
m_TeamState[m_Core.Team(ClientID)] = TEAMSTATE_EMPTY;
|
2013-11-15 23:44:49 +00:00
|
|
|
|
|
|
|
// unlock team when last player leaves
|
|
|
|
SetTeamLock(m_Core.Team(ClientID), false);
|
|
|
|
}
|
2010-08-28 13:47:52 +00:00
|
|
|
}
|
2014-01-11 14:19:34 +00:00
|
|
|
|
2011-12-25 13:51:04 +00:00
|
|
|
if (Count(m_Core.Team(ClientID)) > 0)
|
|
|
|
m_MembersCount[m_Core.Team(ClientID)]--;
|
2011-02-02 10:49:19 +00:00
|
|
|
}
|
2010-11-06 22:54:35 +00:00
|
|
|
|
2011-02-02 10:49:19 +00:00
|
|
|
int CGameTeams::Count(int Team) const
|
2011-01-06 05:30:19 +00:00
|
|
|
{
|
2011-12-25 13:51:04 +00:00
|
|
|
if (Team == TEAM_SUPER)
|
2011-02-02 10:49:19 +00:00
|
|
|
return -1;
|
|
|
|
return m_MembersCount[Team];
|
2010-08-28 13:47:52 +00:00
|
|
|
}
|
|
|
|
|
2011-03-16 13:14:25 +00:00
|
|
|
void CGameTeams::ChangeTeamState(int Team, int State)
|
|
|
|
{
|
2011-12-25 13:19:03 +00:00
|
|
|
int OldState = m_TeamState[Team];
|
2011-03-16 13:14:25 +00:00
|
|
|
m_TeamState[Team] = State;
|
2011-12-25 13:19:03 +00:00
|
|
|
onChangeTeamState(Team, State, OldState);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGameTeams::onChangeTeamState(int Team, int State, int OldState)
|
|
|
|
{
|
2011-12-25 13:51:04 +00:00
|
|
|
if (OldState != State && State == TEAMSTATE_STARTED)
|
2011-12-25 13:19:03 +00:00
|
|
|
{
|
|
|
|
// OnTeamStateStarting
|
|
|
|
}
|
2011-12-25 13:51:04 +00:00
|
|
|
if (OldState != State && State == TEAMSTATE_FINISHED)
|
2011-12-25 13:19:03 +00:00
|
|
|
{
|
|
|
|
// OnTeamStateFinishing
|
|
|
|
}
|
2011-03-16 13:14:25 +00:00
|
|
|
}
|
|
|
|
|
2011-01-06 05:30:19 +00:00
|
|
|
bool CGameTeams::TeamFinished(int Team)
|
|
|
|
{
|
2011-12-25 13:51:04 +00:00
|
|
|
for (int i = 0; i < MAX_CLIENTS; ++i)
|
|
|
|
if (m_Core.Team(i) == Team && !m_TeeFinished[i])
|
2011-03-16 13:14:25 +00:00
|
|
|
return false;
|
2010-08-28 13:47:52 +00:00
|
|
|
return true;
|
2010-09-08 16:22:11 +00:00
|
|
|
}
|
|
|
|
|
2013-12-31 05:13:57 +00:00
|
|
|
int64_t CGameTeams::TeamMask(int Team, int ExceptID, int Asker)
|
2011-01-06 05:30:19 +00:00
|
|
|
{
|
2014-01-22 14:47:01 +00:00
|
|
|
int64_t Mask = 0;
|
2014-01-20 19:12:03 +00:00
|
|
|
|
2011-12-25 13:51:04 +00:00
|
|
|
for (int i = 0; i < MAX_CLIENTS; ++i)
|
2014-01-20 19:12:03 +00:00
|
|
|
{
|
|
|
|
if (i == ExceptID)
|
|
|
|
continue; // Explicitly excluded
|
|
|
|
if (!GetPlayer(i))
|
|
|
|
continue; // Player doesn't exist
|
|
|
|
|
2014-01-24 21:27:34 +00:00
|
|
|
if (!(GetPlayer(i)->GetTeam() == -1 || GetPlayer(i)->m_Paused))
|
2014-01-20 19:12:03 +00:00
|
|
|
{ // Not spectator
|
|
|
|
if (i != Asker)
|
|
|
|
{ // Actions of other players
|
|
|
|
if (!Character(i))
|
|
|
|
continue; // Player is currently dead
|
2014-02-19 21:30:57 +00:00
|
|
|
if (!GetPlayer(i)->m_ShowOthers)
|
|
|
|
{
|
2014-01-24 21:27:34 +00:00
|
|
|
if (m_Core.GetSolo(Asker))
|
|
|
|
continue; // When in solo part don't show others
|
|
|
|
if (m_Core.GetSolo(i))
|
|
|
|
continue; // When in solo part don't show others
|
|
|
|
if (m_Core.Team(i) != Team && m_Core.Team(i) != TEAM_SUPER)
|
|
|
|
continue; // In different teams
|
|
|
|
} // ShowOthers
|
2014-01-20 19:12:03 +00:00
|
|
|
} // See everything of yourself
|
|
|
|
}
|
|
|
|
else if (GetPlayer(i)->m_SpectatorID != SPEC_FREEVIEW)
|
|
|
|
{ // Spectating specific player
|
2014-01-22 20:48:13 +00:00
|
|
|
if (GetPlayer(i)->m_SpectatorID != Asker)
|
2014-01-20 19:12:03 +00:00
|
|
|
{ // Actions of other players
|
2014-01-24 21:27:34 +00:00
|
|
|
if (!Character(GetPlayer(i)->m_SpectatorID))
|
|
|
|
continue; // Player is currently dead
|
2014-02-19 21:30:57 +00:00
|
|
|
if (!GetPlayer(i)->m_ShowOthers)
|
|
|
|
{
|
2014-01-24 21:27:34 +00:00
|
|
|
if (m_Core.GetSolo(Asker))
|
|
|
|
continue; // When in solo part don't show others
|
|
|
|
if (m_Core.GetSolo(GetPlayer(i)->m_SpectatorID))
|
|
|
|
continue; // When in solo part don't show others
|
|
|
|
if (m_Core.Team(GetPlayer(i)->m_SpectatorID) != Team && m_Core.Team(GetPlayer(i)->m_SpectatorID) != TEAM_SUPER)
|
|
|
|
continue; // In different teams
|
|
|
|
} // ShowOthers
|
2014-01-20 19:12:03 +00:00
|
|
|
} // See everything of player you're spectating
|
2014-08-09 17:53:38 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // Freeview
|
|
|
|
if (GetPlayer(i)->m_SpecTeam)
|
|
|
|
{ // Show only players in own team when spectating
|
|
|
|
if (m_Core.Team(i) != Team && m_Core.Team(i) != TEAM_SUPER)
|
|
|
|
continue; // in different teams
|
|
|
|
}
|
|
|
|
}
|
2014-01-20 19:12:03 +00:00
|
|
|
|
|
|
|
Mask |= 1LL << i;
|
|
|
|
}
|
2010-09-08 16:22:11 +00:00
|
|
|
return Mask;
|
|
|
|
}
|
2010-10-24 10:47:25 +00:00
|
|
|
|
2011-02-02 10:49:19 +00:00
|
|
|
void CGameTeams::SendTeamsState(int ClientID)
|
2011-01-06 05:30:19 +00:00
|
|
|
{
|
2014-01-22 00:39:18 +00:00
|
|
|
if (g_Config.m_SvTeam == 3)
|
|
|
|
return;
|
|
|
|
|
2014-01-31 20:21:50 +00:00
|
|
|
if (!m_pGameContext->m_apPlayers[ClientID] || m_pGameContext->m_apPlayers[ClientID]->m_ClientVersion <= VERSION_DDRACE)
|
2014-01-22 14:29:30 +00:00
|
|
|
return;
|
|
|
|
|
2014-01-21 23:08:30 +00:00
|
|
|
CMsgPacker Msg(NETMSGTYPE_SV_TEAMSSTATE);
|
|
|
|
|
2014-01-31 20:21:50 +00:00
|
|
|
for(unsigned i = 0; i < MAX_CLIENTS; i++)
|
|
|
|
Msg.AddInt(m_Core.Team(i));
|
2014-01-21 23:08:30 +00:00
|
|
|
|
|
|
|
Server()->SendMsg(&Msg, MSGFLAG_VITAL, ClientID);
|
2010-10-24 10:47:25 +00:00
|
|
|
}
|
2011-06-06 19:24:27 +00:00
|
|
|
|
|
|
|
int CGameTeams::GetDDRaceState(CPlayer* Player)
|
|
|
|
{
|
2011-12-25 13:51:04 +00:00
|
|
|
if (!Player)
|
2011-06-06 19:24:27 +00:00
|
|
|
return DDRACE_NONE;
|
|
|
|
|
|
|
|
CCharacter* pChar = Player->GetCharacter();
|
2011-12-25 13:51:04 +00:00
|
|
|
if (pChar)
|
2011-06-06 19:24:27 +00:00
|
|
|
return pChar->m_DDRaceState;
|
|
|
|
return DDRACE_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGameTeams::SetDDRaceState(CPlayer* Player, int DDRaceState)
|
|
|
|
{
|
2011-12-25 13:51:04 +00:00
|
|
|
if (!Player)
|
2011-06-06 19:24:27 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
CCharacter* pChar = Player->GetCharacter();
|
2011-12-25 13:51:04 +00:00
|
|
|
if (pChar)
|
2011-06-06 19:24:27 +00:00
|
|
|
pChar->m_DDRaceState = DDRaceState;
|
|
|
|
}
|
|
|
|
|
|
|
|
int CGameTeams::GetStartTime(CPlayer* Player)
|
|
|
|
{
|
2011-12-25 13:51:04 +00:00
|
|
|
if (!Player)
|
2011-06-06 19:24:27 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
CCharacter* pChar = Player->GetCharacter();
|
2011-12-25 13:51:04 +00:00
|
|
|
if (pChar)
|
2011-06-06 19:24:27 +00:00
|
|
|
return pChar->m_StartTime;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGameTeams::SetStartTime(CPlayer* Player, int StartTime)
|
|
|
|
{
|
2011-12-25 13:51:04 +00:00
|
|
|
if (!Player)
|
2011-06-06 19:24:27 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
CCharacter* pChar = Player->GetCharacter();
|
2011-12-25 13:51:04 +00:00
|
|
|
if (pChar)
|
2011-06-06 19:24:27 +00:00
|
|
|
pChar->m_StartTime = StartTime;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGameTeams::SetCpActive(CPlayer* Player, int CpActive)
|
|
|
|
{
|
2011-12-25 13:51:04 +00:00
|
|
|
if (!Player)
|
2011-06-06 19:24:27 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
CCharacter* pChar = Player->GetCharacter();
|
2011-12-25 13:51:04 +00:00
|
|
|
if (pChar)
|
2011-06-06 19:24:27 +00:00
|
|
|
pChar->m_CpActive = CpActive;
|
|
|
|
}
|
|
|
|
|
|
|
|
float *CGameTeams::GetCpCurrent(CPlayer* Player)
|
|
|
|
{
|
2011-12-25 13:51:04 +00:00
|
|
|
if (!Player)
|
2011-06-06 19:24:27 +00:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
CCharacter* pChar = Player->GetCharacter();
|
2011-12-25 13:51:04 +00:00
|
|
|
if (pChar)
|
2011-06-06 19:24:27 +00:00
|
|
|
return pChar->m_CpCurrent;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-07-21 06:46:52 +00:00
|
|
|
void CGameTeams::OnTeamFinish(CPlayer** Players, unsigned int Size)
|
|
|
|
{
|
|
|
|
float time = (float) (Server()->Tick() - GetStartTime(Players[0]))
|
|
|
|
/ ((float) Server()->TickSpeed());
|
|
|
|
if (time < 0.000001f)
|
|
|
|
return;
|
|
|
|
|
|
|
|
bool CallSaveScore = false;
|
|
|
|
|
|
|
|
#if defined(CONF_SQL)
|
|
|
|
CallSaveScore = g_Config.m_SvUseSQL;
|
|
|
|
#endif
|
|
|
|
|
2013-07-22 22:15:50 +00:00
|
|
|
int PlayerCIDs[MAX_CLIENTS];
|
2013-07-21 06:46:52 +00:00
|
|
|
|
|
|
|
for(unsigned int i = 0; i < Size; i++)
|
|
|
|
{
|
|
|
|
PlayerCIDs[i] = Players[i]->GetCID();
|
2014-07-07 23:58:27 +00:00
|
|
|
|
2014-07-19 15:11:00 +00:00
|
|
|
if(g_Config.m_SvRejoinTeam0 && g_Config.m_SvTeam != 3 && (m_Core.Team(Players[i]->GetCID()) >= TEAM_SUPER || !m_TeamLocked[m_Core.Team(Players[i]->GetCID())]))
|
2014-08-01 14:00:04 +00:00
|
|
|
{
|
2014-07-07 23:58:27 +00:00
|
|
|
SetForceCharacterTeam(Players[i]->GetCID(), 0);
|
2014-08-01 14:00:04 +00:00
|
|
|
char aBuf[512];
|
|
|
|
str_format(aBuf, sizeof(aBuf), "%s joined team 0",
|
|
|
|
GameServer()->Server()->ClientName(Players[i]->GetCID()));
|
|
|
|
GameServer()->SendChat(-1, CGameContext::CHAT_ALL, aBuf);
|
|
|
|
}
|
2013-07-21 06:46:52 +00:00
|
|
|
}
|
|
|
|
|
2013-12-10 17:45:28 +00:00
|
|
|
if (CallSaveScore && Size >= 2)
|
2013-07-21 06:46:52 +00:00
|
|
|
GameServer()->Score()->SaveTeamScore(PlayerCIDs, Size, time);
|
|
|
|
}
|
|
|
|
|
2011-06-06 19:24:27 +00:00
|
|
|
void CGameTeams::OnFinish(CPlayer* Player)
|
|
|
|
{
|
2011-12-25 13:51:04 +00:00
|
|
|
if (!Player || !Player->IsPlaying())
|
2011-06-06 19:24:27 +00:00
|
|
|
return;
|
|
|
|
//TODO:DDRace:btd: this ugly
|
2011-12-25 13:51:04 +00:00
|
|
|
float time = (float) (Server()->Tick() - GetStartTime(Player))
|
|
|
|
/ ((float) Server()->TickSpeed());
|
|
|
|
if (time < 0.000001f)
|
|
|
|
return;
|
2011-06-06 19:24:27 +00:00
|
|
|
CPlayerData *pData = GameServer()->Score()->PlayerData(Player->GetCID());
|
|
|
|
char aBuf[128];
|
2011-12-25 13:51:04 +00:00
|
|
|
SetCpActive(Player, -2);
|
|
|
|
str_format(aBuf, sizeof(aBuf),
|
|
|
|
"%s finished in: %d minute(s) %5.2f second(s)",
|
|
|
|
Server()->ClientName(Player->GetCID()), (int) time / 60,
|
|
|
|
time - ((int) time / 60 * 60));
|
2014-02-19 02:47:15 +00:00
|
|
|
if (g_Config.m_SvHideScore || !g_Config.m_SvSaveWorseScores)
|
2011-12-25 13:51:04 +00:00
|
|
|
GameServer()->SendChatTarget(Player->GetCID(), aBuf);
|
|
|
|
else
|
|
|
|
GameServer()->SendChat(-1, CGameContext::CHAT_ALL, aBuf);
|
|
|
|
|
2013-12-09 16:24:02 +00:00
|
|
|
float diff = fabs(time - pData->m_BestTime);
|
|
|
|
|
2011-12-25 13:51:04 +00:00
|
|
|
if (time - pData->m_BestTime < 0)
|
|
|
|
{
|
|
|
|
// new record \o/
|
2014-09-26 00:05:22 +00:00
|
|
|
Server()->SaveDemo(Player->GetCID(), time);
|
|
|
|
|
2013-12-09 16:24:02 +00:00
|
|
|
if (diff >= 60)
|
|
|
|
str_format(aBuf, sizeof(aBuf), "New record: %d minute(s) %5.2f second(s) better.",
|
|
|
|
(int) diff / 60, diff - ((int) diff / 60 * 60));
|
|
|
|
else
|
|
|
|
str_format(aBuf, sizeof(aBuf), "New record: %5.2f second(s) better.",
|
|
|
|
diff);
|
2014-02-19 02:47:15 +00:00
|
|
|
if (g_Config.m_SvHideScore || !g_Config.m_SvSaveWorseScores)
|
2011-06-06 19:24:27 +00:00
|
|
|
GameServer()->SendChatTarget(Player->GetCID(), aBuf);
|
|
|
|
else
|
|
|
|
GameServer()->SendChat(-1, CGameContext::CHAT_ALL, aBuf);
|
2011-12-25 13:51:04 +00:00
|
|
|
}
|
|
|
|
else if (pData->m_BestTime != 0) // tee has already finished?
|
|
|
|
{
|
2014-09-26 00:05:22 +00:00
|
|
|
Server()->StopRecord(Player->GetCID());
|
|
|
|
|
2013-12-09 16:24:02 +00:00
|
|
|
if (diff <= 0.005)
|
2011-06-06 19:24:27 +00:00
|
|
|
{
|
2011-12-25 13:51:04 +00:00
|
|
|
GameServer()->SendChatTarget(Player->GetCID(),
|
|
|
|
"You finished with your best time.");
|
2011-06-06 19:24:27 +00:00
|
|
|
}
|
2011-12-25 13:51:04 +00:00
|
|
|
else
|
2011-06-06 19:24:27 +00:00
|
|
|
{
|
2013-12-09 16:24:02 +00:00
|
|
|
if (diff >= 60)
|
|
|
|
str_format(aBuf, sizeof(aBuf), "%d minute(s) %5.2f second(s) worse, better luck next time.",
|
|
|
|
(int) diff / 60, diff - ((int) diff / 60 * 60));
|
|
|
|
else
|
|
|
|
str_format(aBuf, sizeof(aBuf),
|
|
|
|
"%5.2f second(s) worse, better luck next time.",
|
|
|
|
diff);
|
2011-12-25 13:51:04 +00:00
|
|
|
GameServer()->SendChatTarget(Player->GetCID(), aBuf); //this is private, sent only to the tee
|
2011-06-06 19:24:27 +00:00
|
|
|
}
|
2011-12-25 13:51:04 +00:00
|
|
|
}
|
2014-09-26 00:05:22 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
Server()->SaveDemo(Player->GetCID(), time);
|
|
|
|
}
|
2011-06-06 19:24:27 +00:00
|
|
|
|
2011-12-25 13:51:04 +00:00
|
|
|
bool CallSaveScore = false;
|
|
|
|
#if defined(CONF_SQL)
|
2014-02-18 21:08:43 +00:00
|
|
|
CallSaveScore = g_Config.m_SvUseSQL && g_Config.m_SvSaveWorseScores;
|
2011-12-25 13:51:04 +00:00
|
|
|
#endif
|
2011-06-06 19:24:27 +00:00
|
|
|
|
2011-12-25 13:51:04 +00:00
|
|
|
if (!pData->m_BestTime || time < pData->m_BestTime)
|
|
|
|
{
|
|
|
|
// update the score
|
|
|
|
pData->Set(time, GetCpCurrent(Player));
|
|
|
|
CallSaveScore = true;
|
|
|
|
}
|
2011-06-06 19:24:27 +00:00
|
|
|
|
2011-12-25 13:51:04 +00:00
|
|
|
if (CallSaveScore)
|
2011-12-29 09:39:01 +00:00
|
|
|
if (g_Config.m_SvNamelessScore || str_comp_num(Server()->ClientName(Player->GetCID()), "nameless tee",
|
2011-12-25 13:51:04 +00:00
|
|
|
12) != 0)
|
|
|
|
GameServer()->Score()->SaveScore(Player->GetCID(), time,
|
|
|
|
GetCpCurrent(Player));
|
2011-06-06 19:24:27 +00:00
|
|
|
|
2011-12-25 13:51:04 +00:00
|
|
|
bool NeedToSendNewRecord = false;
|
|
|
|
// update server best time
|
|
|
|
if (GameServer()->m_pController->m_CurrentRecord == 0
|
|
|
|
|| time < GameServer()->m_pController->m_CurrentRecord)
|
|
|
|
{
|
|
|
|
// check for nameless
|
2011-12-29 09:39:01 +00:00
|
|
|
if (g_Config.m_SvNamelessScore || str_comp_num(Server()->ClientName(Player->GetCID()), "nameless tee",
|
2011-12-25 13:51:04 +00:00
|
|
|
12) != 0)
|
2011-06-06 19:24:27 +00:00
|
|
|
{
|
2011-12-25 13:51:04 +00:00
|
|
|
GameServer()->m_pController->m_CurrentRecord = time;
|
|
|
|
//dbg_msg("character", "Finish");
|
|
|
|
NeedToSendNewRecord = true;
|
2011-06-06 19:24:27 +00:00
|
|
|
}
|
2011-12-25 13:51:04 +00:00
|
|
|
}
|
2011-06-06 19:24:27 +00:00
|
|
|
|
2011-12-25 13:51:04 +00:00
|
|
|
SetDDRaceState(Player, DDRACE_FINISHED);
|
|
|
|
// set player score
|
|
|
|
if (!pData->m_CurrentTime || pData->m_CurrentTime > time)
|
|
|
|
{
|
|
|
|
pData->m_CurrentTime = time;
|
|
|
|
NeedToSendNewRecord = true;
|
|
|
|
for (int i = 0; i < MAX_CLIENTS; i++)
|
2011-06-06 19:24:27 +00:00
|
|
|
{
|
2014-01-30 15:49:15 +00:00
|
|
|
if (GetPlayer(i) && GetPlayer(i)->m_ClientVersion >= VERSION_DDRACE)
|
2011-06-06 19:24:27 +00:00
|
|
|
{
|
2011-12-25 13:51:04 +00:00
|
|
|
if (!g_Config.m_SvHideScore || i == Player->GetCID())
|
2011-06-06 19:24:27 +00:00
|
|
|
{
|
2011-12-25 13:51:04 +00:00
|
|
|
CNetMsg_Sv_PlayerTime Msg;
|
|
|
|
Msg.m_Time = time * 100.0;
|
|
|
|
Msg.m_ClientID = Player->GetCID();
|
|
|
|
Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, i);
|
2011-06-06 19:24:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-12-25 13:51:04 +00:00
|
|
|
}
|
2011-06-06 19:24:27 +00:00
|
|
|
|
2014-01-30 15:49:15 +00:00
|
|
|
if (NeedToSendNewRecord && Player->m_ClientVersion >= VERSION_DDRACE)
|
2011-12-25 13:51:04 +00:00
|
|
|
{
|
|
|
|
for (int i = 0; i < MAX_CLIENTS; i++)
|
|
|
|
{
|
|
|
|
if (GameServer()->m_apPlayers[i]
|
2014-01-30 15:49:15 +00:00
|
|
|
&& GameServer()->m_apPlayers[i]->m_ClientVersion >= VERSION_DDRACE)
|
2011-06-06 19:24:27 +00:00
|
|
|
{
|
2011-12-25 13:51:04 +00:00
|
|
|
GameServer()->SendRecord(i);
|
2011-06-06 19:24:27 +00:00
|
|
|
}
|
|
|
|
}
|
2011-12-25 13:51:04 +00:00
|
|
|
}
|
2011-06-06 19:24:27 +00:00
|
|
|
|
2014-01-30 15:49:15 +00:00
|
|
|
if (Player->m_ClientVersion >= VERSION_DDRACE)
|
2011-12-25 13:51:04 +00:00
|
|
|
{
|
|
|
|
CNetMsg_Sv_DDRaceTime Msg;
|
|
|
|
Msg.m_Time = (int) (time * 100.0f);
|
|
|
|
Msg.m_Check = 0;
|
|
|
|
Msg.m_Finish = 1;
|
2011-06-06 19:24:27 +00:00
|
|
|
|
2011-12-25 13:51:04 +00:00
|
|
|
if (pData->m_BestTime)
|
|
|
|
{
|
|
|
|
float Diff = (time - pData->m_BestTime) * 100;
|
|
|
|
Msg.m_Check = (int) Diff;
|
2011-06-06 19:24:27 +00:00
|
|
|
}
|
|
|
|
|
2011-12-25 13:51:04 +00:00
|
|
|
Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, Player->GetCID());
|
|
|
|
}
|
|
|
|
|
|
|
|
int TTime = 0 - (int) time;
|
|
|
|
if (Player->m_Score < TTime)
|
|
|
|
Player->m_Score = TTime;
|
2011-06-06 19:24:27 +00:00
|
|
|
|
|
|
|
}
|
2013-02-01 11:08:23 +00:00
|
|
|
|
|
|
|
void CGameTeams::OnCharacterSpawn(int ClientID)
|
|
|
|
{
|
|
|
|
m_Core.SetSolo(ClientID, false);
|
2013-11-15 23:44:49 +00:00
|
|
|
|
2014-02-03 14:46:30 +00:00
|
|
|
if (m_Core.Team(ClientID) >= TEAM_SUPER || !m_TeamLocked[m_Core.Team(ClientID)])
|
2013-11-15 23:44:49 +00:00
|
|
|
SetForceCharacterTeam(ClientID, 0);
|
2013-02-01 11:08:23 +00:00
|
|
|
}
|
|
|
|
|
2014-04-12 10:08:20 +00:00
|
|
|
void CGameTeams::OnCharacterDeath(int ClientID, int Weapon)
|
2013-02-01 11:08:23 +00:00
|
|
|
{
|
|
|
|
m_Core.SetSolo(ClientID, false);
|
2013-11-15 23:44:49 +00:00
|
|
|
|
2014-04-12 10:08:20 +00:00
|
|
|
int Team = m_Core.Team(ClientID);
|
|
|
|
bool Locked = TeamLocked(Team) && Weapon != WEAPON_GAME;
|
|
|
|
|
|
|
|
if (!Locked)
|
2014-09-26 01:42:49 +00:00
|
|
|
{
|
2013-11-15 23:44:49 +00:00
|
|
|
SetForceCharacterTeam(ClientID, 0);
|
2014-09-26 01:42:49 +00:00
|
|
|
CheckTeamFinished(Team);
|
2014-10-09 10:46:20 +00:00
|
|
|
|
|
|
|
char aBuf[256];
|
|
|
|
// console output
|
|
|
|
str_format(aBuf, sizeof(aBuf), "team_join player='%d:%s' team=0", ClientID, Server()->ClientName(ClientID));
|
|
|
|
GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf);
|
|
|
|
// output for died player
|
|
|
|
str_format(aBuf, sizeof(aBuf), "You are back to team 0.");
|
|
|
|
GameServer()->SendChatTarget(ClientID, aBuf);
|
|
|
|
// output for players of same team
|
|
|
|
str_format(aBuf, sizeof(aBuf), "'%s' joined team 0.", Server()->ClientName(ClientID));
|
|
|
|
for (int i = 0; i < MAX_CLIENTS; i++)
|
|
|
|
{
|
|
|
|
if(m_Core.Team(i) == Team && i!= ClientID &&GameServer()->m_apPlayers[i])
|
|
|
|
{
|
|
|
|
GameServer()->SendChatTarget(i, aBuf);
|
|
|
|
}
|
|
|
|
}
|
2014-09-26 01:42:49 +00:00
|
|
|
}
|
2014-02-08 13:33:42 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
SetForceCharacterTeam(ClientID, Team);
|
|
|
|
|
2014-10-09 10:46:20 +00:00
|
|
|
|
2014-04-12 10:08:20 +00:00
|
|
|
if (GetTeamState(Team) != TEAMSTATE_OPEN)
|
2014-10-09 10:46:20 +00:00
|
|
|
{
|
|
|
|
ChangeTeamState(Team, CGameTeams::TEAMSTATE_OPEN);
|
|
|
|
|
|
|
|
char aBuf[256];
|
|
|
|
// console output
|
|
|
|
str_format(aBuf, sizeof(aBuf), "team_restart team=%d cid=%d name='%s'", Team, ClientID,Server()->ClientName(ClientID));
|
|
|
|
GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf);
|
|
|
|
|
|
|
|
// output for Team Killer
|
|
|
|
str_format(aBuf, sizeof(aBuf), "You killed the whole team because it is locked", Server()->ClientName(ClientID));
|
|
|
|
GameServer()->SendChatTarget(ClientID, aBuf);
|
|
|
|
|
|
|
|
// output for whole Team, people dont care which team they are joining
|
|
|
|
str_format(aBuf, sizeof(aBuf), "Your team was killed by %s because team is locked", Server()->ClientName(ClientID));
|
2014-02-08 13:33:42 +00:00
|
|
|
for (int i = 0; i < MAX_CLIENTS; i++)
|
2014-10-09 10:46:20 +00:00
|
|
|
if(m_Core.Team(i) == Team && GameServer()->m_apPlayers[i])
|
|
|
|
{
|
|
|
|
if(i!= ClientID)
|
|
|
|
GameServer()->m_apPlayers[i]->KillCharacter(-2);
|
|
|
|
|
|
|
|
GameServer()->SendChatTarget(i, aBuf);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2014-02-08 13:33:42 +00:00
|
|
|
|
|
|
|
}
|
2013-11-15 23:44:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CGameTeams::SetTeamLock(int Team, bool Lock)
|
|
|
|
{
|
|
|
|
m_TeamLocked[Team] = Lock;
|
2013-02-01 11:08:23 +00:00
|
|
|
}
|
2014-07-26 12:46:31 +00:00
|
|
|
|
|
|
|
void CGameTeams::KillTeam(int Team)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < MAX_CLIENTS; i++)
|
|
|
|
if(m_Core.Team(i) == Team && GameServer()->m_apPlayers[i])
|
|
|
|
GameServer()->m_apPlayers[i]->KillCharacter(-2);
|
|
|
|
|
2014-08-31 12:12:15 +00:00
|
|
|
ChangeTeamState(Team, CGameTeams::TEAMSTATE_EMPTY);
|
2014-09-06 19:08:21 +00:00
|
|
|
|
|
|
|
// unlock team when last player leaves
|
2014-09-06 23:03:55 +00:00
|
|
|
SetTeamLock(Team, false);
|
2014-07-26 12:46:31 +00:00
|
|
|
}
|