codemp/cgame/cg_servercmds.c

Go to the documentation of this file.
00001 // Copyright (C) 1999-2000 Id Software, Inc.
00002 //
00003 // cg_servercmds.c -- reliably sequenced text commands sent by the server
00004 // these are processed at snapshot transition time, so there will definately
00005 // be a valid snapshot this frame
00006 
00007 #include "cg_local.h"
00008 #include "../../ui/menudef.h"
00009 #if !defined(CL_LIGHT_H_INC)
00010         #include "cg_lights.h"
00011 #endif
00012 #include "..\ghoul2\g2.h"
00013 #include "../ui/ui_public.h"
00014 
00015 /*
00016 =================
00017 CG_ParseScores
00018 
00019 =================
00020 */
00021 static void CG_ParseScores( void ) {
00022         int             i, powerups, readScores;
00023 
00024         cg.numScores = atoi( CG_Argv( 1 ) );
00025 
00026         readScores = cg.numScores;
00027 
00028         if (readScores > MAX_CLIENT_SCORE_SEND)
00029         {
00030                 readScores = MAX_CLIENT_SCORE_SEND;
00031         }
00032 
00033         if ( cg.numScores > MAX_CLIENTS ) {
00034                 cg.numScores = MAX_CLIENTS;
00035         }
00036 
00037         cg.numScores = readScores;
00038 
00039         cg.teamScores[0] = atoi( CG_Argv( 2 ) );
00040         cg.teamScores[1] = atoi( CG_Argv( 3 ) );
00041 
00042         memset( cg.scores, 0, sizeof( cg.scores ) );
00043         for ( i = 0 ; i < readScores ; i++ ) {
00044                 //
00045                 cg.scores[i].client = atoi( CG_Argv( i * 14 + 4 ) );
00046                 cg.scores[i].score = atoi( CG_Argv( i * 14 + 5 ) );
00047                 cg.scores[i].ping = atoi( CG_Argv( i * 14 + 6 ) );
00048                 cg.scores[i].time = atoi( CG_Argv( i * 14 + 7 ) );
00049                 cg.scores[i].scoreFlags = atoi( CG_Argv( i * 14 + 8 ) );
00050                 powerups = atoi( CG_Argv( i * 14 + 9 ) );
00051                 cg.scores[i].accuracy = atoi(CG_Argv(i * 14 + 10));
00052                 cg.scores[i].impressiveCount = atoi(CG_Argv(i * 14 + 11));
00053                 cg.scores[i].excellentCount = atoi(CG_Argv(i * 14 + 12));
00054                 cg.scores[i].guantletCount = atoi(CG_Argv(i * 14 + 13));
00055                 cg.scores[i].defendCount = atoi(CG_Argv(i * 14 + 14));
00056                 cg.scores[i].assistCount = atoi(CG_Argv(i * 14 + 15));
00057                 cg.scores[i].perfect = atoi(CG_Argv(i * 14 + 16));
00058                 cg.scores[i].captures = atoi(CG_Argv(i * 14 + 17));
00059 
00060                 if ( cg.scores[i].client < 0 || cg.scores[i].client >= MAX_CLIENTS ) {
00061                         cg.scores[i].client = 0;
00062                 }
00063                 cgs.clientinfo[ cg.scores[i].client ].score = cg.scores[i].score;
00064                 cgs.clientinfo[ cg.scores[i].client ].powerups = powerups;
00065 
00066                 cg.scores[i].team = cgs.clientinfo[cg.scores[i].client].team;
00067         }
00068         CG_SetScoreSelection(NULL);
00069 }
00070 
00071 /*
00072 =================
00073 CG_ParseTeamInfo
00074 
00075 =================
00076 */
00077 static void CG_ParseTeamInfo( void ) {
00078         int             i;
00079         int             client;
00080 
00081         numSortedTeamPlayers = atoi( CG_Argv( 1 ) );
00082 
00083         for ( i = 0 ; i < numSortedTeamPlayers ; i++ ) {
00084                 client = atoi( CG_Argv( i * 6 + 2 ) );
00085 
00086                 sortedTeamPlayers[i] = client;
00087 
00088                 cgs.clientinfo[ client ].location = atoi( CG_Argv( i * 6 + 3 ) );
00089                 cgs.clientinfo[ client ].health = atoi( CG_Argv( i * 6 + 4 ) );
00090                 cgs.clientinfo[ client ].armor = atoi( CG_Argv( i * 6 + 5 ) );
00091                 cgs.clientinfo[ client ].curWeapon = atoi( CG_Argv( i * 6 + 6 ) );
00092                 cgs.clientinfo[ client ].powerups = atoi( CG_Argv( i * 6 + 7 ) );
00093         }
00094 }
00095 
00096 
00097 /*
00098 ================
00099 CG_ParseServerinfo
00100 
00101 This is called explicitly when the gamestate is first received,
00102 and whenever the server updates any serverinfo flagged cvars
00103 ================
00104 */
00105 void CG_ParseServerinfo( void ) {
00106         const char      *info;
00107         const char      *tinfo;
00108         char    *mapname;
00109 
00110         info = CG_ConfigString( CS_SERVERINFO );
00111 
00112         cgs.debugMelee = atoi( Info_ValueForKey( info, "g_debugMelee" ) ); //trap_Cvar_GetHiddenVarValue("g_iknowkungfu");
00113         cgs.stepSlideFix = atoi( Info_ValueForKey( info, "g_stepSlideFix" ) );
00114 
00115         cgs.noSpecMove = atoi( Info_ValueForKey( info, "g_noSpecMove" ) );
00116 
00117         trap_Cvar_Set("bg_fighterAltControl", Info_ValueForKey( info, "bg_fighterAltControl" ));
00118 
00119         cgs.siegeTeamSwitch = atoi( Info_ValueForKey( info, "g_siegeTeamSwitch" ) );
00120 
00121         cgs.showDuelHealths = atoi( Info_ValueForKey( info, "g_showDuelHealths" ) );
00122 
00123         cgs.gametype = atoi( Info_ValueForKey( info, "g_gametype" ) );
00124         trap_Cvar_Set("g_gametype", va("%i", cgs.gametype));
00125         cgs.needpass = atoi( Info_ValueForKey( info, "needpass" ) );
00126         cgs.jediVmerc = atoi( Info_ValueForKey( info, "g_jediVmerc" ) );
00127         cgs.wDisable = atoi( Info_ValueForKey( info, "wdisable" ) );
00128         cgs.fDisable = atoi( Info_ValueForKey( info, "fdisable" ) );
00129         cgs.dmflags = atoi( Info_ValueForKey( info, "dmflags" ) );
00130         cgs.teamflags = atoi( Info_ValueForKey( info, "teamflags" ) );
00131         cgs.fraglimit = atoi( Info_ValueForKey( info, "fraglimit" ) );
00132         cgs.duel_fraglimit = atoi( Info_ValueForKey( info, "duel_fraglimit" ) );
00133         cgs.capturelimit = atoi( Info_ValueForKey( info, "capturelimit" ) );
00134         cgs.timelimit = atoi( Info_ValueForKey( info, "timelimit" ) );
00135         cgs.maxclients = atoi( Info_ValueForKey( info, "sv_maxclients" ) );
00136         mapname = Info_ValueForKey( info, "mapname" );
00137 
00138         //rww - You must do this one here, Info_ValueForKey always uses the same memory pointer.
00139         trap_Cvar_Set ( "ui_about_mapname", mapname );
00140 
00141         Com_sprintf( cgs.mapname, sizeof( cgs.mapname ), "maps/%s.bsp", mapname );
00142 //      Q_strncpyz( cgs.redTeam, Info_ValueForKey( info, "g_redTeam" ), sizeof(cgs.redTeam) );
00143 //      trap_Cvar_Set("g_redTeam", cgs.redTeam);
00144 //      Q_strncpyz( cgs.blueTeam, Info_ValueForKey( info, "g_blueTeam" ), sizeof(cgs.blueTeam) );
00145 //      trap_Cvar_Set("g_blueTeam", cgs.blueTeam);
00146 
00147         trap_Cvar_Set ( "ui_about_gametype", va("%i", cgs.gametype ) );
00148         trap_Cvar_Set ( "ui_about_fraglimit", va("%i", cgs.fraglimit ) );
00149         trap_Cvar_Set ( "ui_about_duellimit", va("%i", cgs.duel_fraglimit ) );
00150         trap_Cvar_Set ( "ui_about_capturelimit", va("%i", cgs.capturelimit ) );
00151         trap_Cvar_Set ( "ui_about_timelimit", va("%i", cgs.timelimit ) );
00152         trap_Cvar_Set ( "ui_about_maxclients", va("%i", cgs.maxclients ) );
00153         trap_Cvar_Set ( "ui_about_dmflags", va("%i", cgs.dmflags ) );
00154         trap_Cvar_Set ( "ui_about_hostname", Info_ValueForKey( info, "sv_hostname" ) );
00155         trap_Cvar_Set ( "ui_about_needpass", Info_ValueForKey( info, "g_needpass" ) );
00156         trap_Cvar_Set ( "ui_about_botminplayers", Info_ValueForKey ( info, "bot_minplayers" ) );
00157 
00158         //Set the siege teams based on what the server has for overrides.
00159         trap_Cvar_Set("cg_siegeTeam1", Info_ValueForKey(info, "g_siegeTeam1"));
00160         trap_Cvar_Set("cg_siegeTeam2", Info_ValueForKey(info, "g_siegeTeam2"));
00161 
00162         tinfo = CG_ConfigString( CS_TERRAINS + 1 );
00163         if ( !tinfo || !*tinfo )
00164         {
00165                 cg.mInRMG = qfalse;
00166         }
00167         else
00168         {
00169                 int weather = 0;
00170 
00171                 cg.mInRMG = qtrue;
00172                 trap_Cvar_Set("RMG", "1");
00173 
00174                 weather = atoi( Info_ValueForKey( info, "RMG_weather" ) );
00175 
00176                 trap_Cvar_Set("RMG_weather", va("%i", weather));
00177 
00178                 if (weather == 1 || weather == 2)
00179                 {
00180                         cg.mRMGWeather = qtrue;
00181                 }
00182                 else
00183                 {
00184                         cg.mRMGWeather = qfalse;
00185                 }
00186         }
00187 }
00188 
00189 /*
00190 ==================
00191 CG_ParseWarmup
00192 ==================
00193 */
00194 static void CG_ParseWarmup( void ) {
00195         const char      *info;
00196         int                     warmup;
00197 
00198         info = CG_ConfigString( CS_WARMUP );
00199 
00200         warmup = atoi( info );
00201         cg.warmupCount = -1;
00202 
00203         cg.warmup = warmup;
00204 }
00205 
00206 /*
00207 ================
00208 CG_SetConfigValues
00209 
00210 Called on load to set the initial values from configure strings
00211 ================
00212 */
00213 void CG_SetConfigValues( void ) 
00214 {
00215         const char *s;
00216         const char *str;
00217 
00218         cgs.scores1 = atoi( CG_ConfigString( CS_SCORES1 ) );
00219         cgs.scores2 = atoi( CG_ConfigString( CS_SCORES2 ) );
00220         cgs.levelStartTime = atoi( CG_ConfigString( CS_LEVEL_START_TIME ) );
00221         if( cgs.gametype == GT_CTF || cgs.gametype == GT_CTY ) {
00222                 s = CG_ConfigString( CS_FLAGSTATUS );
00223                 cgs.redflag = s[0] - '0';
00224                 cgs.blueflag = s[1] - '0';
00225         }
00226         cg.warmup = atoi( CG_ConfigString( CS_WARMUP ) );
00227 
00228         // Track who the jedi master is
00229         cgs.jediMaster = atoi ( CG_ConfigString ( CS_CLIENT_JEDIMASTER ) );
00230         cgs.duelWinner = atoi ( CG_ConfigString ( CS_CLIENT_DUELWINNER ) );
00231 
00232         str = CG_ConfigString(CS_CLIENT_DUELISTS);
00233 
00234         if (str && str[0])
00235         {
00236                 char buf[64];
00237                 int c = 0;
00238                 int i = 0;
00239 
00240                 while (str[i] && str[i] != '|')
00241                 {
00242                         buf[c] = str[i];
00243                         c++;
00244                         i++;
00245                 }
00246                 buf[c] = 0;
00247 
00248                 cgs.duelist1 = atoi ( buf );
00249                 c = 0;
00250 
00251                 i++;
00252                 while (str[i])
00253                 {
00254                         buf[c] = str[i];
00255                         c++;
00256                         i++;
00257                 }
00258                 buf[c] = 0;
00259 
00260                 cgs.duelist2 = atoi ( buf );
00261         }
00262 }
00263 
00264 /*
00265 =====================
00266 CG_ShaderStateChanged
00267 =====================
00268 */
00269 void CG_ShaderStateChanged(void) {
00270         char originalShader[MAX_QPATH];
00271         char newShader[MAX_QPATH];
00272         char timeOffset[16];
00273         const char *o;
00274         char *n,*t;
00275 
00276         o = CG_ConfigString( CS_SHADERSTATE );
00277         while (o && *o) {
00278                 n = strstr(o, "=");
00279                 if (n && *n) {
00280                         strncpy(originalShader, o, n-o);
00281                         originalShader[n-o] = 0;
00282                         n++;
00283                         t = strstr(n, ":");
00284                         if (t && *t) {
00285                                 strncpy(newShader, n, t-n);
00286                                 newShader[t-n] = 0;
00287                         } else {
00288                                 break;
00289                         }
00290                         t++;
00291                         o = strstr(t, "@");
                        if (o) {
                                strncpy(timeOffset, t, o-t);
                                timeOffset[o-t] = 0;
                                o++;
                                trap_R_RemapShader( originalShader, newShader, timeOffset );
                        }
                } else {
                        break;
                }
        }
}

