ddnet/src/game/server/gamecontroller.h
ChillerDragon 157e8b7302 Pass error message as buffer to CanJoinTeam()
Now `CGameContext` no longer assumes the `IGameController`
declined the team join due to slots.

This enables custom gametypes to disallow joining the game if the player
died, an active tournament is running or the player is not logged in
yet. And then the controller can print the correct error message
accordingly.
2023-12-13 14:46:37 +01:00

164 lines
3.7 KiB
C++

/* (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_GAMECONTROLLER_H
#define GAME_SERVER_GAMECONTROLLER_H
#include <base/vmath.h>
#include <engine/map.h>
#include <engine/shared/protocol.h>
#include <game/server/teams.h>
#include <map>
#include <vector>
struct CScoreLoadBestTimeResult;
/*
Class: Game Controller
Controls the main game logic. Keeping track of team and player score,
winning conditions and specific game logic.
*/
class IGameController
{
friend class CSaveTeam; // need access to GameServer() and Server()
std::vector<vec2> m_avSpawnPoints[3];
class CGameContext *m_pGameServer;
class CConfig *m_pConfig;
class IServer *m_pServer;
CGameTeams m_Teams;
protected:
CGameContext *GameServer() const { return m_pGameServer; }
CConfig *Config() { return m_pConfig; }
IServer *Server() const { return m_pServer; }
void DoActivityCheck();
struct CSpawnEval
{
CSpawnEval()
{
m_Got = false;
m_FriendlyTeam = -1;
m_Pos = vec2(100, 100);
}
vec2 m_Pos;
bool m_Got;
int m_FriendlyTeam;
float m_Score;
};
float EvaluateSpawnPos(CSpawnEval *pEval, vec2 Pos, int DDTeam);
void EvaluateSpawnType(CSpawnEval *pEval, int Type, int DDTeam);
void ResetGame();
char m_aMapWish[MAX_MAP_LENGTH];
int m_RoundStartTick;
int m_GameOverTick;
int m_SuddenDeath;
int m_Warmup;
int m_RoundCount;
int m_GameFlags;
int m_UnbalancedTick;
bool m_ForceBalanced;
public:
const char *m_pGameType;
IGameController(class CGameContext *pGameServer);
virtual ~IGameController();
// event
/*
Function: OnCharacterDeath
Called when a CCharacter in the world dies.
Arguments:
victim - The CCharacter that died.
killer - The player that killed it.
weapon - What weapon that killed it. Can be -1 for undefined
weapon when switching team or player suicides.
*/
virtual int OnCharacterDeath(class CCharacter *pVictim, class CPlayer *pKiller, int Weapon);
/*
Function: OnCharacterSpawn
Called when a CCharacter spawns into the game world.
Arguments:
chr - The CCharacter that was spawned.
*/
virtual void OnCharacterSpawn(class CCharacter *pChr);
virtual void HandleCharacterTiles(class CCharacter *pChr, int MapIndex);
/*
Function: OnEntity
Called when the map is loaded to process an entity
in the map.
Arguments:
index - Entity index.
pos - Where the entity is located in the world.
Returns:
bool?
*/
virtual bool OnEntity(int Index, int x, int y, int Layer, int Flags, bool Initial, int Number = 0);
virtual void OnPlayerConnect(class CPlayer *pPlayer);
virtual void OnPlayerDisconnect(class CPlayer *pPlayer, const char *pReason);
virtual void OnReset();
// game
void DoWarmup(int Seconds);
void StartRound();
void EndRound();
void ChangeMap(const char *pToMap);
bool IsForceBalanced();
/*
*/
virtual bool CanBeMovedOnBalance(int ClientID);
virtual void Tick();
virtual void Snap(int SnappingClient);
//spawn
virtual bool CanSpawn(int Team, vec2 *pOutPos, int DDTeam);
virtual void DoTeamChange(class CPlayer *pPlayer, int Team, bool DoChatMsg = true);
/*
*/
virtual const char *GetTeamName(int Team);
virtual int GetAutoTeam(int NotThisID);
virtual bool CanJoinTeam(int Team, int NotThisID, char *pErrorReason, int ErrorReasonSize);
int ClampTeam(int Team);
CClientMask GetMaskForPlayerWorldEvent(int Asker, int ExceptID = -1);
virtual void InitTeleporter();
// DDRace
float m_CurrentRecord;
std::map<int, std::vector<vec2>> m_TeleOuts;
std::map<int, std::vector<vec2>> m_TeleCheckOuts;
CGameTeams &Teams() { return m_Teams; }
std::shared_ptr<CScoreLoadBestTimeResult> m_pLoadBestTimeResult;
};
#endif