diff --git a/engine/client/avi/avi_win.c b/engine/client/avi/avi_win.c index 256ef20e..616e2ca2 100644 --- a/engine/client/avi/avi_win.c +++ b/engine/client/avi/avi_win.c @@ -402,8 +402,11 @@ long AVI_GetAudioChunk( movie_state_t *Avi, char *audiodata, long offset, long l } else { + // we out of soundtrack, just zeroing buffer for( i = 0; i < length; i++ ) audiodata[i] = 0; + + return length; } } diff --git a/engine/client/cl_cmds.c b/engine/client/cl_cmds.c index c69a6b5e..a5d711d6 100644 --- a/engine/client/cl_cmds.c +++ b/engine/client/cl_cmds.c @@ -345,7 +345,7 @@ void CL_LevelShot_f( void ) if( cls.demoplayback && ( cls.demonum != -1 )) { Q_sprintf( cls.shotname, "levelshots/%s_%s.bmp", cls.demoname, glState.wideScreen ? "16x9" : "4x3" ); - Q_snprintf( filename, sizeof( filename ), "demos/%s.dem", cls.demoname ); + Q_snprintf( filename, sizeof( filename ), "%s.dem", cls.demoname ); // make sure what levelshot is newer than demo ft1 = FS_FileTime( filename, false ); @@ -385,25 +385,6 @@ void CL_SaveShot_f( void ) cls.scrshot_action = scrshot_savegame; // build new frame for saveshot } -/* -================== -CL_DemoShot_f - -mini-pic in playdemo menu -================== -*/ -void CL_DemoShot_f( void ) -{ - if( Cmd_Argc() < 2 ) - { - Con_Printf( S_USAGE "demoshot \n" ); - return; - } - - Q_sprintf( cls.shotname, "demos/%s.bmp", Cmd_Argv( 1 )); - cls.scrshot_action = scrshot_demoshot; // build new frame for demoshot -} - /* ============== CL_DeleteDemo_f @@ -424,9 +405,8 @@ void CL_DeleteDemo_f( void ) return; } - // delete save and saveshot - FS_Delete( va( "demos/%s.dem", Cmd_Argv( 1 ))); - FS_Delete( va( "demos/%s.bmp", Cmd_Argv( 1 ))); + // delete demo + FS_Delete( va( "%s.dem", Cmd_Argv( 1 ))); } /* diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index a3ab3ec5..962e99c2 100644 --- a/engine/client/cl_demo.c +++ b/engine/client/cl_demo.c @@ -669,31 +669,6 @@ void CL_DemoStartPlayback( int mode ) cl.last_command_ack = -1; } -/* -================= -CL_PlayDemoQuake -================= -*/ -void CL_PlayDemoQuake( const char *demoname ) -{ - int c, neg = false; - - cls.demofile = FS_Open( demoname, "rb", true ); - Q_strncpy( cls.demoname, demoname, sizeof( cls.demoname )); - Q_strncpy( gameui.globals->demoname, demoname, sizeof( gameui.globals->demoname )); - demo.header.host_fps = host_maxfps->value; - cls.forcetrack = 0; - - while(( c = FS_Getc( cls.demofile )) != '\n' ) - { - if( c == '-' ) neg = true; - else cls.forcetrack = cls.forcetrack * 10 + (c - '0'); - } - - if( neg ) cls.forcetrack = -cls.forcetrack; - CL_DemoStartPlayback( DEMO_QUAKE1 ); -} - /* ================= CL_DemoAborted @@ -1178,6 +1153,7 @@ void CL_StopPlayback( void ) // let game known about demo state Cvar_FullSet( "cl_background", "0", FCVAR_READ_ONLY ); cls.state = ca_disconnected; + cls.set_lastdemo = false; S_StopBackgroundTrack(); cls.connect_time = 0; cls.demonum = -1; @@ -1356,8 +1332,8 @@ Begins recording a demo from the current position */ void CL_Record_f( void ) { + string demoname, demopath; const char *name; - string demoname, demopath, demoshot; int n; if( Cmd_Argc() == 1 ) @@ -1398,7 +1374,7 @@ void CL_Record_f( void ) for( n = 0; n < 10000; n++ ) { CL_DemoGetName( n, demoname ); - if( !FS_FileExists( va( "demos/%s.dem", demoname ), true )) + if( !FS_FileExists( va( "%s.dem", demoname ), true )) break; } @@ -1411,18 +1387,12 @@ void CL_Record_f( void ) else Q_strncpy( demoname, name, sizeof( demoname )); // open the demo file - Q_sprintf( demopath, "demos/%s.dem", demoname ); - Q_sprintf( demoshot, "demos/%s.bmp", demoname ); - - // unload previous image from memory (it's will be overwritten) - GL_FreeImage( demoshot ); + Q_sprintf( demopath, "%s.dem", demoname ); // make sure what old demo is removed - if( FS_FileExists( demopath, false )) FS_Delete( demopath ); - if( FS_FileExists( demoshot, false )) FS_Delete( demoshot ); + if( FS_FileExists( demopath, false )) + FS_Delete( demopath ); - // write demoshot for preview - Cbuf_AddText( va( "demoshot \"%s\"\n", demoname )); Q_strncpy( cls.demoname, demoname, sizeof( cls.demoname )); Q_strncpy( gameui.globals->demoname, demoname, sizeof( gameui.globals->demoname )); @@ -1438,12 +1408,11 @@ playdemo */ void CL_PlayDemo_f( void ) { - char filename1[MAX_QPATH]; - char filename2[MAX_QPATH]; + char filename[MAX_QPATH]; char demoname[MAX_QPATH]; - int i; + int i, ident; - if( Cmd_Argc() != 2 ) + if( Cmd_Argc() < 2 ) { Con_Printf( S_USAGE "playdemo \n" ); return; @@ -1462,26 +1431,50 @@ void CL_PlayDemo_f( void ) Q_strncpy( demoname, Cmd_Argv( 1 ), sizeof( demoname )); COM_StripExtension( demoname ); - Q_snprintf( filename1, sizeof( filename1 ), "%s.dem", demoname ); - Q_snprintf( filename2, sizeof( filename2 ), "demos/%s.dem", demoname ); + Q_snprintf( filename, sizeof( filename ), "%s.dem", demoname ); - if( FS_FileExists( filename1, true )) + // hidden parameter + if( Cmd_Argc() > 2 ) + cls.set_lastdemo = Q_atoi( Cmd_Argv( 2 )); + + // member last demo + if( cls.set_lastdemo ) + Cvar_Set( "lastdemo", demoname ); + + if( !FS_FileExists( filename, true )) { - CL_PlayDemoQuake( filename1 ); - return; - } - else if( !FS_FileExists( filename2, true )) - { - Con_Printf( S_ERROR "couldn't open %s\n", filename2 ); + Con_Printf( S_ERROR "couldn't open %s\n", filename ); CL_DemoAborted(); return; } - cls.demofile = FS_Open( filename2, "rb", true ); + cls.demofile = FS_Open( filename, "rb", true ); Q_strncpy( cls.demoname, demoname, sizeof( cls.demoname )); Q_strncpy( gameui.globals->demoname, demoname, sizeof( gameui.globals->demoname )); - // read in the m_DemoHeader + FS_Read( cls.demofile, &ident, sizeof( int )); + FS_Seek( cls.demofile, 0, SEEK_SET ); // rewind back to start + cls.forcetrack = 0; + + // check for quake demos + if( ident != IDEMOHEADER ) + { + int c, neg = false; + + demo.header.host_fps = host_maxfps->value; + + while(( c = FS_Getc( cls.demofile )) != '\n' ) + { + if( c == '-' ) neg = true; + else cls.forcetrack = cls.forcetrack * 10 + (c - '0'); + } + + if( neg ) cls.forcetrack = -cls.forcetrack; + CL_DemoStartPlayback( DEMO_QUAKE1 ); + return; // quake demo is started + } + + // read in the demo header FS_Read( cls.demofile, &demo.header, sizeof( demoheader_t )); if( demo.header.id != IDEMOHEADER ) diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index b77f05a4..f9992548 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -1390,6 +1390,7 @@ void CL_Disconnect( void ) Netchan_Clear( &cls.netchan ); cls.state = ca_disconnected; + cls.set_lastdemo = false; cls.connect_retry = 0; cls.signon = 0; @@ -2616,6 +2617,7 @@ void CL_InitLocal( void ) hud_scale = Cvar_Get( "hud_scale", "0", FCVAR_ARCHIVE|FCVAR_LATCH, "scale hud at current resolution" ); Cvar_Get( "cl_background", "0", FCVAR_READ_ONLY, "indicate what background map is running" ); cl_showevents = Cvar_Get( "cl_showevents", "0", FCVAR_ARCHIVE, "show events playback" ); + Cvar_Get( "lastdemo", "", FCVAR_ARCHIVE, "last played demo" ); // these two added to shut up CS 1.5 about 'unknown' commands Cvar_Get( "lightgamma", "1", FCVAR_ARCHIVE, "ambient lighting level (legacy, unused)" ); @@ -2647,7 +2649,7 @@ void CL_InitLocal( void ) Cmd_AddCommand ("record", CL_Record_f, "record a demo" ); Cmd_AddCommand ("playdemo", CL_PlayDemo_f, "play a demo" ); Cmd_AddCommand ("timedemo", CL_TimeDemo_f, "demo benchmark" ); - Cmd_AddCommand ("killdemo", CL_DeleteDemo_f, "delete a specified demo file and demoshot" ); + Cmd_AddCommand ("killdemo", CL_DeleteDemo_f, "delete a specified demo file" ); Cmd_AddCommand ("startdemos", CL_StartDemos_f, "start playing back the selected demos sequentially" ); Cmd_AddCommand ("demos", CL_Demos_f, "restart looping demos defined by the last startdemos command" ); Cmd_AddCommand ("movie", CL_PlayVideo_f, "play a movie" ); @@ -2669,7 +2671,6 @@ void CL_InitLocal( void ) Cmd_AddCommand ("skyshot", CL_SkyShot_f, "takes a six-sides envmap (skybox) shot with specified name" ); Cmd_AddCommand ("levelshot", CL_LevelShot_f, "same as \"screenshot\", used for create plaque images" ); Cmd_AddCommand ("saveshot", CL_SaveShot_f, "used for create save previews with LoadGame menu" ); - Cmd_AddCommand ("demoshot", CL_DemoShot_f, "used for create demo previews with PlayDemo menu" ); Cmd_AddCommand ("connect", CL_Connect_f, "connect to a server by hostname" ); Cmd_AddCommand ("reconnect", CL_Reconnect_f, "reconnect to current level" ); diff --git a/engine/client/cl_scrn.c b/engine/client/cl_scrn.c index 89218197..65f590b3 100644 --- a/engine/client/cl_scrn.c +++ b/engine/client/cl_scrn.c @@ -255,7 +255,6 @@ void SCR_MakeScreenShot( void ) iRet = VID_ScreenShot( cls.shotname, VID_LEVELSHOT ); break; case scrshot_savegame: - case scrshot_demoshot: iRet = VID_ScreenShot( cls.shotname, VID_MINISHOT ); break; case scrshot_envshot: diff --git a/engine/client/cl_view.c b/engine/client/cl_view.c index 66f0519e..0e93b736 100644 --- a/engine/client/cl_view.c +++ b/engine/client/cl_view.c @@ -384,6 +384,7 @@ void V_PostRender( void ) CL_DrawDemoRecording(); CL_DrawHUD( CL_CHANGELEVEL ); R_ShowTextures(); + R_ShowTree(); Con_DrawConsole(); UI_UpdateMenu( host.realtime ); Con_DrawVersion(); diff --git a/engine/client/client.h b/engine/client/client.h index b9ba648d..91ad215c 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -320,7 +320,6 @@ typedef enum scrshot_snapshot, // in-game snapshot scrshot_plaque, // levelshot scrshot_savegame, // saveshot - scrshot_demoshot, // for demos preview scrshot_envshot, // cubemap view scrshot_skyshot, // skybox view scrshot_mapshot // overview layer @@ -656,6 +655,7 @@ typedef struct qboolean timedemo; string demoname; // for demo looping double demotime; // recording time + qboolean set_lastdemo; // store name of last played demo into the cvar file_t *demofile; file_t *demoheader; // contain demo startup info in case we record a demo on this level @@ -743,7 +743,6 @@ void CL_PlayCDTrack_f( void ); void CL_EnvShot_f( void ); void CL_SkyShot_f( void ); void CL_SaveShot_f( void ); -void CL_DemoShot_f( void ); void CL_LevelShot_f( void ); void CL_SetSky_f( void ); void SCR_Viewpos_f( void ); diff --git a/engine/client/gl_backend.c b/engine/client/gl_backend.c index 438cc40b..84c7a352 100644 --- a/engine/client/gl_backend.c +++ b/engine/client/gl_backend.c @@ -654,7 +654,7 @@ void R_ShowTextures( void ) static qboolean showHelp = true; string shortname; - if( !gl_showtextures->value ) + if( !CVAR_TO_BOOL( gl_showtextures )) return; if( showHelp ) @@ -747,3 +747,95 @@ rebuild_page: CL_DrawCenterPrint (); pglFinish(); } + +#define POINT_SIZE 16.0f +#define NODE_INTERVAL_X(x) (x * 16.0f) +#define NODE_INTERVAL_Y(x) (x * 16.0f) + +void R_DrawLeafNode( float x, float y, float scale ) +{ + float downScale = scale * 0.25f;// * POINT_SIZE; + + R_DrawStretchPic( x - downScale * 0.5f, y - downScale * 0.5f, downScale, downScale, 0, 0, 1, 1, tr.particleTexture ); +} + +void R_DrawNodeConnection( float x, float y, float x2, float y2 ) +{ + pglBegin( GL_LINES ); + pglVertex2f( x, y ); + pglVertex2f( x2, y2 ); + pglEnd(); +} + +void R_ShowTree_r( mnode_t *node, float x, float y, float scale, int shownodes ) +{ + float downScale = scale * 0.8f; + + downScale = Q_max( downScale, 1.0f ); + + if( !node ) return; + + tr.recursion_level++; + + if( node->contents < 0 ) + { + mleaf_t *leaf = (mleaf_t *)node; + + if( tr.recursion_level > tr.max_recursion ) + tr.max_recursion = tr.recursion_level; + + if( shownodes == 1 ) + { + if( cl.worldmodel->leafs == leaf ) + pglColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); + else if( RI.viewleaf && RI.viewleaf == leaf ) + pglColor4f( 1.0f, 0.0f, 0.0f, 1.0f ); + else pglColor4f( 0.0f, 1.0f, 0.0f, 1.0f ); + R_DrawLeafNode( x, y, scale ); + } + tr.recursion_level--; + return; + } + + if( shownodes == 1 ) + { + pglColor4f( 0.0f, 0.0f, 1.0f, 1.0f ); + R_DrawLeafNode( x, y, scale ); + } + else if( shownodes == 2 ) + { + R_DrawNodeConnection( x, y, x - scale, y + scale ); + R_DrawNodeConnection( x, y, x + scale, y + scale ); + } + + R_ShowTree_r( node->children[1], x - scale, y + scale, downScale, shownodes ); + R_ShowTree_r( node->children[0], x + scale, y + scale, downScale, shownodes ); + + tr.recursion_level--; +} + +void R_ShowTree( void ) +{ + float x = (float)((glState.width - (int)POINT_SIZE) >> 1); + float y = NODE_INTERVAL_Y(1.0); + + if( !cl.worldmodel || !CVAR_TO_BOOL( r_showtree )) + return; + + tr.recursion_level = 0; + + pglEnable( GL_BLEND ); + pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); + + pglLineWidth( 2.0f ); + pglColor3f( 1, 0.7f, 0 ); + pglDisable( GL_TEXTURE_2D ); + R_ShowTree_r( cl.worldmodel->nodes, x, y, tr.max_recursion * 3.5f, 2 ); + pglEnable( GL_TEXTURE_2D ); + pglLineWidth( 1.0f ); + + R_ShowTree_r( cl.worldmodel->nodes, x, y, tr.max_recursion * 3.5f, 1 ); + + Con_NPrintf( 0, "max recursion %d\n", tr.max_recursion ); +} diff --git a/engine/client/gl_local.h b/engine/client/gl_local.h index f9b124c9..0f89427b 100644 --- a/engine/client/gl_local.h +++ b/engine/client/gl_local.h @@ -202,6 +202,10 @@ typedef struct qboolean fResetVis; qboolean fFlipViewModel; + // tree visualization stuff + int recursion_level; + int max_recursion; + byte visbytes[(MAX_MAP_LEAFS+7)/8]; // member custom PVS int lightstylevalue[MAX_LIGHTSTYLES]; // value 0 - 65536 int block_size; // lightmap blocksize @@ -268,6 +272,7 @@ void GL_SetRenderMode( int mode ); void GL_TextureTarget( uint target ); void GL_Cull( GLenum cull ); void R_ShowTextures( void ); +void R_ShowTree( void ); // // gl_cull.c @@ -654,6 +659,7 @@ extern convar_t *gl_stencilbits; extern convar_t *r_speeds; extern convar_t *r_fullbright; extern convar_t *r_norefresh; +extern convar_t *r_showtree; // build graph of visible hull extern convar_t *r_lighting_extended; extern convar_t *r_lighting_modulate; extern convar_t *r_lighting_ambient; diff --git a/engine/client/gl_rmain.c b/engine/client/gl_rmain.c index c03cf17e..b305b99f 100644 --- a/engine/client/gl_rmain.c +++ b/engine/client/gl_rmain.c @@ -659,13 +659,21 @@ static void R_CheckFog( void ) int i, cnt, count; // quake global fog - if( clgame.movevars.fog_settings != 0 && Host_IsQuakeCompatible( )) + if( Host_IsQuakeCompatible( )) { + if( !clgame.movevars.fog_settings ) + { + if( pglIsEnabled( GL_FOG )) + pglDisable( GL_FOG ); + RI.fogEnabled = false; + return; + } + // quake-style global fog RI.fogColor[0] = ((clgame.movevars.fog_settings & 0xFF000000) >> 24) / 255.0f; RI.fogColor[1] = ((clgame.movevars.fog_settings & 0xFF0000) >> 16) / 255.0f; RI.fogColor[2] = ((clgame.movevars.fog_settings & 0xFF00) >> 8) / 255.0f; - RI.fogDensity = ((clgame.movevars.fog_settings & 0xFF) / 255.0f) * 0.015625f; + RI.fogDensity = ((clgame.movevars.fog_settings & 0xFF) / 255.0f) * 0.01f; RI.fogStart = RI.fogEnd = 0.0f; RI.fogColor[3] = 1.0f; RI.fogCustom = false; @@ -774,7 +782,9 @@ void R_DrawFog( void ) if( !RI.fogEnabled ) return; pglEnable( GL_FOG ); - pglFogi( GL_FOG_MODE, GL_EXP ); + if( CL_IsQuakeCompatible( )) + pglFogi( GL_FOG_MODE, GL_EXP2 ); + else pglFogi( GL_FOG_MODE, GL_EXP ); pglFogf( GL_FOG_DENSITY, RI.fogDensity ); pglFogfv( GL_FOG_COLOR, RI.fogColor ); pglHint( GL_FOG_HINT, GL_NICEST ); @@ -988,7 +998,6 @@ qboolean R_DoResetGamma( void ) return false; case scrshot_plaque: case scrshot_savegame: - case scrshot_demoshot: case scrshot_envshot: case scrshot_skyshot: case scrshot_mapshot: diff --git a/engine/client/gl_rmisc.c b/engine/client/gl_rmisc.c index 46e029a5..a7d55c4e 100644 --- a/engine/client/gl_rmisc.c +++ b/engine/client/gl_rmisc.c @@ -179,6 +179,7 @@ void R_NewMap( void ) cl.worldmodel->leafs[i+1].efrags = NULL; tr.skytexturenum = -1; + tr.max_recursion = 0; pglDisable( GL_FOG ); // clearing texture chains diff --git a/engine/client/gl_warp.c b/engine/client/gl_warp.c index bb997b4f..a4ea724d 100644 --- a/engine/client/gl_warp.c +++ b/engine/client/gl_warp.c @@ -372,6 +372,9 @@ void R_DrawSkyBox( void ) // don't fogging skybox (this fix old Half-Life bug) if( !RI.fogSkybox ) R_AllowFog( false ); + if( RI.fogEnabled ) + pglFogf( GL_FOG_DENSITY, RI.fogDensity * 0.5f ); + pglDisable( GL_BLEND ); pglDisable( GL_ALPHA_TEST ); pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE ); @@ -395,6 +398,10 @@ void R_DrawSkyBox( void ) if( !RI.fogSkybox ) R_AllowFog( true ); + + if( RI.fogEnabled ) + pglFogf( GL_FOG_DENSITY, RI.fogDensity ); + R_LoadIdentity(); } diff --git a/engine/client/s_main.c b/engine/client/s_main.c index 1867de2a..8e1d3dac 100644 --- a/engine/client/s_main.c +++ b/engine/client/s_main.c @@ -1584,7 +1584,7 @@ S_RawSamples */ void S_RawSamples( uint samples, uint rate, word width, word channels, const byte *data, int entnum ) { - int snd_vol; + int snd_vol = 128; if( entnum < 0 ) snd_vol = 256; // bg track or movie track if( snd_vol < 0 ) snd_vol = 0; // fixup negative values diff --git a/engine/common/con_utils.c b/engine/common/con_utils.c index 6e8927d6..697fa80b 100644 --- a/engine/common/con_utils.c +++ b/engine/common/con_utils.c @@ -207,7 +207,8 @@ qboolean Cmd_GetDemoList( const char *s, char *completedname, int length ) string matchbuf; int i, numdems; - t = FS_Search( va( "demos/%s*.dem", s ), true, true ); // lookup only in gamedir + // lookup only in gamedir + t = FS_Search( va( "%s*.dem", s ), true, true ); if( !t ) return false; COM_FileBase( t->filenames[0], matchbuf ); diff --git a/engine/common/mod_bmodel.c b/engine/common/mod_bmodel.c index 203df701..6548ab5f 100644 --- a/engine/common/mod_bmodel.c +++ b/engine/common/mod_bmodel.c @@ -1088,7 +1088,7 @@ static void Mod_SetParent( mnode_t *node, mnode_t *parent ) CountClipNodes_r ================== */ -static void CountClipNodes_r( dclipnode32_t *src, hull_t *hull, int nodenum ) +static void CountClipNodes_r( mclipnode_t *src, hull_t *hull, int nodenum ) { // leaf? if( nodenum < 0 ) return; @@ -1101,6 +1101,24 @@ static void CountClipNodes_r( dclipnode32_t *src, hull_t *hull, int nodenum ) CountClipNodes_r( src, hull, src[nodenum].children[1] ); } +/* +================== +CountClipNodes32_r +================== +*/ +static void CountClipNodes32_r( dclipnode32_t *src, hull_t *hull, int nodenum ) +{ + // leaf? + if( nodenum < 0 ) return; + + if( hull->lastclipnode == MAX_MAP_CLIPNODES ) + Host_Error( "MAX_MAP_CLIPNODES limit exceeded\n" ); + hull->lastclipnode++; + + CountClipNodes32_r( src, hull, src[nodenum].children[0] ); + CountClipNodes32_r( src, hull, src[nodenum].children[1] ); +} + /* ================== RemapClipNodes_r @@ -1212,7 +1230,7 @@ static void Mod_SetupHull( dbspmodel_t *bmod, model_t *mod, byte *mempool, int h if( VectorIsNull( hull->clip_mins ) && VectorIsNull( hull->clip_maxs )) return; // no hull specified - CountClipNodes_r( bmod->clipnodes_out, hull, headnode ); + CountClipNodes32_r( bmod->clipnodes_out, hull, headnode ); count = hull->lastclipnode; // fit array to real count @@ -1360,6 +1378,10 @@ static void Mod_SetupSubmodels( dbspmodel_t *bmod ) // hull 0 is just shared across all bmodels mod->hulls[0].firstclipnode = bm->headnode[0]; + mod->hulls[0].lastclipnode = bm->headnode[0]; // need to be real count + + // counting a real number of clipnodes per each submodel + CountClipNodes_r( mod->hulls[0].clipnodes, &mod->hulls[0], bm->headnode[0] ); // but hulls1-3 is build individually for a each given submodel for( j = 1; j < MAX_MAP_HULLS; j++ ) diff --git a/engine/server/sv_cmds.c b/engine/server/sv_cmds.c index 60440b86..29de4872 100644 --- a/engine/server/sv_cmds.c +++ b/engine/server/sv_cmds.c @@ -268,6 +268,57 @@ void SV_MapBackground_f( void ) COM_LoadLevel( mapname, true ); } +/* +================== +SV_NextMap_f + +Change map for next in alpha-bethical ordering +For development work +================== +*/ +void SV_NextMap_f( void ) +{ + char nextmap[MAX_QPATH]; + int i, next; + search_t *t; + + t = FS_Search( "maps/*.bsp", true, true ); // only in gamedir + if( !t ) + { + Con_Printf( "next map can't be found\n" ); + return; + } + + for( i = 0; i < t->numfilenames; i++ ) + { + const char *ext = COM_FileExtension( t->filenames[i] ); + + if( Q_stricmp( ext, "bsp" )) + continue; + + COM_FileBase( t->filenames[i], nextmap ); + if( Q_stricmp( sv_hostmap->string, nextmap )) + continue; + + next = ( i + 1 ) % t->numfilenames; + COM_FileBase( t->filenames[next], nextmap ); + Cvar_DirectSet( sv_hostmap, nextmap ); + + // found current point, check for valid + if( SV_ValidateMap( nextmap, true )) + { + // found and valid + COM_LoadLevel( nextmap, false ); + Mem_Free( t ); + return; + } + // jump to next map + } + + Con_Printf( "failed to load next map\n" ); + Mem_Free( t ); +} + /* ============== SV_NewGame_f @@ -839,6 +890,7 @@ void SV_InitHostCommands( void ) Cmd_AddCommand( "loadquick", SV_QuickLoad_f, "load a quick-saved game file" ); Cmd_AddCommand( "reload", SV_Reload_f, "continue from latest save or restart level" ); Cmd_AddCommand( "killsave", SV_DeleteSave_f, "delete a saved game file and saveshot" ); + Cmd_AddCommand( "nextmap", SV_NextMap_f, "load next level" ); } }