extern char *cg_customSoundNames[MAX_CUSTOM_SOUNDS];
extern const char *cg_customCombatSoundNames[MAX_CUSTOM_COMBAT_SOUNDS];
extern const char *cg_customExtraSoundNames[MAX_CUSTOM_EXTRA_SOUNDS];
extern const char *cg_customJediSoundNames[MAX_CUSTOM_JEDI_SOUNDS];
extern const char *cg_customDuelSoundNames[MAX_CUSTOM_DUEL_SOUNDS];

static const char *GetCustomSoundForType(int setType, int index)
{
        switch (setType)
        {
        case 1:
                return cg_customSoundNames[index];
        case 2:
                return cg_customCombatSoundNames[index];
        case 3:
                return cg_customExtraSoundNames[index];
        case 4:
                return cg_customJediSoundNames[index];
        case 5:
                return bg_customSiegeSoundNames[index];
        case 6:
                return cg_customDuelSoundNames[index];
        default:
                assert(0);
                return NULL;
        }
}

void SetCustomSoundForType(clientInfo_t *ci, int setType, int index, sfxHandle_t sfx)
{
        switch (setType)
        {
        case 1:
                ci->sounds[index] = sfx;
                break;
        case 2:
                ci->combatSounds[index] = sfx;
                break;
        case 3:
                ci->extraSounds[index] = sfx;
                break;
        case 4:
                ci->jediSounds[index] = sfx;
                break;
        case 5:
                ci->siegeSounds[index] = sfx;
                break;
        case 6:
                ci->duelSounds[index] = sfx;
                break;
        default:
                assert(0);
                break;
        }
}

