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
|
|
|
#ifndef GAME_SERVER_TEAMS_H
|
|
|
|
#define GAME_SERVER_TEAMS_H
|
|
|
|
|
2020-06-30 18:22:17 +00:00
|
|
|
#include <engine/shared/config.h>
|
2010-08-28 13:47:52 +00:00
|
|
|
#include <game/server/gamecontext.h>
|
2021-01-09 14:37:02 +00:00
|
|
|
#include <game/server/score.h>
|
2020-09-26 19:41:58 +00:00
|
|
|
#include <game/teamscore.h>
|
2010-08-28 13:47:52 +00:00
|
|
|
|
2020-11-05 10:34:20 +00:00
|
|
|
#include <utility>
|
|
|
|
|
2011-01-06 05:30:19 +00:00
|
|
|
class CGameTeams
|
|
|
|
{
|
2013-12-28 15:09:03 +00:00
|
|
|
int m_TeamState[MAX_CLIENTS];
|
2021-07-20 11:37:02 +00:00
|
|
|
// `m_TeeStarted` is used to keep track whether a given tee has hit the
|
|
|
|
// start of the map yet. If a tee that leaves hasn't hit the start line
|
|
|
|
// yet, the team will be marked as "not allowed to finish"
|
|
|
|
// (`TEAMSTATE_STARTED_UNFINISHABLE`). If this were not the case, tees
|
|
|
|
// could go around the startline on a map, leave one tee behind at
|
|
|
|
// start, go to the finish line, let the tee start and kill, allowing
|
|
|
|
// the team to finish instantly.
|
|
|
|
bool m_TeeStarted[MAX_CLIENTS];
|
2013-12-28 15:09:03 +00:00
|
|
|
bool m_TeeFinished[MAX_CLIENTS];
|
|
|
|
bool m_TeamLocked[MAX_CLIENTS];
|
2021-06-23 05:05:49 +00:00
|
|
|
uint64_t m_Invited[MAX_CLIENTS];
|
2020-05-22 21:59:47 +00:00
|
|
|
bool m_Practice[MAX_CLIENTS];
|
2020-06-24 21:14:09 +00:00
|
|
|
std::shared_ptr<CScoreSaveResult> m_pSaveTeamResult[MAX_CLIENTS];
|
2021-06-23 05:05:49 +00:00
|
|
|
uint64_t m_LastSwap[MAX_CLIENTS];
|
2021-07-20 20:34:09 +00:00
|
|
|
bool m_TeamSentStartWarning[MAX_CLIENTS];
|
2021-09-10 16:14:16 +00:00
|
|
|
// `m_TeamUnfinishableKillTick` is -1 by default and gets set when a
|
|
|
|
// team becomes unfinishable. If the team hasn't entered practice mode
|
|
|
|
// by that time, it'll get killed to prevent people not understanding
|
|
|
|
// the message from playing for a long time in an unfinishable team.
|
|
|
|
int m_TeamUnfinishableKillTick[MAX_CLIENTS];
|
2011-12-25 13:51:04 +00:00
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
class CGameContext *m_pGameContext;
|
2011-12-25 13:51:04 +00:00
|
|
|
|
2021-09-10 16:14:16 +00:00
|
|
|
// Kill the whole team, making the player `NewStrongID` have strong
|
|
|
|
// hook on everyone else. `NewStrongID` can be -1 to get the normal
|
|
|
|
// spawning order.
|
|
|
|
void KillTeam(int Team, int NewStrongID);
|
2019-01-10 08:32:23 +00:00
|
|
|
bool TeamFinished(int Team);
|
2020-09-26 19:41:58 +00:00
|
|
|
void OnTeamFinish(CPlayer **Players, unsigned int Size, float Time, const char *pTimestamp);
|
|
|
|
void OnFinish(CPlayer *Player, float Time, const char *pTimestamp);
|
2019-01-10 08:32:23 +00:00
|
|
|
|
2010-08-28 13:47:52 +00:00
|
|
|
public:
|
2011-03-16 13:14:25 +00:00
|
|
|
enum
|
2011-01-06 05:30:19 +00:00
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
TEAMSTATE_EMPTY,
|
|
|
|
TEAMSTATE_OPEN,
|
|
|
|
TEAMSTATE_STARTED,
|
2021-07-20 11:37:02 +00:00
|
|
|
// Happens when a tee that hasn't hit the start tiles leaves
|
|
|
|
// the team.
|
|
|
|
TEAMSTATE_STARTED_UNFINISHABLE,
|
2020-09-26 19:41:58 +00:00
|
|
|
TEAMSTATE_FINISHED
|
2010-08-28 13:47:52 +00:00
|
|
|
};
|
2011-12-25 13:51:04 +00:00
|
|
|
|
2010-08-30 12:13:43 +00:00
|
|
|
CTeamsCore m_Core;
|
2011-12-25 13:51:04 +00:00
|
|
|
|
2010-08-30 12:13:43 +00:00
|
|
|
CGameTeams(CGameContext *pGameContext);
|
2011-12-25 13:51:04 +00:00
|
|
|
|
2021-01-23 14:45:07 +00:00
|
|
|
// helper methods
|
2020-09-26 19:41:58 +00:00
|
|
|
CCharacter *Character(int ClientID)
|
2011-12-25 13:51:04 +00:00
|
|
|
{
|
|
|
|
return GameServer()->GetPlayerChar(ClientID);
|
|
|
|
}
|
2020-09-26 19:41:58 +00:00
|
|
|
CPlayer *GetPlayer(int ClientID)
|
2011-12-25 13:51:04 +00:00
|
|
|
{
|
|
|
|
return GameServer()->m_apPlayers[ClientID];
|
|
|
|
}
|
|
|
|
|
|
|
|
class CGameContext *GameServer()
|
|
|
|
{
|
|
|
|
return m_pGameContext;
|
|
|
|
}
|
|
|
|
class IServer *Server()
|
|
|
|
{
|
|
|
|
return m_pGameContext->Server();
|
|
|
|
}
|
2010-08-28 20:53:42 +00:00
|
|
|
|
2011-02-02 10:49:19 +00:00
|
|
|
void OnCharacterStart(int ClientID);
|
|
|
|
void OnCharacterFinish(int ClientID);
|
2013-02-01 11:08:23 +00:00
|
|
|
void OnCharacterSpawn(int ClientID);
|
2014-04-12 10:08:20 +00:00
|
|
|
void OnCharacterDeath(int ClientID, int Weapon);
|
2021-07-20 20:34:09 +00:00
|
|
|
void Tick();
|
2011-12-25 13:51:04 +00:00
|
|
|
|
2021-01-23 14:45:07 +00:00
|
|
|
// returns nullptr if successful, error string if failed
|
|
|
|
const char *SetCharacterTeam(int ClientID, int Team);
|
2020-11-20 17:11:06 +00:00
|
|
|
void CheckTeamFinished(int ClientID);
|
2011-12-25 13:51:04 +00:00
|
|
|
|
2011-03-16 13:14:25 +00:00
|
|
|
void ChangeTeamState(int Team, int State);
|
2011-12-25 13:51:04 +00:00
|
|
|
|
2021-06-23 05:05:49 +00:00
|
|
|
int64_t TeamMask(int Team, int ExceptID = -1, int Asker = -1);
|
2011-12-25 13:51:04 +00:00
|
|
|
|
2010-11-06 22:54:35 +00:00
|
|
|
int Count(int Team) const;
|
2011-12-25 13:51:04 +00:00
|
|
|
|
2021-01-23 14:45:07 +00:00
|
|
|
// need to be very careful using this method. SERIOUSLY...
|
2020-05-30 22:34:29 +00:00
|
|
|
void SetForceCharacterTeam(int ClientID, int Team);
|
2011-12-25 13:51:04 +00:00
|
|
|
|
2010-09-24 13:37:13 +00:00
|
|
|
void Reset();
|
2021-03-16 22:31:16 +00:00
|
|
|
void ResetRoundState(int Team);
|
2020-07-01 06:49:51 +00:00
|
|
|
void ResetSwitchers(int Team);
|
2011-12-25 13:51:04 +00:00
|
|
|
|
2020-05-30 22:34:29 +00:00
|
|
|
void SendTeamsState(int ClientID);
|
2013-11-15 23:44:49 +00:00
|
|
|
void SetTeamLock(int Team, bool Lock);
|
2017-04-23 20:50:07 +00:00
|
|
|
void ResetInvited(int Team);
|
|
|
|
void SetClientInvited(int Team, int ClientID, bool Invited);
|
2010-12-19 03:48:16 +00:00
|
|
|
|
|
|
|
int m_LastChat[MAX_CLIENTS];
|
2011-06-06 19:24:27 +00:00
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
int GetDDRaceState(CPlayer *Player);
|
|
|
|
int GetStartTime(CPlayer *Player);
|
|
|
|
float *GetCpCurrent(CPlayer *Player);
|
|
|
|
void SetDDRaceState(CPlayer *Player, int DDRaceState);
|
|
|
|
void SetStartTime(CPlayer *Player, int StartTime);
|
|
|
|
void SetCpActive(CPlayer *Player, int CpActive);
|
2020-06-02 14:27:31 +00:00
|
|
|
void KillSavedTeam(int ClientID, int Team);
|
|
|
|
void ResetSavedTeam(int ClientID, int Team);
|
2021-03-20 16:33:34 +00:00
|
|
|
void RequestTeamSwap(CPlayer *pPlayer, CPlayer *pTargetPlayer, int Team);
|
|
|
|
void SwapTeamCharacters(CPlayer *pPlayer, CPlayer *pTargetPlayer, int Team);
|
2020-06-02 14:27:31 +00:00
|
|
|
void ProcessSaveTeam();
|
2014-12-17 19:38:05 +00:00
|
|
|
|
2021-08-10 19:26:07 +00:00
|
|
|
int GetFirstEmptyTeam() const;
|
|
|
|
|
2021-07-20 20:16:40 +00:00
|
|
|
bool TeeStarted(int ClientID)
|
|
|
|
{
|
|
|
|
return m_TeeStarted[ClientID];
|
|
|
|
}
|
|
|
|
|
2011-12-25 13:51:04 +00:00
|
|
|
bool TeeFinished(int ClientID)
|
|
|
|
{
|
|
|
|
return m_TeeFinished[ClientID];
|
|
|
|
}
|
2014-12-17 19:38:05 +00:00
|
|
|
|
2011-12-25 13:51:04 +00:00
|
|
|
int GetTeamState(int Team)
|
|
|
|
{
|
|
|
|
return m_TeamState[Team];
|
|
|
|
}
|
2014-12-17 19:38:05 +00:00
|
|
|
|
2013-11-15 23:44:49 +00:00
|
|
|
bool TeamLocked(int Team)
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
if(Team <= TEAM_FLOCK || Team >= TEAM_SUPER)
|
2014-01-30 02:37:45 +00:00
|
|
|
return false;
|
|
|
|
|
2013-11-15 23:44:49 +00:00
|
|
|
return m_TeamLocked[Team];
|
|
|
|
}
|
2014-12-17 19:38:05 +00:00
|
|
|
|
2017-04-23 20:50:07 +00:00
|
|
|
bool IsInvited(int Team, int ClientID)
|
|
|
|
{
|
|
|
|
return m_Invited[Team] & 1LL << ClientID;
|
|
|
|
}
|
|
|
|
|
2021-03-16 22:31:16 +00:00
|
|
|
bool IsStarted(int Team)
|
|
|
|
{
|
|
|
|
return m_TeamState[Team] == CGameTeams::TEAMSTATE_STARTED;
|
|
|
|
}
|
|
|
|
|
2021-07-20 20:16:40 +00:00
|
|
|
void SetStarted(int ClientID, bool Started)
|
|
|
|
{
|
|
|
|
m_TeeStarted[ClientID] = Started;
|
|
|
|
}
|
|
|
|
|
2021-07-20 11:37:02 +00:00
|
|
|
void SetFinished(int ClientID, bool Finished)
|
2014-07-26 12:46:31 +00:00
|
|
|
{
|
2021-07-20 11:37:02 +00:00
|
|
|
m_TeeFinished[ClientID] = Finished;
|
2014-07-26 12:46:31 +00:00
|
|
|
}
|
2020-06-24 21:14:09 +00:00
|
|
|
|
2020-12-04 09:53:28 +00:00
|
|
|
void SetSaving(int TeamID, std::shared_ptr<CScoreSaveResult> &SaveResult)
|
2014-12-17 19:38:05 +00:00
|
|
|
{
|
2020-12-04 09:53:28 +00:00
|
|
|
m_pSaveTeamResult[TeamID] = SaveResult;
|
2014-12-17 19:38:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool GetSaving(int TeamID)
|
|
|
|
{
|
2020-06-30 18:22:17 +00:00
|
|
|
if(TeamID < TEAM_FLOCK || TeamID >= TEAM_SUPER)
|
|
|
|
return false;
|
|
|
|
if(g_Config.m_SvTeam != 3 && TeamID == TEAM_FLOCK)
|
2020-06-28 11:25:39 +00:00
|
|
|
return false;
|
|
|
|
|
2020-06-02 14:27:31 +00:00
|
|
|
return m_pSaveTeamResult[TeamID] != nullptr;
|
2014-12-17 19:38:05 +00:00
|
|
|
}
|
2020-05-22 21:59:47 +00:00
|
|
|
|
|
|
|
void EnablePractice(int Team)
|
|
|
|
{
|
2020-06-30 18:22:17 +00:00
|
|
|
if(Team < TEAM_FLOCK || Team >= TEAM_SUPER)
|
|
|
|
return;
|
|
|
|
if(g_Config.m_SvTeam != 3 && Team == TEAM_FLOCK)
|
2020-05-22 21:59:47 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
m_Practice[Team] = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsPractice(int Team)
|
|
|
|
{
|
2020-06-30 18:22:17 +00:00
|
|
|
if(Team < TEAM_FLOCK || Team >= TEAM_SUPER)
|
|
|
|
return false;
|
|
|
|
if(g_Config.m_SvTeam != 3 && Team == TEAM_FLOCK)
|
2020-05-22 21:59:47 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
return m_Practice[Team];
|
|
|
|
}
|
2010-08-28 13:47:52 +00:00
|
|
|
};
|
|
|
|
|
2010-09-08 16:22:11 +00:00
|
|
|
#endif
|