diff --git a/ratoa_gamecode/code/game/g_local.h b/ratoa_gamecode/code/game/g_local.h index 65a1db9..21b5b99 100644 --- a/ratoa_gamecode/code/game/g_local.h +++ b/ratoa_gamecode/code/game/g_local.h @@ -924,6 +924,11 @@ typedef struct { qboolean arenasLoaded; + qboolean maplistFromVotemaps; + qboolean maplistCached; + struct maplist_s maplistSource; + struct maplist_s maplistRecommended; + int teamBalanceTime; @@ -1463,6 +1468,7 @@ extern char custom_vote_info[2048]; extern t_mappage getMappage(int page, qboolean largepage, qboolean recommendedonly); extern t_mappage getGTMappage(int page, qboolean largepage); +void G_BuildMaplistCache( void ); void getCompleteMaplist(qboolean recommenedonly, int gametypebits_filter, int numPlayers, struct maplist_s *out); extern int allowedMap(char *mapname); extern int allowedGametype(char *gametypeStr); diff --git a/ratoa_gamecode/code/game/g_main.c b/ratoa_gamecode/code/game/g_main.c index bbe4587..7dbe3a4 100644 --- a/ratoa_gamecode/code/game/g_main.c +++ b/ratoa_gamecode/code/game/g_main.c @@ -1076,6 +1076,8 @@ void G_InitGame( int levelTime, int randomSeed, int restart ) { level.time = levelTime; level.startTime = levelTime; + G_BuildMaplistCache(); + level.snd_fry = G_SoundIndex("sound/player/fry.wav"); // FIXME standing in lava / slime level.snd_thaw = G_FreezeThawSound(); diff --git a/ratoa_gamecode/code/game/g_vote.c b/ratoa_gamecode/code/game/g_vote.c index 9ae34c4..978c129 100644 --- a/ratoa_gamecode/code/game/g_vote.c +++ b/ratoa_gamecode/code/game/g_vote.c @@ -55,200 +55,231 @@ int allowedVote(char *commandStr) { /* ================== -getMappage +MapFilter ================== */ +static qboolean MapFilter(const char *mapname, int gametypebits_filter, int numPlayers) { + if ((gametypebits_filter != 0 && !(gametypebits_filter & G_GametypeBitsForMap(mapname)))) { + return qfalse; + } + if (numPlayers > 0) { + int minPlayers = 0, maxPlayers = 0; + G_MapMinMaxPlayers(mapname, &minPlayers, &maxPlayers); + if ((minPlayers > 0 && numPlayers < minPlayers) || (maxPlayers > 0 && numPlayers > maxPlayers)) { + return qfalse; + } + } + return qtrue; +} -t_mappage getMappage(int page, qboolean largepage, qboolean recommenedonly) { - t_mappage result; - fileHandle_t file; - char *token,*pointer; +/* +================== +Maplist_LoadFromTokens +================== + */ +static void Maplist_LoadFromTokens( char *buffer, struct maplist_s *out ) { + char *token; + char *pointer; + + memset( out, 0, sizeof( *out ) ); + pointer = buffer; + token = COM_Parse( &pointer ); + while ( token && token[0] != 0 && out->num < MAX_MAPS ) { + Q_strncpyz( out->mapname[out->num], token, MAX_MAPNAME ); + out->num++; + token = COM_Parse( &pointer ); + } +} + +/* +================== +Maplist_LoadFromBspDir +================== + */ +static void Maplist_LoadFromBspDir( struct maplist_s *out ) { char *buffer; - int i, nummaps,maplen; - int maps_in_page = largepage ? MAPS_PER_LARGEPAGE : MAPS_PER_PAGE; + char *pointer; + int nummaps; + int maplen; + int copylen; - buffer = BG_Alloc(MAX_MAPNAME_BUFFER); - - memset(&result,0,sizeof(result)); - memset(buffer,0, MAX_MAPNAME_BUFFER); - - //Check if there is a votemaps.cfg - trap_FS_FOpenFile(g_votemaps.string,&file,FS_READ); - if (!file && recommenedonly) { - // if no votemaps.cfg and we only want recommened maps, try recommenedmaps.cfg - trap_FS_FOpenFile(g_recommendedMapsFile.string,&file,FS_READ); - } - if(file) - { - //there is a votemaps.cfg file, take allowed maps from there - trap_FS_Read(buffer,MAX_MAPNAME_BUFFER-1,file); - pointer = buffer; - token = COM_Parse(&pointer); - if(token[0]==0 && page == 0) { - //First page empty - result.pagenumber = -1; - trap_FS_FCloseFile(file); - goto out; - } - //Skip the first pages - for(i=0;i MAX_MAPS ) { + nummaps = MAX_MAPS; + } + + for ( ; out->num < nummaps && *pointer; pointer += maplen + 1 ) { + maplen = strlen( pointer ); + copylen = maplen - 3; + if ( copylen < 1 ) { + continue; } - //There is an actual page: - result.pagenumber = page; - for(i=0;i MAX_MAPNAME ) { + copylen = MAX_MAPNAME; } - trap_FS_FCloseFile(file); - goto out; + Q_strncpyz( out->mapname[out->num], pointer, copylen ); + out->num++; } - //There is no votemaps.cfg file, find filelist of maps - nummaps = trap_FS_GetFileList("maps",".bsp",buffer,MAX_MAPNAME_BUFFER); - if(nummaps && nummaps<=maps_in_page*page) { - result = getMappage(0, largepage, recommenedonly); - goto out; + BG_Free( buffer ); +} + +/* +================== +Maplist_GetBase +================== + */ +static const struct maplist_s *Maplist_GetBase( qboolean recommendedonly ) { + if ( !recommendedonly ) { + return &level.maplistSource; + } + if ( level.maplistFromVotemaps ) { + return &level.maplistSource; } + return &level.maplistRecommended; +} - pointer = buffer; - result.pagenumber = page; +/* +================== +Maplist_FilterCopy +================== + */ +static void Maplist_FilterCopy( const struct maplist_s *base, int gametypebits_filter, int numPlayers, struct maplist_s *out ) { + int i; - for (i = 0; i < nummaps; i++, pointer += maplen+1) { - int copylen = 0; - maplen = strlen(pointer); - copylen = maplen-3; - if (copylen > MAX_MAPNAME) { - copylen = MAX_MAPNAME; + memset( out, 0, sizeof( *out ) ); + for ( i = 0; i < base->num && out->num < MAX_MAPS; i++ ) { + if ( MapFilter( base->mapname[i], gametypebits_filter, numPlayers ) ) { + Q_strncpyz( out->mapname[out->num], base->mapname[i], MAX_MAPNAME ); + out->num++; } - if(i>=maps_in_page*page && inum < 1 && page == 0 ) { + result.pagenumber = -1; + return result; + } start = maps_in_page * page; - if (start >= maplist->num) { - if (page > 0) { - result = getGTMappage(0, largepage); - goto out; + if ( start >= list->num ) { + if ( page > 0 ) { + return Maplist_MappageFromList( list, 0, largepage ); } - goto out; + return result; } - for(i = 0; i < maps_in_page && i+start < maplist->num; ++i) { - Q_strncpyz(result.mapname[i],maplist->mapname[i+start],MAX_MAPNAME); + result.pagenumber = page; + for ( i = 0; i < maps_in_page && i + start < list->num; i++ ) { + Q_strncpyz( result.mapname[i], list->mapname[i + start], MAX_MAPNAME ); } -out: - BG_Free(maplist); return result; } -static qboolean MapFilter(const char *mapname, int gametypebits_filter, int numPlayers) { - if ((gametypebits_filter != 0 && !(gametypebits_filter & G_GametypeBitsForMap(mapname)))) { - return qfalse; - } - if (numPlayers > 0) { - int minPlayers = 0, maxPlayers = 0; - G_MapMinMaxPlayers(mapname, &minPlayers, &maxPlayers); - if ((minPlayers > 0 && numPlayers < minPlayers) || (maxPlayers > 0 && numPlayers > maxPlayers)) { - return qfalse; - } - } - return qtrue; -} +/* +================== +G_BuildMaplistCache -void getCompleteMaplist(qboolean recommenedonly, int gametypebits_filter, int numPlayers, struct maplist_s *out) { - fileHandle_t file; - char *token,*pointer; +Build map source lists once per level from disk. +================== + */ +void G_BuildMaplistCache( void ) { + fileHandle_t file; char *buffer; - int nummaps, maplen; - buffer = BG_Alloc(MAX_MAPNAME_BUFFER); + memset( &level.maplistSource, 0, sizeof( level.maplistSource ) ); + memset( &level.maplistRecommended, 0, sizeof( level.maplistRecommended ) ); + level.maplistFromVotemaps = qfalse; - memset(out,0,sizeof(*out)); - memset(buffer,0,MAX_MAPNAME_BUFFER); + G_LoadArenas(); - //Check if there is a votemaps.cfg - trap_FS_FOpenFile(g_votemaps.string,&file,FS_READ); - if (!file && recommenedonly) { - // if no votemaps.cfg and we only want recommened maps, try recommenedmaps.cfg - trap_FS_FOpenFile(g_recommendedMapsFile.string,&file,FS_READ); - } + buffer = BG_Alloc( MAX_MAPNAME_BUFFER ); + memset( buffer, 0, MAX_MAPNAME_BUFFER ); - if (gametypebits_filter != 0 || numPlayers != 0) { - G_LoadArenas(); + trap_FS_FOpenFile( g_votemaps.string, &file, FS_READ ); + if ( file ) { + trap_FS_Read( buffer, MAX_MAPNAME_BUFFER - 1, file ); + trap_FS_FCloseFile( file ); + Maplist_LoadFromTokens( buffer, &level.maplistSource ); + level.maplistFromVotemaps = qtrue; + } else { + Maplist_LoadFromBspDir( &level.maplistSource ); + + trap_FS_FOpenFile( g_recommendedMapsFile.string, &file, FS_READ ); + if ( file ) { + memset( buffer, 0, MAX_MAPNAME_BUFFER ); + trap_FS_Read( buffer, MAX_MAPNAME_BUFFER - 1, file ); + trap_FS_FCloseFile( file ); + Maplist_LoadFromTokens( buffer, &level.maplistRecommended ); + } } - if(file) - { - //there is a recommendedmaps file or a votemaps.cfg file, take allowed maps from there - trap_FS_Read(buffer,MAX_MAPNAME_BUFFER-1,file); - pointer = buffer; - token = COM_Parse(&pointer); - while (token && token[0] != 0 && out->num < MAX_MAPS) { - if (MapFilter(token, gametypebits_filter, numPlayers)) { - Q_strncpyz(out->mapname[out->num],token,MAX_MAPNAME); - out->num++; - } - token = COM_Parse(&pointer); - } - trap_FS_FCloseFile(file); - goto out; + BG_Free( buffer ); + level.maplistCached = qtrue; +} + +/* +================== +getMappage +================== + */ + +t_mappage getMappage(int page, qboolean largepage, qboolean recommenedonly) { + if ( !level.maplistCached ) { + G_BuildMaplistCache(); } - if (!file && recommenedonly) { - goto out; + return Maplist_MappageFromList( Maplist_GetBase( recommenedonly ), page, largepage ); +} + +t_mappage getGTMappage(int page, qboolean largepage) { + t_mappage result; + struct maplist_s *filtered; + + if ( !level.maplistCached ) { + G_BuildMaplistCache(); } - nummaps = trap_FS_GetFileList("maps",".bsp",buffer,MAX_MAPNAME_BUFFER); - pointer = buffer; + filtered = BG_Alloc( sizeof( *filtered ) ); + Maplist_FilterCopy( &level.maplistSource, G_GametypeBitsCurrent(), 0, filtered ); + result = Maplist_MappageFromList( filtered, page, largepage ); + BG_Free( filtered ); + return result; +} + +void getCompleteMaplist(qboolean recommenedonly, int gametypebits_filter, int numPlayers, struct maplist_s *out) { + const struct maplist_s *base; - if (nummaps > MAX_MAPS) { - nummaps = MAX_MAPS; + if ( !level.maplistCached ) { + G_BuildMaplistCache(); } - for (out->num = 0; (out->num < nummaps && *pointer); pointer += maplen+1) { - char mapname[MAX_MAPNAME]; - int copylen = 0; - maplen = strlen(pointer); - copylen = maplen-3; - if (copylen > MAX_MAPNAME) { - copylen = MAX_MAPNAME; - } - Q_strncpyz(mapname, pointer, copylen); - if (MapFilter(mapname, gametypebits_filter, numPlayers)) { - Q_strncpyz(out->mapname[out->num],pointer,copylen); - out->num++; - } + base = Maplist_GetBase( recommenedonly ); + if ( recommenedonly && !level.maplistFromVotemaps && base->num < 1 ) { + memset( out, 0, sizeof( *out ) ); + return; } -out: - BG_Free(buffer); + + Maplist_FilterCopy( base, gametypebits_filter, numPlayers, out ); } /*