dhewm3/neo/d3xp/MultiplayerGame.h

489 lines
14 KiB
C
Raw Permalink Normal View History

2011-11-22 21:28:15 +00:00
/*
===========================================================================
Doom 3 GPL Source Code
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
2011-11-22 21:28:15 +00:00
2011-12-06 16:14:59 +00:00
This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
2011-11-22 21:28:15 +00:00
Doom 3 Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#ifndef __MULTIPLAYERGAME_H__
#define __MULTIPLAYERGAME_H__
#include "idlib/BitMsg.h"
#include "idlib/Str.h"
#include "ui/UserInterface.h"
#include "GameBase.h"
2011-11-22 21:28:15 +00:00
/*
===============================================================================
Basic DOOM multiplayer
===============================================================================
*/
class idPlayer;
#ifdef CTF
class idItemTeam;
#endif
typedef enum {
GAME_SP = 0,
GAME_DM,
GAME_TOURNEY,
GAME_TDM,
GAME_LASTMAN,
#ifdef CTF
GAME_CTF,
2011-11-22 21:28:15 +00:00
GAME_COUNT,
#endif
} gameType_t;
#ifdef CTF
// Used by the UI
typedef enum {
FLAGSTATUS_INBASE = 0,
FLAGSTATUS_TAKEN = 1,
FLAGSTATUS_STRAY = 2,
FLAGSTATUS_NONE = 3
2011-11-22 21:28:15 +00:00
} flagStatus_t;
#endif
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;
const int NUM_CHAT_NOTIFY = 5;
const int CHAT_FADE_TIME = 400;
const int FRAGLIMIT_DELAY = 2000;
const int MP_PLAYER_MINFRAGS = -100;
#ifdef CTF
const int MP_PLAYER_MAXFRAGS = 400; // in CTF frags are player points
#else
const int MP_PLAYER_MAXFRAGS = 100;
#endif
const int MP_PLAYER_MAXWINS = 100;
const int MP_PLAYER_MAXPING = 999;
#ifdef CTF
const int MP_CTF_MAXPOINTS = 25;
#endif
typedef struct mpChatLine_s {
idStr line;
short fade; // starts high and decreases, line is removed once reached 0
} mpChatLine_t;
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,
#ifdef CTF
2011-11-22 21:28:15 +00:00
SND_FLAG_CAPTURED_YOURS,
SND_FLAG_CAPTURED_THEIRS,
SND_FLAG_RETURN,
SND_FLAG_TAKEN_YOURS,
SND_FLAG_TAKEN_THEIRS,
SND_FLAG_DROPPED_YOURS,
SND_FLAG_DROPPED_THEIRS,
#endif
SND_COUNT
} snd_evt_t;
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..
2011-11-22 21:28:15 +00:00
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, bool telefrag );
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 );
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 );
#ifdef CTF
void PlayTeamSound( int toTeam, snd_evt_t evt, const char *shader = NULL ); // sound that's sent only to member of toTeam team
#endif
// more compact than a chat line
typedef enum {
MSG_SUICIDE = 0,
MSG_KILLED,
MSG_KILLEDTEAM,
MSG_DIED,
MSG_VOTE,
MSG_VOTEPASSED,
MSG_VOTEFAILED,
MSG_SUDDENDEATH,
MSG_FORCEREADY,
MSG_JOINEDSPEC,
MSG_TIMELIMIT,
MSG_FRAGLIMIT,
MSG_TELEFRAGGED,
MSG_JOINTEAM,
MSG_HOLYSHIT,
#ifdef CTF
MSG_POINTLIMIT,
MSG_FLAGTAKEN,
MSG_FLAGDROP,
MSG_FLAGRETURN,
MSG_FLAGCAPTURE,
MSG_SCOREUPDATE,
#endif
MSG_COUNT
} msg_evt_t;
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 );
void ClientStartVote( int clientNum, const char *voteString );
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 );
2011-11-22 21:28:15 +00:00
// 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 );
#ifdef CTF
void ClearHUDStatus( void );
int GetFlagPoints( int team ); // Team points in CTF
2011-11-22 21:28:15 +00:00
void SetFlagMsg( bool b ); // allow flag event messages to be sent
bool IsFlagMsgOn( void ); // should flag event messages go through?
void ClearGuis( void );
2011-11-22 21:28:15 +00:00
int player_red_flag; // Ent num of red flag carrier for HUD
int player_blue_flag; // Ent num of blue flag carrier for HUD
2011-11-22 21:28:15 +00:00
#endif
2011-11-22 21:28:15 +00:00
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.
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
// chat data
mpChatLine_t chatHistory[ NUM_CHAT_NOTIFY ];
int chatHistoryIndex;
int chatHistorySize; // 0 <= x < NUM_CHAT_NOTIFY
bool chatDataUpdated;
int lastChatLineTime;
// 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
#ifdef CTF
idItemTeam * teamFlags[ 2 ];
int teamPoints[ 2 ];
bool flagMsgOn;
const char * gameTypeVoteMap[ GAME_COUNT ];
#endif
private:
void UpdatePlayerRanks();
// updates the passed gui with current score information
void UpdateRankColor( idUserInterface *gui, const char *mask, int i, const idVec3 &vec );
void UpdateScoreboard( idUserInterface *scoreBoard, idPlayer *player );
#ifdef CTF
void UpdateCTFScoreboard( idUserInterface *scoreBoard, idPlayer *player );
2011-11-22 21:28:15 +00:00
#endif
#ifndef CTF
// We declare this publically above so we can call it during a map restart.
2011-11-22 21:28:15 +00:00
void ClearGuis( void );
#endif
2011-11-22 21:28:15 +00:00
void DrawScoreBoard( idPlayer *player );
void UpdateHud( idPlayer *player, idUserInterface *hud );
bool Warmup( void );
void CheckVote( void );
bool AllPlayersReady( void );
idPlayer * FragLimitHit( void );
idPlayer * FragLeader( void );
bool TimeLimitHit( void );
#ifdef CTF
bool PointLimitHit( void );
// return team with most points
int WinningTeam( void );
#endif
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 );
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
void TeamScore( int entityNumber, int team, int delta );
void VoiceChat( const idCmdArgs &args, bool team );
void DumpTourneyLine( void );
void SuddenRespawn( void );
#ifdef CTF
void FindTeamFlags( void );
#endif
2011-11-22 21:28:15 +00:00
public:
#ifdef CTF
2011-11-22 21:28:15 +00:00
idItemTeam * GetTeamFlag( int team );
flagStatus_t GetFlagStatus( int team );
2011-11-22 21:28:15 +00:00
void TeamScoreCTF( int team, int delta );
void PlayerScoreCTF( int playerIdx, int delta );
// returns entityNum to team flag carrier, -1 if no flag carrier
int GetFlagCarrier( int team );
void UpdateScoreboardFlagStatus( void );
2011-11-22 21:28:15 +00:00
void SetBestGametype( const char * map );
void ReloadScoreboard();
#endif
#ifdef _D3XP
idStr GetBestGametype( const char* map, const char* gametype );
#endif
/* #ifdef CTF ... merge the below IsGametypeFlagBased */
bool IsGametypeFlagBased( void );
bool IsGametypeTeamBased( void );
/* #endif CTF */
2011-11-22 21:28:15 +00:00
};
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 ) {
playerState[ clientNum ].fragCount = 0;
}
ID_INLINE bool idMultiplayerGame::IsInGame( int clientNum ) {
return playerState[ clientNum ].ingame;
}
#endif /* !__MULTIPLAYERGAME_H__ */