mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-16 08:10:32 +02:00
395 lines
12 KiB
C++
395 lines
12 KiB
C++
// Copyright (C) 2004 Id Software, Inc.
|
|
//
|
|
|
|
#ifndef __MULTIPLAYERGAME_H__
|
|
#define __MULTIPLAYERGAME_H__
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
Basic DOOM multiplayer
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
class idPlayer;
|
|
|
|
typedef enum {
|
|
GAME_SP,
|
|
GAME_DM,
|
|
GAME_TOURNEY,
|
|
GAME_TDM,
|
|
GAME_LASTMAN
|
|
} gameType_t;
|
|
|
|
typedef enum {
|
|
PLAYER_VOTE_NONE,
|
|
PLAYER_VOTE_NO,
|
|
PLAYER_VOTE_YES,
|
|
PLAYER_VOTE_WAIT // mark a player allowed to vote
|
|
} playerVote_t;
|
|
|
|
typedef struct mpPlayerState_s {
|
|
int ping; // player ping
|
|
int fragCount; // kills
|
|
int teamFragCount; // team kills
|
|
int wins; // wins
|
|
playerVote_t vote; // player's vote
|
|
bool scoreBoardUp; // toggle based on player scoreboard button, used to activate de-activate the scoreboard gui
|
|
bool ingame;
|
|
} mpPlayerState_t;
|
|
|
|
// HUMANHEAD pdm: Reworked for our chat system
|
|
const int NUM_CHAT_HISTORY_LINES = 10;
|
|
const int NUM_CHAT_DISPLAY_LINES = 10;
|
|
const int CHAT_MAX_LIFE_TIME = 8000;
|
|
const int MAX_HISTORY_LIST = 50; //fixme: bump up once we fix the wrap around case
|
|
// HUMANHEAD END
|
|
const int FRAGLIMIT_DELAY = -1; //HUMANHEAD rww - was 2000, doing away with sudden death
|
|
|
|
const int MP_PLAYER_MINFRAGS = -100;
|
|
const int MP_PLAYER_MAXFRAGS = 100;
|
|
const int MP_PLAYER_MAXWINS = 100;
|
|
const int MP_PLAYER_MAXPING = 999;
|
|
|
|
// HUMANHEAD pdm: Reworked for our chat system
|
|
typedef struct mpChatLine_s {
|
|
idStr line;
|
|
int startTime;
|
|
} mpChatLine_t;
|
|
// HUMANHEAD END
|
|
|
|
typedef enum {
|
|
SND_YOUWIN = 0,
|
|
SND_YOULOSE,
|
|
SND_FIGHT,
|
|
SND_VOTE,
|
|
SND_VOTE_PASSED,
|
|
SND_VOTE_FAILED,
|
|
SND_THREE,
|
|
SND_TWO,
|
|
SND_ONE,
|
|
SND_SUDDENDEATH,
|
|
//HUMANHEAD rww
|
|
SND_LEADTAKEN,
|
|
SND_LEADLOST,
|
|
SND_LEADTIED,
|
|
//HUMANHEAD END
|
|
SND_COUNT
|
|
} snd_evt_t;
|
|
|
|
//HUMANHEAD PCF rww 05/17/06 - terrible lastminute hackjob for localized vote text
|
|
#define _HH_LOCALIZE_VOTESTRINGS 1
|
|
//HUMANHEAD END
|
|
|
|
class idMultiplayerGame {
|
|
public:
|
|
|
|
idMultiplayerGame();
|
|
|
|
void Shutdown( void );
|
|
|
|
// resets everything and prepares for a match
|
|
void Reset( void );
|
|
|
|
// setup local data for a new player
|
|
void SpawnPlayer( int clientNum );
|
|
|
|
// checks rules and updates state of the mp game
|
|
void Run( void );
|
|
|
|
// draws mp hud, scoredboard, etc..
|
|
bool Draw( int clientNum );
|
|
|
|
// updates a player vote
|
|
void PlayerVote( int clientNum, playerVote_t vote );
|
|
|
|
// updates frag counts and potentially ends the match in sudden death
|
|
void PlayerDeath( idPlayer *dead, idPlayer *killer, idEntity *inflictor, bool telefrag ); //HUMANHEAD rww - pass inflictor
|
|
|
|
void AddChatLine( const char *fmt, ... ) id_attribute((format(printf,2,3)));
|
|
|
|
void UpdateMainGui( void );
|
|
idUserInterface*StartMenu( void );
|
|
const char* HandleGuiCommands( const char *menuCommand );
|
|
// void SetMenuSkin( void ); // HUMANHEAD pdm: removed
|
|
|
|
void CheckScoreChange(int clientNum, int oldScore, int newScore, bool leavingGame); //HUMANHEAD rww
|
|
|
|
void WriteToSnapshot( idBitMsgDelta &msg ) const;
|
|
void ReadFromSnapshot( const idBitMsgDelta &msg );
|
|
|
|
// game state
|
|
typedef enum {
|
|
INACTIVE = 0, // not running
|
|
WARMUP, // warming up
|
|
COUNTDOWN, // post warmup pre-game
|
|
GAMEON, // game is on
|
|
SUDDENDEATH, // game is on but in sudden death, first frag wins
|
|
GAMEREVIEW, // game is over, scoreboard is up. we wait si_gameReviewPause seconds (which has a min value)
|
|
NEXTGAME,
|
|
STATE_COUNT
|
|
} gameState_t;
|
|
static const char *GameStateStrings[ STATE_COUNT ];
|
|
idMultiplayerGame::gameState_t GetGameState( void ) const;
|
|
|
|
static const char *GlobalSoundStrings[ SND_COUNT ];
|
|
void PlayGlobalSound( int to, snd_evt_t evt, const char *shader = NULL );
|
|
|
|
// more compact than a chat line
|
|
typedef enum {
|
|
MSG_SUICIDE = 0,
|
|
MSG_KILLED,
|
|
MSG_KILLEDTEAM,
|
|
MSG_DIED,
|
|
MSG_VOTE,
|
|
MSG_PLAYERVOTED, // HUMANHEAD pdm
|
|
MSG_VOTEPASSED,
|
|
MSG_VOTEFAILED,
|
|
MSG_SUDDENDEATH,
|
|
MSG_FORCEREADY,
|
|
MSG_JOINEDSPEC,
|
|
MSG_TIMELIMIT,
|
|
MSG_FRAGLIMIT,
|
|
MSG_TELEFRAGGED,
|
|
MSG_JOINTEAM,
|
|
MSG_HOLYSHIT,
|
|
MSG_COUNT
|
|
} msg_evt_t;
|
|
//HUMANHEAD rww
|
|
const char *DeathStringForProjectile(int projectileDefNum);
|
|
void PrintDeathMessageEvent( int to, msg_evt_t evt, int parm1, int parm2, int inflictorDef );
|
|
//HUMANHEAD END
|
|
void PrintMessageEvent( int to, msg_evt_t evt, int parm1 = -1, int parm2 = -1 );
|
|
|
|
void DisconnectClient( int clientNum );
|
|
static void ForceReady_f( const idCmdArgs &args );
|
|
static void DropWeapon_f( const idCmdArgs &args );
|
|
static void MessageMode_f( const idCmdArgs &args );
|
|
static void VoiceChat_f( const idCmdArgs &args );
|
|
static void VoiceChatTeam_f( const idCmdArgs &args );
|
|
|
|
typedef enum {
|
|
VOTE_RESTART = 0,
|
|
VOTE_TIMELIMIT,
|
|
VOTE_FRAGLIMIT,
|
|
VOTE_GAMETYPE,
|
|
VOTE_KICK,
|
|
VOTE_MAP,
|
|
VOTE_SPECTATORS,
|
|
VOTE_NEXTMAP,
|
|
VOTE_COUNT,
|
|
VOTE_NONE
|
|
} vote_flags_t;
|
|
|
|
typedef enum {
|
|
VOTE_UPDATE,
|
|
VOTE_FAILED,
|
|
VOTE_PASSED, // passed, but no reset yet
|
|
VOTE_ABORTED,
|
|
VOTE_RESET // tell clients to reset vote state
|
|
} vote_result_t;
|
|
|
|
static void Vote_f( const idCmdArgs &args );
|
|
static void CallVote_f( const idCmdArgs &args );
|
|
void ClientCallVote( vote_flags_t voteIndex, const char *voteValue );
|
|
void ServerCallVote( int clientNum, const idBitMsg &msg );
|
|
#if _HH_LOCALIZE_VOTESTRINGS
|
|
typedef enum {
|
|
VOTESTR_JUSTONE,
|
|
VOTESTR_TIMELIMIT,
|
|
VOTESTR_FRAGLIMIT,
|
|
VOTESTR_VALUE,
|
|
VOTESTR_CLNUMNAME,
|
|
VOTESTR_NAMEVAL
|
|
} voteStringType_e;
|
|
void ClientStartVote( int clientNum, voteStringType_e strType, const int numStrings, const char **strings );
|
|
#else
|
|
void ClientStartVote( int clientNum, const char *voteString );
|
|
#endif
|
|
void ServerStartVote( int clientNum, vote_flags_t voteIndex, const char *voteValue );
|
|
void ClientUpdateVote( vote_result_t result, int yesCount, int noCount );
|
|
void CastVote( int clientNum, bool vote );
|
|
void ExecuteVote( void );
|
|
|
|
void WantKilled( int clientNum );
|
|
int NumActualClients( bool countSpectators, int *teamcount = NULL );
|
|
void DropWeapon( int clientNum );
|
|
void MapRestart( void );
|
|
// called by idPlayer whenever it detects a team change (init or switch)
|
|
void SwitchToTeam( int clientNum, int oldteam, int newteam );
|
|
bool IsPureReady( void ) const;
|
|
void ProcessChatMessage( int clientNum, bool team, const char *name, const char *text, const char *sound );
|
|
void ProcessVoiceChat( int clientNum, bool team, int index );
|
|
|
|
void Precache( void );
|
|
|
|
// throttle UI switch rates
|
|
void ThrottleUserInfo( void );
|
|
void ToggleSpectate( void );
|
|
void ToggleReady( void );
|
|
void ToggleTeam( void );
|
|
|
|
void ClearFrags( int clientNum );
|
|
|
|
void EnterGame( int clientNum );
|
|
bool CanPlay( idPlayer *p );
|
|
bool IsInGame( int clientNum );
|
|
bool WantRespawn( idPlayer *p );
|
|
|
|
void ServerWriteInitialReliableMessages( int clientNum );
|
|
void ClientReadStartState( const idBitMsg &msg );
|
|
void ClientReadWarmupTime( const idBitMsg &msg );
|
|
|
|
void ServerClientConnect( int clientNum );
|
|
|
|
void PlayerStats( int clientNum, char *data, const int len );
|
|
|
|
private:
|
|
static const char *MPGuis[];
|
|
static const char *ThrottleVars[];
|
|
static const char *ThrottleVarsInEnglish[];
|
|
static const int ThrottleDelay[];
|
|
|
|
// state vars
|
|
gameState_t gameState; // what state the current game is in
|
|
gameState_t nextState; // state to switch to when nextStateSwitch is hit
|
|
int pingUpdateTime; // time to update ping
|
|
|
|
mpPlayerState_t playerState[ MAX_CLIENTS ];
|
|
|
|
// keep track of clients which are willingly in spectator mode
|
|
|
|
// vote vars
|
|
vote_flags_t vote; // active vote or VOTE_NONE
|
|
int voteTimeOut; // when the current vote expires
|
|
int voteExecTime; // delay between vote passed msg and execute
|
|
float yesVotes; // counter for yes votes
|
|
float noVotes; // and for no votes
|
|
idStr voteValue; // the data voted upon ( server )
|
|
idStr voteString; // the vote string ( client )
|
|
bool voted; // hide vote box ( client )
|
|
int kickVoteMap[ MAX_CLIENTS ];
|
|
|
|
// time related
|
|
int nextStateSwitch; // time next state switch
|
|
int warmupEndTime; // warmup till..
|
|
int matchStartedTime; // time current match started
|
|
|
|
// tourney
|
|
int currentTourneyPlayer[2];// our current set of players
|
|
int lastWinner; // plays again
|
|
|
|
// warmup
|
|
idStr warmupText; // text shown in warmup area of screen
|
|
bool one, two, three; // keeps count down voice from repeating
|
|
|
|
// guis
|
|
idUserInterface *scoreBoard; // scoreboard
|
|
idUserInterface *spectateGui; // spectate info
|
|
idUserInterface *guiChat; // chat text
|
|
idUserInterface *mainGui; // ready / nick / votes etc.
|
|
#ifdef _GUITEST_SERVERWAIT
|
|
idUserInterface *serverWaitGui; //HUMANHEAD rww
|
|
#endif
|
|
idListGUI *mapList;
|
|
idUserInterface *msgmodeGui; // message mode
|
|
int currentMenu; // 0 - none, 1 - mainGui, 2 - msgmodeGui
|
|
int nextMenu; // if 0, will do mainGui
|
|
bool bCurrentMenuMsg; // send menu state updates to server
|
|
|
|
//HUMANHEAD rww - persistent player data dict, to store wins (and potentially other things) between map changes and player disconnects
|
|
idDict persistentPlayerDict;
|
|
//HUMANHEAD END
|
|
|
|
// chat data
|
|
// HUMANHEAD pdm: Reworked for our chat system
|
|
mpChatLine_t chatHistory[ NUM_CHAT_HISTORY_LINES ];
|
|
int chatHistoryIndex;
|
|
idListGUI *chatHistoryList;
|
|
// HUMANHEAD END
|
|
|
|
// rankings are used by UpdateScoreboard and UpdateHud
|
|
int numRankedPlayers; // ranked players, others may be empty slots or spectators
|
|
idPlayer * rankedPlayers[MAX_CLIENTS];
|
|
|
|
bool pureReady; // defaults to false, set to true once server game is running with pure checksums
|
|
int fragLimitTimeout;
|
|
|
|
int switchThrottle[ 3 ];
|
|
int voiceChatThrottle;
|
|
|
|
gameType_t lastGameType; // for restarts
|
|
int startFragLimit; // synchronize to clients in initial state, set on -> GAMEON
|
|
|
|
bool bTeamsTied; //HUMANHEAD rww - needs to be set in TDM before any calls to UpdateWinsLosses with removal of suddendeath concept
|
|
|
|
private:
|
|
void UpdatePlayerRanks();
|
|
|
|
// updates the passed gui with current score information
|
|
void UpdateScoreboard( idUserInterface *scoreBoard, idPlayer *player );
|
|
void UpdateDMScoreboard( idUserInterface *scoreBoard, idPlayer *player );
|
|
void UpdateTeamScoreboard( idUserInterface *scoreBoard, idPlayer *player );
|
|
|
|
void ClearGuis( void );
|
|
void DrawScoreBoard( idPlayer *player );
|
|
void UpdateHud( idPlayer *player, idUserInterface *hud );
|
|
bool Warmup( void );
|
|
void CheckVote( void );
|
|
//HUMANHEAD rww
|
|
void DisconnectVotingPlayer(int clientNum);
|
|
//HUMANHEAD END
|
|
bool AllPlayersReady( void );
|
|
idPlayer * FragLimitHit( void );
|
|
idPlayer * FragLeader( void );
|
|
bool TimeLimitHit( void );
|
|
bool CheckTeamsTied(void); //HUMANHEAD rww
|
|
void NewState( gameState_t news, idPlayer *player = NULL );
|
|
void UpdateWinsLosses( idPlayer *winner );
|
|
// fill any empty tourney slots based on the current tourney ranks
|
|
void FillTourneySlots( void );
|
|
void CycleTourneyPlayers( void );
|
|
// walk through the tourneyRank to build a wait list for the clients
|
|
void UpdateTourneyLine( void );
|
|
const char * GameTime( void );
|
|
const char * GameFrags( idPlayer *localPlayer );
|
|
void Clear( void );
|
|
bool EnoughClientsToPlay( void );
|
|
void ClearChatData( void );
|
|
void DrawChat( void );
|
|
// go through the clients, and see if they want to be respawned, and if the game allows it
|
|
// called during normal gameplay for death -> respawn cycles
|
|
// and for a spectator who want back in the game (see param)
|
|
void CheckRespawns( idPlayer *spectator = NULL );
|
|
void ForceReady();
|
|
// when clients disconnect or join spectate during game, check if we need to end the game
|
|
void CheckAbortGame( void );
|
|
void MessageMode( const idCmdArgs &args );
|
|
void DisableMenu( void );
|
|
void SetMapShot( void );
|
|
// scores in TDM
|
|
int GetTeamScore(int team);
|
|
void TeamScore( int entityNumber, int team, int delta );
|
|
void VoiceChat( const idCmdArgs &args, bool team );
|
|
void DumpTourneyLine( void );
|
|
void SuddenRespawn( void );
|
|
};
|
|
|
|
ID_INLINE idMultiplayerGame::gameState_t idMultiplayerGame::GetGameState( void ) const {
|
|
return gameState;
|
|
}
|
|
|
|
ID_INLINE bool idMultiplayerGame::IsPureReady( void ) const {
|
|
return pureReady;
|
|
}
|
|
|
|
//ID_INLINE void idMultiplayerGame::ClearFrags( int clientNum ) //HUMANHEAD rww - no longer inlined
|
|
|
|
ID_INLINE bool idMultiplayerGame::IsInGame( int clientNum ) {
|
|
return playerState[ clientNum ].ingame;
|
|
}
|
|
|
|
#endif /* !__MULTIPLAYERGAME_H__ */
|
|
|