static void CG_RegisterCustomSounds(clientInfo_t *ci, int setType, const char *psDir)
{
        int iTableEntries = 0;
        int i;

        switch (setType)
        {
        case 1:
                iTableEntries = MAX_CUSTOM_SOUNDS;
                break;
        case 2:
                iTableEntries = MAX_CUSTOM_COMBAT_SOUNDS;
                break;
        case 3:
                iTableEntries = MAX_CUSTOM_EXTRA_SOUNDS;
                break;
        case 4:
                iTableEntries = MAX_CUSTOM_JEDI_SOUNDS;
                break;
        case 5:
                iTableEntries = MAX_CUSTOM_SIEGE_SOUNDS;
        default:
                assert(0);
                return;
        }

        for ( i = 0 ; i<iTableEntries; i++ ) 
        {
                sfxHandle_t hSFX;
                const char *s = GetCustomSoundForType(setType, i);

                if ( !s ) 
                {
                        break;
                }

                s++;
                hSFX = trap_S_RegisterSound( va("sound/chars/%s/misc/%s", psDir, s) );
00292 
00293                 if (hSFX == 0)
00294                 {
00295                         char modifiedSound[MAX_QPATH];
00296                         char *p;
00297 
00298                         strcpy(modifiedSound, s);
00299                         p = strchr(modifiedSound,'.');
00300 
00301                         if (p)
00302                         {
00303                                 char testNumber[2];
00304                                 p--;
00305 
00306                                 //before we destroy it.. we want to see if this is actually a number.
00307                                 //If it isn't a number then don't try decrementing and registering as
00308                                 //it will only cause a disk hit (we don't try precaching such files)
00309                                 testNumber[0] = *p;
00310                                 testNumber[1] = 0;
00311                                 if (atoi(testNumber))
00312                                 {
00313                                         *p = 0;
00314 
00315                                         strcat(modifiedSound, "1.wav");
00316 
00317                                         hSFX = trap_S_RegisterSound( va("sound/chars/%s/misc/%s", psDir, modifiedSound) );
00318                                 }
00319                         }
00320                 }
00321                 
00322                 SetCustomSoundForType(ci, setType, i, hSFX);
00323         }
00324 }
00325 
00326 void CG_PrecacheNPCSounds(const char *str)
00327 {
00328         char sEnd[MAX_QPATH];
00329         char pEnd[MAX_QPATH];
00330         int i = 0;
00331         int j = 0;
00332         int k = 0;
00333 
00334         k = 2;
00335 
00336         while (str[k])
00337         {
00338                 pEnd[k-2] = str[k];
00339                 k++;
00340         }
00341         pEnd[k-2] = 0;
00342 
00343         while (i < 4) //4 types
00344         { //It would be better if we knew what type this actually was (extra, combat, jedi, etc).
00345           //But that would require extra configstring indexing and that is a bad thing.
00346 
00347                 while (j < MAX_CUSTOM_SOUNDS)
00348                 {
00349                         const char *s = GetCustomSoundForType(i+1, j);
00350 
00351                         if (s && s[0])
00352                         { //whatever it is, try registering it under this folder.
00353                                 k = 1;
00354                                 while (s[k])
00355                                 {
00356                                         sEnd[k-1] = s[k];
00357                                         k++;
00358                                 }
00359                                 sEnd[k-1] = 0;
00360 
00361                                 trap_S_ShutUp(qtrue);
00362                                 trap_S_RegisterSound( va("sound/chars/%s/misc/%s", pEnd, sEnd) );
00363                                 trap_S_ShutUp(qfalse);
00364                         }
00365                         else
00366                         { //move onto the next set
00367                                 break;
00368                         }
00369 
00370                         j++;
00371                 }
00372 
00373                 j = 0;
00374                 i++;
00375         }
00376 }
00377 
00378 void CG_HandleNPCSounds(centity_t *cent)
00379 {
00380         if (!cent->npcClient)
00381         {
00382                 return;
00383         }
00384 
00385         //standard
00386         if (cent->currentState.csSounds_Std)
00387         {
00388                 const char *s = CG_ConfigString( CS_SOUNDS + cent->currentState.csSounds_Std );
00389 
00390                 if (s && s[0])
00391                 {
00392                         char sEnd[MAX_QPATH];
00393                         int i = 2;
00394                         int j = 0;
00395 
00396                         //Parse past the initial "*" which indicates this is a custom sound, and the $ which indicates
00397                         //it is an NPC custom sound dir.
00398                         while (s[i])
00399                         {
00400                                 sEnd[j] = s[i];
00401                                 j++;
00402                                 i++;
00403                         }
00404                         sEnd[j] = 0;
00405 
00406                         CG_RegisterCustomSounds(cent->npcClient, 1, sEnd);
00407                 }
00408         }
00409         else
00410         {
00411                 memset(&cent->npcClient->sounds, 0, sizeof(cent->npcClient->sounds));
00412         }
00413 
00414         //combat
00415         if (cent->currentState.csSounds_Combat)
00416         {
00417                 const char *s = CG_ConfigString( CS_SOUNDS + cent->currentState.csSounds_Combat );
00418 
00419                 if (s && s[0])
00420                 {
00421                         char sEnd[MAX_QPATH];
00422                         int i = 2;
00423                         int j = 0;
00424 
00425                         //Parse past the initial "*" which indicates this is a custom sound, and the $ which indicates
00426                         //it is an NPC custom sound dir.
00427                         while (s[i])
00428                         {
00429                                 sEnd[j] = s[i];
00430                                 j++;
00431                                 i++;
00432                         }
00433                         sEnd[j] = 0;
00434 
00435                         CG_RegisterCustomSounds(cent->npcClient, 2, sEnd);
00436                 }
00437         }
00438         else
00439         {
00440                 memset(&cent->npcClient->combatSounds, 0, sizeof(cent->npcClient->combatSounds));
00441         }
00442 
00443         //extra
00444         if (cent->currentState.csSounds_Extra)
00445         {
00446                 const char *s = CG_ConfigString( CS_SOUNDS + cent->currentState.csSounds_Extra );
00447 
00448                 if (s && s[0])
00449                 {
00450                         char sEnd[MAX_QPATH];
00451                         int i = 2;
00452                         int j = 0;
00453 
00454                         //Parse past the initial "*" which indicates this is a custom sound, and the $ which indicates
00455                         //it is an NPC custom sound dir.
00456                         while (s[i])
00457                         {
00458                                 sEnd[j] = s[i];
00459                                 j++;
00460                                 i++;
00461                         }
00462                         sEnd[j] = 0;
00463 
00464                         CG_RegisterCustomSounds(cent->npcClient, 3, sEnd);
00465                 }
00466         }
00467         else
00468         {
00469                 memset(&cent->npcClient->extraSounds, 0, sizeof(cent->npcClient->extraSounds));
00470         }
00471 
00472         //jedi
00473         if (cent->currentState.csSounds_Jedi)
00474         {
00475                 const char *s = CG_ConfigString( CS_SOUNDS + cent->currentState.csSounds_Jedi );
00476 
00477                 if (s && s[0])
00478                 {
00479                         char sEnd[MAX_QPATH];
00480                         int i = 2;
00481                         int j = 0;
00482 
00483                         //Parse past the initial "*" which indicates this is a custom sound, and the $ which indicates
00484                         //it is an NPC custom sound dir.
00485                         while (s[i])
00486                         {
00487                                 sEnd[j] = s[i];
00488                                 j++;
00489                                 i++;
00490                         }
00491                         sEnd[j] = 0;
00492 
00493                         CG_RegisterCustomSounds(cent->npcClient, 4, sEnd);
00494                 }
00495         }
00496         else
00497         {
00498                 memset(&cent->npcClient->jediSounds, 0, sizeof(cent->npcClient->jediSounds));
00499         }
00500 }
00501 
00502 int CG_HandleAppendedSkin(char *modelName);
00503 void CG_CacheG2AnimInfo(char *modelName);
00504 
00505 // nmckenzie: DUEL_HEALTH - fixme - we could really clean this up immensely with some helper functions.
00506 void SetDuelistHealthsFromConfigString ( const char *str ) {
00507         char buf[64];
00508         int c = 0;
00509         int i = 0;
00510 
00511         while (str[i] && str[i] != '|')
00512         {
00513                 buf[c] = str[i];
00514                 c++;
00515                 i++;
00516         }
00517         buf[c] = 0;
00518 
00519         cgs.duelist1health = atoi ( buf );
00520 
00521         c = 0;
00522         i++;
00523         while (str[i] && str[i] != '|')
00524         {
00525                 buf[c] = str[i];
00526                 c++;
00527                 i++;
00528         }
00529         buf[c] = 0;
00530 
00531         cgs.duelist2health = atoi ( buf );
00532 
00533         c = 0;
00534         i++;
00535         if ( str[i] == '!' )
00536         {       // we only have 2 duelists, apparently.
00537                 cgs.duelist3health = -1;
00538                 return;
00539         }
00540 
00541         while (str[i] && str[i] != '|')
00542         {
00543                 buf[c] = str[i];
00544                 c++;
00545                 i++;
00546         }
00547         buf[c] = 0;
00548 
00549         cgs.duelist3health = atoi ( buf );
00550 }
00551 
00552 /*
00553 ================
00554 CG_ConfigStringModified
00555 
00556 ================
00557 */
00558 extern int cgSiegeRoundState;
00559 extern int cgSiegeRoundTime;
00560 void CG_ParseSiegeObjectiveStatus(const char *str);
00561 void CG_ParseWeatherEffect(const char *str);
00562 extern void CG_ParseSiegeState(const char *str); //cg_main.c
00563 extern int cg_beatingSiegeTime;
00564 extern int cg_siegeWinTeam;
00565 static void CG_ConfigStringModified( void ) {
00566         const char      *str;
00567         int             num;
00568 
00569         num = atoi( CG_Argv( 1 ) );
00570 
00571         // get the gamestate from the client system, which will have the
00572         // new configstring already integrated
00573         trap_GetGameState( &cgs.gameState );
00574 
00575         // look up the individual string that was modified
00576         str = CG_ConfigString( num );
00577 
00578         // do something with it if necessary
00579         if ( num == CS_MUSIC ) {
00580                 CG_StartMusic( qtrue );
00581         } else if ( num == CS_SERVERINFO ) {
00582                 CG_ParseServerinfo();
00583         } else if ( num == CS_WARMUP ) {
00584                 CG_ParseWarmup();
00585         } else if ( num == CS_SCORES1 ) {
00586                 cgs.scores1 = atoi( str );
00587         } else if ( num == CS_SCORES2 ) {
00588                 cgs.scores2 = atoi( str );
00589         } else if ( num == CS_CLIENT_JEDIMASTER ) {
00590                 cgs.jediMaster = atoi ( str );
00591         }
00592         else if ( num == CS_CLIENT_DUELWINNER )
00593         {
00594                 cgs.duelWinner = atoi ( str );
00595         }
00596         else if ( num == CS_CLIENT_DUELISTS )
00597         {
00598                 char buf[64];
00599                 int c = 0;
00600                 int i = 0;
00601 
00602                 while (str[i] && str[i] != '|')
00603                 {
00604                         buf[c] = str[i];
00605                         c++;
00606                         i++;
00607                 }
00608                 buf[c] = 0;
00609 
00610                 cgs.duelist1 = atoi ( buf );
00611                 c = 0;
00612 
00613                 i++;
00614                 while (str[i] && str[i] != '|')
00615                 {
00616                         buf[c] = str[i];
00617                         c++;
00618                         i++;
00619                 }
00620                 buf[c] = 0;
00621 
00622                 cgs.duelist2 = atoi ( buf );
00623 
00624                 if (str[i])
00625                 {
00626                         c = 0;
00627                         i++;
00628 
00629                         while (str[i])
00630                         {
00631                                 buf[c] = str[i];
00632                                 c++;
00633                                 i++;
00634                         }
00635                         buf[c] = 0;
00636 
00637                         cgs.duelist3 = atoi(buf);
00638                 }
00639         }
00640         else if ( num == CS_CLIENT_DUELHEALTHS ) {      // nmckenzie: DUEL_HEALTH
00641                 SetDuelistHealthsFromConfigString(str);
00642         }
00643         else if ( num == CS_LEVEL_START_TIME ) {
00644                 cgs.levelStartTime = atoi( str );
00645         } else if ( num == CS_VOTE_TIME ) {
00646                 cgs.voteTime = atoi( str );
00647                 cgs.voteModified = qtrue;
00648         } else if ( num == CS_VOTE_YES ) {
00649                 cgs.voteYes = atoi( str );
00650                 cgs.voteModified = qtrue;
00651         } else if ( num == CS_VOTE_NO ) {
00652                 cgs.voteNo = atoi( str );
00653                 cgs.voteModified = qtrue;
00654         } else if ( num == CS_VOTE_STRING ) {
00655                 Q_strncpyz( cgs.voteString, str, sizeof( cgs.voteString ) );
00656         } else if ( num >= CS_TEAMVOTE_TIME && num <= CS_TEAMVOTE_TIME + 1) {
00657                 cgs.teamVoteTime[num-CS_TEAMVOTE_TIME] = atoi( str );
00658                 cgs.teamVoteModified[num-CS_TEAMVOTE_TIME] = qtrue;
00659         } else if ( num >= CS_TEAMVOTE_YES && num <= CS_TEAMVOTE_YES + 1) {
00660                 cgs.teamVoteYes[num-CS_TEAMVOTE_YES] = atoi( str );
00661                 cgs.teamVoteModified[num-CS_TEAMVOTE_YES] = qtrue;
00662         } else if ( num >= CS_TEAMVOTE_NO && num <= CS_TEAMVOTE_NO + 1) {
00663                 cgs.teamVoteNo[num-CS_TEAMVOTE_NO] = atoi( str );
00664                 cgs.teamVoteModified[num-CS_TEAMVOTE_NO] = qtrue;
00665         } else if ( num >= CS_TEAMVOTE_STRING && num <= CS_TEAMVOTE_STRING + 1) {
00666                 Q_strncpyz( cgs.teamVoteString[num-CS_TEAMVOTE_STRING], str, sizeof( cgs.teamVoteString ) );
00667         } else if ( num == CS_INTERMISSION ) {
00668                 cg.intermissionStarted = atoi( str );
00669         } else if ( num >= CS_MODELS && num < CS_MODELS+MAX_MODELS ) {
00670                 char modelName[MAX_QPATH];
00671                 strcpy(modelName, str);
00672                 if (strstr(modelName, ".glm") || modelName[0] == '$')
00673                 { //Check to see if it has a custom skin attached.
00674                         CG_HandleAppendedSkin(modelName);
00675                         CG_CacheG2AnimInfo(modelName);
00676                 }
00677 
00678                 if (modelName[0] != '$' && modelName[0] != '@')
00679                 { //don't register vehicle names and saber names as models.
00680                         cgs.gameModels[ num-CS_MODELS ] = trap_R_RegisterModel( modelName );
00681                 }
00682                 else
00683                 {
00684             cgs.gameModels[ num-CS_MODELS ] = 0;
00685                 }
00686 // GHOUL2 Insert start
00687                 /*
00688         } else if ( num >= CS_CHARSKINS && num < CS_CHARSKINS+MAX_CHARSKINS ) {
00689                 cgs.skins[ num-CS_CHARSKINS ] = trap_R_RegisterSkin( str );
00690                 */
00691                 //rww - removed and replaced with CS_G2BONES
00692 // Ghoul2 Insert end
00693         } else if ( num >= CS_SOUNDS && num < CS_SOUNDS+MAX_SOUNDS ) {
00694                 if ( str[0] != '*' ) {  // player specific sounds don't register here
00695                         cgs.gameSounds[ num-CS_SOUNDS] = trap_S_RegisterSound( str );
00696                 }
00697                 else if (str[1] == '$')
00698                 { //an NPC soundset
00699                         CG_PrecacheNPCSounds(str);
00700                 }
00701         } else if ( num >= CS_EFFECTS && num < CS_EFFECTS+MAX_FX ) {
00702                 if (str[0] == '*')
00703                 { //it's a special global weather effect
00704                         CG_ParseWeatherEffect(str);
00705                         cgs.gameEffects[ num-CS_EFFECTS] = 0;
00706                 }
00707                 else
00708                 {
00709                         cgs.gameEffects[ num-CS_EFFECTS] = trap_FX_RegisterEffect( str );
00710                 }
00711         }
00712         else if ( num >= CS_SIEGE_STATE && num < CS_SIEGE_STATE+1 )
00713         {
00714                 if (str[0])
00715                 {
00716                         CG_ParseSiegeState(str);
00717                 }
00718         }
00719         else if ( num >= CS_SIEGE_WINTEAM && num < CS_SIEGE_WINTEAM+1 )
00720         {
00721                 if (str[0])
00722                 {
00723                         cg_siegeWinTeam = atoi(str);
00724                 }
00725         }
00726         else if ( num >= CS_SIEGE_OBJECTIVES && num < CS_SIEGE_OBJECTIVES+1 )
00727         {
00728                 CG_ParseSiegeObjectiveStatus(str);
00729         }
00730         else if (num >= CS_SIEGE_TIMEOVERRIDE && num < CS_SIEGE_TIMEOVERRIDE+1)
00731         {
00732                 cg_beatingSiegeTime = atoi(str);
00733                 CG_SetSiegeTimerCvar ( cg_beatingSiegeTime );
00734         }
00735         else if ( num >= CS_PLAYERS && num < CS_PLAYERS+MAX_CLIENTS )
00736         {
00737                 CG_NewClientInfo( num - CS_PLAYERS, qtrue);
00738                 CG_BuildSpectatorString();
00739         } else if ( num == CS_FLAGSTATUS ) {
00740                 if( cgs.gametype == GT_CTF || cgs.gametype == GT_CTY ) {
00741                         // format is rb where its red/blue, 0 is at base, 1 is taken, 2 is dropped
00742                         cgs.redflag = str[0] - '0';
00743                         cgs.blueflag = str[1] - '0';
00744                 }
00745         }
00746         else if ( num == CS_SHADERSTATE ) {
00747                 CG_ShaderStateChanged();
00748         }
00749         else if ( num >= CS_LIGHT_STYLES && num < CS_LIGHT_STYLES + (MAX_LIGHT_STYLES * 3))
00750         {
00751                 CG_SetLightstyle(num - CS_LIGHT_STYLES);
00752         }
00753                 
00754 }
00755 
00756 //frees all ghoul2 stuff and npc stuff from a centity -rww
00757 void CG_KillCEntityG2(int entNum)
00758 {
00759         int j;
00760         clientInfo_t *ci = NULL;
00761         centity_t *cent = &cg_entities[entNum];
00762 
00763         if (entNum < MAX_CLIENTS)
00764         {
00765                 ci = &cgs.clientinfo[entNum];
00766         }
00767         else
00768         {
00769                 ci = cent->npcClient;
00770         }
00771 
00772         if (ci)
00773         {
00774                 if (ci == cent->npcClient)
00775                 { //never going to be != cent->ghoul2, unless cent->ghoul2 has already been removed (and then this ptr is not valid)
00776                         ci->ghoul2Model = NULL;
00777                 }
00778                 else if (ci->ghoul2Model == cent->ghoul2)
00779                 {
00780                         ci->ghoul2Model = NULL;
00781                 }
00782                 else if (ci->ghoul2Model && trap_G2_HaveWeGhoul2Models(ci->ghoul2Model))
00783                 {
00784                         trap_G2API_CleanGhoul2Models(&ci->ghoul2Model);
00785                         ci->ghoul2Model = NULL;
00786                 }
00787 
00788                 //Clean up any weapon instances for custom saber stuff
00789                 j = 0;
00790                 while (j < MAX_SABERS)
00791                 {
00792                         if (ci->ghoul2Weapons[j] && trap_G2_HaveWeGhoul2Models(ci->ghoul2Weapons[j]))
00793                         {
00794                                 trap_G2API_CleanGhoul2Models(&ci->ghoul2Weapons[j]);
00795                                 ci->ghoul2Weapons[j] = NULL;
00796                         }
00797 
00798                         j++;
00799                 }
00800         }
00801 
00802         if (cent->ghoul2 && trap_G2_HaveWeGhoul2Models(cent->ghoul2))
00803         {
00804                 trap_G2API_CleanGhoul2Models(&cent->ghoul2);
00805                 cent->ghoul2 = NULL;
00806         }
00807 
00808         if (cent->grip_arm && trap_G2_HaveWeGhoul2Models(cent->grip_arm))
00809         {
00810                 trap_G2API_CleanGhoul2Models(&cent->grip_arm);
00811                 cent->grip_arm = NULL;
00812         }
00813 
00814         if (cent->frame_hold && trap_G2_HaveWeGhoul2Models(cent->frame_hold))
00815         {
00816                 trap_G2API_CleanGhoul2Models(&cent->frame_hold);
00817                 cent->frame_hold = NULL;
00818         }
00819 
00820         if (cent->npcClient)
00821         {
00822                 CG_DestroyNPCClient(&cent->npcClient);
00823         }
00824 
00825         cent->isRagging = qfalse; //just in case.
00826         cent->ikStatus = qfalse;
00827 
00828         cent->localAnimIndex = 0;
00829 }
00830 
00831 void CG_KillCEntityInstances(void)
00832 {
00833         int i = 0;
00834         centity_t *cent;
00835 
00836         while (i < MAX_GENTITIES)
00837         {
00838                 cent = &cg_entities[i];
00839 
00840                 if (i >= MAX_CLIENTS && cent->currentState.number == i)
00841                 { //do not clear G2 instances on client ents, they are constant
00842                         CG_KillCEntityG2(i);
00843                 }
00844 
00845                 cent->bolt1 = 0;
00846                 cent->bolt2 = 0;
00847                 cent->bolt3 = 0;
00848                 cent->bolt4 = 0;
00849 
00850                 cent->bodyHeight = 0;//SABER_LENGTH_MAX;
00851                 //cent->saberExtendTime = 0;
00852 
00853                 cent->boltInfo = 0;
00854 
00855                 cent->frame_minus1_refreshed = 0;
00856                 cent->frame_minus2_refreshed = 0;
00857                 cent->dustTrailTime = 0;
00858                 cent->ghoul2weapon = NULL;
00859                 //cent->torsoBolt = 0;
00860                 cent->trailTime = 0;
00861                 cent->frame_hold_time = 0;
00862                 cent->frame_hold_refreshed = 0;
00863                 cent->trickAlpha = 0;
00864                 cent->trickAlphaTime = 0;
00865                 VectorClear(cent->turAngles);
00866                 cent->weapon = 0;
00867                 cent->teamPowerEffectTime = 0;
00868                 cent->teamPowerType = 0;
00869                 cent->numLoopingSounds = 0;
00870 
00871                 cent->localAnimIndex = 0;
00872 
00873                 i++;
00874         }
00875 }
00876 
00877 /*
00878 ===============
00879 CG_MapRestart
00880 
00881 The server has issued a map_restart, so the next snapshot
00882 is completely new and should not be interpolated to.
00883 
00884 A tournement restart will clear everything, but doesn't
00885 require a reload of all the media
00886 ===============
00887 */
00888 static void CG_MapRestart( void ) {
00889         if ( cg_showmiss.integer ) {
00890                 CG_Printf( "CG_MapRestart\n" );
00891         }
00892 
00893         trap_R_ClearDecals ( );
00894         //FIXME: trap_FX_Reset?
00895 
00896         CG_InitLocalEntities();
00897         CG_InitMarkPolys();
00898         CG_ClearParticles ();
00899         CG_KillCEntityInstances();
00900 
00901         // make sure the "3 frags left" warnings play again
00902         cg.fraglimitWarnings = 0;
00903 
00904         cg.timelimitWarnings = 0;
00905 
00906         cg.intermissionStarted = qfalse;
00907 
00908         cgs.voteTime = 0;
00909 
00910         cg.mapRestart = qtrue;
00911 
00912         CG_StartMusic(qtrue);
00913 
00914         trap_S_ClearLoopingSounds();
00915 
00916         // we really should clear more parts of cg here and stop sounds
00917 
00918         // play the "fight" sound if this is a restart without warmup
00919         if ( cg.warmup == 0 && cgs.gametype != GT_SIEGE && cgs.gametype != GT_POWERDUEL/* && cgs.gametype == GT_DUEL */) {
00920                 trap_S_StartLocalSound( cgs.media.countFightSound, CHAN_ANNOUNCER );
00921                 CG_CenterPrint( CG_GetStringEdString("MP_SVGAME", "BEGIN_DUEL"), 120, GIANTCHAR_WIDTH*2 );
00922         }
00923         /*
00924         if (cg_singlePlayerActive.integer) {
00925                 trap_Cvar_Set("ui_matchStartTime", va("%i", cg.time));
00926                 if (cg_recordSPDemo.integer && cg_recordSPDemoName.string && *cg_recordSPDemoName.string) {
00927                         trap_SendConsoleCommand(va("set g_synchronousclients 1 ; record %s \n", cg_recordSPDemoName.string));
00928                 }
00929         }
00930         */
00931         trap_Cvar_Set("cg_thirdPerson", "0");
00932 }
00933 
00934 /*
00935 =================
00936 CG_RemoveChatEscapeChar
00937 =================
00938 */
00939 static void CG_RemoveChatEscapeChar( char *text ) {
00940         int i, l;
00941 
00942         l = 0;
00943         for ( i = 0; text[i]; i++ ) {
00944                 if (text[i] == '\x19')
00945                         continue;
00946                 text[l++] = text[i];
00947         }
00948         text[l] = '\0';
00949 }
00950 
00951 #define MAX_STRINGED_SV_STRING 1024     // this is an quake-engine limit, not a StringEd limit
00952 
00953 void CG_CheckSVStringEdRef(char *buf, const char *str)
00954 { //I don't really like doing this. But it utilizes the system that was already in place.
00955         int i = 0;
00956         int b = 0;
00957         int strLen = 0;
00958         qboolean gotStrip = qfalse;
00959 
00960         if (!str || !str[0])
00961         {
00962                 if (str)
00963                 {
00964                         strcpy(buf, str);
00965                 }
00966                 return;
00967         }
00968 
00969         strcpy(buf, str);
00970 
00971         strLen = strlen(str);
00972 
00973         if (strLen >= MAX_STRINGED_SV_STRING)
00974         {
00975                 return;
00976         }
00977 
00978         while (i < strLen && str[i])
00979         {
00980                 gotStrip = qfalse;
00981 
00982                 if (str[i] == '@' && (i+1) < strLen)
00983                 {
00984                         if (str[i+1] == '@' && (i+2) < strLen)
00985                         {
00986                                 if (str[i+2] == '@' && (i+3) < strLen)
00987                                 { //@@@ should mean to insert a StringEd reference here, so insert it into buf at the current place
00988                                         char stringRef[MAX_STRINGED_SV_STRING];
00989                                         int r = 0;
00990 
00991                                         while (i < strLen && str[i] == '@')
00992                                         {
00993                                                 i++;
00994                                         }
00995 
00996                                         while (i < strLen && str[i] && str[i] != ' ' && str[i] != ':' && str[i] != '.' && str[i] != '\n')
00997                                         {
00998                                                 stringRef[r] = str[i];
00999                                                 r++;
01000                                                 i++;
01001                                         }
01002                                         stringRef[r] = 0;
01003 
01004                                         buf[b] = 0;
01005                                         Q_strcat(buf, MAX_STRINGED_SV_STRING, CG_GetStringEdString("MP_SVGAME", stringRef));
01006                                         b = strlen(buf);
01007                                 }
01008                         }
01009                 }
01010 
01011                 if (!gotStrip)
01012                 {
01013                         buf[b] = str[i];
01014                         b++;
01015                 }
01016                 i++;
01017         }
01018 
01019         buf[b] = 0;
01020 }
01021 
01022 static void CG_BodyQueueCopy(centity_t *cent, int clientNum, int knownWeapon)
01023 {
01024         centity_t               *source;
01025         animation_t             *anim;
01026         float                   animSpeed;
01027         int                             flags=BONE_ANIM_OVERRIDE_FREEZE;
01028         clientInfo_t    *ci;
01029 
01030         if (cent->ghoul2)
01031         {
01032                 trap_G2API_CleanGhoul2Models(&cent->ghoul2);
01033         }
01034 
01035         if (clientNum < 0 || clientNum >= MAX_CLIENTS)
01036         {
01037                 return;
01038         }
01039 
01040         source = &cg_entities[ clientNum ];
01041         ci = &cgs.clientinfo[ clientNum ];
01042 
01043         if (!source)
01044         {
01045                 return;
01046         }
01047 
01048         if (!source->ghoul2)
01049         {
01050                 return;
01051         }
01052 
01053         cent->isRagging = qfalse; //reset in case it's still set from another body that was in this cent slot.
01054         cent->ownerRagging = source->isRagging; //if the owner was in ragdoll state, then we want to go into it too right away.
01055 
01056 #if 0
01057         VectorCopy(source->lerpOriginOffset, cent->lerpOriginOffset);
01058 #endif
01059 
01060         cent->bodyFadeTime = 0;
01061         cent->bodyHeight = 0;
01062 
01063         cent->dustTrailTime = source->dustTrailTime;
01064 
01065         trap_G2API_DuplicateGhoul2Instance(source->ghoul2, &cent->ghoul2);
01066 
01067         if (source->isRagging)
01068         { //just reset it now.
01069                 source->isRagging = qfalse;
01070                 trap_G2API_SetRagDoll(source->ghoul2, NULL); //calling with null parms resets to no ragdoll.
01071         }
01072 
01073         //either force the weapon from when we died or remove it if it was a dropped weapon
01074         if (knownWeapon > WP_BRYAR_PISTOL && trap_G2API_HasGhoul2ModelOnIndex(&(cent->ghoul2), 1))
01075         {
01076                 trap_G2API_RemoveGhoul2Model(&(cent->ghoul2), 1);
01077         }
01078         else if (trap_G2API_HasGhoul2ModelOnIndex(&(cent->ghoul2), 1))
01079         {
01080                 trap_G2API_CopySpecificGhoul2Model(CG_G2WeaponInstance(cent, knownWeapon), 0, cent->ghoul2, 1);
01081         }
01082 
01083         if (!cent->ownerRagging)
01084         {
01085                 int aNum;
01086                 int eFrame;
01087                 qboolean fallBack = qfalse;
01088 
01089                 //anim = &bgAllAnims[cent->localAnimIndex].anims[ cent->currentState.torsoAnim ];
01090                 if (!BG_InDeathAnim(source->currentState.torsoAnim))
01091                 { //then just snap the corpse into a default
01092                         anim = &bgAllAnims[source->localAnimIndex].anims[ BOTH_DEAD1 ];
01093                         fallBack = qtrue;
01094                 }
01095                 else
01096                 {
01097                         anim = &bgAllAnims[source->localAnimIndex].anims[ source->currentState.torsoAnim ];
01098                 }
01099                 animSpeed = 50.0f / anim->frameLerp;
01100 
01101                 if (!fallBack)
01102                 {
01103                         //this will just set us to the last frame of the animation, in theory
01104                         aNum = cgs.clientinfo[source->currentState.number].frame+1;
01105 
01106                         while (aNum >= anim->firstFrame+anim->numFrames)
01107                         {
01108                                 aNum--;
01109                         }
01110 
01111                         if (aNum < anim->firstFrame-1)
01112                         { //wrong animation...?
01113                                 aNum = (anim->firstFrame+anim->numFrames)-1;
01114                         }
01115                 }
01116                 else
01117                 {
01118                         aNum = anim->firstFrame;
01119                 }
01120 
01121                 eFrame = anim->firstFrame + anim->numFrames;
01122 
01123                 //if (!cgs.clientinfo[source->currentState.number].frame || (cent->currentState.torsoAnim) != (source->currentState.torsoAnim) )
01124                 //{
01125                 //      aNum = (anim->firstFrame+anim->numFrames)-1;
01126                 //}
01127 
01128                 trap_G2API_SetBoneAnim(cent->ghoul2, 0, "upper_lumbar", aNum, eFrame, flags, animSpeed, cg.time, -1, 150);
01129                 trap_G2API_SetBoneAnim(cent->ghoul2, 0, "model_root", aNum, eFrame, flags, animSpeed, cg.time, -1, 150);
01130                 trap_G2API_SetBoneAnim(cent->ghoul2, 0, "Motion", aNum, eFrame, flags, animSpeed, cg.time, -1, 150);
01131         }
01132 
01133         //After we create the bodyqueue, regenerate any limbs on the real instance
01134         if (source->torsoBolt)
01135         {
01136                 CG_ReattachLimb(source);
01137         }
01138 }
01139 
01140 /*
01141 =================
01142 CG_ServerCommand
01143 
01144 The string has been tokenized and can be retrieved with
01145 Cmd_Argc() / Cmd_Argv()
01146 =================
01147 */
01148 void CG_SiegeBriefingDisplay(int team, int dontshow);
01149 void CG_ParseSiegeExtendedData(void);
01150 extern void CG_ChatBox_AddString(char *chatStr); //cg_draw.c
01151 static void CG_ServerCommand( void ) {
01152         const char      *cmd;
01153         char            text[MAX_SAY_TEXT];
01154         qboolean        IRCG = qfalse;
01155 
01156         cmd = CG_Argv(0);
01157 
01158         if ( !cmd[0] ) {
01159                 // server claimed the command
01160                 return;
01161         }
01162 
01163 #if 0
01164         // never seems to get used -Ste
01165         if ( !strcmp( cmd, "spd" ) ) 
01166         {
01167                 const char *ID;
01168                 int holdInt,count,i;
01169                 char string[1204];
01170 
01171                 count = trap_Argc();
01172 
01173                 ID =  CG_Argv(1);
01174                 holdInt = atoi(ID);
01175 
01176                 memset( &string, 0, sizeof( string ) );
01177 
01178                 Com_sprintf( string,sizeof(string)," \"%s\"", (const char *) CG_Argv(2));
01179 
01180                 for (i=3;i<count;i++)
01181                 {
01182                         Com_sprintf( string,sizeof(string)," %s \"%s\"", string, (const char *) CG_Argv(i));
01183                 }
01184 
01185                 trap_SP_Print(holdInt, (byte *)string);
01186                 return;
01187         }
01188 #endif
01189 
01190         if (!strcmp(cmd, "sxd"))
01191         { //siege extended data, contains extra info certain classes may want to know about other clients
01192         CG_ParseSiegeExtendedData();
01193                 return;
01194         }
01195 
01196         if (!strcmp(cmd, "sb"))
01197         { //siege briefing display
01198                 CG_SiegeBriefingDisplay(atoi(CG_Argv(1)), 0);
01199                 return;
01200         }
01201 
01202         if ( !strcmp( cmd, "scl" ) )
01203         {
01204                 //if (!( trap_Key_GetCatcher() & KEYCATCH_UI ))
01205                 //Well, I want it to come up even if the briefing display is up.
01206                 {
01207                         trap_OpenUIMenu(UIMENU_CLASSSEL); //UIMENU_CLASSSEL
01208                 }
01209                 return;
01210         }
01211 
01212         if ( !strcmp( cmd, "spc" ) )
01213         {
01214                 trap_Cvar_Set("ui_myteam", "3");
01215                 trap_OpenUIMenu(UIMENU_PLAYERCONFIG); //UIMENU_CLASSSEL
01216                 return;
01217         }
01218 
01219         if ( !strcmp( cmd, "nfr" ) )
01220         { //"nfr" == "new force rank" (want a short string)
01221                 int doMenu = 0;
01222                 int setTeam = 0;
01223                 int newRank = 0;
01224 
01225                 if (trap_Argc() < 3)
01226                 {
01227 #ifdef _DEBUG
01228                         Com_Printf("WARNING: Invalid newForceRank string\n");
01229 #endif
01230                         return;
01231                 }
01232 
01233                 newRank = atoi(CG_Argv(1));
01234                 doMenu = atoi(CG_Argv(2));
01235                 setTeam = atoi(CG_Argv(3));
01236 
01237                 trap_Cvar_Set("ui_rankChange", va("%i", newRank));
01238 
01239                 trap_Cvar_Set("ui_myteam", va("%i", setTeam));
01240 
01241                 if (!( trap_Key_GetCatcher() & KEYCATCH_UI ) && doMenu)
01242                 {
01243                         trap_OpenUIMenu(UIMENU_PLAYERCONFIG);
01244                 }
01245 
01246                 return;
01247         }
01248 
01249         if ( !strcmp( cmd, "kg2" ) )
01250         { //Kill a ghoul2 instance in this slot.
01251           //If it has been occupied since this message was sent somehow, the worst that can (should) happen
01252           //is the instance will have to reinit with its current info.
01253                 int indexNum = 0;
01254                 int argNum = trap_Argc();
01255                 int i = 1;
01256                 
01257                 if (argNum < 1)
01258                 {
01259                         return;
01260                 }
01261 
01262                 while (i < argNum)
01263                 {
01264                         indexNum = atoi(CG_Argv(i));
01265 
01266                         if (cg_entities[indexNum].ghoul2 && trap_G2_HaveWeGhoul2Models(cg_entities[indexNum].ghoul2))
01267                         {
01268                                 if (indexNum < MAX_CLIENTS)
01269                                 { //You try to do very bad thing!
01270 #ifdef _DEBUG
01271                                         Com_Printf("WARNING: Tried to kill a client ghoul2 instance with a kg2 command!\n");
01272 #endif
01273                                         return;
01274                                 }
01275 
01276                                 CG_KillCEntityG2(indexNum);
01277                         }
01278 
01279                         i++;
01280                 }
01281                 
01282                 return;
01283         }
01284 
01285         if (!strcmp(cmd, "kls"))
01286         { //kill looping sounds
01287                 int indexNum = 0;
01288                 int argNum = trap_Argc();
01289                 centity_t *clent = NULL;
01290                 centity_t *trackerent = NULL;
01291                 
01292                 if (argNum < 1)
01293                 {
01294                         assert(0);
01295                         return;
01296                 }
01297 
01298                 indexNum = atoi(CG_Argv(1));
01299 
01300                 if (indexNum != -1)
01301                 {
01302                         clent = &cg_entities[indexNum];
01303                 }
01304 
01305                 if (argNum >= 2)
01306                 {
01307                         indexNum = atoi(CG_Argv(2));
01308 
01309                         if (indexNum != -1)
01310                         {
01311                                 trackerent = &cg_entities[indexNum];
01312                         }
01313                 }
01314 
01315                 if (clent)
01316                 {
01317                         CG_S_StopLoopingSound(clent->currentState.number, -1);
01318                 }
01319                 if (trackerent)
01320                 {
01321                         CG_S_StopLoopingSound(trackerent->currentState.number, -1);
01322                 }
01323 
01324                 return;
01325         }
01326 
01327         if (!strcmp(cmd, "ircg"))
01328         { //this means param 2 is the body index and we want to copy to bodyqueue on it
01329                 IRCG = qtrue;
01330         }
01331 
01332         if (!strcmp(cmd, "rcg") || IRCG)
01333         { //rcg - Restore Client Ghoul (make sure limbs are reattached and ragdoll state is reset - this must be done reliably)
01334                 int indexNum = 0;
01335                 int argNum = trap_Argc();
01336                 centity_t *clent;
01337                 
01338                 if (argNum < 1)
01339                 {
01340                         assert(0);
01341                         return;
01342                 }
01343 
01344                 indexNum = atoi(CG_Argv(1));
01345                 if (indexNum < 0 || indexNum >= MAX_CLIENTS)
01346                 {
01347                         assert(0);
01348                         return;
01349                 }
01350 
01351                 clent = &cg_entities[indexNum];
01352 
01353                 //assert(clent->ghoul2);
01354                 if (!clent->ghoul2)
01355                 { //this can happen while connecting as a client
01356                         return;
01357                 }
01358 
01359 #ifdef _DEBUG
01360                 if (!trap_G2_HaveWeGhoul2Models(clent->ghoul2))
01361                 {
01362                         assert(!"Tried to reset state on a bad instance. Crash is inevitable.");
01363                 }
01364 #endif
01365 
01366                 if (IRCG)
01367                 {
01368                         int bodyIndex = 0;
01369                         int weaponIndex = 0;
01370                         int side = 0;
01371                         centity_t *body;
01372 
01373                         assert(argNum >= 3);
01374                         bodyIndex = atoi(CG_Argv(2));
01375                         weaponIndex = atoi(CG_Argv(3));
01376                         side = atoi(CG_Argv(4));
01377 
01378                         body = &cg_entities[bodyIndex];
01379 
01380                         if (side)
01381                         {
01382                                 body->teamPowerType = qtrue; //light side
01383                         }
01384                         else
01385                         {
01386                                 body->teamPowerType = qfalse; //dark side
01387                         }
01388 
01389                         CG_BodyQueueCopy(body, clent->currentState.number, weaponIndex);
01390                 }
01391 
01392                 //reattach any missing limbs
01393                 if (clent->torsoBolt)
01394                 {
01395                         CG_ReattachLimb(clent);
01396                 }
01397 
01398                 //make sure ragdoll state is reset
01399                 if (clent->isRagging)
01400                 {
01401                         clent->isRagging = qfalse;
01402                         trap_G2API_SetRagDoll(clent->ghoul2, NULL); //calling with null parms resets to no ragdoll.
01403                 }
01404                 
01405                 //clear all the decals as well
01406                 trap_G2API_ClearSkinGore(clent->ghoul2);
01407 
01408                 clent->weapon = 0;
01409                 clent->ghoul2weapon = NULL; //force a weapon reinit
01410 
01411                 return;
01412         }
01413 
01414         if ( !strcmp( cmd, "cp" ) ) {
01415                 char strEd[MAX_STRINGED_SV_STRING];
01416                 CG_CheckSVStringEdRef(strEd, CG_Argv(1));
01417                 CG_CenterPrint( strEd, SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
01418                 return;
01419         }
01420 
01421         if ( !strcmp( cmd, "cps" ) ) {
01422                 char strEd[MAX_STRINGED_SV_STRING];
01423                 char *x = (char *)CG_Argv(1);
01424                 if (x[0] == '@')
01425                 {
01426                         x++;
01427                 }
01428                 trap_SP_GetStringTextString(x, strEd, MAX_STRINGED_SV_STRING);
01429                 CG_CenterPrint( strEd, SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
01430                 return;
01431         }
01432 
01433         if ( !strcmp( cmd, "cs" ) ) {
01434                 CG_ConfigStringModified();
01435                 return;
01436         }
01437 
01438         if ( !strcmp( cmd, "print" ) ) {
01439                 char strEd[MAX_STRINGED_SV_STRING];
01440                 CG_CheckSVStringEdRef(strEd, CG_Argv(1));
01441                 CG_Printf( "%s", strEd );
01442                 return;
01443         }
01444 
01445         if ( !strcmp( cmd, "chat" ) ) {
01446                 if ( !cg_teamChatsOnly.integer ) {
01447                         trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
01448                         Q_strncpyz( text, CG_Argv(1), MAX_SAY_TEXT );
01449                         CG_RemoveChatEscapeChar( text );
01450                         CG_ChatBox_AddString(text);
01451                         CG_Printf( "*%s\n", text );
01452                 }
01453                 return;
01454         }
01455 
01456         if ( !strcmp( cmd, "tchat" ) ) {
01457                 trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
01458                 Q_strncpyz( text, CG_Argv(1), MAX_SAY_TEXT );
01459                 CG_RemoveChatEscapeChar( text );
01460                 CG_ChatBox_AddString(text);
01461                 CG_Printf( "*%s\n", text );
01462 
01463                 return;
01464         }
01465 
01466         //chat with location, possibly localized.
01467         if ( !strcmp( cmd, "lchat" ) ) {
01468                 if ( !cg_teamChatsOnly.integer ) {
01469                         char name[MAX_STRING_CHARS];
01470                         char loc[MAX_STRING_CHARS];
01471                         char color[8];
01472                         char message[MAX_STRING_CHARS];
01473 
01474                         if (trap_Argc() < 4)
01475                         {
01476                                 return;
01477                         }
01478 
01479                         strcpy(name, CG_Argv(1));
01480                         strcpy(loc, CG_Argv(2));
01481                         strcpy(color, CG_Argv(3));
01482                         strcpy(message, CG_Argv(4));
01483 
01484                         if (loc[0] == '@')
01485                         { //get localized text
01486                                 trap_SP_GetStringTextString(loc+1, loc, MAX_STRING_CHARS);
01487                         }
01488 
01489                         trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
01490                         //Q_strncpyz( text, CG_Argv(1), MAX_SAY_TEXT );
01491                         Com_sprintf(text, MAX_SAY_TEXT, "%s<%s>^%s%s", name, loc, color, message);
01492                         CG_RemoveChatEscapeChar( text );
01493                         CG_ChatBox_AddString(text);
01494                         CG_Printf( "*%s\n", text );
01495                 }
01496                 return;
01497         }
01498         if ( !strcmp( cmd, "ltchat" ) ) {
01499                 char name[MAX_STRING_CHARS];
01500                 char loc[MAX_STRING_CHARS];
01501                 char color[8];
01502                 char message[MAX_STRING_CHARS];
01503 
01504                 if (trap_Argc() < 4)
01505                 {
01506                         return;
01507                 }
01508 
01509                 strcpy(name, CG_Argv(1));
01510                 strcpy(loc, CG_Argv(2));
01511                 strcpy(color, CG_Argv(3));
01512                 strcpy(message, CG_Argv(4));
01513 
01514                 if (loc[0] == '@')
01515                 { //get localized text
01516                         trap_SP_GetStringTextString(loc+1, loc, MAX_STRING_CHARS);
01517                 }
01518 
01519                 trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
01520                 //Q_strncpyz( text, CG_Argv(1), MAX_SAY_TEXT );
01521                 Com_sprintf(text, MAX_SAY_TEXT, "%s<%s> ^%s%s", name, loc, color, message);
01522                 CG_RemoveChatEscapeChar( text );
01523                 CG_ChatBox_AddString(text);
01524                 CG_Printf( "*%s\n", text );
01525 
01526                 return;
01527         }
01528 
01529         if ( !strcmp( cmd, "scores" ) ) {
01530                 CG_ParseScores();
01531                 return;
01532         }
01533 
01534         if ( !strcmp( cmd, "tinfo" ) ) {
01535                 CG_ParseTeamInfo();
01536                 return;
01537         }
01538 
01539         if ( !strcmp( cmd, "map_restart" ) ) {
01540                 CG_MapRestart();
01541                 return;
01542         }
01543 
01544   if ( Q_stricmp (cmd, "remapShader") == 0 ) {
01545                 if (trap_Argc() == 4) {
01546                         trap_R_RemapShader(CG_Argv(1), CG_Argv(2), CG_Argv(3));
01547                 }
01548         }
01549 
01550         // loaddeferred can be both a servercmd and a consolecmd
01551         if ( !strcmp( cmd, "loaddefered" ) ) {  // FIXME: spelled wrong, but not changing for demo
01552                 CG_LoadDeferredPlayers();
01553                 return;
01554         }
01555 
01556         // clientLevelShot is sent before taking a special screenshot for
01557         // the menu system during development
01558         if ( !strcmp( cmd, "clientLevelShot" ) ) {
01559                 cg.levelShot = qtrue;
01560                 return;
01561         }
01562 
01563         CG_Printf( "Unknown client game command: %s\n", cmd );
01564 }
01565 
01566 
01567 /*
01568 ====================
01569 CG_ExecuteNewServerCommands
01570 
01571 Execute all of the server commands that were received along
01572 with this this snapshot.
01573 ====================
01574 */
01575 void CG_ExecuteNewServerCommands( int latestSequence ) {
01576         while ( cgs.serverCommandSequence < latestSequence ) {
01577                 if ( trap_GetServerCommand( ++cgs.serverCommandSequence ) ) {
01578                         CG_ServerCommand();
01579                 }
01580         }
01581 }
01582