/* =========================================================================== Copyright (C) 1999 - 2005, Id Software, Inc. Copyright (C) 2000 - 2013, Raven Software, Inc. Copyright (C) 2001 - 2013, Activision, Inc. Copyright (C) 2013 - 2015, OpenJK contributors This file is part of the OpenJK source code. OpenJK is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program 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 this program; if not, see . =========================================================================== */ // cg_servercmds.c -- text commands sent by the server #include "cg_local.h" #include "cg_media.h" #include "FxScheduler.h" /* ================ CG_ParseServerinfo 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; const char *mapname; info = CG_ConfigString( CS_SERVERINFO ); cgs.dmflags = atoi( Info_ValueForKey( info, "dmflags" ) ); cgs.teamflags = atoi( Info_ValueForKey( info, "teamflags" ) ); cgs.timelimit = atoi( Info_ValueForKey( info, "timelimit" ) ); cgs.maxclients = 1; mapname = Info_ValueForKey( info, "mapname" ); Com_sprintf( cgs.mapname, sizeof( cgs.mapname ), "maps/%s.bsp", mapname ); const char *p = strrchr(mapname,'/'); Q_strncpyz( cgs.stripLevelName[0], p?p+1:mapname, sizeof(cgs.stripLevelName[0]) ); Q_strupr( cgs.stripLevelName[0] ); for (int i=1; i= CS_MODELS && num < CS_MODELS+MAX_MODELS ) { cgs.model_draw[ num-CS_MODELS ] = cgi_R_RegisterModel( str ); // OutputDebugString(va("### CG_ConfigStringModified(): cgs.model_draw[%d] = \"%s\"\n",num-CS_MODELS,str)); // GHOUL2 Insert start } else if ( num >= CS_CHARSKINS && num < CS_CHARSKINS+MAX_CHARSKINS ) { cgs.skins[ num-CS_CHARSKINS ] = cgi_R_RegisterSkin( str ); // Ghoul2 Insert end } else if ( num >= CS_SOUNDS && num < CS_SOUNDS+MAX_SOUNDS ) { if ( str[0] != '*' ) { cgs.sound_precache[ num-CS_SOUNDS] = cgi_S_RegisterSound( str ); } } else if ( num >= CS_EFFECTS && num < CS_EFFECTS + MAX_FX ) { theFxScheduler.RegisterEffect( str ); } else if ( num >= CS_PLAYERS && num < CS_PLAYERS+MAX_CLIENTS ) { CG_NewClientinfo( num - CS_PLAYERS ); CG_RegisterClientModels( num - CS_PLAYERS ); } else if ( num >= CS_LIGHT_STYLES && num < CS_LIGHT_STYLES + (MAX_LIGHT_STYLES*3)) { CG_SetLightstyle(num - CS_LIGHT_STYLES); } else if ( num >= CS_WORLD_FX && num < CS_WORLD_FX + MAX_WORLD_FX ) { cgi_R_WorldEffectCommand( str ); } } static void CG_CenterPrint_f( void ) { CG_CenterPrint( CG_Argv( 1 ), SCREEN_HEIGHT * 0.25 ); } static void CG_Print_f( void ) { CG_Printf( "%s", CG_Argv( 1 ) ); } static void CG_CaptionText_f( void ) { sfxHandle_t sound = (sfxHandle_t)atoi( CG_Argv( 2 ) ); CG_CaptionText( CG_Argv( 1 ), sound >= 0 && sound < MAX_SOUNDS ? cgs.sound_precache[sound] : NULL_SOUND ); } static void CG_ScrollText_f( void ) { CG_ScrollText( CG_Argv( 1 ), SCREEN_WIDTH - 16 ); } static void CG_LCARSText_f( void ) { CG_Printf( "CG_LCARSText() being called. Tell Ste\n" "String: \"%s\"\n", CG_Argv( 1 ) ); } static void CG_ClientLevelShot_f( void ) { // clientLevelShot is sent before taking a special screenshot for // the menu system during development cg.levelShot = qtrue; } typedef struct serverCommand_s { const char *cmd; void( *func )(void); } serverCommand_t; static int svcmdcmp( const void *a, const void *b ) { return Q_stricmp( (const char *)a, ((serverCommand_t*)b)->cmd ); } /* This array MUST be sorted correctly by alphabetical name field */ static serverCommand_t commands[] = { { "chat", CG_Print_f }, { "clientLevelShot", CG_ClientLevelShot_f }, { "cp", CG_CenterPrint_f }, { "cs", CG_ConfigStringModified }, { "ct", CG_CaptionText_f }, { "cts", CG_CaptionTextStop }, { "lt", CG_LCARSText_f }, { "print", CG_Print_f }, { "st", CG_ScrollText_f }, }; static const size_t numCommands = ARRAY_LEN( commands ); /* ================= CG_ServerCommand The string has been tokenized and can be retrieved with Cmd_Argc() / Cmd_Argv() ================= */ static void CG_ServerCommand( void ) { const char *cmd = CG_Argv( 0 ); serverCommand_t *command = NULL; if ( !cmd[0] ) { // server claimed the command return; } command = (serverCommand_t *)Q_LinearSearch( cmd, commands, numCommands, sizeof( commands[0] ), svcmdcmp ); if ( command ) { command->func(); return; } CG_Printf( "Unknown client game command: %s\n", cmd ); } /* ==================== CG_ExecuteNewServerCommands Execute all of the server commands that were received along with this this snapshot. ==================== */ void CG_ExecuteNewServerCommands( int latestSequence ) { while ( cgs.serverCommandSequence < latestSequence ) { if ( cgi_GetServerCommand( ++cgs.serverCommandSequence ) ) { CG_ServerCommand(); } } }