summaryrefslogtreecommitdiff
path: root/src/cl_precache.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cl_precache.c')
-rw-r--r--src/cl_precache.c404
1 files changed, 404 insertions, 0 deletions
diff --git a/src/cl_precache.c b/src/cl_precache.c
new file mode 100644
index 0000000..a646d58
--- /dev/null
+++ b/src/cl_precache.c
@@ -0,0 +1,404 @@
+/*
+Copyright (C) 1997-2001 Id Software, Inc.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+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, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+//
+// cl_precache.c
+//
+
+#include "cl_local.h"
+
+/*
+================
+CL_ParsePlayerSkin
+
+Breaks up playerskin into name (optional), model and skin components.
+If model or skin are found to be invalid, replaces them with sane defaults.
+================
+*/
+void CL_ParsePlayerSkin( char *name, char *model, char *skin, const char *s ) {
+ size_t len;
+ char *t;
+
+ // configstring parsing guarantees that playerskins can never
+ // overflow, but still check the length to be entirely fool-proof
+ len = strlen( s );
+ if( len >= MAX_QPATH ) {
+ Com_Error( ERR_DROP, "%s: oversize playerskin", __func__ );
+ }
+
+ // isolate the player's name
+ t = strchr( s, '\\' );
+ if( t ) {
+ len = t - s;
+ strcpy( model, t + 1 );
+ } else {
+ len = 0;
+ strcpy( model, s );
+ }
+
+ // copy the player's name
+ if( name ) {
+ memcpy( name, s, len );
+ name[len] = 0;
+ }
+
+ // isolate the model name
+ t = strchr( model, '/' );
+ if( !t )
+ t = strchr( model, '\\' );
+ if( !t )
+ t = model;
+ if( t == model )
+ goto default_model;
+ *t++ = 0;
+
+ // apply restrictions on skins
+ if( cl_noskins->integer == 2 || !COM_IsPath( t ) )
+ goto default_skin;
+
+ if( cl_noskins->integer || !COM_IsPath( model ) )
+ goto default_model;
+
+ // isolate the skin name
+ strcpy( skin, t );
+ return;
+
+default_skin:
+ if( !Q_stricmp( model, "female" ) ) {
+ strcpy( model, "female" );
+ strcpy( skin, "athena" );
+ } else {
+default_model:
+ strcpy( model, "male" );
+ strcpy( skin, "grunt" );
+ }
+}
+
+/*
+================
+CL_LoadClientinfo
+
+================
+*/
+void CL_LoadClientinfo( clientinfo_t *ci, const char *s ) {
+ int i;
+ char model_name[MAX_QPATH];
+ char skin_name[MAX_QPATH];
+ char model_filename[MAX_QPATH];
+ char skin_filename[MAX_QPATH];
+ char weapon_filename[MAX_QPATH];
+ char icon_filename[MAX_QPATH];
+
+ CL_ParsePlayerSkin( ci->name, model_name, skin_name, s );
+
+ // model file
+ Q_concat( model_filename, sizeof( model_filename ),
+ "players/", model_name, "/tris.md2", NULL );
+ ci->model = R_RegisterModel( model_filename );
+ if( !ci->model && Q_stricmp( model_name, "male" ) ) {
+ strcpy( model_name, "male" );
+ strcpy( model_filename, "players/male/tris.md2" );
+ ci->model = R_RegisterModel( model_filename );
+ }
+
+ // skin file
+ Q_concat( skin_filename, sizeof( skin_filename ),
+ "players/", model_name, "/", skin_name, ".pcx", NULL );
+ ci->skin = R_RegisterSkin( skin_filename );
+
+ // if we don't have the skin and the model was female,
+ // see if athena skin exists
+ if( !ci->skin && !Q_stricmp( model_name, "female" ) ) {
+ strcpy( skin_name, "athena" );
+ strcpy( skin_filename, "players/female/athena.pcx" );
+ ci->skin = R_RegisterSkin( skin_filename );
+ }
+
+ // if we don't have the skin and the model wasn't male,
+ // see if the male has it (this is for CTF's skins)
+ if( !ci->skin && Q_stricmp( model_name, "male" ) ) {
+ // change model to male
+ strcpy( model_name, "male" );
+ strcpy( model_filename, "players/male/tris.md2" );
+ ci->model = R_RegisterModel( model_filename );
+
+ // see if the skin exists for the male model
+ Q_concat( skin_filename, sizeof( skin_filename ),
+ "players/male/", skin_name, ".pcx", NULL );
+ ci->skin = R_RegisterSkin( skin_filename );
+ }
+
+ // if we still don't have a skin, it means that the male model
+ // didn't have it, so default to grunt
+ if( !ci->skin ) {
+ // see if the skin exists for the male model
+ strcpy( skin_name, "grunt" );
+ strcpy( skin_filename, "players/male/grunt.pcx" );
+ ci->skin = R_RegisterSkin( skin_filename );
+ }
+
+ // weapon file
+ for( i = 0; i < cl.numWeaponModels; i++ ) {
+ Q_concat( weapon_filename, sizeof( weapon_filename ),
+ "players/", model_name, "/", cl.weaponModels[i], NULL );
+ ci->weaponmodel[i] = R_RegisterModel( weapon_filename );
+ if( !ci->weaponmodel[i] && Q_stricmp( model_name, "male" ) ) {
+ // try male
+ Q_concat( weapon_filename, sizeof( weapon_filename ),
+ "players/male/", cl.weaponModels[i], NULL );
+ ci->weaponmodel[i] = R_RegisterModel( weapon_filename );
+ }
+ }
+
+ // icon file
+ Q_concat( icon_filename, sizeof( icon_filename ),
+ "/players/", model_name, "/", skin_name, "_i.pcx", NULL );
+ ci->icon = R_RegisterPic( icon_filename );
+
+ strcpy( ci->model_name, model_name );
+ strcpy( ci->skin_name, skin_name );
+
+ // must have loaded all data types to be valid
+ if( !ci->skin || !ci->icon || !ci->model || !ci->weaponmodel[0] ) {
+ ci->skin = 0;
+ ci->icon = 0;
+ ci->model = 0;
+ ci->weaponmodel[0] = 0;
+ ci->model_name[0] = 0;
+ ci->skin_name[0] = 0;
+ }
+}
+
+/*
+=================
+CL_LoadState
+=================
+*/
+void CL_LoadState( load_state_t state ) {
+ extern void VID_PumpEvents( void );
+ const char *s;
+
+ switch( state ) {
+ case LOAD_MAP:
+ s = cl.configstrings[ CS_MODELS + 1 ];
+ break;
+ case LOAD_MODELS:
+ s = "models";
+ break;
+ case LOAD_IMAGES:
+ s = "images";
+ break;
+ case LOAD_CLIENTS:
+ s = "clients";
+ break;
+ case LOAD_SOUNDS:
+ s = "sounds";
+ break;
+ case LOAD_FINISH:
+ s = NULL;
+ break;
+ default:
+ return;
+ }
+
+ if( s ) {
+ Con_Printf( "Loading %s...\r", s );
+ } else {
+ Con_Print( "\r" );
+ }
+
+ SCR_UpdateScreen();
+ VID_PumpEvents();
+}
+
+/*
+=================
+CL_RegisterSounds
+=================
+*/
+void CL_RegisterSounds( void ) {
+ int i;
+ char *s;
+
+ S_BeginRegistration ();
+ CL_RegisterTEntSounds ();
+ for ( i = 1; i < MAX_SOUNDS; i++ ) {
+ s = cl.configstrings[ CS_SOUNDS + i ];
+ if ( !s[ 0 ] )
+ break;
+ cl.sound_precache[ i ] = S_RegisterSound( s );
+ }
+ S_EndRegistration ();
+}
+
+/*
+=================
+CL_RegisterBspModels
+
+Registers main BSP file and inline models
+=================
+*/
+void CL_RegisterBspModels( void ) {
+ qerror_t ret;
+ char *name;
+ int i;
+
+ ret = BSP_Load( cl.configstrings[ CS_MODELS + 1 ], &cl.bsp );
+ if( cl.bsp == NULL ) {
+ Com_Error( ERR_DROP, "Couldn't load %s: %s",
+ cl.configstrings[ CS_MODELS + 1 ], Q_ErrorString( ret ) );
+ }
+
+#if USE_MAPCHECKSUM
+ if( cl.bsp->checksum != atoi( cl.configstrings[ CS_MAPCHECKSUM ] ) ) {
+ if( cls.demo.playback ) {
+ Com_WPrintf( "Local map version differs from demo: %i != %s\n",
+ cl.bsp->checksum, cl.configstrings[ CS_MAPCHECKSUM ] );
+ } else {
+ Com_Error( ERR_DROP, "Local map version differs from server: %i != %s",
+ cl.bsp->checksum, cl.configstrings[ CS_MAPCHECKSUM ] );
+ }
+ }
+#endif
+
+ for ( i = 1; i < MAX_MODELS; i++ ) {
+ name = cl.configstrings[CS_MODELS+i];
+ if( !name[0] ) {
+ break;
+ }
+ if( name[0] == '*' )
+ cl.model_clip[i] = BSP_InlineModel( cl.bsp, name );
+ else
+ cl.model_clip[i] = NULL;
+ }
+}
+
+/*
+=================
+CL_RegisterVWepModels
+
+Builds a list of visual weapon models
+=================
+*/
+void CL_RegisterVWepModels( void ) {
+ int i;
+ char *name;
+
+ cl.numWeaponModels = 1;
+ strcpy( cl.weaponModels[0], "weapon.md2" );
+
+ // only default model when vwep is off
+ if( !cl_vwep->integer ) {
+ return;
+ }
+
+ for( i = 2; i < MAX_MODELS; i++ ) {
+ name = cl.configstrings[ CS_MODELS + i ];
+ if( !name[0] ) {
+ break;
+ }
+ if( name[0] != '#' ) {
+ continue;
+ }
+
+ // special player weapon model
+ strcpy( cl.weaponModels[cl.numWeaponModels++], name + 1 );
+
+ if( cl.numWeaponModels == MAX_CLIENTWEAPONMODELS ) {
+ break;
+ }
+ }
+}
+
+/*
+=================
+CL_PrepRefresh
+
+Call before entering a new level, or after changing dlls
+=================
+*/
+void CL_PrepRefresh (void) {
+ int i;
+ char *name;
+ float rotate;
+ vec3_t axis;
+
+ if( !cls.ref_initialized )
+ return;
+ if( !cl.mapname[0] )
+ return; // no map loaded
+
+ // register models, pics, and skins
+ R_BeginRegistration( cl.mapname );
+
+ CL_LoadState( LOAD_MODELS );
+
+ CL_RegisterTEntModels ();
+
+ for( i = 2; i < MAX_MODELS; i++ ) {
+ name = cl.configstrings[ CS_MODELS + i ];
+ if( !name[0] ) {
+ break;
+ }
+ if( name[0] == '#' ) {
+ continue;
+ }
+ cl.model_draw[i] = R_RegisterModel( name );
+ }
+
+ CL_LoadState( LOAD_IMAGES );
+ for( i = 1; i < MAX_IMAGES; i++ ) {
+ name = cl.configstrings[ CS_IMAGES + i ];
+ if( !name[0] ) {
+ break;
+ }
+ cl.image_precache[i] = R_RegisterPic( name );
+ }
+
+ CL_LoadState( LOAD_CLIENTS );
+ for(i = 0; i < MAX_CLIENTS; i++ ) {
+ name = cl.configstrings[ CS_PLAYERSKINS + i ];
+ if( !name[0] ) {
+ continue;
+ }
+ CL_LoadClientinfo( &cl.clientinfo[i], name );
+ }
+
+ CL_LoadClientinfo( &cl.baseclientinfo, "unnamed\\male/grunt" );
+
+ // set sky textures and speed
+ rotate = atof( cl.configstrings[CS_SKYROTATE] );
+ if( sscanf( cl.configstrings[CS_SKYAXIS], "%f %f %f",
+ &axis[0], &axis[1], &axis[2]) != 3 )
+ {
+ Com_DPrintf( "Couldn't parse CS_SKYAXIS\n" );
+ VectorClear( axis );
+ }
+ R_SetSky( cl.configstrings[CS_SKY], rotate, axis );
+
+ // the renderer can now free unneeded stuff
+ R_EndRegistration();
+
+ // clear any lines of console text
+ Con_ClearNotify_f();
+
+ SCR_UpdateScreen();
+}
+