home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2000 March / maximum-cd-2000-03.iso / Quake3 Game Source / Q3AGameSource.exe / Main / cg_servercmds.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-01-18  |  9.9 KB  |  409 lines

  1. // Copyright (C) 1999-2000 Id Software, Inc.
  2. //
  3. // cg_servercmds.c -- reliably sequenced text commands sent by the server
  4. // these are processed at snapshot transition time, so there will definately
  5. // be a valid snapshot this frame
  6.  
  7. #include "cg_local.h"
  8.  
  9.  
  10. /*
  11. =================
  12. CG_ParseScores
  13.  
  14. =================
  15. */
  16. static void CG_ParseScores( void ) {
  17.     int        i, powerups;
  18.  
  19.     cg.numScores = atoi( CG_Argv( 1 ) );
  20.     if ( cg.numScores > MAX_CLIENTS ) {
  21.         cg.numScores = MAX_CLIENTS;
  22.     }
  23.  
  24.     cg.teamScores[0] = atoi( CG_Argv( 2 ) );
  25.     cg.teamScores[1] = atoi( CG_Argv( 3 ) );
  26.  
  27.     memset( cg.scores, 0, sizeof( cg.scores ) );
  28.     for ( i = 0 ; i < cg.numScores ; i++ ) {
  29.         cg.scores[i].client = atoi( CG_Argv( i * 6 + 4 ) );
  30.         cg.scores[i].score = atoi( CG_Argv( i * 6 + 5 ) );
  31.         cg.scores[i].ping = atoi( CG_Argv( i * 6 + 6 ) );
  32.         cg.scores[i].time = atoi( CG_Argv( i * 6 + 7 ) );
  33.         cg.scores[i].scoreFlags = atoi( CG_Argv( i * 6 + 8 ) );
  34.         powerups = atoi( CG_Argv( i * 6 + 9 ) );
  35.  
  36.         if ( cg.scores[i].client < 0 || cg.scores[i].client >= MAX_CLIENTS ) {
  37.             cg.scores[i].client = 0;
  38.         }
  39.         cgs.clientinfo[ cg.scores[i].client ].score = cg.scores[i].score;
  40.         cgs.clientinfo[ cg.scores[i].client ].powerups = powerups;
  41.     }
  42.  
  43. }
  44.  
  45. /*
  46. =================
  47. CG_ParseTeamInfo
  48.  
  49. =================
  50. */
  51. static void CG_ParseTeamInfo( void ) {
  52.     int        i;
  53.     int        client;
  54.  
  55.     numSortedTeamPlayers = atoi( CG_Argv( 1 ) );
  56.  
  57.     for ( i = 0 ; i < numSortedTeamPlayers ; i++ ) {
  58.         client = atoi( CG_Argv( i * 6 + 2 ) );
  59.  
  60.         sortedTeamPlayers[i] = client;
  61.  
  62.         cgs.clientinfo[ client ].location = atoi( CG_Argv( i * 6 + 3 ) );
  63.         cgs.clientinfo[ client ].health = atoi( CG_Argv( i * 6 + 4 ) );
  64.         cgs.clientinfo[ client ].armor = atoi( CG_Argv( i * 6 + 5 ) );
  65.         cgs.clientinfo[ client ].curWeapon = atoi( CG_Argv( i * 6 + 6 ) );
  66.         cgs.clientinfo[ client ].powerups = atoi( CG_Argv( i * 6 + 7 ) );
  67.     }
  68. }
  69.  
  70.  
  71. /*
  72. ================
  73. CG_ParseServerinfo
  74.  
  75. This is called explicitly when the gamestate is first received,
  76. and whenever the server updates any serverinfo flagged cvars
  77. ================
  78. */
  79. void CG_ParseServerinfo( void ) {
  80.     const char    *info;
  81.     char    *mapname;
  82.  
  83.     info = CG_ConfigString( CS_SERVERINFO );
  84.     cgs.gametype = atoi( Info_ValueForKey( info, "g_gametype" ) );
  85.     cgs.dmflags = atoi( Info_ValueForKey( info, "dmflags" ) );
  86.     cgs.teamflags = atoi( Info_ValueForKey( info, "teamflags" ) );
  87.     cgs.fraglimit = atoi( Info_ValueForKey( info, "fraglimit" ) );
  88.     cgs.capturelimit = atoi( Info_ValueForKey( info, "capturelimit" ) );
  89.     cgs.timelimit = atoi( Info_ValueForKey( info, "timelimit" ) );
  90.     cgs.maxclients = atoi( Info_ValueForKey( info, "sv_maxclients" ) );
  91.     mapname = Info_ValueForKey( info, "mapname" );
  92.     Com_sprintf( cgs.mapname, sizeof( cgs.mapname ), "maps/%s.bsp", mapname );
  93. }
  94.  
  95. /*
  96. ==================
  97. CG_ParseWarmup
  98. ==================
  99. */
  100. static void CG_ParseWarmup( void ) {
  101.     const char    *info;
  102.     int            warmup;
  103.  
  104.     info = CG_ConfigString( CS_WARMUP );
  105.  
  106.     warmup = atoi( info );
  107.     cg.warmupCount = -1;
  108.  
  109.     if ( warmup == 0 && cg.warmup ) {
  110.  
  111.     } else if ( warmup > 0 && cg.warmup <= 0 ) {
  112.         trap_S_StartLocalSound( cgs.media.countPrepareSound, CHAN_ANNOUNCER );
  113.     }
  114.  
  115.     cg.warmup = warmup;
  116. }
  117.  
  118. /*
  119. ================
  120. CG_SetConfigValues
  121.  
  122. Called on load to set the initial values from configure strings
  123. ================
  124. */
  125. void CG_SetConfigValues( void ) {
  126.     const char *s;
  127.  
  128.     cgs.scores1 = atoi( CG_ConfigString( CS_SCORES1 ) );
  129.     cgs.scores2 = atoi( CG_ConfigString( CS_SCORES2 ) );
  130.     cgs.levelStartTime = atoi( CG_ConfigString( CS_LEVEL_START_TIME ) );
  131.     s = CG_ConfigString( CS_FLAGSTATUS );
  132.     cgs.redflag = s[0] - '0';
  133.     cgs.blueflag = s[1] - '0';
  134.     cg.warmup = atoi( CG_ConfigString( CS_WARMUP ) );
  135. }
  136.  
  137. /*
  138. ================
  139. CG_ConfigStringModified
  140.  
  141. ================
  142. */
  143. static void CG_ConfigStringModified( void ) {
  144.     const char    *str;
  145.     int        num;
  146.  
  147.     num = atoi( CG_Argv( 1 ) );
  148.  
  149.     // get the gamestate from the client system, which will have the
  150.     // new configstring already integrated
  151.     trap_GetGameState( &cgs.gameState );
  152.  
  153.     // look up the individual string that was modified
  154.     str = CG_ConfigString( num );
  155.  
  156.     // do something with it if necessary
  157.     if ( num == CS_MUSIC ) {
  158.         CG_StartMusic();
  159.     } else if ( num == CS_SERVERINFO ) {
  160.         CG_ParseServerinfo();
  161.     } else if ( num == CS_WARMUP ) {
  162.         CG_ParseWarmup();
  163.     } else if ( num == CS_SCORES1 ) {
  164.         cgs.scores1 = atoi( str );
  165.     } else if ( num == CS_SCORES2 ) {
  166.         cgs.scores2 = atoi( str );
  167.     } else if ( num == CS_WARMUP ) {
  168.         CG_ParseWarmup();
  169.     } else if ( num == CS_LEVEL_START_TIME ) {
  170.         cgs.levelStartTime = atoi( str );
  171.     } else if ( num == CS_VOTE_TIME ) {
  172.         cgs.voteTime = atoi( str );
  173.         cgs.voteModified = qtrue;
  174.     } else if ( num == CS_VOTE_YES ) {
  175.         cgs.voteYes = atoi( str );
  176.         cgs.voteModified = qtrue;
  177.     } else if ( num == CS_VOTE_NO ) {
  178.         cgs.voteNo = atoi( str );
  179.         cgs.voteModified = qtrue;
  180.     } else if ( num == CS_VOTE_STRING ) {
  181.         Q_strncpyz( cgs.voteString, str, sizeof( cgs.voteString ) );
  182.     } else if ( num == CS_INTERMISSION ) {
  183.         cg.intermissionStarted = atoi( str );
  184.     } else if ( num >= CS_MODELS && num < CS_MODELS+MAX_MODELS ) {
  185.         cgs.gameModels[ num-CS_MODELS ] = trap_R_RegisterModel( str );
  186.     } else if ( num >= CS_SOUNDS && num < CS_SOUNDS+MAX_MODELS ) {
  187.         if ( str[0] != '*' ) {    // player specific sounds don't register here
  188.             cgs.gameSounds[ num-CS_SOUNDS] = trap_S_RegisterSound( str );
  189.         }
  190.     } else if ( num >= CS_PLAYERS && num < CS_PLAYERS+MAX_CLIENTS ) {
  191.         CG_NewClientInfo( num - CS_PLAYERS );
  192.     } else if ( num == CS_FLAGSTATUS ) {
  193.         // format is rb where its red/blue, 0 is at base, 1 is taken, 2 is dropped
  194.         cgs.redflag = str[0] - '0';
  195.         cgs.blueflag = str[1] - '0';
  196.     }
  197.         
  198. }
  199.  
  200.  
  201. /*
  202. =======================
  203. CG_AddToTeamChat
  204.  
  205. =======================
  206. */
  207. static void CG_AddToTeamChat( const char *str ) {
  208.     int len;
  209.     char *p, *ls;
  210.     int lastcolor;
  211.     int chatHeight;
  212.  
  213.     if (cg_teamChatHeight.integer < TEAMCHAT_HEIGHT) {
  214.         chatHeight = cg_teamChatHeight.integer;
  215.     } else {
  216.         chatHeight = TEAMCHAT_HEIGHT;
  217.     }
  218.  
  219.     if (chatHeight <= 0 || cg_teamChatTime.integer <= 0) {
  220.         // team chat disabled, dump into normal chat
  221.         cgs.teamChatPos = cgs.teamLastChatPos = 0;
  222.         return;
  223.     }
  224.  
  225.     len = 0;
  226.  
  227.     p = cgs.teamChatMsgs[cgs.teamChatPos % chatHeight];
  228.     *p = 0;
  229.  
  230.     lastcolor = '7';
  231.  
  232.     ls = NULL;
  233.     while (*str) {
  234.         if (len > TEAMCHAT_WIDTH - 1) {
  235.             if (ls) {
  236.                 str -= (p - ls);
  237.                 str++;
  238.                 p -= (p - ls);
  239.             }
  240.             *p = 0;
  241.  
  242.             cgs.teamChatMsgTimes[cgs.teamChatPos % chatHeight] = cg.time;
  243.  
  244.             cgs.teamChatPos++;
  245.             p = cgs.teamChatMsgs[cgs.teamChatPos % chatHeight];
  246.             *p = 0;
  247.             *p++ = Q_COLOR_ESCAPE;
  248.             *p++ = lastcolor;
  249.             len = 0;
  250.             ls = NULL;
  251.         }
  252.  
  253.         if ( Q_IsColorString( str ) ) {
  254.             *p++ = *str++;
  255.             lastcolor = *str;
  256.             *p++ = *str++;
  257.             continue;
  258.         }
  259.         if (*str == ' ') {
  260.             ls = p;
  261.         }
  262.         *p++ = *str++;
  263.         len++;
  264.     }
  265.     *p = 0;
  266.  
  267.     cgs.teamChatMsgTimes[cgs.teamChatPos % chatHeight] = cg.time;
  268.     cgs.teamChatPos++;
  269.  
  270.     if (cgs.teamChatPos - cgs.teamLastChatPos > chatHeight)
  271.         cgs.teamLastChatPos = cgs.teamChatPos - chatHeight;
  272. }
  273.  
  274.  
  275.  
  276. /*
  277. ===============
  278. CG_MapRestart
  279.  
  280. The server has issued a map_restart, so the next snapshot
  281. is completely new and should not be interpolated to.
  282.  
  283. A tournement restart will clear everything, but doesn't
  284. require a reload of all the media
  285. ===============
  286. */
  287. static void CG_MapRestart( void ) {
  288.     if ( cg_showmiss.integer ) {
  289.         CG_Printf( "CG_MapRestart\n" );
  290.     }
  291.  
  292.     CG_InitLocalEntities();
  293.     CG_InitMarkPolys();
  294.  
  295.     // make sure the "3 frags left" warnings play again
  296.     cg.fraglimitWarnings = 0;
  297.  
  298.     cg.timelimitWarnings = 0;
  299.  
  300.     cg.intermissionStarted = qfalse;
  301.  
  302.     cgs.voteTime = 0;
  303.  
  304.     CG_StartMusic();
  305.  
  306.     // we really should clear more parts of cg here and stop sounds
  307.  
  308.     // play the "fight" sound if this is a restart without warmup
  309.     if ( cg.warmup == 0 /* && cgs.gametype == GT_TOURNAMENT */) {
  310.         trap_S_StartLocalSound( cgs.media.countFightSound, CHAN_ANNOUNCER );
  311.         CG_CenterPrint( "FIGHT!", 20, GIANTCHAR_WIDTH*2 );
  312.     }
  313. }
  314.  
  315.  
  316. /*
  317. =================
  318. CG_ServerCommand
  319.  
  320. The string has been tokenized and can be retrieved with
  321. Cmd_Argc() / Cmd_Argv()
  322. =================
  323. */
  324. static void CG_ServerCommand( void ) {
  325.     const char    *cmd;
  326.  
  327.     cmd = CG_Argv(0);
  328.  
  329.     if ( !cmd[0] ) {
  330.         // server claimed the command
  331.         return;
  332.     }
  333.  
  334.     if ( !strcmp( cmd, "cp" ) ) {
  335.         CG_CenterPrint( CG_Argv(1), SCREEN_HEIGHT * 0.25, BIGCHAR_WIDTH );
  336.         return;
  337.     }
  338.  
  339.     if ( !strcmp( cmd, "cs" ) ) {
  340.         CG_ConfigStringModified();
  341.         return;
  342.     }
  343.  
  344.     if ( !strcmp( cmd, "print" ) ) {
  345.         CG_Printf( "%s", CG_Argv(1) );
  346.         return;
  347.     }
  348.  
  349.     if ( !strcmp( cmd, "chat" ) ) {
  350.         trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
  351.         CG_Printf( "%s\n", CG_Argv(1) );
  352.         return;
  353.     }
  354.  
  355.     if ( !strcmp( cmd, "tchat" ) ) {
  356.         trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
  357.         CG_AddToTeamChat( CG_Argv(1) );
  358.         CG_Printf( "%s\n", CG_Argv(1) );
  359.         return;
  360.     }
  361.  
  362.     if ( !strcmp( cmd, "scores" ) ) {
  363.         CG_ParseScores();
  364.         return;
  365.     }
  366.  
  367.     if ( !strcmp( cmd, "tinfo" ) ) {
  368.         CG_ParseTeamInfo();
  369.         return;
  370.     }
  371.  
  372.     if ( !strcmp( cmd, "map_restart" ) ) {
  373.         CG_MapRestart();
  374.         return;
  375.     }
  376.  
  377.     // loaddeferred can be both a servercmd and a consolecmd
  378.     if ( !strcmp( cmd, "loaddefered" ) ) {    // FIXME: spelled wrong, but not changing for demo
  379.         CG_LoadDeferredPlayers();
  380.         return;
  381.     }
  382.  
  383.     // clientLevelShot is sent before taking a special screenshot for
  384.     // the menu system during development
  385.     if ( !strcmp( cmd, "clientLevelShot" ) ) {
  386.         cg.levelShot = qtrue;
  387.         return;
  388.     }
  389.  
  390.     CG_Printf( "Unknown client game command: %s\n", cmd );
  391. }
  392.  
  393.  
  394. /*
  395. ====================
  396. CG_ExecuteNewServerCommands
  397.  
  398. Execute all of the server commands that were received along
  399. with this this snapshot.
  400. ====================
  401. */
  402. void CG_ExecuteNewServerCommands( int latestSequence ) {
  403.     while ( cgs.serverCommandSequence < latestSequence ) {
  404.         if ( trap_GetServerCommand( ++cgs.serverCommandSequence ) ) {
  405.             CG_ServerCommand();
  406.         }
  407.     }
  408. }
  409.