ddnet/src/game/server/teams.cpp

729 lines
19 KiB
C++
Raw Normal View History

/* (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>
2010-08-28 13:47:52 +00:00
CGameTeams::CGameTeams(CGameContext *pGameContext) :
m_pGameContext(pGameContext)
{
Reset();
}
void CGameTeams::Reset()
{
m_Core.Reset();
for (int i = 0; i < MAX_CLIENTS; ++i)
{
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;
m_LastChat[i] = 0;
2013-11-15 23:44:49 +00:00
m_TeamLocked[i] = false;
m_IsSaving[i] = false;
m_Invited[i] = 0;
2010-08-28 13:47:52 +00:00
}
}
void CGameTeams::OnCharacterStart(int ClientID)
{
int Tick = Server()->Tick();
CCharacter* pStartingChar = Character(ClientID);
if (!pStartingChar)
return;
if (m_Core.Team(ClientID) != TEAM_FLOCK && pStartingChar->m_DDRaceState == DDRACE_FINISHED)
return;
if (m_Core.Team(ClientID) == TEAM_FLOCK
|| m_Core.Team(ClientID) == TEAM_SUPER)
{
pStartingChar->m_DDRaceState = DDRACE_STARTED;
pStartingChar->m_StartTime = Tick;
2011-02-14 21:34:46 +00:00
}
else
{
bool Waiting = false;
for (int i = 0; i < MAX_CLIENTS; ++i)
{
if (m_Core.Team(ClientID) == m_Core.Team(i))
{
CPlayer* pPlayer = GetPlayer(i);
if (pPlayer && pPlayer->IsPlaying()
&& GetDDRaceState(pPlayer) == DDRACE_FINISHED)
{
Waiting = true;
2011-11-08 13:21:03 +00:00
pStartingChar->m_DDRaceState = DDRACE_NONE;
2013-11-15 23:44:49 +00:00
if (m_LastChat[ClientID] + Server()->TickSpeed()
+ g_Config.m_SvChatDelay < Tick)
{
char aBuf[128];
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));
GameServer()->SendChatTarget(ClientID, aBuf);
m_LastChat[ClientID] = Tick;
}
if (m_LastChat[i] + Server()->TickSpeed()
+ g_Config.m_SvChatDelay < Tick)
{
char aBuf[128];
str_format(
aBuf,
sizeof(aBuf),
"%s wants to start a new round, kill or walk to start.",
Server()->ClientName(ClientID));
GameServer()->SendChatTarget(i, aBuf);
m_LastChat[i] = Tick;
}
}
}
}
if (m_TeamState[m_Core.Team(ClientID)] < TEAMSTATE_STARTED && !Waiting)
{
ChangeTeamState(m_Core.Team(ClientID), TEAMSTATE_STARTED);
char aBuf[512];
str_format(
aBuf,
sizeof(aBuf),
"Team %d started with these %d players: ",
m_Core.Team(ClientID),
Count(m_Core.Team(ClientID)));
bool First = true;
for (int i = 0; i < MAX_CLIENTS; ++i)
{
if (m_Core.Team(ClientID) == m_Core.Team(i))
{
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))))
{
SetDDRaceState(pPlayer, DDRACE_STARTED);
SetStartTime(pPlayer, Tick);
if (First)
First = false;
else
str_append(aBuf, ", ", sizeof(aBuf));
str_append(aBuf, GameServer()->Server()->ClientName(i), sizeof(aBuf));
}
}
}
2017-07-30 12:15:45 +00:00
if (g_Config.m_SvTeam < 3 && g_Config.m_SvTeamMaxSize != 2 && g_Config.m_SvPauseable)
{
2017-07-30 12:15:45 +00:00
for (int i = 0; i < MAX_CLIENTS; ++i)
2017-07-29 21:13:04 +00:00
{
2017-07-30 12:15:45 +00:00
CPlayer* pPlayer = GetPlayer(i);
if (m_Core.Team(ClientID) == m_Core.Team(i) && pPlayer && (pPlayer->IsPlaying() || TeamLocked(m_Core.Team(ClientID))))
{
GameServer()->SendChatTarget(i, aBuf);
}
}
2010-08-28 13:47:52 +00:00
}
}
}
}
void CGameTeams::OnCharacterFinish(int ClientID)
{
if (m_Core.Team(ClientID) == TEAM_FLOCK
|| m_Core.Team(ClientID) == TEAM_SUPER)
{
CPlayer* pPlayer = GetPlayer(ClientID);
if (pPlayer && pPlayer->IsPlaying())
{
float Time = (float)(Server()->Tick() - GetStartTime(pPlayer))
/ ((float)Server()->TickSpeed());
if (Time < 0.000001f)
return;
OnFinish(pPlayer, Time);
}
}
else
{
m_TeeFinished[ClientID] = true;
2013-07-21 06:46:52 +00:00
CheckTeamFinished(m_Core.Team(ClientID));
}
}
2013-07-21 06:46:52 +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))
{
CPlayer* pPlayer = GetPlayer(i);
if (pPlayer && pPlayer->IsPlaying())
{
m_TeeFinished[i] = false;
2013-07-21 06:46:52 +00:00
TeamPlayers[PlayersCount++] = pPlayer;
}
}
2010-08-28 13:47:52 +00:00
}
2014-09-26 10:43:56 +00:00
if (PlayersCount > 0)
2014-09-26 11:03:01 +00:00
{
float Time = (float)(Server()->Tick() - GetStartTime(TeamPlayers[0]))
/ ((float)Server()->TickSpeed());
if (Time < 0.000001f)
return;
2019-01-10 20:11:23 +00:00
for (unsigned int i = 0; i < PlayersCount; ++i)
OnFinish(TeamPlayers[i], Time);
2014-09-26 11:03:01 +00:00
ChangeTeamState(Team, TEAMSTATE_FINISHED); //TODO: Make it better
//ChangeTeamState(Team, TEAMSTATE_OPEN);
OnTeamFinish(TeamPlayers, PlayersCount, Time);
2014-09-26 11:03:01 +00:00
}
2010-08-28 13:47:52 +00:00
}
}
bool CGameTeams::SetCharacterTeam(int ClientID, int Team)
{
//Check on wrong parameters. +1 for TEAM_SUPER
if (ClientID < 0 || ClientID >= MAX_CLIENTS || Team < 0
|| Team >= MAX_CLIENTS + 1)
return false;
//You can join to TEAM_SUPER at any time, but any other group you cannot if it started
if (Team != TEAM_SUPER && m_TeamState[Team] > TEAMSTATE_OPEN)
return false;
//No need to switch team if you there
if (m_Core.Team(ClientID) == Team)
return false;
2014-01-10 23:13:35 +00:00
if (!Character(ClientID))
return false;
//You cannot be in TEAM_SUPER if you not super
if (Team == TEAM_SUPER && !Character(ClientID)->m_Super)
return false;
//if you begin race
2013-10-07 12:09:30 +00:00
if (Character(ClientID)->m_DDRaceState != DDRACE_NONE && Team != TEAM_SUPER)
return false;
SetForceCharacterTeam(ClientID, Team);
//GameServer()->CreatePlayerSpawn(Character(id)->m_Core.m_Pos, TeamMask());
return true;
2010-09-22 10:43:59 +00:00
}
void CGameTeams::SetForceCharacterTeam(int ClientID, int Team)
{
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)]--;
}
m_Core.Team(ClientID, Team);
2014-09-29 17:32:43 +00:00
if (m_Core.Team(ClientID) != TEAM_SUPER)
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]))
{
if (!m_TeamLocked[Team])
ChangeTeamState(Team, TEAMSTATE_OPEN);
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] = GameServer()->Collision()->m_pSwitchers[i].m_Initial;
GameServer()->Collision()->m_pSwitchers[i].m_EndTick[Team] = 0;
GameServer()->Collision()->m_pSwitchers[i].m_Type[Team] = TILE_SWITCHOPEN;
}
}
}
if (OldTeam != Team)
for (int LoopClientID = 0; LoopClientID < MAX_CLIENTS; ++LoopClientID)
if (GetPlayer(LoopClientID))
SendTeamsState(LoopClientID);
}
void CGameTeams::ForceLeaveTeam(int ClientID)
{
m_TeeFinished[ClientID] = false;
if (m_Core.Team(ClientID) != TEAM_FLOCK
&& m_Core.Team(ClientID) != TEAM_SUPER
&& m_TeamState[m_Core.Team(ClientID)] != TEAMSTATE_EMPTY)
{
bool NoOneInOldTeam = true;
for (int i = 0; i < MAX_CLIENTS; ++i)
if (i != ClientID && m_Core.Team(ClientID) == m_Core.Team(i))
{
NoOneInOldTeam = false; //all good exists someone in old team
break;
}
if (NoOneInOldTeam)
2013-11-15 23:44:49 +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);
2017-04-24 09:54:28 +00:00
ResetInvited(m_Core.Team(ClientID));
2013-11-15 23:44:49 +00:00
}
2010-08-28 13:47:52 +00:00
}
if (Count(m_Core.Team(ClientID)) > 0)
m_MembersCount[m_Core.Team(ClientID)]--;
}
2010-11-06 22:54:35 +00:00
int CGameTeams::Count(int Team) const
{
if (Team == TEAM_SUPER)
return -1;
return m_MembersCount[Team];
2010-08-28 13:47:52 +00:00
}
void CGameTeams::ChangeTeamState(int Team, int State)
{
int OldState = m_TeamState[Team];
m_TeamState[Team] = State;
onChangeTeamState(Team, State, OldState);
}
void CGameTeams::onChangeTeamState(int Team, int State, int OldState)
{
if (OldState != State && State == TEAMSTATE_STARTED)
{
// OnTeamStateStarting
}
if (OldState != State && State == TEAMSTATE_FINISHED)
{
// OnTeamStateFinishing
}
}
bool CGameTeams::TeamFinished(int Team)
{
for (int i = 0; i < MAX_CLIENTS; ++i)
if (m_Core.Team(i) == Team && !m_TeeFinished[i])
return false;
2010-08-28 13:47:52 +00:00
return true;
}
2013-12-31 05:13:57 +00:00
int64_t CGameTeams::TeamMask(int Team, int ExceptID, int Asker)
{
2014-01-22 14:47:01 +00:00
int64_t Mask = 0;
2014-01-20 19:12:03 +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
2017-04-08 22:20:41 +00:00
if (!(GetPlayer(i)->GetTeam() == -1 || GetPlayer(i)->IsPaused()))
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
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;
}
return Mask;
}
void CGameTeams::SendTeamsState(int ClientID)
{
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)
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);
}
int CGameTeams::GetDDRaceState(CPlayer* Player)
{
if (!Player)
return DDRACE_NONE;
CCharacter* pChar = Player->GetCharacter();
if (pChar)
return pChar->m_DDRaceState;
return DDRACE_NONE;
}
void CGameTeams::SetDDRaceState(CPlayer* Player, int DDRaceState)
{
if (!Player)
return;
CCharacter* pChar = Player->GetCharacter();
if (pChar)
pChar->m_DDRaceState = DDRaceState;
}
int CGameTeams::GetStartTime(CPlayer* Player)
{
if (!Player)
return 0;
CCharacter* pChar = Player->GetCharacter();
if (pChar)
return pChar->m_StartTime;
return 0;
}
void CGameTeams::SetStartTime(CPlayer* Player, int StartTime)
{
if (!Player)
return;
CCharacter* pChar = Player->GetCharacter();
if (pChar)
pChar->m_StartTime = StartTime;
}
void CGameTeams::SetCpActive(CPlayer* Player, int CpActive)
{
if (!Player)
return;
CCharacter* pChar = Player->GetCharacter();
if (pChar)
pChar->m_CpActive = CpActive;
}
float *CGameTeams::GetCpCurrent(CPlayer* Player)
{
if (!Player)
return NULL;
CCharacter* pChar = Player->GetCharacter();
if (pChar)
return pChar->m_CpCurrent;
return NULL;
}
void CGameTeams::OnTeamFinish(CPlayer** Players, unsigned int Size, float Time)
2013-07-21 06:46:52 +00:00
{
bool CallSaveScore = false;
#if defined(CONF_SQL)
CallSaveScore = g_Config.m_SvUseSQL;
#endif
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();
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())]))
{
SetForceCharacterTeam(Players[i]->GetCID(), 0);
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
}
if (CallSaveScore && Size >= 2)
2017-03-21 10:24:44 +00:00
GameServer()->Score()->SaveTeamScore(PlayerCIDs, Size, Time);
2013-07-21 06:46:52 +00:00
}
void CGameTeams::OnFinish(CPlayer* Player, float Time)
{
if (!Player || !Player->IsPlaying())
return;
//TODO:DDRace:btd: this ugly
CPlayerData *pData = GameServer()->Score()->PlayerData(Player->GetCID());
char aBuf[128];
SetCpActive(Player, -2);
str_format(aBuf, sizeof(aBuf),
"%s finished in: %d minute(s) %5.2f second(s)",
2017-03-21 10:24:44 +00:00
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)
GameServer()->SendChatTarget(Player->GetCID(), aBuf);
else
GameServer()->SendChat(-1, CGameContext::CHAT_ALL, aBuf);
2017-03-21 10:24:44 +00:00
float Diff = fabs(Time - pData->m_BestTime);
2017-03-21 10:24:44 +00:00
if (Time - pData->m_BestTime < 0)
{
// new record \o/
2017-03-21 10:24:44 +00:00
Server()->SaveDemo(Player->GetCID(), Time);
2017-03-21 10:24:44 +00:00
if (Diff >= 60)
str_format(aBuf, sizeof(aBuf), "New record: %d minute(s) %5.2f second(s) better.",
2017-03-21 10:24:44 +00:00
(int)Diff / 60, Diff - ((int)Diff / 60 * 60));
else
str_format(aBuf, sizeof(aBuf), "New record: %5.2f second(s) better.",
2017-03-21 10:24:44 +00:00
Diff);
2014-02-19 02:47:15 +00:00
if (g_Config.m_SvHideScore || !g_Config.m_SvSaveWorseScores)
GameServer()->SendChatTarget(Player->GetCID(), aBuf);
else
GameServer()->SendChat(-1, CGameContext::CHAT_ALL, aBuf);
}
else if (pData->m_BestTime != 0) // tee has already finished?
{
Server()->StopRecord(Player->GetCID());
2017-03-21 10:24:44 +00:00
if (Diff <= 0.005)
{
GameServer()->SendChatTarget(Player->GetCID(),
"You finished with your best time.");
}
else
{
2017-03-21 10:24:44 +00:00
if (Diff >= 60)
str_format(aBuf, sizeof(aBuf), "%d minute(s) %5.2f second(s) worse, better luck next time.",
2017-03-21 10:24:44 +00:00
(int)Diff / 60, Diff - ((int)Diff / 60 * 60));
else
str_format(aBuf, sizeof(aBuf),
"%5.2f second(s) worse, better luck next time.",
2017-03-21 10:24:44 +00:00
Diff);
GameServer()->SendChatTarget(Player->GetCID(), aBuf); //this is private, sent only to the tee
}
}
else
{
2017-03-21 10:24:44 +00:00
Server()->SaveDemo(Player->GetCID(), Time);
}
bool CallSaveScore = false;
#if defined(CONF_SQL)
2014-02-18 21:08:43 +00:00
CallSaveScore = g_Config.m_SvUseSQL && g_Config.m_SvSaveWorseScores;
#endif
2017-03-21 10:24:44 +00:00
if (!pData->m_BestTime || Time < pData->m_BestTime)
{
// update the score
2017-03-21 10:24:44 +00:00
pData->Set(Time, GetCpCurrent(Player));
CallSaveScore = true;
}
if (CallSaveScore)
if (g_Config.m_SvNamelessScore || !str_startswith(Server()->ClientName(Player->GetCID()), "nameless tee"))
2017-03-21 10:24:44 +00:00
GameServer()->Score()->SaveScore(Player->GetCID(), Time,
2018-12-17 13:55:58 +00:00
GetCpCurrent(Player), Player->m_NotEligibleForFinish);
bool NeedToSendNewRecord = false;
// update server best time
if (GameServer()->m_pController->m_CurrentRecord == 0
2017-03-21 10:24:44 +00:00
|| Time < GameServer()->m_pController->m_CurrentRecord)
{
// check for nameless
if (g_Config.m_SvNamelessScore || !str_startswith(Server()->ClientName(Player->GetCID()), "nameless tee"))
{
2017-03-21 10:24:44 +00:00
GameServer()->m_pController->m_CurrentRecord = Time;
//dbg_msg("character", "Finish");
NeedToSendNewRecord = true;
}
}
SetDDRaceState(Player, DDRACE_FINISHED);
// set player score
2017-03-21 10:24:44 +00:00
if (!pData->m_CurrentTime || pData->m_CurrentTime > Time)
{
2017-03-21 10:24:44 +00:00
pData->m_CurrentTime = Time;
NeedToSendNewRecord = true;
for (int i = 0; i < MAX_CLIENTS; i++)
{
if (GetPlayer(i) && GetPlayer(i)->m_ClientVersion >= VERSION_DDRACE)
{
if (!g_Config.m_SvHideScore || i == Player->GetCID())
{
CNetMsg_Sv_PlayerTime Msg;
2017-03-21 10:24:44 +00:00
Msg.m_Time = Time * 100.0;
Msg.m_ClientID = Player->GetCID();
Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, i);
}
}
}
}
if (NeedToSendNewRecord && Player->m_ClientVersion >= VERSION_DDRACE)
{
for (int i = 0; i < MAX_CLIENTS; i++)
{
if (GameServer()->m_apPlayers[i]
&& GameServer()->m_apPlayers[i]->m_ClientVersion >= VERSION_DDRACE)
{
GameServer()->SendRecord(i);
}
}
}
if (Player->m_ClientVersion >= VERSION_DDRACE)
{
CNetMsg_Sv_DDRaceTime Msg;
2017-03-21 10:24:44 +00:00
Msg.m_Time = (int)(Time * 100.0f);
Msg.m_Check = 0;
Msg.m_Finish = 1;
if (pData->m_BestTime)
{
2017-03-21 10:24:44 +00:00
float Diff = (Time - pData->m_BestTime) * 100;
Msg.m_Check = (int)Diff;
}
Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, Player->GetCID());
}
2017-03-21 10:24:44 +00:00
int TTime = 0 - (int)Time;
if (Player->m_Score < TTime || !Player->m_HasFinishScore)
{
Player->m_Score = TTime;
Player->m_HasFinishScore = true;
}
}
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);
}
void CGameTeams::OnCharacterDeath(int ClientID, int Weapon)
{
m_Core.SetSolo(ClientID, false);
2013-11-15 23:44:49 +00:00
int Team = m_Core.Team(ClientID);
bool Locked = TeamLocked(Team) && Weapon != WEAPON_GAME;
if(!Locked)
{
2013-11-15 23:44:49 +00:00
SetForceCharacterTeam(ClientID, 0);
CheckTeamFinished(Team);
}
else
{
SetForceCharacterTeam(ClientID, Team);
if(GetTeamState(Team) != TEAMSTATE_OPEN)
{
ChangeTeamState(Team, CGameTeams::TEAMSTATE_OPEN);
char aBuf[512];
str_format(aBuf, sizeof(aBuf), "Everyone in your locked team was killed because '%s' %s.", Server()->ClientName(ClientID), Weapon == WEAPON_SELF ? "killed" : "died");
for(int i = 0; i < MAX_CLIENTS; i++)
2017-05-20 23:20:04 +00:00
if(m_Core.Team(i) == Team && GameServer()->m_apPlayers[i])
{
2017-05-20 23:20:04 +00:00
if(i != ClientID)
{
GameServer()->m_apPlayers[i]->KillCharacter(WEAPON_SELF);
if (Weapon == WEAPON_SELF)
GameServer()->m_apPlayers[i]->Respawn(true); // spawn the rest of team with weak hook on the killer
}
if(m_MembersCount[Team] > 1)
GameServer()->SendChatTarget(i, aBuf);
}
}
}
2013-11-15 23:44:49 +00:00
}
void CGameTeams::SetTeamLock(int Team, bool Lock)
{
if(Team > TEAM_FLOCK && Team < TEAM_SUPER)
m_TeamLocked[Team] = Lock;
}
void CGameTeams::ResetInvited(int Team)
{
m_Invited[Team] = 0;
}
void CGameTeams::SetClientInvited(int Team, int ClientID, bool Invited)
{
if(Team > TEAM_FLOCK && Team < TEAM_SUPER)
{
if(Invited)
m_Invited[Team] |= 1ULL << ClientID;
else
m_Invited[Team] &= ~(1ULL << ClientID);
}
}
2014-07-26 12:46:31 +00:00
void CGameTeams::KillSavedTeam(int Team)
2014-07-26 12:46:31 +00:00
{
// Set so that no finish is accidentally given to some of the players
ChangeTeamState(Team, CGameTeams::TEAMSTATE_OPEN);
2014-10-21 12:57:58 +00:00
for (int i = 0; i < MAX_CLIENTS; i++)
2015-08-22 13:16:14 +00:00
{
2014-10-21 12:57:58 +00:00
if(m_Core.Team(i) == Team && GameServer()->m_apPlayers[i])
2015-08-22 13:16:14 +00:00
{
// Set so that no finish is accidentally given to some of the players
GameServer()->m_apPlayers[i]->GetCharacter()->m_DDRaceState = DDRACE_NONE;
2014-10-21 12:57:58 +00:00
m_TeeFinished[i] = false;
2015-08-22 13:16:14 +00:00
}
}
2014-10-21 12:57:58 +00:00
2014-07-26 12:46:31 +00:00
for (int i = 0; i < MAX_CLIENTS; i++)
if(m_Core.Team(i) == Team && GameServer()->m_apPlayers[i])
GameServer()->m_apPlayers[i]->ThreadKillCharacter(-2);
2014-07-26 12:46:31 +00:00
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);
2017-04-24 09:54:28 +00:00
ResetInvited(Team);
2014-07-26 12:46:31 +00:00
}