123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411 |
- /*
- ===========================================================================
- Doom 3 GPL Source Code
- Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
- 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.
- ===========================================================================
- */
- #include "../idlib/precompiled.h"
- #pragma hdrstop
- #include "Game_local.h"
- // could be a problem if players manage to go down sudden deaths till this .. oh well
- #define LASTMAN_NOLIVES -20
- idCVar g_spectatorChat( "g_spectatorChat", "0", CVAR_GAME | CVAR_ARCHIVE | CVAR_BOOL, "let spectators talk to everyone during game" );
- // global sounds transmitted by index - 0 .. SND_COUNT
- // sounds in this list get precached on MP start
- const char *idMultiplayerGame::GlobalSoundStrings[] = {
- "sound/feedback/voc_youwin.wav",
- "sound/feedback/voc_youlose.wav",
- "sound/feedback/fight.wav",
- "sound/feedback/vote_now.wav",
- "sound/feedback/vote_passed.wav",
- "sound/feedback/vote_failed.wav",
- "sound/feedback/three.wav",
- "sound/feedback/two.wav",
- "sound/feedback/one.wav",
- "sound/feedback/sudden_death.wav",
- };
- // handy verbose
- const char *idMultiplayerGame::GameStateStrings[] = {
- "INACTIVE",
- "WARMUP",
- "COUNTDOWN",
- "GAMEON",
- "SUDDENDEATH",
- "GAMEREVIEW",
- "NEXTGAME"
- };
- const char *idMultiplayerGame::MPGuis[] = {
- "guis/mphud.gui",
- "guis/mpmain.gui",
- "guis/mpmsgmode.gui",
- "guis/netmenu.gui",
- NULL
- };
- const char *idMultiplayerGame::ThrottleVars[] = {
- "ui_spectate",
- "ui_ready",
- "ui_team",
- NULL
- };
- const char *idMultiplayerGame::ThrottleVarsInEnglish[] = {
- "#str_06738",
- "#str_06737",
- "#str_01991",
- NULL
- };
- const int idMultiplayerGame::ThrottleDelay[] = {
- 8,
- 5,
- 5
- };
- /*
- ================
- idMultiplayerGame::idMultiplayerGame
- ================
- */
- idMultiplayerGame::idMultiplayerGame() {
- scoreBoard = NULL;
- spectateGui = NULL;
- guiChat = NULL;
- mainGui = NULL;
- mapList = NULL;
- msgmodeGui = NULL;
- lastGameType = GAME_SP;
- Clear();
- }
- /*
- ================
- idMultiplayerGame::Shutdown
- ================
- */
- void idMultiplayerGame::Shutdown( void ) {
- Clear();
- }
- /*
- ================
- idMultiplayerGame::SetMenuSkin
- ================
- */
- void idMultiplayerGame::SetMenuSkin( void ) {
- // skins
- idStr str = cvarSystem->GetCVarString( "mod_validSkins" );
- idStr uiSkin = cvarSystem->GetCVarString( "ui_skin" );
- idStr skin;
- int skinId = 1;
- int count = 1;
- while ( str.Length() ) {
- int n = str.Find( ";" );
- if ( n >= 0 ) {
- skin = str.Left( n );
- str = str.Right( str.Length() - n - 1 );
- } else {
- skin = str;
- str = "";
- }
- if ( skin.Icmp( uiSkin ) == 0 ) {
- skinId = count;
- }
- count++;
- }
- for ( int i = 0; i < count; i++ ) {
- mainGui->SetStateInt( va( "skin%i", i+1 ), 0 );
- }
- mainGui->SetStateInt( va( "skin%i", skinId ), 1 );
- }
- /*
- ================
- idMultiplayerGame::Reset
- ================
- */
- void idMultiplayerGame::Reset() {
- Clear();
- assert( !scoreBoard && !spectateGui && !guiChat && !mainGui && !mapList );
- scoreBoard = uiManager->FindGui( "guis/scoreboard.gui", true, false, true );
- spectateGui = uiManager->FindGui( "guis/spectate.gui", true, false, true );
- guiChat = uiManager->FindGui( "guis/chat.gui", true, false, true );
- mainGui = uiManager->FindGui( "guis/mpmain.gui", true, false, true );
- mapList = uiManager->AllocListGUI( );
- mapList->Config( mainGui, "mapList" );
- // set this GUI so that our Draw function is still called when it becomes the active/fullscreen GUI
- mainGui->SetStateBool( "gameDraw", true );
- mainGui->SetKeyBindingNames();
- mainGui->SetStateInt( "com_machineSpec", cvarSystem->GetCVarInteger( "com_machineSpec" ) );
- SetMenuSkin();
- msgmodeGui = uiManager->FindGui( "guis/mpmsgmode.gui", true, false, true );
- msgmodeGui->SetStateBool( "gameDraw", true );
- ClearGuis();
- ClearChatData();
- warmupEndTime = 0;
- }
- /*
- ================
- idMultiplayerGame::ServerClientConnect
- ================
- */
- void idMultiplayerGame::ServerClientConnect( int clientNum ) {
- memset( &playerState[ clientNum ], 0, sizeof( playerState[ clientNum ] ) );
- }
- /*
- ================
- idMultiplayerGame::SpawnPlayer
- ================
- */
- void idMultiplayerGame::SpawnPlayer( int clientNum ) {
- bool ingame = playerState[ clientNum ].ingame;
- memset( &playerState[ clientNum ], 0, sizeof( playerState[ clientNum ] ) );
- if ( !gameLocal.isClient ) {
- idPlayer *p = static_cast< idPlayer * >( gameLocal.entities[ clientNum ] );
- p->spawnedTime = gameLocal.time;
- if ( gameLocal.gameType == GAME_TDM ) {
- SwitchToTeam( clientNum, -1, p->team );
- }
- p->tourneyRank = 0;
- if ( gameLocal.gameType == GAME_TOURNEY && gameState == GAMEON ) {
- p->tourneyRank++;
- }
- playerState[ clientNum ].ingame = ingame;
- }
- }
- /*
- ================
- idMultiplayerGame::Clear
- ================
- */
- void idMultiplayerGame::Clear() {
- int i;
- gameState = INACTIVE;
- nextState = INACTIVE;
- pingUpdateTime = 0;
- vote = VOTE_NONE;
- voteTimeOut = 0;
- voteExecTime = 0;
- nextStateSwitch = 0;
- matchStartedTime = 0;
- currentTourneyPlayer[ 0 ] = -1;
- currentTourneyPlayer[ 1 ] = -1;
- one = two = three = false;
- memset( &playerState, 0 , sizeof( playerState ) );
- lastWinner = -1;
- currentMenu = 0;
- bCurrentMenuMsg = false;
- nextMenu = 0;
- pureReady = false;
- scoreBoard = NULL;
- spectateGui = NULL;
- guiChat = NULL;
- mainGui = NULL;
- msgmodeGui = NULL;
- if ( mapList ) {
- uiManager->FreeListGUI( mapList );
- mapList = NULL;
- }
- fragLimitTimeout = 0;
- memset( &switchThrottle, 0, sizeof( switchThrottle ) );
- voiceChatThrottle = 0;
- for ( i = 0; i < NUM_CHAT_NOTIFY; i++ ) {
- chatHistory[ i ].line.Clear();
- }
- warmupText.Clear();
- voteValue.Clear();
- voteString.Clear();
- startFragLimit = -1;
- }
- /*
- ================
- idMultiplayerGame::ClearGuis
- ================
- */
- void idMultiplayerGame::ClearGuis() {
- int i;
-
- for ( i = 0; i < MAX_CLIENTS; i++ ) {
- scoreBoard->SetStateString( va( "player%i",i+1 ), "" );
- scoreBoard->SetStateString( va( "player%i_score", i+1 ), "" );
- scoreBoard->SetStateString( va( "player%i_tdm_tscore", i+1 ), "" );
- scoreBoard->SetStateString( va( "player%i_tdm_score", i+1 ), "" );
- scoreBoard->SetStateString( va( "player%i_wins", i+1 ), "" );
- scoreBoard->SetStateString( va( "player%i_status", i+1 ), "" );
- scoreBoard->SetStateInt( va( "rank%i", i+1 ), 0 );
- scoreBoard->SetStateInt( "rank_self", 0 );
- idPlayer *player = static_cast<idPlayer *>( gameLocal.entities[ i ] );
- if ( !player || !player->hud ) {
- continue;
- }
- player->hud->SetStateString( va( "player%i",i+1 ), "" );
- player->hud->SetStateString( va( "player%i_score", i+1 ), "" );
- player->hud->SetStateString( va( "player%i_ready", i+1 ), "" );
- scoreBoard->SetStateInt( va( "rank%i", i+1 ), 0 );
- player->hud->SetStateInt( "rank_self", 0 );
- }
- }
- /*
- ================
- idMultiplayerGame::UpdatePlayerRanks
- ================
- */
- void idMultiplayerGame::UpdatePlayerRanks() {
- int i, j, k;
- idPlayer *players[MAX_CLIENTS];
- idEntity *ent;
- idPlayer *player;
- memset( players, 0, sizeof( players ) );
- numRankedPlayers = 0;
- for ( i = 0; i < gameLocal.numClients; i++ ) {
- ent = gameLocal.entities[ i ];
- if ( !ent || !ent->IsType( idPlayer::Type ) ) {
- continue;
- }
- player = static_cast< idPlayer * >( ent );
- if ( !CanPlay( player ) ) {
- continue;
- }
- if ( gameLocal.gameType == GAME_TOURNEY ) {
- if ( i != currentTourneyPlayer[ 0 ] && i != currentTourneyPlayer[ 1 ] ) {
- continue;
- }
- }
- if ( gameLocal.gameType == GAME_LASTMAN && playerState[ i ].fragCount == LASTMAN_NOLIVES ) {
- continue;
- }
- for ( j = 0; j < numRankedPlayers; j++ ) {
- bool insert = false;
- if ( gameLocal.gameType == GAME_TDM ) {
- if ( player->team != players[ j ]->team ) {
- if ( playerState[ i ].teamFragCount > playerState[ players[ j ]->entityNumber ].teamFragCount ) {
- // team scores
- insert = true;
- } else if ( playerState[ i ].teamFragCount == playerState[ players[ j ]->entityNumber ].teamFragCount && player->team < players[ j ]->team ) {
- // at equal scores, sort by team number
- insert = true;
- }
- } else if ( playerState[ i ].fragCount > playerState[ players[ j ]->entityNumber ].fragCount ) {
- // in the same team, sort by frag count
- insert = true;
- }
- } else {
- insert = ( playerState[ i ].fragCount > playerState[ players[ j ]->entityNumber ].fragCount );
- }
- if ( insert ) {
- for ( k = numRankedPlayers; k > j; k-- ) {
- players[ k ] = players[ k-1 ];
- }
- players[ j ] = player;
- break;
- }
- }
- if ( j == numRankedPlayers ) {
- players[ numRankedPlayers ] = player;
- }
- numRankedPlayers++;
- }
- memcpy( rankedPlayers, players, sizeof( players ) );
- }
- /*
- ================
- idMultiplayerGame::UpdateRankColor
- ================
- */
- void idMultiplayerGame::UpdateRankColor( idUserInterface *gui, const char *mask, int i, const idVec3 &vec ) {
- for ( int j = 1; j < 4; j++ ) {
- gui->SetStateFloat( va( mask, i, j ), vec[ j - 1 ] );
- }
- }
- /*
- ================
- idMultiplayerGame::UpdateScoreboard
- ================
- */
- void idMultiplayerGame::UpdateScoreboard( idUserInterface *scoreBoard, idPlayer *player ) {
- int i, j, iline, k;
- idStr gameinfo;
- idStr livesinfo;
- idStr timeinfo;
- idEntity *ent;
- idPlayer *p;
- int value;
- scoreBoard->SetStateString( "scoretext", gameLocal.gameType == GAME_LASTMAN ? common->GetLanguageDict()->GetString( "#str_04242" ) : common->GetLanguageDict()->GetString( "#str_04243" ) );
- iline = 0; // the display lines
- if ( gameState != WARMUP ) {
- for ( i = 0; i < numRankedPlayers; i++ ) {
- // ranked player
- iline++;
- scoreBoard->SetStateString( va( "player%i", iline ), rankedPlayers[ i ]->GetUserInfo()->GetString( "ui_name" ) );
- if ( gameLocal.gameType == GAME_TDM ) {
- value = idMath::ClampInt( MP_PLAYER_MINFRAGS, MP_PLAYER_MAXFRAGS, playerState[ rankedPlayers[ i ]->entityNumber ].fragCount );
- scoreBoard->SetStateInt( va( "player%i_tdm_score", iline ), value );
- value = idMath::ClampInt( MP_PLAYER_MINFRAGS, MP_PLAYER_MAXFRAGS, playerState[ rankedPlayers[ i ]->entityNumber ].teamFragCount );
- scoreBoard->SetStateString( va( "player%i_tdm_tscore", iline ), va( "/ %i", value ) );
- scoreBoard->SetStateString( va( "player%i_score", iline ), "" );
- } else {
- value = idMath::ClampInt( MP_PLAYER_MINFRAGS, MP_PLAYER_MAXFRAGS, playerState[ rankedPlayers[ i ]->entityNumber ].fragCount );
- scoreBoard->SetStateInt( va( "player%i_score", iline ), value );
- scoreBoard->SetStateString( va( "player%i_tdm_tscore", iline ), "" );
- scoreBoard->SetStateString( va( "player%i_tdm_score", iline ), "" );
- }
- value = idMath::ClampInt( 0, MP_PLAYER_MAXWINS, playerState[ rankedPlayers[ i ]->entityNumber ].wins );
- scoreBoard->SetStateInt( va( "player%i_wins", iline ), value );
- scoreBoard->SetStateInt( va( "player%i_ping", iline ), playerState[ rankedPlayers[ i ]->entityNumber ].ping );
- // set the color band
- scoreBoard->SetStateInt( va( "rank%i", iline ), 1 );
- UpdateRankColor( scoreBoard, "rank%i_color%i", iline, rankedPlayers[ i ]->colorBar );
- if ( rankedPlayers[ i ] == player ) {
- // highlight who we are
- scoreBoard->SetStateInt( "rank_self", iline );
- }
- }
- }
- // if warmup, this draws everyone, otherwise it goes over spectators only
- // when doing warmup we loop twice to draw ready/not ready first *then* spectators
- // NOTE: in tourney, shows spectators according to their playing rank order?
- for ( k = 0; k < ( gameState == WARMUP ? 2 : 1 ); k++ ) {
- for ( i = 0; i < MAX_CLIENTS; i++ ) {
- ent = gameLocal.entities[ i ];
- if ( !ent || !ent->IsType( idPlayer::Type ) ) {
- continue;
- }
- if ( gameState != WARMUP ) {
- // check he's not covered by ranks already
- for ( j = 0; j < numRankedPlayers; j++ ) {
- if ( ent == rankedPlayers[ j ] ) {
- break;
- }
- }
- if ( j != numRankedPlayers ) {
- continue;
- }
- }
- p = static_cast< idPlayer * >( ent );
- if ( gameState == WARMUP ) {
- if ( k == 0 && p->spectating ) {
- continue;
- }
- if ( k == 1 && !p->spectating ) {
- continue;
- }
- }
-
- iline++;
- if ( !playerState[ i ].ingame ) {
- scoreBoard->SetStateString( va( "player%i", iline ), common->GetLanguageDict()->GetString( "#str_04244" ) );
- scoreBoard->SetStateString( va( "player%i_score", iline ), common->GetLanguageDict()->GetString( "#str_04245" ) );
- // no color band
- scoreBoard->SetStateInt( va( "rank%i", iline ), 0 );
- } else {
- scoreBoard->SetStateString( va( "player%i", iline ), gameLocal.userInfo[ i ].GetString( "ui_name" ) );
- if ( gameState == WARMUP ) {
- if ( p->spectating ) {
- scoreBoard->SetStateString( va( "player%i_score", iline ), common->GetLanguageDict()->GetString( "#str_04246" ) );
- // no color band
- scoreBoard->SetStateInt( va( "rank%i", iline ), 0 );
- } else {
- scoreBoard->SetStateString( va( "player%i_score", iline ), p->IsReady() ? common->GetLanguageDict()->GetString( "#str_04247" ) : common->GetLanguageDict()->GetString( "#str_04248" ) );
- // set the color band
- scoreBoard->SetStateInt( va( "rank%i", iline ), 1 );
- UpdateRankColor( scoreBoard, "rank%i_color%i", iline, p->colorBar );
- }
- } else {
- if ( gameLocal.gameType == GAME_LASTMAN && playerState[ i ].fragCount == LASTMAN_NOLIVES ) {
- scoreBoard->SetStateString( va( "player%i_score", iline ), common->GetLanguageDict()->GetString( "#str_06736" ) );
- // set the color band
- scoreBoard->SetStateInt( va( "rank%i", iline ), 1 );
- UpdateRankColor( scoreBoard, "rank%i_color%i", iline, p->colorBar );
- } else {
- scoreBoard->SetStateString( va( "player%i_score", iline ), common->GetLanguageDict()->GetString( "#str_04246" ) );
- // no color band
- scoreBoard->SetStateInt( va( "rank%i", iline ), 0 );
- }
- }
- }
- scoreBoard->SetStateString( va( "player%i_tdm_tscore", iline ), "" );
- scoreBoard->SetStateString( va( "player%i_tdm_score", iline ), "" );
- scoreBoard->SetStateString( va( "player%i_wins", iline ), "" );
- scoreBoard->SetStateInt( va( "player%i_ping", iline ), playerState[ i ].ping );
- if ( i == player->entityNumber ) {
- // highlight who we are
- scoreBoard->SetStateInt( "rank_self", iline );
- }
- }
- }
- // clear remaining lines (empty slots)
- iline++;
- while ( iline < 5 ) {
- scoreBoard->SetStateString( va( "player%i", iline ), "" );
- scoreBoard->SetStateString( va( "player%i_score", iline ), "" );
- scoreBoard->SetStateString( va( "player%i_tdm_tscore", iline ), "" );
- scoreBoard->SetStateString( va( "player%i_tdm_score", iline ), "" );
- scoreBoard->SetStateString( va( "player%i_wins", iline ), "" );
- scoreBoard->SetStateString( va( "player%i_ping", iline ), "" );
- scoreBoard->SetStateInt( va( "rank%i", iline ), 0 );
- iline++;
- }
- gameinfo = va( "%s: %s", common->GetLanguageDict()->GetString( "#str_02376" ), gameLocal.serverInfo.GetString( "si_gameType" ) );
- if ( gameLocal.gameType == GAME_LASTMAN ) {
- if ( gameState == GAMEON || gameState == SUDDENDEATH ) {
- livesinfo = va( "%s: %i", common->GetLanguageDict()->GetString( "#str_04264" ), startFragLimit );
- } else {
- livesinfo = va( "%s: %i", common->GetLanguageDict()->GetString( "#str_04264" ), gameLocal.serverInfo.GetInt( "si_fragLimit" ) );
- }
- } else {
- livesinfo = va( "%s: %i", common->GetLanguageDict()->GetString( "#str_01982" ), gameLocal.serverInfo.GetInt( "si_fragLimit" ) );
- }
- if ( gameLocal.serverInfo.GetInt( "si_timeLimit" ) > 0 ) {
- timeinfo = va( "%s: %i", common->GetLanguageDict()->GetString( "#str_01983" ), gameLocal.serverInfo.GetInt( "si_timeLimit" ) );
- } else {
- timeinfo = va("%s", common->GetLanguageDict()->GetString( "#str_07209" ));
- }
- scoreBoard->SetStateString( "gameinfo", gameinfo );
- scoreBoard->SetStateString( "livesinfo", livesinfo );
- scoreBoard->SetStateString( "timeinfo", timeinfo );
- scoreBoard->Redraw( gameLocal.time );
- }
- /*
- ================
- idMultiplayerGame::GameTime
- ================
- */
- const char *idMultiplayerGame::GameTime() {
- static char buff[16];
- int m, s, t, ms;
- if ( gameState == COUNTDOWN ) {
- ms = warmupEndTime - gameLocal.realClientTime;
- s = ms / 1000 + 1;
- if ( ms <= 0 ) {
- strcpy( buff, "WMP --" );
- } else {
- sprintf( buff, "WMP %i", s );
- }
- } else {
- int timeLimit = gameLocal.serverInfo.GetInt( "si_timeLimit" );
- if ( timeLimit ) {
- ms = ( timeLimit * 60000 ) - ( gameLocal.time - matchStartedTime );
- } else {
- ms = gameLocal.time - matchStartedTime;
- }
- if ( ms < 0 ) {
- ms = 0;
- }
-
- s = ms / 1000;
- m = s / 60;
- s -= m * 60;
- t = s / 10;
- s -= t * 10;
- sprintf( buff, "%i:%i%i", m, t, s );
- }
- return &buff[0];
- }
- /*
- ================
- idMultiplayerGame::NumActualClients
- ================
- */
- int idMultiplayerGame::NumActualClients( bool countSpectators, int *teamcounts ) {
- idPlayer *p;
- int c = 0;
- if ( teamcounts ) {
- teamcounts[ 0 ] = teamcounts[ 1 ] = 0;
- }
- for( int i = 0 ; i < gameLocal.numClients ; i++ ) {
- idEntity *ent = gameLocal.entities[ i ];
- if ( !ent || !ent->IsType( idPlayer::Type ) ) {
- continue;
- }
- p = static_cast< idPlayer * >( ent );
- if ( countSpectators || CanPlay( p ) ) {
- c++;
- }
- if ( teamcounts && CanPlay( p ) ) {
- teamcounts[ p->team ]++;
- }
- }
- return c;
- }
- /*
- ================
- idMultiplayerGame::EnoughClientsToPlay
- ================
- */
- bool idMultiplayerGame::EnoughClientsToPlay() {
- int team[ 2 ];
- int clients = NumActualClients( false, &team[ 0 ] );
- if ( gameLocal.gameType == GAME_TDM ) {
- return clients >= 2 && team[ 0 ] && team[ 1 ];
- } else {
- return clients >= 2;
- }
- }
- /*
- ================
- idMultiplayerGame::AllPlayersReady
- ================
- */
- bool idMultiplayerGame::AllPlayersReady() {
- int i;
- idEntity *ent;
- idPlayer *p;
- int team[ 2 ];
- if ( NumActualClients( false, &team[ 0 ] ) <= 1 ) {
- return false;
- }
- if ( gameLocal.gameType == GAME_TDM ) {
- if ( !team[ 0 ] || !team[ 1 ] ) {
- return false;
- }
- }
- if ( !gameLocal.serverInfo.GetBool( "si_warmup" ) ) {
- return true;
- }
- for( i = 0; i < gameLocal.numClients; i++ ) {
- if ( gameLocal.gameType == GAME_TOURNEY && i != currentTourneyPlayer[ 0 ] && i != currentTourneyPlayer[ 1 ] ) {
- continue;
- }
- ent = gameLocal.entities[ i ];
- if ( !ent || !ent->IsType( idPlayer::Type ) ) {
- continue;
- }
- p = static_cast< idPlayer * >( ent );
- if ( CanPlay( p ) && !p->IsReady() ) {
- return false;
- }
- team[ p->team ]++;
- }
- return true;
- }
- /*
- ================
- idMultiplayerGame::FragLimitHit
- return the winning player (team player)
- if there is no FragLeader(), the game is tied and we return NULL
- ================
- */
- idPlayer *idMultiplayerGame::FragLimitHit() {
- int i;
- int fragLimit = gameLocal.serverInfo.GetInt( "si_fragLimit" );
- idPlayer *leader;
- leader = FragLeader();
- if ( !leader ) {
- return NULL;
- }
- if ( fragLimit <= 0 ) {
- fragLimit = MP_PLAYER_MAXFRAGS;
- }
- if ( gameLocal.gameType == GAME_LASTMAN ) {
- // we have a leader, check if any other players have frags left
- assert( !static_cast< idPlayer * >( leader )->lastManOver );
- for( i = 0 ; i < gameLocal.numClients ; i++ ) {
- idEntity *ent = gameLocal.entities[ i ];
- if ( !ent || !ent->IsType( idPlayer::Type ) ) {
- continue;
- }
- if ( !CanPlay( static_cast< idPlayer * >( ent ) ) ) {
- continue;
- }
- if ( ent == leader ) {
- continue;
- }
- if ( playerState[ ent->entityNumber ].fragCount > 0 ) {
- return NULL;
- }
- }
- // there is a leader, his score may even be negative, but no one else has frags left or is !lastManOver
- return leader;
- } else if ( gameLocal.gameType == GAME_TDM ) {
- if ( playerState[ leader->entityNumber ].teamFragCount >= fragLimit ) {
- return leader;
- }
- } else {
- if ( playerState[ leader->entityNumber ].fragCount >= fragLimit ) {
- return leader;
- }
- }
- return NULL;
- }
- /*
- ================
- idMultiplayerGame::TimeLimitHit
- ================
- */
- bool idMultiplayerGame::TimeLimitHit() {
- int timeLimit = gameLocal.serverInfo.GetInt( "si_timeLimit" );
- if ( timeLimit ) {
- if ( gameLocal.time >= matchStartedTime + timeLimit * 60000 ) {
- return true;
- }
- }
- return false;
- }
- /*
- ================
- idMultiplayerGame::FragLeader
- return the current winner ( or a player from the winning team )
- NULL if even
- ================
- */
- idPlayer *idMultiplayerGame::FragLeader( void ) {
- int i;
- int frags[ MAX_CLIENTS ];
- idPlayer *leader = NULL;
- idEntity *ent;
- idPlayer *p;
- int high = -9999;
- int count = 0;
- bool teamLead[ 2 ] = { false, false };
- for ( i = 0 ; i < gameLocal.numClients ; i++ ) {
- ent = gameLocal.entities[ i ];
- if ( !ent || !ent->IsType( idPlayer::Type ) ) {
- continue;
- }
- if ( !CanPlay( static_cast< idPlayer * >( ent ) ) ) {
- continue;
- }
- if ( gameLocal.gameType == GAME_TOURNEY && ent->entityNumber != currentTourneyPlayer[ 0 ] && ent->entityNumber != currentTourneyPlayer[ 1 ] ) {
- continue;
- }
- if ( static_cast< idPlayer * >( ent )->lastManOver ) {
- continue;
- }
- int fragc = ( gameLocal.gameType == GAME_TDM ) ? playerState[i].teamFragCount : playerState[i].fragCount;
- if ( fragc > high ) {
- high = fragc;
- }
- frags[ i ] = fragc;
- }
- for ( i = 0; i < gameLocal.numClients; i++ ) {
- ent = gameLocal.entities[ i ];
- if ( !ent || !ent->IsType( idPlayer::Type ) ) {
- continue;
- }
- p = static_cast< idPlayer * >( ent );
- p->SetLeader( false );
- if ( !CanPlay( p ) ) {
- continue;
- }
- if ( gameLocal.gameType == GAME_TOURNEY && ent->entityNumber != currentTourneyPlayer[ 0 ] && ent->entityNumber != currentTourneyPlayer[ 1 ] ) {
- continue;
- }
- if ( p->lastManOver ) {
- continue;
- }
- if ( p->spectating ) {
- continue;
- }
- if ( frags[ i ] >= high ) {
- leader = p;
- count++;
- p->SetLeader( true );
- if ( gameLocal.gameType == GAME_TDM ) {
- teamLead[ p->team ] = true;
- }
- }
- }
- if ( gameLocal.gameType != GAME_TDM ) {
- // more than one player at the highest frags
- if ( count > 1 ) {
- return NULL;
- } else {
- return leader;
- }
- } else {
- if ( teamLead[ 0 ] && teamLead[ 1 ] ) {
- // even game in team play
- return NULL;
- }
- return leader;
- }
- }
- /*
- ================
- idGameLocal::UpdateWinsLosses
- ================
- */
- void idMultiplayerGame::UpdateWinsLosses( idPlayer *winner ) {
- if ( winner ) {
- // run back through and update win/loss count
- for( int i = 0; i < gameLocal.numClients; i++ ) {
- idEntity *ent = gameLocal.entities[ i ];
- if ( !ent || !ent->IsType( idPlayer::Type ) ) {
- continue;
- }
- idPlayer *player = static_cast<idPlayer *>(ent);
- if ( gameLocal.gameType == GAME_TDM ) {
- if ( player == winner || ( player != winner && player->team == winner->team ) ) {
- playerState[ i ].wins++;
- PlayGlobalSound( player->entityNumber, SND_YOUWIN );
- } else {
- PlayGlobalSound( player->entityNumber, SND_YOULOSE );
- }
- } else if ( gameLocal.gameType == GAME_LASTMAN ) {
- if ( player == winner ) {
- playerState[ i ].wins++;
- PlayGlobalSound( player->entityNumber, SND_YOUWIN );
- } else if ( !player->wantSpectate ) {
- PlayGlobalSound( player->entityNumber, SND_YOULOSE );
- }
- } else if ( gameLocal.gameType == GAME_TOURNEY ) {
- if ( player == winner ) {
- playerState[ i ].wins++;
- PlayGlobalSound( player->entityNumber, SND_YOUWIN );
- } else if ( i == currentTourneyPlayer[ 0 ] || i == currentTourneyPlayer[ 1 ] ) {
- PlayGlobalSound( player->entityNumber, SND_YOULOSE );
- }
- } else {
- if ( player == winner ) {
- playerState[i].wins++;
- PlayGlobalSound( player->entityNumber, SND_YOUWIN );
- } else if ( !player->wantSpectate ) {
- PlayGlobalSound( player->entityNumber, SND_YOULOSE );
- }
- }
- }
- }
- if ( winner ) {
- lastWinner = winner->entityNumber;
- } else {
- lastWinner = -1;
- }
- }
- /*
- ================
- idMultiplayerGame::TeamScore
- ================
- */
- void idMultiplayerGame::TeamScore( int entityNumber, int team, int delta ) {
- playerState[ entityNumber ].fragCount += delta;
- for( int i = 0 ; i < gameLocal.numClients ; i++ ) {
- idEntity *ent = gameLocal.entities[ i ];
- if ( !ent || !ent->IsType( idPlayer::Type ) ) {
- continue;
- }
- idPlayer *player = static_cast<idPlayer *>(ent);
- if ( player->team == team ) {
- playerState[ player->entityNumber ].teamFragCount += delta;
- }
- }
- }
- /*
- ================
- idMultiplayerGame::PlayerDeath
- ================
- */
- void idMultiplayerGame::PlayerDeath( idPlayer *dead, idPlayer *killer, bool telefrag ) {
- // don't do PrintMessageEvent and shit
- assert( !gameLocal.isClient );
- if ( killer ) {
- if ( gameLocal.gameType == GAME_LASTMAN ) {
- playerState[ dead->entityNumber ].fragCount--;
- } else if ( gameLocal.gameType == GAME_TDM ) {
- if ( killer == dead || killer->team == dead->team ) {
- // suicide or teamkill
- TeamScore( killer->entityNumber, killer->team, -1 );
- } else {
- TeamScore( killer->entityNumber, killer->team, +1 );
- }
- } else {
- playerState[ killer->entityNumber ].fragCount += ( killer == dead ) ? -1 : 1;
- }
- }
- if ( killer && killer == dead ) {
- PrintMessageEvent( -1, MSG_SUICIDE, dead->entityNumber );
- } else if ( killer ) {
- if ( telefrag ) {
- PrintMessageEvent( -1, MSG_TELEFRAGGED, dead->entityNumber, killer->entityNumber );
- } else if ( gameLocal.gameType == GAME_TDM && dead->team == killer->team ) {
- PrintMessageEvent( -1, MSG_KILLEDTEAM, dead->entityNumber, killer->entityNumber );
- } else {
- PrintMessageEvent( -1, MSG_KILLED, dead->entityNumber, killer->entityNumber );
- }
- } else {
- PrintMessageEvent( -1, MSG_DIED, dead->entityNumber );
- playerState[ dead->entityNumber ].fragCount--;
- }
- }
- /*
- ================
- idMultiplayerGame::PlayerStats
- ================
- */
- void idMultiplayerGame::PlayerStats( int clientNum, char *data, const int len ) {
- idEntity *ent;
- int team;
- *data = 0;
- // make sure we don't exceed the client list
- if ( clientNum < 0 || clientNum > gameLocal.numClients ) {
- return;
- }
- // find which team this player is on
- ent = gameLocal.entities[ clientNum ];
- if ( ent && ent->IsType( idPlayer::Type ) ) {
- team = static_cast< idPlayer * >(ent)->team;
- } else {
- return;
- }
- idStr::snPrintf( data, len, "team=%d score=%ld tks=%ld", team, playerState[ clientNum ].fragCount, playerState[ clientNum ].teamFragCount );
- return;
- }
- /*
- ================
- idMultiplayerGame::PlayerVote
- ================
- */
- void idMultiplayerGame::PlayerVote( int clientNum, playerVote_t vote ) {
- playerState[ clientNum ].vote = vote;
- }
- /*
- ================
- idMultiplayerGame::DumpTourneyLine
- ================
- */
- void idMultiplayerGame::DumpTourneyLine( void ) {
- int i;
- for ( i = 0; i < gameLocal.numClients; i++ ) {
- if ( gameLocal.entities[ i ] && gameLocal.entities[ i ]->IsType( idPlayer::Type ) ) {
- common->Printf( "client %d: rank %d\n", i, static_cast< idPlayer * >( gameLocal.entities[ i ] )->tourneyRank );
- }
- }
- }
- /*
- ================
- idMultiplayerGame::NewState
- ================
- */
- void idMultiplayerGame::NewState( gameState_t news, idPlayer *player ) {
- idBitMsg outMsg;
- byte msgBuf[MAX_GAME_MESSAGE_SIZE];
- int i;
- assert( news != gameState );
- assert( !gameLocal.isClient );
- gameLocal.DPrintf( "%s -> %s\n", GameStateStrings[ gameState ], GameStateStrings[ news ] );
- switch( news ) {
- case GAMEON: {
- gameLocal.LocalMapRestart();
- outMsg.Init( msgBuf, sizeof( msgBuf ) );
- outMsg.WriteByte( GAME_RELIABLE_MESSAGE_RESTART );
- outMsg.WriteBits( 0, 1 );
- networkSystem->ServerSendReliableMessage( -1, outMsg );
- PlayGlobalSound( -1, SND_FIGHT );
- matchStartedTime = gameLocal.time;
- fragLimitTimeout = 0;
- for( i = 0; i < gameLocal.numClients; i++ ) {
- idEntity *ent = gameLocal.entities[ i ];
- if ( !ent || !ent->IsType( idPlayer::Type ) ) {
- continue;
- }
- idPlayer *p = static_cast<idPlayer *>( ent );
- p->SetLeader( false ); // don't carry the flag from previous games
- if ( gameLocal.gameType == GAME_TOURNEY && currentTourneyPlayer[ 0 ] != i && currentTourneyPlayer[ 1 ] != i ) {
- p->ServerSpectate( true );
- p->tourneyRank++;
- } else {
- int fragLimit = gameLocal.serverInfo.GetInt( "si_fragLimit" );
- int startingCount = ( gameLocal.gameType == GAME_LASTMAN ) ? fragLimit : 0;
- playerState[ i ].fragCount = startingCount;
- playerState[ i ].teamFragCount = startingCount;
- if ( !static_cast<idPlayer *>(ent)->wantSpectate ) {
- static_cast<idPlayer *>(ent)->ServerSpectate( false );
- if ( gameLocal.gameType == GAME_TOURNEY ) {
- p->tourneyRank = 0;
- }
- }
- }
- if ( CanPlay( p ) ) {
- p->lastManPresent = true;
- } else {
- p->lastManPresent = false;
- }
- }
- cvarSystem->SetCVarString( "ui_ready", "Not Ready" );
- switchThrottle[ 1 ] = 0; // passby the throttle
- startFragLimit = gameLocal.serverInfo.GetInt( "si_fragLimit" );
- break;
- }
- case GAMEREVIEW: {
- nextState = INACTIVE; // used to abort a game. cancel out any upcoming state change
- // set all players not ready and spectating
- for( i = 0; i < gameLocal.numClients; i++ ) {
- idEntity *ent = gameLocal.entities[ i ];
- if ( !ent || !ent->IsType( idPlayer::Type ) ) {
- continue;
- }
- static_cast< idPlayer *>( ent )->forcedReady = false;
- static_cast<idPlayer *>(ent)->ServerSpectate( true );
- }
- UpdateWinsLosses( player );
- break;
- }
- case SUDDENDEATH: {
- PrintMessageEvent( -1, MSG_SUDDENDEATH );
- PlayGlobalSound( -1, SND_SUDDENDEATH );
- break;
- }
- case COUNTDOWN: {
- idBitMsg outMsg;
- byte msgBuf[ 128 ];
- warmupEndTime = gameLocal.time + 1000*cvarSystem->GetCVarInteger( "g_countDown" );
- outMsg.Init( msgBuf, sizeof( msgBuf ) );
- outMsg.WriteByte( GAME_RELIABLE_MESSAGE_WARMUPTIME );
- outMsg.WriteLong( warmupEndTime );
- networkSystem->ServerSendReliableMessage( -1, outMsg );
- break;
- }
- default:
- break;
- }
- gameState = news;
- }
- /*
- ================
- idMultiplayerGame::FillTourneySlots
- NOTE: called each frame during warmup to keep the tourney slots filled
- ================
- */
- void idMultiplayerGame::FillTourneySlots( ) {
- int i, j, rankmax, rankmaxindex;
- idEntity *ent;
- idPlayer *p;
- // fill up the slots based on tourney ranks
- for ( i = 0; i < 2; i++ ) {
- if ( currentTourneyPlayer[ i ] != -1 ) {
- continue;
- }
- rankmax = -1;
- rankmaxindex = -1;
- for ( j = 0; j < gameLocal.numClients; j++ ) {
- ent = gameLocal.entities[ j ];
- if ( !ent || !ent->IsType( idPlayer::Type ) ) {
- continue;
- }
- if ( currentTourneyPlayer[ 0 ] == j || currentTourneyPlayer[ 1 ] == j ) {
- continue;
- }
- p = static_cast< idPlayer * >( ent );
- if ( p->wantSpectate ) {
- continue;
- }
- if ( p->tourneyRank >= rankmax ) {
- // when ranks are equal, use time in game
- if ( p->tourneyRank == rankmax ) {
- assert( rankmaxindex >= 0 );
- if ( p->spawnedTime > static_cast< idPlayer * >( gameLocal.entities[ rankmaxindex ] )->spawnedTime ) {
- continue;
- }
- }
- rankmax = static_cast< idPlayer * >( ent )->tourneyRank;
- rankmaxindex = j;
- }
- }
- currentTourneyPlayer[ i ] = rankmaxindex; // may be -1 if we found nothing
- }
- }
- /*
- ================
- idMultiplayerGame::UpdateTourneyLine
- we manipulate tourneyRank on player entities for internal ranking. it's easier to deal with.
- but we need a real wait list to be synced down to clients for GUI
- ignore current players, ignore wantSpectate
- ================
- */
- void idMultiplayerGame::UpdateTourneyLine( void ) {
- int i, j, imax, max, globalmax = -1;
- idPlayer *p;
- assert( !gameLocal.isClient );
- if ( gameLocal.gameType != GAME_TOURNEY ) {
- return;
- }
- for ( j = 1; j <= gameLocal.numClients; j++ ) {
- max = -1; imax = -1;
- for ( i = 0; i < gameLocal.numClients; i++ ) {
- if ( currentTourneyPlayer[ 0 ] == i || currentTourneyPlayer[ 1 ] == i ) {
- continue;
- }
- p = static_cast< idPlayer * >( gameLocal.entities[ i ] );
- if ( !p || p->wantSpectate ) {
- continue;
- }
- if ( p->tourneyRank > max && ( globalmax == -1 || p->tourneyRank < globalmax ) ) {
- imax = i;
- max = p->tourneyRank;
- }
- }
- if ( imax == -1 ) {
- break;
- }
- idBitMsg outMsg;
- byte msgBuf[1024];
- outMsg.Init( msgBuf, sizeof( msgBuf ) );
- outMsg.WriteByte( GAME_RELIABLE_MESSAGE_TOURNEYLINE );
- outMsg.WriteByte( j );
- networkSystem->ServerSendReliableMessage( imax, outMsg );
- globalmax = max;
- }
- }
- /*
- ================
- idMultiplayerGame::CycleTourneyPlayers
- ================
- */
- void idMultiplayerGame::CycleTourneyPlayers( ) {
- int i;
- idEntity *ent;
- idPlayer *player;
- currentTourneyPlayer[ 0 ] = -1;
- currentTourneyPlayer[ 1 ] = -1;
- // if any, winner from last round will play again
- if ( lastWinner != -1 ) {
- idEntity *ent = gameLocal.entities[ lastWinner ];
- if ( ent && ent->IsType( idPlayer::Type ) ) {
- currentTourneyPlayer[ 0 ] = lastWinner;
- }
- }
- FillTourneySlots( );
- // force selected players in/out of the game and update the ranks
- for ( i = 0 ; i < gameLocal.numClients ; i++ ) {
- if ( currentTourneyPlayer[ 0 ] == i || currentTourneyPlayer[ 1 ] == i ) {
- player = static_cast<idPlayer *>( gameLocal.entities[ i ] );
- player->ServerSpectate( false );
- } else {
- ent = gameLocal.entities[ i ];
- if ( ent && ent->IsType( idPlayer::Type ) ) {
- player = static_cast<idPlayer *>( gameLocal.entities[ i ] );
- player->ServerSpectate( true );
- }
- }
- }
- UpdateTourneyLine();
- }
- /*
- ================
- idMultiplayerGame::ExecuteVote
- the votes are checked for validity/relevance before they are started
- we assume that they are still legit when reaching here
- ================
- */
- void idMultiplayerGame::ExecuteVote( void ) {
- bool needRestart;
- switch ( vote ) {
- case VOTE_RESTART:
- gameLocal.MapRestart();
- break;
- case VOTE_TIMELIMIT:
- si_timeLimit.SetInteger( atoi( voteValue ) );
- needRestart = gameLocal.NeedRestart();
- cmdSystem->BufferCommandText( CMD_EXEC_NOW, "rescanSI" );
- if ( needRestart ) {
- cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "nextMap" );
- }
- break;
- case VOTE_FRAGLIMIT:
- si_fragLimit.SetInteger( atoi( voteValue ) );
- needRestart = gameLocal.NeedRestart();
- cmdSystem->BufferCommandText( CMD_EXEC_NOW, "rescanSI" );
- if ( needRestart ) {
- cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "nextMap" );
- }
- break;
- case VOTE_GAMETYPE:
- si_gameType.SetString( voteValue );
- gameLocal.MapRestart();
- break;
- case VOTE_KICK:
- cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "kick %s", voteValue.c_str() ) );
- break;
- case VOTE_MAP:
- si_map.SetString( voteValue );
- gameLocal.MapRestart();
- break;
- case VOTE_SPECTATORS:
- si_spectators.SetBool( !si_spectators.GetBool() );
- needRestart = gameLocal.NeedRestart();
- cmdSystem->BufferCommandText( CMD_EXEC_NOW, "rescanSI" );
- if ( needRestart ) {
- cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "nextMap" );
- }
- break;
- case VOTE_NEXTMAP:
- cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "serverNextMap\n" );
- break;
- }
- }
- /*
- ================
- idMultiplayerGame::CheckVote
- ================
- */
- void idMultiplayerGame::CheckVote( void ) {
- int numVoters, i;
- if ( vote == VOTE_NONE ) {
- return;
- }
- if ( voteExecTime ) {
- if ( gameLocal.time > voteExecTime ) {
- voteExecTime = 0;
- ClientUpdateVote( VOTE_RESET, 0, 0 );
- ExecuteVote();
- vote = VOTE_NONE;
- }
- return;
- }
- // count voting players
- numVoters = 0;
- for ( i = 0; i < gameLocal.numClients; i++ ) {
- idEntity *ent = gameLocal.entities[ i ];
- if ( !ent || !ent->IsType( idPlayer::Type ) ) {
- continue;
- }
- if ( playerState[ i ].vote != PLAYER_VOTE_NONE ) {
- numVoters++;
- }
- }
- if ( !numVoters ) {
- // abort
- vote = VOTE_NONE;
- ClientUpdateVote( VOTE_ABORTED, yesVotes, noVotes );
- return;
- }
- if ( yesVotes / numVoters > 0.5f ) {
- ClientUpdateVote( VOTE_PASSED, yesVotes, noVotes );
- voteExecTime = gameLocal.time + 2000;
- return;
- }
- if ( gameLocal.time > voteTimeOut || noVotes / numVoters >= 0.5f ) {
- ClientUpdateVote( VOTE_FAILED, yesVotes, noVotes );
- vote = VOTE_NONE;
- return;
- }
- }
- /*
- ================
- idMultiplayerGame::Warmup
- ================
- */
- bool idMultiplayerGame::Warmup() {
- return ( gameState == WARMUP );
- }
- /*
- ================
- idMultiplayerGame::Run
- ================
- */
- void idMultiplayerGame::Run() {
- int i, timeLeft;
- idPlayer *player;
- int gameReviewPause;
- assert( gameLocal.isMultiplayer );
- assert( !gameLocal.isClient );
- pureReady = true;
- if ( gameState == INACTIVE ) {
- lastGameType = gameLocal.gameType;
- NewState( WARMUP );
- }
- CheckVote();
- CheckRespawns();
- if ( nextState != INACTIVE && gameLocal.time > nextStateSwitch ) {
- NewState( nextState );
- nextState = INACTIVE;
- }
- // don't update the ping every frame to save bandwidth
- if ( gameLocal.time > pingUpdateTime ) {
- for ( i = 0; i < gameLocal.numClients; i++ ) {
- playerState[i].ping = networkSystem->ServerGetClientPing( i );
- }
- pingUpdateTime = gameLocal.time + 1000;
- }
- warmupText = "";
- switch( gameState ) {
- case GAMEREVIEW: {
- if ( nextState == INACTIVE ) {
- gameReviewPause = cvarSystem->GetCVarInteger( "g_gameReviewPause" );
- nextState = NEXTGAME;
- nextStateSwitch = gameLocal.time + 1000 * gameReviewPause;
- }
- break;
- }
- case NEXTGAME: {
- if ( nextState == INACTIVE ) {
- // game rotation, new map, gametype etc.
- if ( gameLocal.NextMap() ) {
- cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "serverMapRestart\n" );
- return;
- }
- NewState( WARMUP );
- if ( gameLocal.gameType == GAME_TOURNEY ) {
- CycleTourneyPlayers();
- }
- // put everyone back in from endgame spectate
- for ( i = 0; i < gameLocal.numClients; i++ ) {
- idEntity *ent = gameLocal.entities[ i ];
- if ( ent && ent->IsType( idPlayer::Type ) ) {
- if ( !static_cast< idPlayer * >( ent )->wantSpectate ) {
- CheckRespawns( static_cast<idPlayer *>( ent ) );
- }
- }
- }
- }
- break;
- }
- case WARMUP: {
- if ( AllPlayersReady() ) {
- NewState( COUNTDOWN );
- nextState = GAMEON;
- nextStateSwitch = gameLocal.time + 1000 * cvarSystem->GetCVarInteger( "g_countDown" );
- }
- warmupText = "Warming up.. waiting for players to get ready";
- one = two = three = false;
- break;
- }
- case COUNTDOWN: {
- timeLeft = ( nextStateSwitch - gameLocal.time ) / 1000 + 1;
- if ( timeLeft == 3 && !three ) {
- PlayGlobalSound( -1, SND_THREE );
- three = true;
- } else if ( timeLeft == 2 && !two ) {
- PlayGlobalSound( -1, SND_TWO );
- two = true;
- } else if ( timeLeft == 1 && !one ) {
- PlayGlobalSound( -1, SND_ONE );
- one = true;
- }
- warmupText = va( "Match starts in %i", timeLeft );
- break;
- }
- case GAMEON: {
- player = FragLimitHit();
- if ( player ) {
- // delay between detecting frag limit and ending game. let the death anims play
- if ( !fragLimitTimeout ) {
- common->DPrintf( "enter FragLimit timeout, player %d is leader\n", player->entityNumber );
- fragLimitTimeout = gameLocal.time + FRAGLIMIT_DELAY;
- }
- if ( gameLocal.time > fragLimitTimeout ) {
- NewState( GAMEREVIEW, player );
- PrintMessageEvent( -1, MSG_FRAGLIMIT, player->entityNumber );
- }
- } else {
- if ( fragLimitTimeout ) {
- // frag limit was hit and cancelled. means the two teams got even during FRAGLIMIT_DELAY
- // enter sudden death, the next frag leader will win
- SuddenRespawn();
- PrintMessageEvent( -1, MSG_HOLYSHIT );
- fragLimitTimeout = 0;
- NewState( SUDDENDEATH );
- } else if ( TimeLimitHit() ) {
- player = FragLeader();
- if ( !player ) {
- NewState( SUDDENDEATH );
- } else {
- NewState( GAMEREVIEW, player );
- PrintMessageEvent( -1, MSG_TIMELIMIT );
- }
- }
- }
- break;
- }
- case SUDDENDEATH: {
- player = FragLeader();
- if ( player ) {
- if ( !fragLimitTimeout ) {
- common->DPrintf( "enter sudden death FragLeader timeout, player %d is leader\n", player->entityNumber );
- fragLimitTimeout = gameLocal.time + FRAGLIMIT_DELAY;
- }
- if ( gameLocal.time > fragLimitTimeout ) {
- NewState( GAMEREVIEW, player );
- PrintMessageEvent( -1, MSG_FRAGLIMIT, player->entityNumber );
- }
- } else if ( fragLimitTimeout ) {
- SuddenRespawn();
- PrintMessageEvent( -1, MSG_HOLYSHIT );
- fragLimitTimeout = 0;
- }
- break;
- }
- }
- }
- /*
- ================
- idMultiplayerGame::UpdateMainGui
- ================
- */
- void idMultiplayerGame::UpdateMainGui( void ) {
- int i;
- mainGui->SetStateInt( "readyon", gameState == WARMUP ? 1 : 0 );
- mainGui->SetStateInt( "readyoff", gameState != WARMUP ? 1 : 0 );
- idStr strReady = cvarSystem->GetCVarString( "ui_ready" );
- if ( strReady.Icmp( "ready") == 0 ){
- strReady = common->GetLanguageDict()->GetString( "#str_04248" );
- } else {
- strReady = common->GetLanguageDict()->GetString( "#str_04247" );
- }
- mainGui->SetStateString( "ui_ready", strReady );
- mainGui->SetStateInt( "teamon", gameLocal.gameType == GAME_TDM ? 1 : 0 );
- mainGui->SetStateInt( "teamoff", gameLocal.gameType != GAME_TDM ? 1 : 0 );
- if ( gameLocal.gameType == GAME_TDM ) {
- idPlayer *p = gameLocal.GetClientByNum( gameLocal.localClientNum );
- mainGui->SetStateInt( "team", p->team );
- }
- // setup vote
- mainGui->SetStateInt( "voteon", ( vote != VOTE_NONE && !voted ) ? 1 : 0 );
- mainGui->SetStateInt( "voteoff", ( vote != VOTE_NONE && !voted ) ? 0 : 1 );
- // last man hack
- mainGui->SetStateInt( "isLastMan", gameLocal.gameType == GAME_LASTMAN ? 1 : 0 );
- // send the current serverinfo values
- for ( i = 0; i < gameLocal.serverInfo.GetNumKeyVals(); i++ ) {
- const idKeyValue *keyval = gameLocal.serverInfo.GetKeyVal( i );
- mainGui->SetStateString( keyval->GetKey(), keyval->GetValue() );
- }
- mainGui->StateChanged( gameLocal.time );
- #if defined( __linux__ )
- // replacing the oh-so-useful s_reverse with sound backend prompt
- mainGui->SetStateString( "driver_prompt", "1" );
- #else
- mainGui->SetStateString( "driver_prompt", "0" );
- #endif
- }
- /*
- ================
- idMultiplayerGame::StartMenu
- ================
- */
- idUserInterface* idMultiplayerGame::StartMenu( void ) {
- if ( mainGui == NULL ) {
- return NULL;
- }
- int i, j;
- if ( currentMenu ) {
- currentMenu = 0;
- cvarSystem->SetCVarBool( "ui_chat", false );
- } else {
- if ( nextMenu >= 2 ) {
- currentMenu = nextMenu;
- } else {
- // for default and explicit
- currentMenu = 1;
- }
- cvarSystem->SetCVarBool( "ui_chat", true );
- }
- nextMenu = 0;
- gameLocal.sessionCommand = ""; // in case we used "game_startMenu" to trigger the menu
- if ( currentMenu == 1 ) {
- UpdateMainGui();
- // UpdateMainGui sets most things, but it doesn't set these because
- // it'd be pointless and/or harmful to set them every frame (for various reasons)
- // Currenty the gui doesn't update properly if they change anyway, so we'll leave it like this.
- // setup callvote
- if ( vote == VOTE_NONE ) {
- bool callvote_ok = false;
- for ( i = 0; i < VOTE_COUNT; i++ ) {
- // flag on means vote is denied, so default value 0 means all votes and -1 disables
- mainGui->SetStateInt( va( "vote%d", i ), g_voteFlags.GetInteger() & ( 1 << i ) ? 0 : 1 );
- if ( !( g_voteFlags.GetInteger() & ( 1 << i ) ) ) {
- callvote_ok = true;
- }
- }
- mainGui->SetStateInt( "callvote", callvote_ok );
- } else {
- mainGui->SetStateInt( "callvote", 2 );
- }
- // player kick data
- idStr kickList;
- j = 0;
- for ( i = 0; i < gameLocal.numClients; i++ ) {
- if ( gameLocal.entities[ i ] && gameLocal.entities[ i ]->IsType( idPlayer::Type ) ) {
- if ( kickList.Length() ) {
- kickList += ";";
- }
- kickList += va( "\"%d - %s\"", i, gameLocal.userInfo[ i ].GetString( "ui_name" ) );
- kickVoteMap[ j ] = i;
- j++;
- }
- }
- mainGui->SetStateString( "kickChoices", kickList );
- mainGui->SetStateString( "chattext", "" );
- mainGui->Activate( true, gameLocal.time );
- return mainGui;
- } else if ( currentMenu == 2 ) {
- // the setup is done in MessageMode
- msgmodeGui->Activate( true, gameLocal.time );
- cvarSystem->SetCVarBool( "ui_chat", true );
- return msgmodeGui;
- }
- return NULL;
- }
- /*
- ================
- idMultiplayerGame::DisableMenu
- ================
- */
- void idMultiplayerGame::DisableMenu( void ) {
- gameLocal.sessionCommand = ""; // in case we used "game_startMenu" to trigger the menu
- if ( currentMenu == 1 ) {
- mainGui->Activate( false, gameLocal.time );
- } else if ( currentMenu == 2 ) {
- msgmodeGui->Activate( false, gameLocal.time );
- }
- currentMenu = 0;
- nextMenu = 0;
- cvarSystem->SetCVarBool( "ui_chat", false );
- }
- /*
- ================
- idMultiplayerGame::SetMapShot
- ================
- */
- void idMultiplayerGame::SetMapShot( void ) {
- char screenshot[ MAX_STRING_CHARS ];
- int mapNum = mapList->GetSelection( NULL, 0 );
- const idDict *dict = NULL;
- if ( mapNum >= 0 ) {
- dict = fileSystem->GetMapDecl( mapNum );
- }
- fileSystem->FindMapScreenshot( dict ? dict->GetString( "path" ) : "", screenshot, MAX_STRING_CHARS );
- mainGui->SetStateString( "current_levelshot", screenshot );
- }
- /*
- ================
- idMultiplayerGame::HandleGuiCommands
- ================
- */
- const char* idMultiplayerGame::HandleGuiCommands( const char *_menuCommand ) {
- idUserInterface *currentGui;
- const char *voteValue;
- int vote_clientNum;
- int icmd;
- idCmdArgs args;
- if ( !_menuCommand[ 0 ] ) {
- common->Printf( "idMultiplayerGame::HandleGuiCommands: empty command\n" );
- return "continue";
- }
- assert( currentMenu );
- if ( currentMenu == 1 ) {
- currentGui = mainGui;
- } else {
- currentGui = msgmodeGui;
- }
- args.TokenizeString( _menuCommand, false );
- for( icmd = 0; icmd < args.Argc(); ) {
- const char *cmd = args.Argv( icmd++ );
- if ( !idStr::Icmp( cmd, ";" ) ) {
- continue;
- } else if ( !idStr::Icmp( cmd, "video" ) ) {
- idStr vcmd;
- if ( args.Argc() - icmd >= 1 ) {
- vcmd = args.Argv( icmd++ );
- }
- int oldSpec = cvarSystem->GetCVarInteger( "com_machineSpec" );
- if ( idStr::Icmp( vcmd, "low" ) == 0 ) {
- cvarSystem->SetCVarInteger( "com_machineSpec", 0 );
- } else if ( idStr::Icmp( vcmd, "medium" ) == 0 ) {
- cvarSystem->SetCVarInteger( "com_machineSpec", 1 );
- } else if ( idStr::Icmp( vcmd, "high" ) == 0 ) {
- cvarSystem->SetCVarInteger( "com_machineSpec", 2 );
- } else if ( idStr::Icmp( vcmd, "ultra" ) == 0 ) {
- cvarSystem->SetCVarInteger( "com_machineSpec", 3 );
- } else if ( idStr::Icmp( vcmd, "recommended" ) == 0 ) {
- cmdSystem->BufferCommandText( CMD_EXEC_NOW, "setMachineSpec\n" );
- }
- if ( oldSpec != cvarSystem->GetCVarInteger( "com_machineSpec" ) ) {
- currentGui->SetStateInt( "com_machineSpec", cvarSystem->GetCVarInteger( "com_machineSpec" ) );
- currentGui->StateChanged( gameLocal.realClientTime );
- cmdSystem->BufferCommandText( CMD_EXEC_NOW, "execMachineSpec\n" );
- }
- if ( idStr::Icmp( vcmd, "restart" ) == 0) {
- cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "vid_restart\n" );
- }
- continue;
- } else if ( !idStr::Icmp( cmd, "play" ) ) {
- if ( args.Argc() - icmd >= 1 ) {
- idStr snd = args.Argv( icmd++ );
- int channel = 1;
- if ( snd.Length() == 1 ) {
- channel = atoi( snd );
- snd = args.Argv( icmd++ );
- }
- gameSoundWorld->PlayShaderDirectly( snd, channel );
- }
- continue;
- } else if ( !idStr::Icmp( cmd, "mpSkin" ) ) {
- idStr skin;
- if ( args.Argc() - icmd >= 1 ) {
- skin = args.Argv( icmd++ );
- cvarSystem->SetCVarString( "ui_skin", skin );
- }
- SetMenuSkin();
- continue;
- } else if ( !idStr::Icmp( cmd, "quit" ) ) {
- cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "quit\n" );
- return NULL;
- } else if ( !idStr::Icmp( cmd, "disconnect" ) ) {
- cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "disconnect\n" );
- return NULL;
- } else if ( !idStr::Icmp( cmd, "close" ) ) {
- DisableMenu( );
- return NULL;
- } else if ( !idStr::Icmp( cmd, "spectate" ) ) {
- ToggleSpectate();
- DisableMenu( );
- return NULL;
- } else if ( !idStr::Icmp( cmd, "chatmessage" ) ) {
- int mode = currentGui->State().GetInt( "messagemode" );
- if ( mode ) {
- cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "sayTeam \"%s\"", currentGui->State().GetString( "chattext" ) ) );
- } else {
- cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "say \"%s\"", currentGui->State().GetString( "chattext" ) ) );
- }
- currentGui->SetStateString( "chattext", "" );
- if ( currentMenu == 1 ) {
- return "continue";
- } else {
- DisableMenu();
- return NULL;
- }
- } else if ( !idStr::Icmp( cmd, "readytoggle" ) ) {
- ToggleReady( );
- DisableMenu( );
- return NULL;
- } else if ( !idStr::Icmp( cmd, "teamtoggle" ) ) {
- ToggleTeam( );
- DisableMenu( );
- return NULL;
- } else if ( !idStr::Icmp( cmd, "callVote" ) ) {
- vote_flags_t voteIndex = (vote_flags_t)mainGui->State().GetInt( "voteIndex" );
- if ( voteIndex == VOTE_MAP ) {
- int mapNum = mapList->GetSelection( NULL, 0 );
- if ( mapNum >= 0 ) {
- const idDict *dict = fileSystem->GetMapDecl( mapNum );
- if ( dict ) {
- ClientCallVote( VOTE_MAP, dict->GetString( "path" ) );
- }
- }
- } else {
- voteValue = mainGui->State().GetString( "str_voteValue" );
- if ( voteIndex == VOTE_KICK ) {
- vote_clientNum = kickVoteMap[ atoi( voteValue ) ];
- ClientCallVote( voteIndex, va( "%d", vote_clientNum ) );
- } else {
- ClientCallVote( voteIndex, voteValue );
- }
- }
- DisableMenu();
- return NULL;
- } else if ( !idStr::Icmp( cmd, "voteyes" ) ) {
- CastVote( gameLocal.localClientNum, true );
- DisableMenu();
- return NULL;
- } else if ( !idStr::Icmp( cmd, "voteno" ) ) {
- CastVote( gameLocal.localClientNum, false );
- DisableMenu();
- return NULL;
- } else if ( !idStr::Icmp( cmd, "bind" ) ) {
- if ( args.Argc() - icmd >= 2 ) {
- idStr key = args.Argv( icmd++ );
- idStr bind = args.Argv( icmd++ );
- cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "bindunbindtwo \"%s\" \"%s\"", key.c_str(), bind.c_str() ) );
- mainGui->SetKeyBindingNames();
- }
- continue;
- } else if ( !idStr::Icmp( cmd, "clearbind" ) ) {
- if ( args.Argc() - icmd >= 1 ) {
- idStr bind = args.Argv( icmd++ );
- cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "unbind \"%s\"", bind.c_str() ) );
- mainGui->SetKeyBindingNames();
- }
- continue;
- } else if ( !idStr::Icmp( cmd, "MAPScan" ) ) {
- const char *gametype = gameLocal.serverInfo.GetString( "si_gameType" );
- if ( gametype == NULL || *gametype == 0 || idStr::Icmp( gametype, "singleplayer" ) == 0 ) {
- gametype = "Deathmatch";
- }
- int i, num;
- idStr si_map = gameLocal.serverInfo.GetString("si_map");
- const idDict *dict;
- mapList->Clear();
- mapList->SetSelection( -1 );
- num = fileSystem->GetNumMaps();
- for ( i = 0; i < num; i++ ) {
- dict = fileSystem->GetMapDecl( i );
- if ( dict ) {
- // any MP gametype supported
- bool isMP = false;
- int igt = GAME_SP + 1;
- while ( si_gameTypeArgs[ igt ] ) {
- if ( dict->GetBool( si_gameTypeArgs[ igt ] ) ) {
- isMP = true;
- break;
- }
- igt++;
- }
- if ( isMP ) {
- const char *mapName = dict->GetString( "name" );
- if ( mapName[0] == '\0' ) {
- mapName = dict->GetString( "path" );
- }
- mapName = common->GetLanguageDict()->GetString( mapName );
- mapList->Add( i, mapName );
- if ( !si_map.Icmp( dict->GetString( "path" ) ) ) {
- mapList->SetSelection( mapList->Num() - 1 );
- }
- }
- }
- }
- // set the current level shot
- SetMapShot( );
- return "continue";
- } else if ( !idStr::Icmp( cmd, "click_maplist" ) ) {
- SetMapShot( );
- return "continue";
- } else if ( strstr( cmd, "sound" ) == cmd ) {
- // pass that back to the core, will know what to do with it
- return _menuCommand;
- }
- common->Printf( "idMultiplayerGame::HandleGuiCommands: '%s' unknown\n", cmd );
- }
- return "continue";
- }
- /*
- ================
- idMultiplayerGame::Draw
- ================
- */
- bool idMultiplayerGame::Draw( int clientNum ) {
- idPlayer *player, *viewPlayer;
- // clear the render entities for any players that don't need
- // icons and which might not be thinking because they weren't in
- // the last snapshot.
- for ( int i = 0; i < gameLocal.numClients; i++ ) {
- player = static_cast<idPlayer *>( gameLocal.entities[ i ] );
- if ( player && !player->NeedsIcon() ) {
- player->HidePlayerIcons();
- }
- }
- player = viewPlayer = static_cast<idPlayer *>( gameLocal.entities[ clientNum ] );
- if ( player == NULL ) {
- return false;
- }
- if ( player->spectating ) {
- viewPlayer = static_cast<idPlayer *>( gameLocal.entities[ player->spectator ] );
- if ( viewPlayer == NULL ) {
- return false;
- }
- }
- UpdatePlayerRanks();
- UpdateHud( viewPlayer, player->hud );
- // use the hud of the local player
- viewPlayer->playerView.RenderPlayerView( player->hud );
- if ( currentMenu ) {
- #if 0
- // uncomment this if you want to track when players are in a menu
- if ( !bCurrentMenuMsg ) {
- idBitMsg outMsg;
- byte msgBuf[ 128 ];
- outMsg.Init( msgBuf, sizeof( msgBuf ) );
- outMsg.WriteByte( GAME_RELIABLE_MESSAGE_MENU );
- outMsg.WriteBits( 1, 1 );
- networkSystem->ClientSendReliableMessage( outMsg );
- bCurrentMenuMsg = true;
- }
- #endif
- if ( player->wantSpectate ) {
- mainGui->SetStateString( "spectext", common->GetLanguageDict()->GetString( "#str_04249" ) );
- } else {
- mainGui->SetStateString( "spectext", common->GetLanguageDict()->GetString( "#str_04250" ) );
- }
- DrawChat();
- if ( currentMenu == 1 ) {
- UpdateMainGui();
- mainGui->Redraw( gameLocal.time );
- } else {
- msgmodeGui->Redraw( gameLocal.time );
- }
- } else {
- #if 0
- // uncomment this if you want to track when players are in a menu
- if ( bCurrentMenuMsg ) {
- idBitMsg outMsg;
- byte msgBuf[ 128 ];
- outMsg.Init( msgBuf, sizeof( msgBuf ) );
- outMsg.WriteByte( GAME_RELIABLE_MESSAGE_MENU );
- outMsg.WriteBits( 0, 1 );
- networkSystem->ClientSendReliableMessage( outMsg );
- bCurrentMenuMsg = false;
- }
- #endif
- if ( player->spectating ) {
- idStr spectatetext[ 2 ];
- int ispecline = 0;
- if ( gameLocal.gameType == GAME_TOURNEY ) {
- if ( !player->wantSpectate ) {
- spectatetext[ 0 ] = common->GetLanguageDict()->GetString( "#str_04246" );
- switch ( player->tourneyLine ) {
- case 0:
- spectatetext[ 0 ] += common->GetLanguageDict()->GetString( "#str_07003" );
- break;
- case 1:
- spectatetext[ 0 ] += common->GetLanguageDict()->GetString( "#str_07004" );
- break;
- case 2:
- spectatetext[ 0 ] += common->GetLanguageDict()->GetString( "#str_07005" );
- break;
- default:
- spectatetext[ 0 ] += va( common->GetLanguageDict()->GetString( "#str_07006" ), player->tourneyLine );
- break;
- }
- ispecline++;
- }
- } else if ( gameLocal.gameType == GAME_LASTMAN ) {
- if ( !player->wantSpectate ) {
- spectatetext[ 0 ] = common->GetLanguageDict()->GetString( "#str_07007" );
- ispecline++;
- }
- }
- if ( player->spectator != player->entityNumber ) {
- spectatetext[ ispecline ] = va( common->GetLanguageDict()->GetString( "#str_07008" ), viewPlayer->GetUserInfo()->GetString( "ui_name" ) );
- } else if ( !ispecline ) {
- spectatetext[ 0 ] = common->GetLanguageDict()->GetString( "#str_04246" );
- }
- spectateGui->SetStateString( "spectatetext0", spectatetext[0].c_str() );
- spectateGui->SetStateString( "spectatetext1", spectatetext[1].c_str() );
- if ( vote != VOTE_NONE ) {
- spectateGui->SetStateString( "vote", va( "%s (y: %d n: %d)", voteString.c_str(), (int)yesVotes, (int)noVotes ) );
- } else {
- spectateGui->SetStateString( "vote", "" );
- }
- spectateGui->Redraw( gameLocal.time );
- }
- DrawChat();
- DrawScoreBoard( player );
- }
- return true;
- }
- /*
- ================
- idMultiplayerGame::UpdateHud
- ================
- */
- void idMultiplayerGame::UpdateHud( idPlayer *player, idUserInterface *hud ) {
- int i;
- if ( !hud ) {
- return;
- }
- hud->SetStateBool( "warmup", Warmup() );
- if ( gameState == WARMUP ) {
- if ( player->IsReady() ) {
- hud->SetStateString( "warmuptext", common->GetLanguageDict()->GetString( "#str_04251" ) );
- } else {
- hud->SetStateString( "warmuptext", common->GetLanguageDict()->GetString( "#str_07002" ) );
- }
- }
- hud->SetStateString( "timer", ( Warmup() ) ? common->GetLanguageDict()->GetString( "#str_04251" ) : ( gameState == SUDDENDEATH ) ? common->GetLanguageDict()->GetString( "#str_04252" ) : GameTime() );
- if ( vote != VOTE_NONE ) {
- hud->SetStateString( "vote", va( "%s (y: %d n: %d)", voteString.c_str(), (int)yesVotes, (int)noVotes ) );
- } else {
- hud->SetStateString( "vote", "" );
- }
- hud->SetStateInt( "rank_self", 0 );
- if ( gameState == GAMEON ) {
- for ( i = 0; i < numRankedPlayers; i++ ) {
- if ( gameLocal.gameType == GAME_TDM ) {
- hud->SetStateInt( va( "player%i_score", i+1 ), playerState[ rankedPlayers[ i ]->entityNumber ].teamFragCount );
- } else {
- hud->SetStateInt( va( "player%i_score", i+1 ), playerState[ rankedPlayers[ i ]->entityNumber ].fragCount );
- }
- hud->SetStateInt( va( "rank%i", i+1 ), 1 );
- UpdateRankColor( hud, "rank%i_color%i", i+1, rankedPlayers[ i ]->colorBar );
- if ( rankedPlayers[ i ] == player ) {
- hud->SetStateInt( "rank_self", i+1 );
- }
- }
- }
- for ( i = ( gameState == GAMEON ? numRankedPlayers : 0 ) ; i < 5; i++ ) {
- hud->SetStateString( va( "player%i", i+1 ), "" );
- hud->SetStateString( va( "player%i_score", i+1 ), "" );
- hud->SetStateInt( va( "rank%i", i+1 ), 0 );
- }
- }
- /*
- ================
- idMultiplayerGame::DrawScoreBoard
- ================
- */
- void idMultiplayerGame::DrawScoreBoard( idPlayer *player ) {
- if ( player->scoreBoardOpen || gameState == GAMEREVIEW ) {
- if ( !playerState[ player->entityNumber ].scoreBoardUp ) {
- scoreBoard->Activate( true, gameLocal.time );
- playerState[ player->entityNumber ].scoreBoardUp = true;
- }
- UpdateScoreboard( scoreBoard, player );
- } else {
- if ( playerState[ player->entityNumber ].scoreBoardUp ) {
- scoreBoard->Activate( false, gameLocal.time );
- playerState[ player->entityNumber ].scoreBoardUp = false;
- }
- }
- }
- /*
- ===============
- idMultiplayerGame::ClearChatData
- ===============
- */
- void idMultiplayerGame::ClearChatData() {
- chatHistoryIndex = 0;
- chatHistorySize = 0;
- chatDataUpdated = true;
- }
- /*
- ===============
- idMultiplayerGame::AddChatLine
- ===============
- */
- void idMultiplayerGame::AddChatLine( const char *fmt, ... ) {
- idStr temp;
- va_list argptr;
-
- va_start( argptr, fmt );
- vsprintf( temp, fmt, argptr );
- va_end( argptr );
-
- gameLocal.Printf( "%s\n", temp.c_str() );
- chatHistory[ chatHistoryIndex % NUM_CHAT_NOTIFY ].line = temp;
- chatHistory[ chatHistoryIndex % NUM_CHAT_NOTIFY ].fade = 6;
- chatHistoryIndex++;
- if ( chatHistorySize < NUM_CHAT_NOTIFY ) {
- chatHistorySize++;
- }
- chatDataUpdated = true;
- lastChatLineTime = gameLocal.time;
- }
- /*
- ===============
- idMultiplayerGame::DrawChat
- ===============
- */
- void idMultiplayerGame::DrawChat() {
- int i, j;
- if ( guiChat ) {
- if ( gameLocal.time - lastChatLineTime > CHAT_FADE_TIME ) {
- if ( chatHistorySize > 0 ) {
- for ( i = chatHistoryIndex - chatHistorySize; i < chatHistoryIndex; i++ ) {
- chatHistory[ i % NUM_CHAT_NOTIFY ].fade--;
- if ( chatHistory[ i % NUM_CHAT_NOTIFY ].fade < 0 ) {
- chatHistorySize--; // this assumes the removals are always at the beginning
- }
- }
- chatDataUpdated = true;
- }
- lastChatLineTime = gameLocal.time;
- }
- if ( chatDataUpdated ) {
- j = 0;
- i = chatHistoryIndex - chatHistorySize;
- while ( i < chatHistoryIndex ) {
- guiChat->SetStateString( va( "chat%i", j ), chatHistory[ i % NUM_CHAT_NOTIFY ].line );
- // don't set alpha above 4, the gui only knows that
- guiChat->SetStateInt( va( "alpha%i", j ), Min( 4, (int)chatHistory[ i % NUM_CHAT_NOTIFY ].fade ) );
- j++; i++;
- }
- while ( j < NUM_CHAT_NOTIFY ) {
- guiChat->SetStateString( va( "chat%i", j ), "" );
- j++;
- }
- guiChat->Activate( true, gameLocal.time );
- chatDataUpdated = false;
- }
- guiChat->Redraw( gameLocal.time );
- }
- }
- const int ASYNC_PLAYER_FRAG_BITS = -idMath::BitsForInteger( MP_PLAYER_MAXFRAGS - MP_PLAYER_MINFRAGS ); // player can have negative frags
- const int ASYNC_PLAYER_WINS_BITS = idMath::BitsForInteger( MP_PLAYER_MAXWINS );
- const int ASYNC_PLAYER_PING_BITS = idMath::BitsForInteger( MP_PLAYER_MAXPING );
- /*
- ================
- idMultiplayerGame::WriteToSnapshot
- ================
- */
- void idMultiplayerGame::WriteToSnapshot( idBitMsgDelta &msg ) const {
- int i;
- int value;
- msg.WriteByte( gameState );
- msg.WriteShort( currentTourneyPlayer[ 0 ] );
- msg.WriteShort( currentTourneyPlayer[ 1 ] );
- for ( i = 0; i < MAX_CLIENTS; i++ ) {
- // clamp all values to min/max possible value that we can send over
- value = idMath::ClampInt( MP_PLAYER_MINFRAGS, MP_PLAYER_MAXFRAGS, playerState[i].fragCount );
- msg.WriteBits( value, ASYNC_PLAYER_FRAG_BITS );
- value = idMath::ClampInt( MP_PLAYER_MINFRAGS, MP_PLAYER_MAXFRAGS, playerState[i].teamFragCount );
- msg.WriteBits( value, ASYNC_PLAYER_FRAG_BITS );
- value = idMath::ClampInt( 0, MP_PLAYER_MAXWINS, playerState[i].wins );
- msg.WriteBits( value, ASYNC_PLAYER_WINS_BITS );
- value = idMath::ClampInt( 0, MP_PLAYER_MAXPING, playerState[i].ping );
- msg.WriteBits( value, ASYNC_PLAYER_PING_BITS );
- msg.WriteBits( playerState[i].ingame, 1 );
- }
- }
- /*
- ================
- idMultiplayerGame::ReadFromSnapshot
- ================
- */
- void idMultiplayerGame::ReadFromSnapshot( const idBitMsgDelta &msg ) {
- int i;
- gameState_t newState;
- newState = (idMultiplayerGame::gameState_t)msg.ReadByte();
- if ( newState != gameState ) {
- gameLocal.DPrintf( "%s -> %s\n", GameStateStrings[ gameState ], GameStateStrings[ newState ] );
- gameState = newState;
- // these could be gathered in a BGNewState() kind of thing, as we have to do them in NewState as well
- if ( gameState == GAMEON ) {
- matchStartedTime = gameLocal.time;
- cvarSystem->SetCVarString( "ui_ready", "Not Ready" );
- switchThrottle[ 1 ] = 0; // passby the throttle
- startFragLimit = gameLocal.serverInfo.GetInt( "si_fragLimit" );
- }
- }
- currentTourneyPlayer[ 0 ] = msg.ReadShort();
- currentTourneyPlayer[ 1 ] = msg.ReadShort();
- for ( i = 0; i < MAX_CLIENTS; i++ ) {
- playerState[i].fragCount = msg.ReadBits( ASYNC_PLAYER_FRAG_BITS );
- playerState[i].teamFragCount = msg.ReadBits( ASYNC_PLAYER_FRAG_BITS );
- playerState[i].wins = msg.ReadBits( ASYNC_PLAYER_WINS_BITS );
- playerState[i].ping = msg.ReadBits( ASYNC_PLAYER_PING_BITS );
- playerState[i].ingame = msg.ReadBits( 1 ) != 0;
- }
- }
- /*
- ================
- idMultiplayerGame::PlayGlobalSound
- ================
- */
- void idMultiplayerGame::PlayGlobalSound( int to, snd_evt_t evt, const char *shader ) {
- const idSoundShader *shaderDecl;
- if ( to == -1 || to == gameLocal.localClientNum ) {
- if ( shader ) {
- gameSoundWorld->PlayShaderDirectly( shader );
- } else {
- gameSoundWorld->PlayShaderDirectly( GlobalSoundStrings[ evt ] );
- }
- }
- if ( !gameLocal.isClient ) {
- idBitMsg outMsg;
- byte msgBuf[1024];
- outMsg.Init( msgBuf, sizeof( msgBuf ) );
- if ( shader ) {
- shaderDecl = declManager->FindSound( shader );
- if ( !shaderDecl ) {
- return;
- }
- outMsg.WriteByte( GAME_RELIABLE_MESSAGE_SOUND_INDEX );
- outMsg.WriteLong( gameLocal.ServerRemapDecl( to, DECL_SOUND, shaderDecl->Index() ) );
- } else {
- outMsg.WriteByte( GAME_RELIABLE_MESSAGE_SOUND_EVENT );
- outMsg.WriteByte( evt );
- }
- networkSystem->ServerSendReliableMessage( to, outMsg );
- }
- }
- /*
- ================
- idMultiplayerGame::PrintMessageEvent
- ================
- */
- void idMultiplayerGame::PrintMessageEvent( int to, msg_evt_t evt, int parm1, int parm2 ) {
- switch ( evt ) {
- case MSG_SUICIDE:
- assert( parm1 >= 0 );
- AddChatLine( common->GetLanguageDict()->GetString( "#str_04293" ), gameLocal.userInfo[ parm1 ].GetString( "ui_name" ) );
- break;
- case MSG_KILLED:
- assert( parm1 >= 0 && parm2 >= 0 );
- AddChatLine( common->GetLanguageDict()->GetString( "#str_04292" ), gameLocal.userInfo[ parm1 ].GetString( "ui_name" ), gameLocal.userInfo[ parm2 ].GetString( "ui_name" ) );
- break;
- case MSG_KILLEDTEAM:
- assert( parm1 >= 0 && parm2 >= 0 );
- AddChatLine( common->GetLanguageDict()->GetString( "#str_04291" ), gameLocal.userInfo[ parm1 ].GetString( "ui_name" ), gameLocal.userInfo[ parm2 ].GetString( "ui_name" ) );
- break;
- case MSG_TELEFRAGGED:
- assert( parm1 >= 0 && parm2 >= 0 );
- AddChatLine( common->GetLanguageDict()->GetString( "#str_04290" ), gameLocal.userInfo[ parm1 ].GetString( "ui_name" ), gameLocal.userInfo[ parm2 ].GetString( "ui_name" ) );
- break;
- case MSG_DIED:
- assert( parm1 >= 0 );
- AddChatLine( common->GetLanguageDict()->GetString( "#str_04289" ), gameLocal.userInfo[ parm1 ].GetString( "ui_name" ) );
- break;
- case MSG_VOTE:
- AddChatLine( common->GetLanguageDict()->GetString( "#str_04288" ) );
- break;
- case MSG_SUDDENDEATH:
- AddChatLine( common->GetLanguageDict()->GetString( "#str_04287" ) );
- break;
- case MSG_FORCEREADY:
- AddChatLine( common->GetLanguageDict()->GetString( "#str_04286" ), gameLocal.userInfo[ parm1 ].GetString( "ui_name" ) );
- if ( gameLocal.entities[ parm1 ] && gameLocal.entities[ parm1 ]->IsType( idPlayer::Type ) ) {
- static_cast< idPlayer * >( gameLocal.entities[ parm1 ] )->forcedReady = true;
- }
- break;
- case MSG_JOINEDSPEC:
- AddChatLine( common->GetLanguageDict()->GetString( "#str_04285" ), gameLocal.userInfo[ parm1 ].GetString( "ui_name" ) );
- break;
- case MSG_TIMELIMIT:
- AddChatLine( common->GetLanguageDict()->GetString( "#str_04284" ) );
- break;
- case MSG_FRAGLIMIT:
- if ( gameLocal.gameType == GAME_LASTMAN ) {
- AddChatLine( common->GetLanguageDict()->GetString( "#str_04283" ), gameLocal.userInfo[ parm1 ].GetString( "ui_name" ) );
- } else if ( gameLocal.gameType == GAME_TDM ) {
- AddChatLine( common->GetLanguageDict()->GetString( "#str_04282" ), gameLocal.userInfo[ parm1 ].GetString( "ui_team" ) );
- } else {
- AddChatLine( common->GetLanguageDict()->GetString( "#str_04281" ), gameLocal.userInfo[ parm1 ].GetString( "ui_name" ) );
- }
- break;
- case MSG_JOINTEAM:
- AddChatLine( common->GetLanguageDict()->GetString( "#str_04280" ), gameLocal.userInfo[ parm1 ].GetString( "ui_name" ), parm2 ? common->GetLanguageDict()->GetString( "#str_02500" ) : common->GetLanguageDict()->GetString( "#str_02499" ) );
- break;
- case MSG_HOLYSHIT:
- AddChatLine( common->GetLanguageDict()->GetString( "#str_06732" ) );
- break;
- default:
- gameLocal.DPrintf( "PrintMessageEvent: unknown message type %d\n", evt );
- return;
- }
- if ( !gameLocal.isClient ) {
- idBitMsg outMsg;
- byte msgBuf[1024];
- outMsg.Init( msgBuf, sizeof( msgBuf ) );
- outMsg.WriteByte( GAME_RELIABLE_MESSAGE_DB );
- outMsg.WriteByte( evt );
- outMsg.WriteByte( parm1 );
- outMsg.WriteByte( parm2 );
- networkSystem->ServerSendReliableMessage( to, outMsg );
- }
- }
- /*
- ================
- idMultiplayerGame::SuddenRespawns
- solely for LMN if an end game ( fragLimitTimeout ) was entered and aborted before expiration
- LMN players which still have lives left need to be respawned without being marked lastManOver
- ================
- */
- void idMultiplayerGame::SuddenRespawn( void ) {
- int i;
- if ( gameLocal.gameType != GAME_LASTMAN ) {
- return;
- }
- for ( i = 0; i < gameLocal.numClients; i++ ) {
- if ( !gameLocal.entities[ i ] || !gameLocal.entities[ i ]->IsType( idPlayer::Type ) ) {
- continue;
- }
- if ( !CanPlay( static_cast< idPlayer * >( gameLocal.entities[ i ] ) ) ) {
- continue;
- }
- if ( static_cast< idPlayer * >( gameLocal.entities[ i ] )->lastManOver ) {
- continue;
- }
- static_cast< idPlayer * >( gameLocal.entities[ i ] )->lastManPlayAgain = true;
- }
- }
- /*
- ================
- idMultiplayerGame::CheckSpawns
- ================
- */
- void idMultiplayerGame::CheckRespawns( idPlayer *spectator ) {
- for( int i = 0 ; i < gameLocal.numClients ; i++ ) {
- idEntity *ent = gameLocal.entities[ i ];
- if ( !ent || !ent->IsType( idPlayer::Type ) ) {
- continue;
- }
- idPlayer *p = static_cast<idPlayer *>(ent);
- // once we hit sudden death, nobody respawns till game has ended
- if ( WantRespawn( p ) || p == spectator ) {
- if ( gameState == SUDDENDEATH && gameLocal.gameType != GAME_LASTMAN ) {
- // respawn rules while sudden death are different
- // sudden death may trigger while a player is dead, so there are still cases where we need to respawn
- // don't do any respawns while we are in end game delay though
- if ( !fragLimitTimeout ) {
- if ( gameLocal.gameType == GAME_TDM || p->IsLeader() ) {
- #ifdef _DEBUG
- if ( gameLocal.gameType == GAME_TOURNEY ) {
- assert( p->entityNumber == currentTourneyPlayer[ 0 ] || p->entityNumber == currentTourneyPlayer[ 1 ] );
- }
- #endif
- p->ServerSpectate( false );
- } else if ( !p->IsLeader() ) {
- // sudden death is rolling, this player is not a leader, have him spectate
- p->ServerSpectate( true );
- CheckAbortGame();
- }
- }
- } else {
- if ( gameLocal.gameType == GAME_DM ||
- gameLocal.gameType == GAME_TDM ) {
- if ( gameState == WARMUP || gameState == COUNTDOWN || gameState == GAMEON ) {
- p->ServerSpectate( false );
- }
- } else if ( gameLocal.gameType == GAME_TOURNEY ) {
- if ( i == currentTourneyPlayer[ 0 ] || i == currentTourneyPlayer[ 1 ] ) {
- if ( gameState == WARMUP || gameState == COUNTDOWN || gameState == GAMEON ) {
- p->ServerSpectate( false );
- }
- } else if ( gameState == WARMUP ) {
- // make sure empty tourney slots get filled first
- FillTourneySlots( );
- if ( i == currentTourneyPlayer[ 0 ] || i == currentTourneyPlayer[ 1 ] ) {
- p->ServerSpectate( false );
- }
- }
- } else if ( gameLocal.gameType == GAME_LASTMAN ) {
- if ( gameState == WARMUP || gameState == COUNTDOWN ) {
- p->ServerSpectate( false );
- } else if ( gameState == GAMEON || gameState == SUDDENDEATH ) {
- if ( gameState == GAMEON && playerState[ i ].fragCount > 0 && p->lastManPresent ) {
- assert( !p->lastManOver );
- p->ServerSpectate( false );
- } else if ( p->lastManPlayAgain && p->lastManPresent ) {
- assert( gameState == SUDDENDEATH );
- p->ServerSpectate( false );
- } else {
- // if a fragLimitTimeout was engaged, do NOT mark lastManOver as that could mean
- // everyone ends up spectator and game is stalled with no end
- // if the frag limit delay is engaged and cancels out before expiring, LMN players are
- // respawned to play the tie again ( through SuddenRespawn and lastManPlayAgain )
- if ( !fragLimitTimeout && !p->lastManOver ) {
- common->DPrintf( "client %d has lost all last man lives\n", i );
- // end of the game for this guy, send him to spectators
- p->lastManOver = true;
- // clients don't have access to lastManOver
- // so set the fragCount to something silly ( used in scoreboard and player ranking )
- playerState[ i ].fragCount = LASTMAN_NOLIVES;
- p->ServerSpectate( true );
-
- //Check for a situation where the last two player dies at the same time and don't
- //try to respawn manually...This was causing all players to go into spectate mode
- //and the server got stuck
- {
- int j;
- for ( j = 0; j < gameLocal.numClients; j++ ) {
- if ( !gameLocal.entities[ j ] ) {
- continue;
- }
- if ( !CanPlay( static_cast< idPlayer * >( gameLocal.entities[ j ] ) ) ) {
- continue;
- }
- if ( !static_cast< idPlayer * >( gameLocal.entities[ j ] )->lastManOver ) {
- break;
- }
- }
- if( j == gameLocal.numClients) {
- //Everyone is dead so don't allow this player to spectate
- //so the match will end
- p->ServerSpectate( false );
- }
- }
- }
- }
- }
- }
- }
- } else if ( p->wantSpectate && !p->spectating ) {
- playerState[ i ].fragCount = 0; // whenever you willingly go spectate during game, your score resets
- p->ServerSpectate( true );
- UpdateTourneyLine();
- CheckAbortGame();
- }
- }
- }
- /*
- ================
- idMultiplayerGame::ForceReady
- ================
- */
- void idMultiplayerGame::ForceReady( ) {
- for( int i = 0 ; i < gameLocal.numClients ; i++ ) {
- idEntity *ent = gameLocal.entities[ i ];
- if ( !ent || !ent->IsType( idPlayer::Type ) ) {
- continue;
- }
- idPlayer *p = static_cast<idPlayer *>( ent );
- if ( !p->IsReady() ) {
- PrintMessageEvent( -1, MSG_FORCEREADY, i );
- p->forcedReady = true;
- }
- }
- }
- /*
- ================
- idMultiplayerGame::ForceReady_f
- ================
- */
- void idMultiplayerGame::ForceReady_f( const idCmdArgs &args ) {
- if ( !gameLocal.isMultiplayer || gameLocal.isClient ) {
- common->Printf( "forceReady: multiplayer server only\n" );
- return;
- }
- gameLocal.mpGame.ForceReady();
- }
- /*
- ================
- idMultiplayerGame::DropWeapon
- ================
- */
- void idMultiplayerGame::DropWeapon( int clientNum ) {
- assert( !gameLocal.isClient );
- idEntity *ent = gameLocal.entities[ clientNum ];
- if ( !ent || !ent->IsType( idPlayer::Type ) ) {
- return;
- }
- static_cast< idPlayer* >( ent )->DropWeapon( false );
- }
- /*
- ================
- idMultiplayerGame::DropWeapon_f
- ================
- */
- void idMultiplayerGame::DropWeapon_f( const idCmdArgs &args ) {
- if ( !gameLocal.isMultiplayer ) {
- common->Printf( "clientDropWeapon: only valid in multiplayer\n" );
- return;
- }
- idBitMsg outMsg;
- byte msgBuf[128];
- outMsg.Init( msgBuf, sizeof( msgBuf ) );
- outMsg.WriteByte( GAME_RELIABLE_MESSAGE_DROPWEAPON );
- networkSystem->ClientSendReliableMessage( outMsg );
- }
- /*
- ================
- idMultiplayerGame::MessageMode_f
- ================
- */
- void idMultiplayerGame::MessageMode_f( const idCmdArgs &args ) {
- gameLocal.mpGame.MessageMode( args );
- }
- /*
- ================
- idMultiplayerGame::MessageMode
- ================
- */
- void idMultiplayerGame::MessageMode( const idCmdArgs &args ) {
- const char *mode;
- int imode;
- if ( !gameLocal.isMultiplayer ) {
- common->Printf( "clientMessageMode: only valid in multiplayer\n" );
- return;
- }
- if ( !mainGui ) {
- common->Printf( "no local client\n" );
- return;
- }
- mode = args.Argv( 1 );
- if ( !mode[ 0 ] ) {
- imode = 0;
- } else {
- imode = atoi( mode );
- }
- msgmodeGui->SetStateString( "messagemode", imode ? "1" : "0" );
- msgmodeGui->SetStateString( "chattext", "" );
- nextMenu = 2;
- // let the session know that we want our ingame main menu opened
- gameLocal.sessionCommand = "game_startmenu";
- }
- /*
- ================
- idMultiplayerGame::Vote_f
- FIXME: voting from console
- ================
- */
- void idMultiplayerGame::Vote_f( const idCmdArgs &args ) { }
- /*
- ================
- idMultiplayerGame::CallVote_f
- FIXME: voting from console
- ================
- */
- void idMultiplayerGame::CallVote_f( const idCmdArgs &args ) { }
- /*
- ================
- idMultiplayerGame::ServerStartVote
- ================
- */
- void idMultiplayerGame::ServerStartVote( int clientNum, vote_flags_t voteIndex, const char *value ) {
- int i;
- assert( vote == VOTE_NONE );
- // setup
- yesVotes = 1;
- noVotes = 0;
- vote = voteIndex;
- voteValue = value;
- voteTimeOut = gameLocal.time + 20000;
- // mark players allowed to vote - only current ingame players, players joining during vote will be ignored
- for ( i = 0; i < gameLocal.numClients; i++ ) {
- if ( gameLocal.entities[ i ] && gameLocal.entities[ i ]->IsType( idPlayer::Type ) ) {
- playerState[ i ].vote = ( i == clientNum ) ? PLAYER_VOTE_YES : PLAYER_VOTE_WAIT;
- } else {
- playerState[i].vote = PLAYER_VOTE_NONE;
- }
- }
- }
- /*
- ================
- idMultiplayerGame::ClientStartVote
- ================
- */
- void idMultiplayerGame::ClientStartVote( int clientNum, const char *_voteString ) {
- idBitMsg outMsg;
- byte msgBuf[ MAX_GAME_MESSAGE_SIZE ];
- if ( !gameLocal.isClient ) {
- outMsg.Init( msgBuf, sizeof( msgBuf ) );
- outMsg.WriteByte( GAME_RELIABLE_MESSAGE_STARTVOTE );
- outMsg.WriteByte( clientNum );
- outMsg.WriteString( _voteString );
- networkSystem->ServerSendReliableMessage( -1, outMsg );
- }
- voteString = _voteString;
- AddChatLine( va( common->GetLanguageDict()->GetString( "#str_04279" ), gameLocal.userInfo[ clientNum ].GetString( "ui_name" ) ) );
- gameSoundWorld->PlayShaderDirectly( GlobalSoundStrings[ SND_VOTE ] );
- if ( clientNum == gameLocal.localClientNum ) {
- voted = true;
- } else {
- voted = false;
- }
- if ( gameLocal.isClient ) {
- // the the vote value to something so the vote line is displayed
- vote = VOTE_RESTART;
- yesVotes = 1;
- noVotes = 0;
- }
- }
- /*
- ================
- idMultiplayerGame::ClientUpdateVote
- ================
- */
- void idMultiplayerGame::ClientUpdateVote( vote_result_t status, int yesCount, int noCount ) {
- idBitMsg outMsg;
- byte msgBuf[ MAX_GAME_MESSAGE_SIZE ];
- if ( !gameLocal.isClient ) {
- outMsg.Init( msgBuf, sizeof( msgBuf ) );
- outMsg.WriteByte( GAME_RELIABLE_MESSAGE_UPDATEVOTE );
- outMsg.WriteByte( status );
- outMsg.WriteByte( yesCount );
- outMsg.WriteByte( noCount );
- networkSystem->ServerSendReliableMessage( -1, outMsg );
- }
- if ( vote == VOTE_NONE ) {
- // clients coming in late don't get the vote start and are not allowed to vote
- return;
- }
- switch ( status ) {
- case VOTE_FAILED:
- AddChatLine( common->GetLanguageDict()->GetString( "#str_04278" ) );
- gameSoundWorld->PlayShaderDirectly( GlobalSoundStrings[ SND_VOTE_FAILED ] );
- if ( gameLocal.isClient ) {
- vote = VOTE_NONE;
- }
- break;
- case VOTE_PASSED:
- AddChatLine( common->GetLanguageDict()->GetString( "#str_04277" ) );
- gameSoundWorld->PlayShaderDirectly( GlobalSoundStrings[ SND_VOTE_PASSED ] );
- break;
- case VOTE_RESET:
- if ( gameLocal.isClient ) {
- vote = VOTE_NONE;
- }
- break;
- case VOTE_ABORTED:
- AddChatLine( common->GetLanguageDict()->GetString( "#str_04276" ) );
- if ( gameLocal.isClient ) {
- vote = VOTE_NONE;
- }
- break;
- default:
- break;
- }
- if ( gameLocal.isClient ) {
- yesVotes = yesCount;
- noVotes = noCount;
- }
- }
- /*
- ================
- idMultiplayerGame::ClientCallVote
- ================
- */
- void idMultiplayerGame::ClientCallVote( vote_flags_t voteIndex, const char *voteValue ) {
- idBitMsg outMsg;
- byte msgBuf[ MAX_GAME_MESSAGE_SIZE ];
- // send
- outMsg.Init( msgBuf, sizeof( msgBuf ) );
- outMsg.WriteByte( GAME_RELIABLE_MESSAGE_CALLVOTE );
- outMsg.WriteByte( voteIndex );
- outMsg.WriteString( voteValue );
- networkSystem->ClientSendReliableMessage( outMsg );
- }
- /*
- ================
- idMultiplayerGame::CastVote
- ================
- */
- void idMultiplayerGame::CastVote( int clientNum, bool castVote ) {
- idBitMsg outMsg;
- byte msgBuf[ 128 ];
- if ( clientNum == gameLocal.localClientNum ) {
- voted = true;
- }
- if ( gameLocal.isClient ) {
- outMsg.Init( msgBuf, sizeof( msgBuf ) );
- outMsg.WriteByte( GAME_RELIABLE_MESSAGE_CASTVOTE );
- outMsg.WriteByte( castVote );
- networkSystem->ClientSendReliableMessage( outMsg );
- return;
- }
- // sanity
- if ( vote == VOTE_NONE ) {
- gameLocal.ServerSendChatMessage( clientNum, "server", common->GetLanguageDict()->GetString( "#str_04275" ) );
- common->DPrintf( "client %d: cast vote while no vote in progress\n", clientNum );
- return;
- }
- if ( playerState[ clientNum ].vote != PLAYER_VOTE_WAIT ) {
- gameLocal.ServerSendChatMessage( clientNum, "server", common->GetLanguageDict()->GetString( "#str_04274" ) );
- common->DPrintf( "client %d: cast vote - vote %d != PLAYER_VOTE_WAIT\n", clientNum, playerState[ clientNum ].vote );
- return;
- }
- if ( castVote ) {
- playerState[ clientNum ].vote = PLAYER_VOTE_YES;
- yesVotes++;
- } else {
- playerState[ clientNum ].vote = PLAYER_VOTE_NO;
- noVotes++;
- }
- ClientUpdateVote( VOTE_UPDATE, yesVotes, noVotes );
- }
- /*
- ================
- idMultiplayerGame::ServerCallVote
- ================
- */
- void idMultiplayerGame::ServerCallVote( int clientNum, const idBitMsg &msg ) {
- vote_flags_t voteIndex;
- int vote_timeLimit, vote_fragLimit, vote_clientNum, vote_gameTypeIndex; //, vote_kickIndex;
- char value[ MAX_STRING_CHARS ];
- assert( clientNum != -1 );
- assert( !gameLocal.isClient );
- voteIndex = (vote_flags_t)msg.ReadByte( );
- msg.ReadString( value, sizeof( value ) );
- // sanity checks - setup the vote
- if ( vote != VOTE_NONE ) {
- gameLocal.ServerSendChatMessage( clientNum, "server", common->GetLanguageDict()->GetString( "#str_04273" ) );
- common->DPrintf( "client %d: called vote while voting already in progress - ignored\n", clientNum );
- return;
- }
- switch ( voteIndex ) {
- case VOTE_RESTART:
- ServerStartVote( clientNum, voteIndex, "" );
- ClientStartVote( clientNum, common->GetLanguageDict()->GetString( "#str_04271" ) );
- break;
- case VOTE_NEXTMAP:
- ServerStartVote( clientNum, voteIndex, "" );
- ClientStartVote( clientNum, common->GetLanguageDict()->GetString( "#str_04272" ) );
- break;
- case VOTE_TIMELIMIT:
- vote_timeLimit = strtol( value, NULL, 10 );
- if ( vote_timeLimit == gameLocal.serverInfo.GetInt( "si_timeLimit" ) ) {
- gameLocal.ServerSendChatMessage( clientNum, "server", common->GetLanguageDict()->GetString( "#str_04270" ) );
- common->DPrintf( "client %d: already at the voted Time Limit\n", clientNum );
- return;
- }
- if ( vote_timeLimit < si_timeLimit.GetMinValue() || vote_timeLimit > si_timeLimit.GetMaxValue() ) {
- gameLocal.ServerSendChatMessage( clientNum, "server", common->GetLanguageDict()->GetString( "#str_04269" ) );
- common->DPrintf( "client %d: timelimit value out of range for vote: %s\n", clientNum, value );
- return;
- }
- ServerStartVote( clientNum, voteIndex, value );
- ClientStartVote( clientNum, va( common->GetLanguageDict()->GetString( "#str_04268" ), vote_timeLimit ) );
- break;
- case VOTE_FRAGLIMIT:
- vote_fragLimit = strtol( value, NULL, 10 );
- if ( vote_fragLimit == gameLocal.serverInfo.GetInt( "si_fragLimit" ) ) {
- gameLocal.ServerSendChatMessage( clientNum, "server", common->GetLanguageDict()->GetString( "#str_04267" ) );
- common->DPrintf( "client %d: already at the voted Frag Limit\n", clientNum );
- return;
- }
- if ( vote_fragLimit < si_fragLimit.GetMinValue() || vote_fragLimit > si_fragLimit.GetMaxValue() ) {
- gameLocal.ServerSendChatMessage( clientNum, "server", common->GetLanguageDict()->GetString( "#str_04266" ) );
- common->DPrintf( "client %d: fraglimit value out of range for vote: %s\n", clientNum, value );
- return;
- }
- ServerStartVote( clientNum, voteIndex, value );
- ClientStartVote( clientNum, va( common->GetLanguageDict()->GetString( "#str_04303" ), gameLocal.gameType == GAME_LASTMAN ? common->GetLanguageDict()->GetString( "#str_04264" ) : common->GetLanguageDict()->GetString( "#str_04265" ), vote_fragLimit ) );
- break;
- case VOTE_GAMETYPE:
- vote_gameTypeIndex = strtol( value, NULL, 10 );
- assert( vote_gameTypeIndex >= 0 && vote_gameTypeIndex <= 3 );
- switch ( vote_gameTypeIndex ) {
- case 0:
- strcpy( value, "Deathmatch" );
- break;
- case 1:
- strcpy( value, "Tourney" );
- break;
- case 2:
- strcpy( value, "Team DM" );
- break;
- case 3:
- strcpy( value, "Last Man" );
- break;
- }
- if ( !idStr::Icmp( value, gameLocal.serverInfo.GetString( "si_gameType" ) ) ) {
- gameLocal.ServerSendChatMessage( clientNum, "server", common->GetLanguageDict()->GetString( "#str_04259" ) );
- common->DPrintf( "client %d: already at the voted Game Type\n", clientNum );
- return;
- }
- ServerStartVote( clientNum, voteIndex, value );
- ClientStartVote( clientNum, va( common->GetLanguageDict()->GetString( "#str_04258" ), value ) );
- break;
- case VOTE_KICK:
- vote_clientNum = strtol( value, NULL, 10 );
- if ( vote_clientNum == gameLocal.localClientNum ) {
- gameLocal.ServerSendChatMessage( clientNum, "server", common->GetLanguageDict()->GetString( "#str_04257" ) );
- common->DPrintf( "client %d: called kick for the server host\n", clientNum );
- return;
- }
- ServerStartVote( clientNum, voteIndex, va( "%d", vote_clientNum ) );
- ClientStartVote( clientNum, va( common->GetLanguageDict()->GetString( "#str_04302" ), vote_clientNum, gameLocal.userInfo[ vote_clientNum ].GetString( "ui_name" ) ) );
- break;
- case VOTE_MAP: {
- if ( idStr::FindText( gameLocal.serverInfo.GetString( "si_map" ), value ) != -1 ) {
- gameLocal.ServerSendChatMessage( clientNum, "server", va( common->GetLanguageDict()->GetString( "#str_04295" ), value ) );
- common->DPrintf( "client %d: already running the voted map: %s\n", clientNum, value );
- return;
- }
- int num = fileSystem->GetNumMaps();
- int i;
- const idDict *dict;
- bool haveMap = false;
- for ( i = 0; i < num; i++ ) {
- dict = fileSystem->GetMapDecl( i );
- if ( dict && !idStr::Icmp( dict->GetString( "path" ), value ) ) {
- haveMap = true;
- break;
- }
- }
- if ( !haveMap ) {
- gameLocal.ServerSendChatMessage( clientNum, "server", va( common->GetLanguageDict()->GetString( "#str_04296" ), value ) );
- common->Printf( "client %d: map not found: %s\n", clientNum, value );
- return;
- }
- ServerStartVote( clientNum, voteIndex, value );
- ClientStartVote( clientNum, va( common->GetLanguageDict()->GetString( "#str_04256" ), common->GetLanguageDict()->GetString( dict ? dict->GetString( "name" ) : value ) ) );
- break;
- }
- case VOTE_SPECTATORS:
- if ( gameLocal.serverInfo.GetBool( "si_spectators" ) ) {
- ServerStartVote( clientNum, voteIndex, "" );
- ClientStartVote( clientNum, common->GetLanguageDict()->GetString( "#str_04255" ) );
- } else {
- ServerStartVote( clientNum, voteIndex, "" );
- ClientStartVote( clientNum, common->GetLanguageDict()->GetString( "#str_04254" ) );
- }
- break;
- default:
- gameLocal.ServerSendChatMessage( clientNum, "server", va( common->GetLanguageDict()->GetString( "#str_04297" ), (int)voteIndex ) );
- common->DPrintf( "client %d: unknown vote index %d\n", clientNum, voteIndex );
- }
- }
- /*
- ================
- idMultiplayerGame::DisconnectClient
- ================
- */
- void idMultiplayerGame::DisconnectClient( int clientNum ) {
- if ( lastWinner == clientNum ) {
- lastWinner = -1;
- }
- UpdatePlayerRanks();
- CheckAbortGame();
- }
- /*
- ================
- idMultiplayerGame::CheckAbortGame
- ================
- */
- void idMultiplayerGame::CheckAbortGame( void ) {
- int i;
- if ( gameLocal.gameType == GAME_TOURNEY && gameState == WARMUP ) {
- // if a tourney player joined spectators, let someone else have his spot
- for ( i = 0; i < 2; i++ ) {
- if ( !gameLocal.entities[ currentTourneyPlayer[ i ] ] || static_cast< idPlayer * >( gameLocal.entities[ currentTourneyPlayer[ i ] ] )->spectating ) {
- currentTourneyPlayer[ i ] = -1;
- }
- }
- }
- // only checks for aborts -> game review below
- if ( gameState != COUNTDOWN && gameState != GAMEON && gameState != SUDDENDEATH ) {
- return;
- }
- switch ( gameLocal.gameType ) {
- case GAME_TOURNEY:
- for ( i = 0; i < 2; i++ ) {
- if ( !gameLocal.entities[ currentTourneyPlayer[ i ] ] || static_cast< idPlayer * >( gameLocal.entities[ currentTourneyPlayer[ i ] ] )->spectating ) {
- NewState( GAMEREVIEW );
- return;
- }
- }
- break;
- default:
- if ( !EnoughClientsToPlay() ) {
- NewState( GAMEREVIEW );
- }
- break;
- }
- }
- /*
- ================
- idMultiplayerGame::WantKilled
- ================
- */
- void idMultiplayerGame::WantKilled( int clientNum ) {
- idEntity *ent = gameLocal.entities[ clientNum ];
- if ( ent && ent->IsType( idPlayer::Type ) ) {
- static_cast<idPlayer *>( ent )->Kill( false, false );
- }
- }
- /*
- ================
- idMultiplayerGame::MapRestart
- ================
- */
- void idMultiplayerGame::MapRestart( void ) {
- int clientNum;
- assert( !gameLocal.isClient );
- if ( gameState != WARMUP ) {
- NewState( WARMUP );
- nextState = INACTIVE;
- nextStateSwitch = 0;
- }
- if ( g_balanceTDM.GetBool() && lastGameType != GAME_TDM && gameLocal.gameType == GAME_TDM ) {
- for ( clientNum = 0; clientNum < gameLocal.numClients; clientNum++ ) {
- if ( gameLocal.entities[ clientNum ] && gameLocal.entities[ clientNum ]->IsType( idPlayer::Type ) ) {
- if ( static_cast< idPlayer* >( gameLocal.entities[ clientNum ] )->BalanceTDM() ) {
- // core is in charge of syncing down userinfo changes
- // it will also call back game through SetUserInfo with the current info for update
- cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "updateUI %d\n", clientNum ) );
- }
- }
- }
- }
- lastGameType = gameLocal.gameType;
- }
- /*
- ================
- idMultiplayerGame::SwitchToTeam
- ================
- */
- void idMultiplayerGame::SwitchToTeam( int clientNum, int oldteam, int newteam ) {
- idEntity *ent;
- int i;
- assert( gameLocal.gameType == GAME_TDM );
- assert( oldteam != newteam );
- assert( !gameLocal.isClient );
- if ( !gameLocal.isClient && newteam >= 0 && IsInGame( clientNum ) ) {
- PrintMessageEvent( -1, MSG_JOINTEAM, clientNum, newteam );
- }
- // assign the right teamFragCount
- for( i = 0; i < gameLocal.numClients; i++ ) {
- if ( i == clientNum ) {
- continue;
- }
- ent = gameLocal.entities[ i ];
- if ( ent && ent->IsType( idPlayer::Type ) && static_cast< idPlayer * >(ent)->team == newteam ) {
- playerState[ clientNum ].teamFragCount = playerState[ i ].teamFragCount;
- break;
- }
- }
- if ( i == gameLocal.numClients ) {
- // alone on this team
- playerState[ clientNum ].teamFragCount = 0;
- }
- if ( gameState == GAMEON && oldteam != -1 ) {
- // when changing teams during game, kill and respawn
- idPlayer *p = static_cast<idPlayer *>( gameLocal.entities[ clientNum ] );
- if ( p->IsInTeleport() ) {
- p->ServerSendEvent( idPlayer::EVENT_ABORT_TELEPORTER, NULL, false, -1 );
- p->SetPrivateCameraView( NULL );
- }
- p->Kill( true, true );
- CheckAbortGame();
- }
- }
- /*
- ================
- idMultiplayerGame::ProcessChatMessage
- ================
- */
- void idMultiplayerGame::ProcessChatMessage( int clientNum, bool team, const char *name, const char *text, const char *sound ) {
- idBitMsg outMsg;
- byte msgBuf[ 256 ];
- const char *prefix = NULL;
- int send_to; // 0 - all, 1 - specs, 2 - team
- int i;
- idEntity *ent;
- idPlayer *p;
- idStr prefixed_name;
- assert( !gameLocal.isClient );
- if ( clientNum >= 0 ) {
- p = static_cast< idPlayer * >( gameLocal.entities[ clientNum ] );
- if ( !( p && p->IsType( idPlayer::Type ) ) ) {
- return;
- }
- if ( p->spectating ) {
- prefix = "spectating";
- if ( team || ( !g_spectatorChat.GetBool() && ( gameState == GAMEON || gameState == SUDDENDEATH ) ) ) {
- // to specs
- send_to = 1;
- } else {
- // to all
- send_to = 0;
- }
- } else if ( team ) {
- prefix = "team";
- // to team
- send_to = 2;
- } else {
- // to all
- send_to = 0;
- }
- } else {
- p = NULL;
- send_to = 0;
- }
- // put the message together
- outMsg.Init( msgBuf, sizeof( msgBuf ) );
- outMsg.WriteByte( GAME_RELIABLE_MESSAGE_CHAT );
- if ( prefix ) {
- prefixed_name = va( "(%s) %s", prefix, name );
- } else {
- prefixed_name = name;
- }
- outMsg.WriteString( prefixed_name );
- outMsg.WriteString( text, -1, false );
- if ( !send_to ) {
- AddChatLine( "%s^0: %s\n", prefixed_name.c_str(), text );
- networkSystem->ServerSendReliableMessage( -1, outMsg );
- if ( sound ) {
- PlayGlobalSound( -1, SND_COUNT, sound );
- }
- } else {
- for ( i = 0; i < gameLocal.numClients; i++ ) {
- ent = gameLocal.entities[ i ];
- if ( !ent || !ent->IsType( idPlayer::Type ) ) {
- continue;
- }
- if ( send_to == 1 && static_cast< idPlayer * >( ent )->spectating ) {
- if ( sound ) {
- PlayGlobalSound( i, SND_COUNT, sound );
- }
- if ( i == gameLocal.localClientNum ) {
- AddChatLine( "%s^0: %s\n", prefixed_name.c_str(), text );
- } else {
- networkSystem->ServerSendReliableMessage( i, outMsg );
- }
- } else if ( send_to == 2 && static_cast< idPlayer * >( ent )->team == p->team ) {
- if ( sound ) {
- PlayGlobalSound( i, SND_COUNT, sound );
- }
- if ( i == gameLocal.localClientNum ) {
- AddChatLine( "%s^0: %s\n", prefixed_name.c_str(), text );
- } else {
- networkSystem->ServerSendReliableMessage( i, outMsg );
- }
- }
- }
- }
- }
- /*
- ================
- idMultiplayerGame::Precache
- ================
- */
- void idMultiplayerGame::Precache( void ) {
- int i;
- idFile *f;
- if ( !gameLocal.isMultiplayer ) {
- return;
- }
- gameLocal.FindEntityDefDict( "player_doommarine", false );;
-
- // skins
- idStr str = cvarSystem->GetCVarString( "mod_validSkins" );
- idStr skin;
- while ( str.Length() ) {
- int n = str.Find( ";" );
- if ( n >= 0 ) {
- skin = str.Left( n );
- str = str.Right( str.Length() - n - 1 );
- } else {
- skin = str;
- str = "";
- }
- declManager->FindSkin( skin, false );
- }
- for ( i = 0; ui_skinArgs[ i ]; i++ ) {
- declManager->FindSkin( ui_skinArgs[ i ], false );
- }
- // MP game sounds
- for ( i = 0; i < SND_COUNT; i++ ) {
- f = fileSystem->OpenFileRead( GlobalSoundStrings[ i ] );
- fileSystem->CloseFile( f );
- }
- // MP guis. just make sure we hit all of them
- i = 0;
- while ( MPGuis[ i ] ) {
- uiManager->FindGui( MPGuis[ i ], true );
- i++;
- }
- }
- /*
- ================
- idMultiplayerGame::ToggleSpectate
- ================
- */
- void idMultiplayerGame::ToggleSpectate( void ) {
- bool spectating;
- assert( gameLocal.isClient || gameLocal.localClientNum == 0 );
- spectating = ( idStr::Icmp( cvarSystem->GetCVarString( "ui_spectate" ), "Spectate" ) == 0 );
- if ( spectating ) {
- // always allow toggling to play
- cvarSystem->SetCVarString( "ui_spectate", "Play" );
- } else {
- // only allow toggling to spectate if spectators are enabled.
- if ( gameLocal.serverInfo.GetBool( "si_spectators" ) ) {
- cvarSystem->SetCVarString( "ui_spectate", "Spectate" );
- } else {
- gameLocal.mpGame.AddChatLine( common->GetLanguageDict()->GetString( "#str_06747" ) );
- }
- }
- }
- /*
- ================
- idMultiplayerGame::ToggleReady
- ================
- */
- void idMultiplayerGame::ToggleReady( void ) {
- bool ready;
- assert( gameLocal.isClient || gameLocal.localClientNum == 0 );
- ready = ( idStr::Icmp( cvarSystem->GetCVarString( "ui_ready" ), "Ready" ) == 0 );
- if ( ready ) {
- cvarSystem->SetCVarString( "ui_ready", "Not Ready" );
- } else {
- cvarSystem->SetCVarString( "ui_ready", "Ready" );
- }
- }
- /*
- ================
- idMultiplayerGame::ToggleTeam
- ================
- */
- void idMultiplayerGame::ToggleTeam( void ) {
- bool team;
- assert( gameLocal.isClient || gameLocal.localClientNum == 0 );
-
- team = ( idStr::Icmp( cvarSystem->GetCVarString( "ui_team" ), "Red" ) == 0 );
- if ( team ) {
- cvarSystem->SetCVarString( "ui_team", "Blue" );
- } else {
- cvarSystem->SetCVarString( "ui_team", "Red" );
- }
- }
- /*
- ================
- idMultiplayerGame::ToggleUserInfo
- ================
- */
- void idMultiplayerGame::ThrottleUserInfo( void ) {
- int i;
- assert( gameLocal.localClientNum >= 0 );
- i = 0;
- while ( ThrottleVars[ i ] ) {
- if ( idStr::Icmp( gameLocal.userInfo[ gameLocal.localClientNum ].GetString( ThrottleVars[ i ] ),
- cvarSystem->GetCVarString( ThrottleVars[ i ] ) ) ) {
- if ( gameLocal.realClientTime < switchThrottle[ i ] ) {
- AddChatLine( common->GetLanguageDict()->GetString( "#str_04299" ), common->GetLanguageDict()->GetString( ThrottleVarsInEnglish[ i ] ), ( switchThrottle[ i ] - gameLocal.time ) / 1000 + 1 );
- cvarSystem->SetCVarString( ThrottleVars[ i ], gameLocal.userInfo[ gameLocal.localClientNum ].GetString( ThrottleVars[ i ] ) );
- } else {
- switchThrottle[ i ] = gameLocal.time + ThrottleDelay[ i ] * 1000;
- }
- }
- i++;
- }
- }
- /*
- ================
- idMultiplayerGame::CanPlay
- ================
- */
- bool idMultiplayerGame::CanPlay( idPlayer *p ) {
- return !p->wantSpectate && playerState[ p->entityNumber ].ingame;
- }
- /*
- ================
- idMultiplayerGame::EnterGame
- ================
- */
- void idMultiplayerGame::EnterGame( int clientNum ) {
- assert( !gameLocal.isClient );
- if ( !playerState[ clientNum ].ingame ) {
- playerState[ clientNum ].ingame = true;
- if ( gameLocal.isMultiplayer ) {
- // can't use PrintMessageEvent as clients don't know the nickname yet
- gameLocal.ServerSendChatMessage( -1, common->GetLanguageDict()->GetString( "#str_02047" ), va( common->GetLanguageDict()->GetString( "#str_07177" ), gameLocal.userInfo[ clientNum ].GetString( "ui_name" ) ) );
- }
- }
- }
- /*
- ================
- idMultiplayerGame::WantRespawn
- ================
- */
- bool idMultiplayerGame::WantRespawn( idPlayer *p ) {
- return p->forceRespawn && !p->wantSpectate && playerState[ p->entityNumber ].ingame;
- }
- /*
- ================
- idMultiplayerGame::VoiceChat
- ================
- */
- void idMultiplayerGame::VoiceChat_f( const idCmdArgs &args ) {
- gameLocal.mpGame.VoiceChat( args, false );
- }
- /*
- ================
- idMultiplayerGame::VoiceChatTeam
- ================
- */
- void idMultiplayerGame::VoiceChatTeam_f( const idCmdArgs &args ) {
- gameLocal.mpGame.VoiceChat( args, true );
- }
- /*
- ================
- idMultiplayerGame::VoiceChat
- ================
- */
- void idMultiplayerGame::VoiceChat( const idCmdArgs &args, bool team ) {
- idBitMsg outMsg;
- byte msgBuf[128];
- const char *voc;
- const idDict *spawnArgs;
- const idKeyValue *keyval;
- int index;
- if ( !gameLocal.isMultiplayer ) {
- common->Printf( "clientVoiceChat: only valid in multiplayer\n" );
- return;
- }
- if ( args.Argc() != 2 ) {
- common->Printf( "clientVoiceChat: bad args\n" );
- return;
- }
- // throttle
- if ( gameLocal.realClientTime < voiceChatThrottle ) {
- return;
- }
- voc = args.Argv( 1 );
- spawnArgs = gameLocal.FindEntityDefDict( "player_doommarine", false );
- keyval = spawnArgs->MatchPrefix( "snd_voc_", NULL );
- index = 0;
- while ( keyval ) {
- if ( !keyval->GetValue().Icmp( voc ) ) {
- break;
- }
- keyval = spawnArgs->MatchPrefix( "snd_voc_", keyval );
- index++;
- }
- if ( !keyval ) {
- common->Printf( "Voice command not found: %s\n", voc );
- return;
- }
- voiceChatThrottle = gameLocal.realClientTime + 1000;
- outMsg.Init( msgBuf, sizeof( msgBuf ) );
- outMsg.WriteByte( GAME_RELIABLE_MESSAGE_VCHAT );
- outMsg.WriteLong( index );
- outMsg.WriteBits( team ? 1 : 0, 1 );
- networkSystem->ClientSendReliableMessage( outMsg );
- }
- /*
- ================
- idMultiplayerGame::ProcessVoiceChat
- ================
- */
- void idMultiplayerGame::ProcessVoiceChat( int clientNum, bool team, int index ) {
- const idDict *spawnArgs;
- const idKeyValue *keyval;
- idStr name;
- idStr snd_key;
- idStr text_key;
- idPlayer *p;
- p = static_cast< idPlayer * >( gameLocal.entities[ clientNum ] );
- if ( !( p && p->IsType( idPlayer::Type ) ) ) {
- return;
- }
- if ( p->spectating ) {
- return;
- }
- // lookup the sound def
- spawnArgs = gameLocal.FindEntityDefDict( "player_doommarine", false );
- keyval = spawnArgs->MatchPrefix( "snd_voc_", NULL );
- while ( index > 0 && keyval ) {
- keyval = spawnArgs->MatchPrefix( "snd_voc_", keyval );
- index--;
- }
- if ( !keyval ) {
- common->DPrintf( "ProcessVoiceChat: unknown chat index %d\n", index );
- return;
- }
- snd_key = keyval->GetKey();
- name = gameLocal.userInfo[ clientNum ].GetString( "ui_name" );
- sprintf( text_key, "txt_%s", snd_key.Right( snd_key.Length() - 4 ).c_str() );
- if ( team || gameState == COUNTDOWN || gameState == GAMEREVIEW ) {
- ProcessChatMessage( clientNum, team, name, spawnArgs->GetString( text_key ), spawnArgs->GetString( snd_key ) );
- } else {
- p->StartSound( snd_key, SND_CHANNEL_ANY, 0, true, NULL );
- ProcessChatMessage( clientNum, team, name, spawnArgs->GetString( text_key ), NULL );
- }
- }
- /*
- ================
- idMultiplayerGame::ServerWriteInitialReliableMessages
- ================
- */
- void idMultiplayerGame::ServerWriteInitialReliableMessages( int clientNum ) {
- idBitMsg outMsg;
- byte msgBuf[ MAX_GAME_MESSAGE_SIZE ];
- int i;
- idEntity *ent;
- outMsg.Init( msgBuf, sizeof( msgBuf ) );
- outMsg.BeginWriting();
- outMsg.WriteByte( GAME_RELIABLE_MESSAGE_STARTSTATE );
- // send the game state and start time
- outMsg.WriteByte( gameState );
- outMsg.WriteLong( matchStartedTime );
- outMsg.WriteShort( startFragLimit );
- // send the powerup states and the spectate states
- for( i = 0; i < gameLocal.numClients; i++ ) {
- ent = gameLocal.entities[ i ];
- if ( i != clientNum && ent && ent->IsType( idPlayer::Type ) ) {
- outMsg.WriteShort( i );
- outMsg.WriteShort( static_cast< idPlayer * >( ent )->inventory.powerups );
- outMsg.WriteBits( static_cast< idPlayer * >( ent )->spectating, 1 );
- }
- }
- outMsg.WriteShort( MAX_CLIENTS );
- networkSystem->ServerSendReliableMessage( clientNum, outMsg );
- // we send SI in connectResponse messages, but it may have been modified already
- outMsg.BeginWriting( );
- outMsg.WriteByte( GAME_RELIABLE_MESSAGE_SERVERINFO );
- outMsg.WriteDeltaDict( gameLocal.serverInfo, NULL );
- networkSystem->ServerSendReliableMessage( clientNum, outMsg );
- // warmup time
- if ( gameState == COUNTDOWN ) {
- outMsg.BeginWriting();
- outMsg.WriteByte( GAME_RELIABLE_MESSAGE_WARMUPTIME );
- outMsg.WriteLong( warmupEndTime );
- networkSystem->ServerSendReliableMessage( clientNum, outMsg );
- }
- }
- /*
- ================
- idMultiplayerGame::ClientReadStartState
- ================
- */
- void idMultiplayerGame::ClientReadStartState( const idBitMsg &msg ) {
- int i, client, powerup;
- // read the state in preparation for reading snapshot updates
- gameState = (idMultiplayerGame::gameState_t)msg.ReadByte();
- matchStartedTime = msg.ReadLong( );
- startFragLimit = msg.ReadShort( );
- while ( ( client = msg.ReadShort() ) != MAX_CLIENTS ) {
- assert( gameLocal.entities[ client ] && gameLocal.entities[ client ]->IsType( idPlayer::Type ) );
- powerup = msg.ReadShort();
- for ( i = 0; i < MAX_POWERUPS; i++ ) {
- if ( powerup & ( 1 << i ) ) {
- static_cast< idPlayer * >( gameLocal.entities[ client ] )->GivePowerUp( i, 0 );
- }
- }
- bool spectate = ( msg.ReadBits( 1 ) != 0 );
- static_cast< idPlayer * >( gameLocal.entities[ client ] )->Spectate( spectate );
- }
- }
- /*
- ================
- idMultiplayerGame::ClientReadWarmupTime
- ================
- */
- void idMultiplayerGame::ClientReadWarmupTime( const idBitMsg &msg ) {
- warmupEndTime = msg.ReadLong();
- }
|