// This is called explicitly when the gamestate is first received, and whenever the server updates any serverinfo flagged cvars void CG_ParseServerinfo( void ) { const char *info = NULL, *tinfo = NULL, *mapname; int i, fraglimit, timelimit; info = CG_ConfigString( CS_SERVERINFO ); cgs.debugMelee = atoi( Info_ValueForKey( info, "g_debugMelee" ) ); cgs.stepSlideFix = atoi( Info_ValueForKey( info, "g_stepSlideFix" ) ); cgs.noSpecMove = atoi( Info_ValueForKey( info, "g_noSpecMove" ) ); cgs.siegeTeamSwitch = atoi( Info_ValueForKey( info, "g_siegeTeamSwitch" ) ); cgs.showDuelHealths = atoi( Info_ValueForKey( info, "g_showDuelHealths" ) ); cgs.needpass = atoi( Info_ValueForKey( info, "needpass" ) ); cgs.jediVmerc = atoi( Info_ValueForKey( info, "g_jediVmerc" ) ); cgs.wDisable = atoi( Info_ValueForKey( info, "wdisable" ) ); cgs.fDisable = atoi( Info_ValueForKey( info, "fdisable" ) ); cgs.dmflags = atoi( Info_ValueForKey( info, "dmflags" ) ); cgs.duel_fraglimit = atoi( Info_ValueForKey( info, "duel_fraglimit" ) ); cgs.capturelimit = atoi( Info_ValueForKey( info, "capturelimit" ) ); cgs.gametype = (gametype_t)atoi( Info_ValueForKey( info, "g_gametype" ) ); cgs.japp.jp_cinfo = atoi( Info_ValueForKey( info, "jp_cinfo" ) ); cgs.japp.overbounce = atoi( Info_ValueForKey( info, "pmove_overbounce" ) ); fraglimit = atoi( Info_ValueForKey( info, "fraglimit" ) ); timelimit = atoi( Info_ValueForKey( info, "timelimit" ) ); trap->Cvar_Set( "g_gametype", va( "%i", cgs.gametype ) ); trap->Cvar_Set( "bg_fighterAltControl", Info_ValueForKey( info, "bg_fighterAltControl" ) ); // reset fraglimit warnings if ( cgs.fraglimit < fraglimit ) cg.fraglimitWarnings &= ~(1 | 2 | 4); cgs.fraglimit = fraglimit; // reset timelimit warnings if ( cgs.timelimit != timelimit ) cg.timelimitWarnings &= ~(1 | 2); cgs.timelimit = timelimit; cgs.maxclients = Q_clampi( 0, atoi( Info_ValueForKey( info, "sv_maxclients" ) ), MAX_CLIENTS ); //Raz: Server support flags tinfo = Info_ValueForKey( info, "ssf" ); if ( !Q_stricmpn( Info_ValueForKey( info, "gamename" ), "JA+ Mod", 7 ) ) cg.japp.SSF = JAPLUS_SERVER_FLAGS; if ( tinfo[0] && sscanf( tinfo, "%X", &cg.japp.SSF ) != 1 ) CG_LogPrintf( cg.log.security, "CG_ParseServerinfo: serverinfo 'ssf' was found, but invalid.\n" ); Com_Printf( "Server support hints: 0x%X\n", cg.japp.SSF ); tinfo = Info_ValueForKey( info, "jp_gripSpeedScale" ); if ( tinfo[0] ) { cgs.japp.gripSpeed.scale = atof( tinfo ); cgs.japp.gripSpeed.set = qtrue; } else { cgs.japp.gripSpeed.set = qfalse; } mapname = Info_ValueForKey( info, "mapname" ); Q_strncpyz( cgs.mapnameClean, mapname, sizeof(cgs.mapnameClean) ); //rww - You must do this one here, Info_ValueForKey always uses the same memory pointer. trap->Cvar_Set( "ui_about_mapname", mapname ); Com_sprintf( cgs.mapname, sizeof(cgs.mapname), "maps/%s.bsp", mapname ); trap->Cvar_Set( "ui_about_gametype", va( "%i", cgs.gametype ) ); trap->Cvar_Set( "ui_about_fraglimit", va( "%i", cgs.fraglimit ) ); trap->Cvar_Set( "ui_about_duellimit", va( "%i", cgs.duel_fraglimit ) ); trap->Cvar_Set( "ui_about_capturelimit", va( "%i", cgs.capturelimit ) ); trap->Cvar_Set( "ui_about_timelimit", va( "%i", cgs.timelimit ) ); trap->Cvar_Set( "ui_about_maxclients", va( "%i", cgs.maxclients ) ); trap->Cvar_Set( "ui_about_dmflags", va( "%i", cgs.dmflags ) ); trap->Cvar_Set( "ui_about_hostname", Info_ValueForKey( info, "sv_hostname" ) ); trap->Cvar_Set( "ui_about_needpass", Info_ValueForKey( info, "g_needpass" ) ); trap->Cvar_Set( "ui_about_botminplayers", Info_ValueForKey( info, "bot_minplayers" ) ); //Set the siege teams based on what the server has for overrides. trap->Cvar_Set( "cg_siegeTeam1", Info_ValueForKey( info, "g_siegeTeam1" ) ); trap->Cvar_Set( "cg_siegeTeam2", Info_ValueForKey( info, "g_siegeTeam2" ) ); tinfo = CG_ConfigString( CS_TERRAINS + 1 ); if ( !tinfo || !*tinfo ) cg.mInRMG = qfalse; else { int weather = 0; cg.mInRMG = qtrue; trap->Cvar_Set( "RMG", "1" ); weather = atoi( Info_ValueForKey( info, "RMG_weather" ) ); trap->Cvar_Set( "RMG_weather", va( "%i", weather ) ); if ( weather == 1 || weather == 2 ) cg.mRMGWeather = qtrue; else cg.mRMGWeather = qfalse; } Q_strncpyz( cgs.japp.serverName, Info_ValueForKey( info, "sv_hostname" ), sizeof(cgs.japp.serverName) ); CPM_UpdateSettings( !!(cgs.japp.jp_cinfo & CINFO_CPMPHYSICS) ); //Fix f****d up vote strings Q_strncpyz( cgs.voteString, CG_ConfigString( CS_VOTE_STRING ), sizeof(cgs.voteString) ); //Raz: Synchronise our expected snaps/sec with the server's framerate // OpenJK servers will try to match us to the sv_fps too (sv_client.cpp -> SV_UserinfoChanged) i = atoi( Info_ValueForKey( info, "sv_fps" ) ); if ( i ) trap->Cvar_Set( "snaps", va( "%i", i ) ); }
/* ================ CG_ConfigStringModified ================ */ static void CG_ConfigStringModified( void ) { const char *str; int num; num = atoi( CG_Argv( 1 ) ); // get the gamestate from the client system, which will have the // new configstring already integrated trap_GetGameState( &cgs.gameState ); // look up the individual string that was modified str = CG_ConfigString( num ); // do something with it if necessary if ( num == CS_MUSIC ) { CG_StartMusic(); } else if ( num == CS_SERVERINFO ) { CG_ParseServerinfo(); } else if ( num == CS_WARMUP ) { CG_ParseWarmup(); } else if ( num == CS_SCORES1 ) { cgs.scores1 = atoi( str ); } else if ( num == CS_SCORES2 ) { cgs.scores2 = atoi( str ); } else if ( num == CS_LEVEL_START_TIME ) { cgs.levelStartTime = atoi( str ); } else if ( num == CS_VOTE_TIME ) { cgs.voteTime = atoi( str ); cgs.voteModified = qtrue; } else if ( num == CS_VOTE_YES ) { cgs.voteYes = atoi( str ); cgs.voteModified = qtrue; } else if ( num == CS_VOTE_NO ) { cgs.voteNo = atoi( str ); cgs.voteModified = qtrue; } else if ( num == CS_VOTE_STRING ) { Q_strncpyz( cgs.voteString, str, sizeof( cgs.voteString ) ); #ifdef MISSIONPACK trap_S_StartLocalSound( cgs.media.voteNow, CHAN_ANNOUNCER ); #endif //MISSIONPACK } else if ( num >= CS_TEAMVOTE_TIME && num <= CS_TEAMVOTE_TIME + 1) { cgs.teamVoteTime[num-CS_TEAMVOTE_TIME] = atoi( str ); cgs.teamVoteModified[num-CS_TEAMVOTE_TIME] = qtrue; } else if ( num >= CS_TEAMVOTE_YES && num <= CS_TEAMVOTE_YES + 1) { cgs.teamVoteYes[num-CS_TEAMVOTE_YES] = atoi( str ); cgs.teamVoteModified[num-CS_TEAMVOTE_YES] = qtrue; } else if ( num >= CS_TEAMVOTE_NO && num <= CS_TEAMVOTE_NO + 1) { cgs.teamVoteNo[num-CS_TEAMVOTE_NO] = atoi( str ); cgs.teamVoteModified[num-CS_TEAMVOTE_NO] = qtrue; } else if ( num >= CS_TEAMVOTE_STRING && num <= CS_TEAMVOTE_STRING + 1) { Q_strncpyz( cgs.teamVoteString[num-CS_TEAMVOTE_STRING], str, sizeof( cgs.teamVoteString[0] ) ); #ifdef MISSIONPACK trap_S_StartLocalSound( cgs.media.voteNow, CHAN_ANNOUNCER ); #endif } else if ( num == CS_INTERMISSION ) { cg.intermissionStarted = atoi( str ); } else if ( num >= CS_MODELS && num < CS_MODELS+MAX_MODELS ) { cgs.gameModels[ num-CS_MODELS ] = trap_R_RegisterModel( str ); } else if ( num >= CS_SOUNDS && num < CS_SOUNDS+MAX_SOUNDS ) { if ( str[0] != '*' ) { // player specific sounds don't register here cgs.gameSounds[ num-CS_SOUNDS] = trap_S_RegisterSound( str, qfalse ); } } else if ( num >= CS_PLAYERS && num < CS_PLAYERS+MAX_CLIENTS ) { CG_NewClientInfo( num - CS_PLAYERS ); CG_BuildSpectatorString(); } else if ( num == CS_FLAGSTATUS ) { if( cgs.gametype == GT_CTF ) { // format is rb where its red/blue, 0 is at base, 1 is taken, 2 is dropped cgs.redflag = str[0] - '0'; cgs.blueflag = str[1] - '0'; } #ifdef MISSIONPACK else if( cgs.gametype == GT_1FCTF ) { cgs.flagStatus = str[0] - '0'; } #endif } else if ( num == CS_SHADERSTATE ) { CG_ShaderStateChanged(); } // CPM else if (num == CS_PRO_MODE) { CPM_UpdateSettings(cgs.gametype, str[0] - '0', str[1] - '0'); } // !CPM }