| 1 | /* (c) Shereef Marzouk. See "licence DDRace.txt" and the readme.txt in the root of the distribution for more information. */ |
| 2 | #ifndef GAME_SERVER_TEAMS_H |
| 3 | #define GAME_SERVER_TEAMS_H |
| 4 | |
| 5 | #include <engine/shared/protocol.h> |
| 6 | |
| 7 | #include <game/race_state.h> |
| 8 | #include <game/server/gamecontext.h> |
| 9 | #include <game/team_state.h> |
| 10 | #include <game/teamscore.h> |
| 11 | |
| 12 | class CCharacter; |
| 13 | class CPlayer; |
| 14 | struct CScoreSaveResult; |
| 15 | |
| 16 | class CGameTeams |
| 17 | { |
| 18 | // `m_TeeStarted` is used to keep track whether a given tee has hit the |
| 19 | // start of the map yet. If a tee that leaves hasn't hit the start line |
| 20 | // yet, the team will be marked as "not allowed to finish" |
| 21 | // (`ETeamState::STARTED_UNFINISHABLE`). If this were not the case, tees |
| 22 | // could go around the startline on a map, leave one tee behind at |
| 23 | // start, go to the finish line, let the tee start and kill, allowing |
| 24 | // the team to finish instantly. |
| 25 | bool m_aTeeStarted[MAX_CLIENTS]; |
| 26 | bool m_aTeeFinished[MAX_CLIENTS]; |
| 27 | int m_aLastChat[MAX_CLIENTS]; |
| 28 | |
| 29 | ETeamState m_aTeamState[NUM_DDRACE_TEAMS]; |
| 30 | bool m_aTeamLocked[NUM_DDRACE_TEAMS]; |
| 31 | bool m_aTeamFlock[NUM_DDRACE_TEAMS]; |
| 32 | CClientMask m_aInvited[NUM_DDRACE_TEAMS]; |
| 33 | bool m_aPractice[NUM_DDRACE_TEAMS]; |
| 34 | std::shared_ptr<CScoreSaveResult> m_apSaveTeamResult[NUM_DDRACE_TEAMS]; |
| 35 | uint64_t m_aLastSwap[MAX_CLIENTS]; // index is id of player who initiated swap |
| 36 | bool m_aTeamSentStartWarning[NUM_DDRACE_TEAMS]; |
| 37 | // `m_aTeamUnfinishableKillTick` is -1 by default and gets set when a |
| 38 | // team becomes unfinishable. If the team hasn't entered practice mode |
| 39 | // by that time, it'll get killed to prevent people not understanding |
| 40 | // the message from playing for a long time in an unfinishable team. |
| 41 | int m_aTeamUnfinishableKillTick[NUM_DDRACE_TEAMS]; |
| 42 | |
| 43 | CGameContext *m_pGameContext; |
| 44 | |
| 45 | /** |
| 46 | * Kill the whole team. |
| 47 | * @param Team The team id to kill |
| 48 | * @param NewStrongId The player with that id will get strong hook on everyone else, -1 will set the normal spawning order |
| 49 | * @param ExceptId The player that should not get killed |
| 50 | */ |
| 51 | void KillTeam(int Team, int NewStrongId, int ExceptId = -1); |
| 52 | bool TeamFinished(int Team); |
| 53 | void OnTeamFinish(int Team, CPlayer **Players, unsigned int Size, int TimeTicks, const char *pTimestamp); |
| 54 | void OnFinish(CPlayer *Player, int TimeTicks, const char *pTimestamp); |
| 55 | |
| 56 | public: |
| 57 | CTeamsCore m_Core; |
| 58 | |
| 59 | CGameTeams(CGameContext *pGameContext); |
| 60 | |
| 61 | // helper methods |
| 62 | CCharacter *Character(int ClientId); |
| 63 | const CCharacter *Character(int ClientId) const; |
| 64 | CPlayer *GetPlayer(int ClientId); |
| 65 | CGameContext *GameServer(); |
| 66 | const CGameContext *GameServer() const; |
| 67 | class IServer *Server(); |
| 68 | |
| 69 | void OnCharacterStart(int ClientId); |
| 70 | void OnCharacterFinish(int ClientId); |
| 71 | void OnCharacterSpawn(int ClientId); |
| 72 | void OnCharacterDeath(int ClientId, int Weapon); |
| 73 | void Tick(); |
| 74 | |
| 75 | // sets pError to an empty string on success (true) |
| 76 | // and sets pError if it returns false |
| 77 | bool CanJoinTeam(int ClientId, int Team, char *pError, int ErrorSize) const; |
| 78 | |
| 79 | // returns true if successful. Writes error into pError on failure |
| 80 | bool SetCharacterTeam(int ClientId, int Team, char *pError, int ErrorSize); |
| 81 | void CheckTeamFinished(int Team); |
| 82 | |
| 83 | void ChangeTeamState(int Team, ETeamState State); |
| 84 | |
| 85 | CClientMask TeamMask(int Team, int ExceptId = -1, int Asker = -1, int VersionFlags = CGameContext::FLAG_SIX | CGameContext::FLAG_SIXUP); |
| 86 | |
| 87 | int Count(int Team) const; |
| 88 | |
| 89 | // need to be very careful using this method. SERIOUSLY... |
| 90 | void SetForceCharacterTeam(int ClientId, int Team); |
| 91 | |
| 92 | void Reset(); |
| 93 | void ResetRoundState(int Team); |
| 94 | void ResetSwitchers(int Team); |
| 95 | |
| 96 | void SendTeamsState(int ClientId); |
| 97 | void SetTeamLock(int Team, bool Lock); |
| 98 | void SetTeamFlock(int Team, bool Mode); |
| 99 | void ResetInvited(int Team); |
| 100 | void SetClientInvited(int Team, int ClientId, bool Invited); |
| 101 | |
| 102 | ERaceState GetDDRaceState(const CPlayer *Player) const; |
| 103 | int GetStartTime(CPlayer *Player); |
| 104 | float *GetCurrentTimeCp(CPlayer *Player); |
| 105 | void SetDDRaceState(CPlayer *Player, ERaceState DDRaceState); |
| 106 | void SetStartTime(CPlayer *Player, int StartTime); |
| 107 | void SetLastTimeCp(CPlayer *Player, int LastTimeCp); |
| 108 | void KillCharacterOrTeam(int ClientId, int Team); |
| 109 | void ResetSavedTeam(int ClientId, int Team); |
| 110 | void RequestTeamSwap(CPlayer *pPlayer, CPlayer *pTargetPlayer, int Team); |
| 111 | void SwapTeamCharacters(CPlayer *pPrimaryPlayer, CPlayer *pTargetPlayer, int Team); |
| 112 | void CancelTeamSwap(CPlayer *pPlayer, int Team); |
| 113 | void ProcessSaveTeam(); |
| 114 | std::optional<int> GetFirstEmptyTeam() const; |
| 115 | bool TeeStarted(int ClientId) const; |
| 116 | bool TeeFinished(int ClientId) const; |
| 117 | ETeamState GetTeamState(int Team) const; |
| 118 | bool TeamLocked(int Team) const; |
| 119 | bool TeamFlock(int Team) const; |
| 120 | bool IsInvited(int Team, int ClientId) const; |
| 121 | bool IsStarted(int Team) const; |
| 122 | void SetStarted(int ClientId, bool Started); |
| 123 | void SetFinished(int ClientId, bool Finished); |
| 124 | void SetSaving(int TeamId, std::shared_ptr<CScoreSaveResult> &SaveResult); |
| 125 | bool GetSaving(int TeamId) const; |
| 126 | void SetPractice(int Team, bool Enabled); |
| 127 | bool IsPractice(int Team); |
| 128 | bool IsValidTeamNumber(int Team) const; |
| 129 | }; |
| 130 | |
| 131 | #endif |
| 132 | |