diff --git a/src/command.c b/src/command.c index d41a551538fa222c85b0919829987f36c9810846..07c084aaa4affdbf28b3c39b82a2fed0f4d7a53a 100644 --- a/src/command.c +++ b/src/command.c @@ -2147,14 +2147,14 @@ void CV_AddValue(consvar_t *var, INT32 increment) if(increment > 0) // Going up! { newvalue++; - if (newvalue == NUMMAPS) + if (newvalue == numgamemaps) newvalue = 0; } else // Going down! { newvalue--; if (newvalue == -1) - newvalue = NUMMAPS-1; + newvalue = numgamemaps-1; } if (newvalue == oldvalue) @@ -2162,7 +2162,6 @@ void CV_AddValue(consvar_t *var, INT32 increment) if(!mapheaderinfo[newvalue]) continue; // Don't allocate the header. That just makes memory usage skyrocket. - } while (newvalue != oldvalue && !M_CanShowLevelInList(newvalue, gt)); var->value = newvalue + 1; diff --git a/src/d_main.c b/src/d_main.c index bc821cf71f19982ba725b9ee6a7b198baf8fcf75..8489155433f1c9c7ca20b6268c80062eaeb021d6 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -950,13 +950,7 @@ void D_StartTitle(void) if (server) { - char mapname[6]; - - strlcpy(mapname, G_BuildMapName(spstage_start), sizeof (mapname)); - strlwr(mapname); - mapname[5] = '\0'; - - COM_BufAddText(va("map %s\n", mapname)); + COM_BufAddText(va("map %s\n", G_BuildMapName(spstage_start))); } } @@ -1375,6 +1369,8 @@ void D_SRB2Main(void) CONS_Printf("Z_Init(): Init zone memory allocation daemon. \n"); Z_Init(); + G_InitMaps(); + clientGamedata = M_NewGameDataStruct(); serverGamedata = M_NewGameDataStruct(); @@ -1692,7 +1688,7 @@ void D_SRB2Main(void) { pstartmap = bootmap; - if (pstartmap < 1 || pstartmap > NUMMAPS) + if (pstartmap < 1 || pstartmap > numgamemaps) I_Error("Cannot warp to map %d (out of range)\n", pstartmap); else { @@ -1739,7 +1735,7 @@ void D_SRB2Main(void) if (server && !M_CheckParm("+map")) { // Prevent warping to nonexistent levels - if (W_CheckNumForName(G_BuildMapName(pstartmap)) == LUMPERROR) + if (!G_MapFileExists(G_BuildMapName(pstartmap))) I_Error("Could not warp to %s (map not found)\n", G_BuildMapName(pstartmap)); else { diff --git a/src/deh_soc.c b/src/deh_soc.c index 6162034de636e54ec8d35f5292720564de8de32d..0e904dda40dd010fa6677f5b56aa6ab290213e87 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -168,7 +168,7 @@ void clear_levels(void) // This is potentially dangerous but if we're resetting these headers, // we may as well try to save some memory, right? - for (i = 0; i < NUMMAPS; ++i) + for (i = 0; i < numgamemaps; ++i) { if (!mapheaderinfo[i] || i == (tutorialmap-1)) continue; @@ -1338,6 +1338,36 @@ void readgametype(MYFILE *f, char *gtname) CONS_Printf("Added gametype %s\n", Gametype_Names[newgtidx]); } +static INT32 ParseNextLevelName(const char *name) +{ + if (fastcmp(name, "TITLE")) return MAP_TITLE; + else if (fastcmp(name, "EVALUATION")) return MAP_EVALUATION; + else if (fastcmp(name, "CREDITS")) return MAP_CREDITS; + else if (fastcmp(name, "ENDING")) return MAP_ENDING; + else + { + // Support using the actual map name, + // i.e., Nextlevel = AB, Nextlevel = FZ, etc. + + // Convert to map number + return G_GetMapNumber(name); + } +} + +static INT32 ConvertLevelHeaderMapNum(INT32 mapnum) +{ + if (mapnum == 1100) + return MAP_TITLE; + else if (mapnum == 1101) + return MAP_EVALUATION; + else if (mapnum == 1102) + return MAP_CREDITS; + else if (mapnum == 1103) + return MAP_ENDING; + else + return mapnum; +} + void readlevelheader(MYFILE *f, INT32 num) { char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); @@ -1554,33 +1584,17 @@ void readlevelheader(MYFILE *f, INT32 num) } else if (fastcmp(word, "NEXTLEVEL")) { - if (fastcmp(word2, "TITLE")) i = 1100; - else if (fastcmp(word2, "EVALUATION")) i = 1101; - else if (fastcmp(word2, "CREDITS")) i = 1102; - else if (fastcmp(word2, "ENDING")) i = 1103; - else - // Support using the actual map name, - // i.e., Nextlevel = AB, Nextlevel = FZ, etc. - - // Convert to map number - if (word2[0] >= 'A' && word2[0] <= 'Z' && word2[2] == '\0') - i = M_MapNumber(word2[0], word2[1]); + i = ConvertLevelHeaderMapNum(i); + if (i == 0) + i = ParseNextLevelName(word2); mapheaderinfo[num-1]->nextlevel = (INT16)i; } else if (fastcmp(word, "MARATHONNEXT")) { - if (fastcmp(word2, "TITLE")) i = 1100; - else if (fastcmp(word2, "EVALUATION")) i = 1101; - else if (fastcmp(word2, "CREDITS")) i = 1102; - else if (fastcmp(word2, "ENDING")) i = 1103; - else - // Support using the actual map name, - // i.e., MarathonNext = AB, MarathonNext = FZ, etc. - - // Convert to map number - if (word2[0] >= 'A' && word2[0] <= 'Z' && word2[2] == '\0') - i = M_MapNumber(word2[0], word2[1]); + i = ConvertLevelHeaderMapNum(i); + if (i == 0) + i = ParseNextLevelName(word2); mapheaderinfo[num-1]->marathonnext = (INT16)i; } @@ -1995,8 +2009,7 @@ static void readcutscenescene(MYFILE *f, INT32 num, INT32 scenenum) } else if (fastcmp(word, "MUSIC")) { - strncpy(cutscenes[num]->scene[scenenum].musswitch, word2, 7); - cutscenes[num]->scene[scenenum].musswitch[6] = 0; + strlcpy(cutscenes[num]->scene[scenenum].musswitch, word2, MAX_MUSIC_NAME+1); } else if (fastcmp(word, "MUSICTRACK")) { @@ -2257,8 +2270,7 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) } else if (fastcmp(word, "MUSIC")) { - strncpy(textprompts[num]->page[pagenum].musswitch, word2, 7); - textprompts[num]->page[pagenum].musswitch[6] = 0; + strlcpy(textprompts[num]->page[pagenum].musswitch, word2, MAX_MUSIC_NAME+1); } else if (fastcmp(word, "MUSICTRACK")) { @@ -2581,8 +2593,7 @@ void readmenu(MYFILE *f, INT32 num) } else if (fastcmp(word, "MUSIC")) { - strncpy(menupres[num].musname, word2, 7); - menupres[num].musname[6] = 0; + strlcpy(menupres[num].musname, word2, MAX_MUSIC_NAME+1); titlechanged = true; } else if (fastcmp(word, "MUSICTRACK")) @@ -2996,12 +3007,12 @@ void reademblemdata(MYFILE *f, INT32 num) emblemlocations[num-1].tag = (INT16)value; else if (fastcmp(word, "MAPNUM")) { - // Support using the actual map name, - // i.e., Level AB, Level FZ, etc. - - // Convert to map number - if (word2[0] >= 'A' && word2[0] <= 'Z') - value = M_MapNumber(word2[0], word2[1]); + if (!value) + { + value = G_GetMapNumber(word2); + if (!value) + value = get_number(word2); + } emblemlocations[num-1].level = (INT16)value; } @@ -3243,6 +3254,12 @@ void readunlockable(MYFILE *f, INT32 num) // Convert to map number if (word2[0] >= 'A' && word2[0] <= 'Z') i = M_MapNumber(word2[0], word2[1]); + else if (unlockables[num].type == SECRET_WARP) + { + INT16 mapnum = G_GetMapNumber(word2); + if (mapnum) + i = mapnum; + } unlockables[num].variable = (INT16)i; } @@ -3316,15 +3333,14 @@ static void readcondition(UINT8 set, UINT32 id, char *word2) PARAMCHECK(1); ty = UC_MAPVISITED + offset; - // Convert to map number if it appears to be one - if (params[1][0] >= 'A' && params[1][0] <= 'Z') - re = M_MapNumber(params[1][0], params[1][1]); - else + // Convert to map number + re = G_GetMapNumber(params[1]); + if (!re) re = atoi(params[1]); - if (re <= 0 || re > NUMMAPS) + if (re <= 0 || re > numgamemaps) { - deh_warning("Level number %d out of range (1 - %d)", re, NUMMAPS); + deh_warning("Level number %d out of range (1 - %d)", re, numgamemaps); return; } } @@ -3336,15 +3352,14 @@ static void readcondition(UINT8 set, UINT32 id, char *word2) ty = UC_MAPSCORE + offset; re = atoi(params[2]); - // Convert to map number if it appears to be one - if (params[1][0] >= 'A' && params[1][0] <= 'Z') - x1 = (INT16)M_MapNumber(params[1][0], params[1][1]); - else + // Convert to map number + x1 = G_GetMapNumber(params[1]); + if (!x1) x1 = (INT16)atoi(params[1]); - if (x1 <= 0 || x1 > NUMMAPS) + if (x1 <= 0 || x1 > numgamemaps) { - deh_warning("Level number %d out of range (1 - %d)", re, NUMMAPS); + deh_warning("Level number %d out of range (1 - %d)", re, numgamemaps); return; } } @@ -3371,15 +3386,14 @@ static void readcondition(UINT8 set, UINT32 id, char *word2) else re = atoi(params[i]); - // Convert to map number if it appears to be one - if (params[1][0] >= 'A' && params[1][0] <= 'Z') - x1 = (INT16)M_MapNumber(params[1][0], params[1][1]); - else + // Convert to map number + x1 = G_GetMapNumber(params[1]); + if (!x1) x1 = (INT16)atoi(params[1]); - if (x1 <= 0 || x1 > NUMMAPS) + if (x1 <= 0 || x1 > numgamemaps) { - deh_warning("Level number %d out of range (1 - %d)", re, NUMMAPS); + deh_warning("Level number %d out of range (1 - %d)", re, numgamemaps); return; } @@ -3589,10 +3603,12 @@ void readmaincfg(MYFILE *f) // i.e., Level AB, Level FZ, etc. // Convert to map number - if (word2[0] >= 'A' && word2[0] <= 'Z') - value = M_MapNumber(word2[0], word2[1]); - else - value = get_number(word2); + if (!value) + { + value = G_GetMapNumber(word2); + if (!value) + value = get_number(word2); + } spstage_start = spmarathon_start = (INT16)value; } @@ -3602,10 +3618,12 @@ void readmaincfg(MYFILE *f) // i.e., Level AB, Level FZ, etc. // Convert to map number - if (word2[0] >= 'A' && word2[0] <= 'Z') - value = M_MapNumber(word2[0], word2[1]); - else - value = get_number(word2); + if (!value) + { + value = G_GetMapNumber(word2); + if (!value) + value = get_number(word2); + } spmarathon_start = (INT16)value; } @@ -3615,10 +3633,12 @@ void readmaincfg(MYFILE *f) // i.e., Level AB, Level FZ, etc. // Convert to map number - if (word2[0] >= 'A' && word2[0] <= 'Z') - value = M_MapNumber(word2[0], word2[1]); - else - value = get_number(word2); + if (!value) + { + value = G_GetMapNumber(word2); + if (!value) + value = get_number(word2); + } sstage_start = (INT16)value; sstage_end = (INT16)(sstage_start+7); // 7 special stages total plus one weirdo @@ -3629,10 +3649,12 @@ void readmaincfg(MYFILE *f) // i.e., Level AB, Level FZ, etc. // Convert to map number - if (word2[0] >= 'A' && word2[0] <= 'Z') - value = M_MapNumber(word2[0], word2[1]); - else - value = get_number(word2); + if (!value) + { + value = G_GetMapNumber(word2); + if (!value) + value = get_number(word2); + } smpstage_start = (INT16)value; smpstage_end = (INT16)(smpstage_start+6); // 7 special stages total @@ -3723,10 +3745,12 @@ void readmaincfg(MYFILE *f) // i.e., Level AB, Level FZ, etc. // Convert to map number - if (word2[0] >= 'A' && word2[0] <= 'Z') - value = M_MapNumber(word2[0], word2[1]); - else - value = get_number(word2); + if (!value) + { + value = G_GetMapNumber(word2); + if (!value) + value = get_number(word2); + } titlemap = (INT16)value; titlechanged = true; @@ -3895,10 +3919,12 @@ void readmaincfg(MYFILE *f) // i.e., Level AB, Level FZ, etc. // Convert to map number - if (word2[0] >= 'A' && word2[0] <= 'Z') - value = M_MapNumber(word2[0], word2[1]); - else - value = get_number(word2); + if (!value) + { + value = G_GetMapNumber(word2); + if (!value) + value = get_number(word2); + } bootmap = (INT16)value; //titlechanged = true; @@ -3914,10 +3940,12 @@ void readmaincfg(MYFILE *f) // i.e., Level AB, Level FZ, etc. // Convert to map number - if (word2[0] >= 'A' && word2[0] <= 'Z') - value = M_MapNumber(word2[0], word2[1]); - else - value = get_number(word2); + if (!value) + { + value = G_GetMapNumber(word2); + if (!value) + value = get_number(word2); + } tutorialmap = (INT16)value; } diff --git a/src/dehacked.c b/src/dehacked.c index fd2a701715e17ce7dab0b6c829147113844972fe..142459fece3b3ccfaf78898df495a3dff42921b0 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -364,18 +364,18 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile) } else if (fastcmp(word, "LEVEL")) { - // Support using the actual map name, - // i.e., Level AB, Level FZ, etc. - - // Convert to map number - if (word2[0] >= 'A' && word2[0] <= 'Z') - i = M_MapNumber(word2[0], word2[1]); + if (!isdigit(word2[0])) + { + INT16 mapnum = G_GetMapNumber(word2); + if (mapnum != 0) + i = mapnum; + } - if (i > 0 && i <= NUMMAPS) + if (i > 0 && i <= numgamemaps) readlevelheader(f, i); else { - deh_warning("Level number %d out of range (1 - %d)", i, NUMMAPS); + deh_warning("Level number %d out of range (1 - %d)", i, numgamemaps); ignorelines(f); } } diff --git a/src/doomdata.h b/src/doomdata.h index 276e03297b6f0d453ad0d0c65fc8bd9196d9680c..33051da656b9237a4ae11c3fb43398422dd4cec6 100644 --- a/src/doomdata.h +++ b/src/doomdata.h @@ -223,6 +223,15 @@ typedef struct #define ZSHIFT 4 -#define NUMMAPS 1035 +#define MAXMAPS 16386 + +#define MAX_MAP_NAME_SIZE 256 // This is an arbitrary limit to prevent exceedingly long map names. + +#define MAP_TITLE (MAXMAPS) +#define MAP_EVALUATION (MAXMAPS+2) +#define MAP_CREDITS (MAXMAPS+3) +#define MAP_ENDING (MAXMAPS+4) + +#define NUMBASEMAPS 1035 // MAP01 to MAPZZ #endif // __DOOMDATA__ diff --git a/src/doomdef.h b/src/doomdef.h index 4e08b11bfb0116c2f60fffc33582d6c9a56f3b27..2626e8f54d6e4e7e27b44227ee83fda3a24ddeb6 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -451,6 +451,8 @@ extern skincolor_t skincolors[MAXSKINCOLORS]; #define MUSICRATE 1000 // sound timing is calculated by milliseconds +#define MAX_MUSIC_NAME 64 + #define RING_DIST 512*FRACUNIT // how close you need to be to a ring to attract it #define PUSHACCEL (2*FRACUNIT) // Acceleration for MF2_SLIDEPUSH items. diff --git a/src/doomstat.h b/src/doomstat.h index 6a2d6acf00f816804c1ec8830b69c9848deadcbe..3141e7cc4446098ed3b5aed16bd4237969e7c90c 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -31,7 +31,7 @@ // Selected by user. extern INT16 gamemap; -extern char mapmusname[7]; +extern char mapmusname[MAX_MUSIC_NAME+1]; extern UINT16 mapmusflags; extern UINT32 mapmusposition; #define MUSIC_TRACKMASK 0x0FFF // ----************ @@ -79,6 +79,7 @@ extern boolean usedCheats; extern boolean disableSpeedAdjust; // Don't alter the duration of player states if true extern boolean imcontinuing; // Temporary flag while continuing extern boolean metalrecording; +extern boolean replacedcurrentmap; #define ATTACKING_NONE 0 #define ATTACKING_RECORD 1 @@ -175,7 +176,7 @@ typedef struct UINT16 textxpos; UINT16 textypos; - char musswitch[7]; + char musswitch[MAX_MUSIC_NAME+1]; UINT16 musswitchflags; UINT32 musswitchposition; @@ -215,7 +216,7 @@ typedef struct UINT16 ycoord[MAX_PROMPT_PICS]; // gfx UINT16 picduration[MAX_PROMPT_PICS]; - char musswitch[7]; + char musswitch[MAX_MUSIC_NAME+1]; UINT16 musswitchflags; UINT8 musicloop; @@ -277,6 +278,16 @@ extern struct quake fixed_t radius, intensity; } quake; +typedef struct +{ + UINT32 hash; + char *name; + char *thumbnail; + char *thumbnail_wide; + char *music; + char *metal_replay; +} gamemap_t; + // NiGHTS grades typedef struct { @@ -303,7 +314,7 @@ typedef struct INT16 nextlevel; ///< Map number of next level, or 1100-1102 to end. INT16 marathonnext; ///< See nextlevel, but for Marathon mode. Necessary to support hub worlds ala SUGOI. char keywords[33]; ///< Keywords separated by space to search for. 32 characters. - char musname[7]; ///< Music track to play. "" for no music. + char musname[MAX_MUSIC_NAME+1]; ///< Music track to play. "" for no music. UINT16 mustrack; ///< Subsong to play. Only really relevant for music modules and specific formats supported by GME. 0 to ignore. UINT32 muspos; ///< Music position to jump to. char forcecharacter[17]; ///< (SKINNAMESIZE+1) Skin to switch to or "" to disable. @@ -351,9 +362,9 @@ typedef struct // Music stuff. UINT32 musinterfadeout; ///< Fade out level music on intermission screen in milliseconds - char musintername[7]; ///< Intermission screen music. + char musintername[MAX_MUSIC_NAME+1]; ///< Intermission screen music. - char muspostbossname[7]; ///< Post-bossdeath music. + char muspostbossname[MAX_MUSIC_NAME+1]; ///< Post-bossdeath music. UINT16 muspostbosstrack; ///< Post-bossdeath track. UINT32 muspostbosspos; ///< Post-bossdeath position UINT32 muspostbossfadein; ///< Post-bossdeath fade-in milliseconds. @@ -388,7 +399,11 @@ typedef struct #define LF2_NOVISITNEEDED 16 ///< Available in time attack/nights mode without visiting the level #define LF2_WIDEICON 32 ///< If you're in a circumstance where it fits, use a wide map icon -extern mapheader_t* mapheaderinfo[NUMMAPS]; +extern mapheader_t* mapheaderinfo[MAXMAPS]; + +extern gamemap_t gamemaps[MAXMAPS]; + +extern UINT16 numgamemaps; // Gametypes #define NUMGAMETYPEFREESLOTS 128 diff --git a/src/f_finale.c b/src/f_finale.c index 5dc18115c9b07f37e3e36db788ed88489e011ef3..12be1393c4a7040950f58a951695ad2552f44f81 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -3914,7 +3914,7 @@ void F_EndCutScene(void) F_StartGameEvaluation(); else if (cutnum == introtoplay-1) D_StartTitle(); - else if (nextmap < 1100-1) + else if (!G_IsGameEndMap(nextmap+1)) G_NextLevel(); else G_EndGame(); diff --git a/src/g_demo.c b/src/g_demo.c index f39efad8e68fe81a37eed65925dc8c1ae394dae3..3df703a19187cb287be10196d97a3a396e4418f1 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -46,7 +46,7 @@ boolean nodrawers; // for comparative timing purposes boolean noblit; // for comparative timing purposes tic_t demostarttime; // for comparative timing purposes -static char demoname[64]; +static char demoname[512]; boolean demorecording; boolean demoplayback; boolean titledemo; // Title Screen demo can be cancelled by any key @@ -1405,15 +1405,14 @@ void G_WriteMetalTic(mobj_t *metal) // void G_RecordDemo(const char *name) { - INT32 maxsize; + strlcpy(demoname, name, sizeof(demoname)); - strcpy(demoname, name); - strcat(demoname, ".lmp"); - maxsize = 1024*1024; + FIL_ForceExtension(demoname, ".lmp"); + + INT32 maxsize = 1024*1024; if (M_CheckParm("-maxdemo") && M_IsNextParm()) maxsize = atoi(M_GetNextParm()) * 1024; -// if (demobuffer) -// free(demobuffer); + demo_p = NULL; demobuffer = malloc(maxsize); demoend = demobuffer + maxsize; @@ -2654,7 +2653,7 @@ void G_DoPlayMetal(void) thinker_t *th; // it's an internal demo - if ((l = W_CheckNumForName(va("%sMS",G_BuildMapName(gamemap)))) == LUMPERROR) + if ((l = W_CheckNumForName(G_GetMapMetalSonicReplay(gamemap))) == LUMPERROR) { CONS_Alert(CONS_WARNING, M_GetText("No bot recording for this map.\n")); return; @@ -2780,7 +2779,7 @@ ATTRNORETURN void FUNCNORETURN G_StopMetalRecording(boolean kill) { WRITEUINT8(demo_p, (kill) ? METALDEATH : DEMOMARKER); // add the demo end (or metal death) marker WriteDemoChecksum(); - sprintf(demoname, "%sMS.LMP", G_BuildMapName(gamemap)); + snprintf(demoname, sizeof(demoname), "%s.lmp", G_GetMapMetalSonicReplay(gamemap)); saved = FIL_WriteFile(va(pandf, srb2home, demoname), demobuffer, demo_p - demobuffer); // finally output the file. } free(demobuffer); diff --git a/src/g_game.c b/src/g_game.c index 121672fa7995fb55c355472bf43571a9e277377c..28e7646a8b7fd1b5b0ad437848364e41be39ae28 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -78,7 +78,7 @@ static void G_DoStartContinue(void); static void G_DoContinued(void); static void G_DoWorldDone(void); -char mapmusname[7]; // Music name +char mapmusname[MAX_MUSIC_NAME+1]; // Music name UINT16 mapmusflags; // Track and reset bit UINT32 mapmusposition; // Position to jump to @@ -105,6 +105,7 @@ UINT8 paused; UINT8 modeattacking = ATTACKING_NONE; boolean disableSpeedAdjust = false; boolean imcontinuing = false; +boolean replacedcurrentmap = false; boolean runemeraldmanager = false; UINT16 emeraldspawndelay = 60*TICRATE; @@ -172,7 +173,10 @@ mapthing_t *bflagpoint; struct quake quake; // Map Header Information -mapheader_t* mapheaderinfo[NUMMAPS] = {NULL}; +mapheader_t* mapheaderinfo[MAXMAPS] = {NULL}; + +gamemap_t gamemaps[MAXMAPS]; +UINT16 numgamemaps = 0; static boolean exitgame = false; static boolean retrying = false; @@ -463,7 +467,7 @@ void G_AllocNightsRecordData(INT16 i, gamedata_t *data) void G_ClearRecords(gamedata_t *data) { INT16 i; - for (i = 0; i < NUMMAPS; ++i) + for (i = 0; i < numgamemaps; ++i) { if (data->mainrecords[i]) { @@ -571,7 +575,8 @@ static void G_SetMainRecords(gamedata_t *data, player_t *player) if (modeattacking) { - const size_t glen = strlen(srb2home)+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1; + const char *mapname = G_BuildMapName(gamemap); + const size_t glen = strlen(srb2home)+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen(mapname)+1; char *gpath; char lastdemo[256], bestdemo[256]; @@ -587,7 +592,7 @@ static void G_SetMainRecords(gamedata_t *data, player_t *player) if ((gpath = malloc(glen)) == NULL) I_Error("Out of memory for replay filepath\n"); - sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap)); + sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, mapname); snprintf(lastdemo, 255, "%s-%s-last.lmp", gpath, skins[cv_chooseskin.value-1].name); if (FIL_FileExists(lastdemo)) @@ -709,7 +714,8 @@ static void G_SetNightsRecords(gamedata_t *data, player_t *player) if (modeattacking) { - const size_t glen = strlen(srb2home)+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1; + const char *mapname = G_BuildMapName(gamemap); + const size_t glen = strlen(srb2home)+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen(mapname)+1; char *gpath; char lastdemo[256], bestdemo[256]; @@ -725,7 +731,7 @@ static void G_SetNightsRecords(gamedata_t *data, player_t *player) if ((gpath = malloc(glen)) == NULL) I_Error("Out of memory for replay filepath\n"); - sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap)); + sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, mapname); snprintf(lastdemo, 255, "%s-%s-last.lmp", gpath, skins[cv_chooseskin.value-1].name); if (FIL_FileExists(lastdemo)) @@ -803,6 +809,20 @@ void G_SetUsedCheats(boolean silent) Command_ExitGame_f(); } +/** Gets a game map name from a map number. + * + * \param map Map number. + * \return The desired map name. + * \sa M_MapNumber + */ +const char *G_BuildMapName(INT32 map) +{ + if (map > 0 && map <= numgamemaps) + return gamemaps[map - 1].name; + + return "UNKNOWN"; +} + /** Builds an original game map name from a map number. * The complexity is due to MAPA0-MAPZZ. * @@ -810,12 +830,12 @@ void G_SetUsedCheats(boolean silent) * \return Pointer to a static buffer containing the desired map name. * \sa M_MapNumber */ -const char *G_BuildMapName(INT32 map) +const char *G_BuildClassicMapName(INT32 map) { static char mapname[10] = "MAPXX"; // internal map name (wad resource name) I_Assert(map > 0); - I_Assert(map <= NUMMAPS); + I_Assert(map <= NUMBASEMAPS); if (map < 100) sprintf(&mapname[3], "%.2d", map); @@ -832,6 +852,158 @@ const char *G_BuildMapName(INT32 map) return mapname; } +void G_InitMaps(void) +{ + for (UINT16 i = 0; i < NUMBASEMAPS; i++) + { + const char *name = G_BuildClassicMapName(i + 1); + G_AddMap(name); + } +} + +UINT16 G_GetMapNumber(const char *name) +{ + size_t name_len = strlen(name); + + // Special case + if (name_len == 2 && name[0] >= 'A' && name[0] <= 'Z') + { + return M_MapNumber(name[0], name[1]); + } + + UINT32 hash = quickncasehash(name, name_len); + + for (UINT16 i = 0; i < numgamemaps; i++) + { + if (hash == gamemaps[i].hash && stricmp(gamemaps[i].name, name) == 0) + return i + 1; + } + + return 0; +} + +UINT16 G_AddMap(const char *name) +{ + if (numgamemaps == MAXMAPS) + return 0; + + UINT16 mapnum = G_GetMapNumber(name); + if (mapnum != 0) + { + // That map already exists, silly. + return mapnum; + } + + size_t name_len = strlen(name); + if (name_len > MAX_MAP_NAME_SIZE) + return 0; + + gamemaps[numgamemaps].hash = quickncasehash(name, name_len); + gamemaps[numgamemaps].name = Z_StrDup(name); + + strupr(gamemaps[numgamemaps].name); + + numgamemaps++; + + CONS_Debug(DBG_SETUP, "Added map %d (%s)\n", numgamemaps, name); + + return numgamemaps; +} + +boolean G_MapFileExists(const char *name) +{ + return W_CheckNumForLongName(name) != LUMPERROR; +} + +boolean G_IsValidMapName(const char *name) +{ + if (name[0] == '\0' || !isalpha(name[0])) + return false; + + return true; +} + +static char *BuildCombinedMapString(INT16 map, const char *newfmt, const char *oldfmt) +{ + const char *mapname = gamemaps[map].name; + const char *fmt = (map < NUMBASEMAPS) ? oldfmt : newfmt; + + size_t len = strlen(mapname) + strlen(fmt) + 1; + + char *text = Z_Malloc(len, PU_STATIC, NULL); + + snprintf(text, len, fmt, mapname); + + return text; +} + +const char *G_GetMapThumbnail(INT16 map) +{ + map--; + + if (map < 0 || map >= numgamemaps) + return ""; + + // This is done lazily -- it's not created until it's needed. + if (gamemaps[map].thumbnail == NULL) + gamemaps[map].thumbnail = BuildCombinedMapString(map, "%s_PIC", "%sP"); + + return gamemaps[map].thumbnail; +} + +const char *G_GetMapThumbnailWide(INT16 map) +{ + map--; + + if (map < 0 || map >= numgamemaps) + return ""; + + if (gamemaps[map].thumbnail_wide == NULL) + gamemaps[map].thumbnail_wide = BuildCombinedMapString(map, "%s_WIDEPIC", "%sW"); + + return gamemaps[map].thumbnail_wide; +} + +const char *G_GetDefaultMapMusic(INT16 map) +{ + map--; + + if (map < 0 || map >= numgamemaps) + return ""; + + if (gamemaps[map].music == NULL) + gamemaps[map].music = BuildCombinedMapString(map, "%s", "%sM"); + + return gamemaps[map].music; +} + +const char *G_GetMapMetalSonicReplay(INT16 map) +{ + map--; + + if (map < 0 || map >= numgamemaps) + return ""; + + if (gamemaps[map].metal_replay == NULL) + gamemaps[map].metal_replay = BuildCombinedMapString(map, "%s_METALREPLAY", "%sMS"); + + return gamemaps[map].metal_replay; +} + +boolean G_IsGameEndMap(INT16 mapnum) +{ + switch (mapnum) + { + case MAP_TITLE: + case MAP_EVALUATION: + case MAP_CREDITS: + case MAP_ENDING: + return true; + default: + return false; + } +} + /** Clips the console player's mouse aiming to the current view. * Used whenever the player view is changed manually. * @@ -1853,7 +2025,7 @@ void G_DoLoadLevel(boolean resetplayer) // cleanup if (titlemapinaction == TITLEMAP_LOADING) { - if (W_CheckNumForName(G_BuildMapName(gamemap)) == LUMPERROR) + if (!G_MapFileExists(G_BuildMapName(gamemap))) { titlemap = 0; // let's not infinite recursion ok Command_ExitGame_f(); @@ -2770,8 +2942,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) { if (mapmusflags & MUSIC_RELOADRESET) { - strncpy(mapmusname, mapheaderinfo[gamemap-1]->musname, 7); - mapmusname[6] = 0; + strlcpy(mapmusname, mapheaderinfo[gamemap-1]->musname, MAX_MUSIC_NAME+1); mapmusflags = (mapheaderinfo[gamemap-1]->mustrack & MUSIC_TRACKMASK); mapmusposition = mapheaderinfo[gamemap-1]->muspos; } @@ -3847,12 +4018,12 @@ UINT32 G_TOLFlag(INT32 pgametype) */ static INT16 RandMap(UINT32 tolflags, INT16 pprevmap) { - INT16 *okmaps = Z_Malloc(NUMMAPS * sizeof(INT16), PU_STATIC, NULL); + INT16 *okmaps = Z_Malloc(numgamemaps * sizeof(INT16), PU_STATIC, NULL); INT32 numokmaps = 0; INT16 ix; // Find all the maps that are ok and and put them in an array. - for (ix = 0; ix < NUMMAPS; ix++) + for (ix = 0; ix < numgamemaps; ix++) if (mapheaderinfo[ix] && (mapheaderinfo[ix]->typeoflevel & tolflags) == tolflags && ix != pprevmap // Don't pick the same map. && (!M_MapLocked(ix+1, serverGamedata)) // Don't pick locked maps. @@ -4060,13 +4231,11 @@ static void G_DoCompleted(void) // for instance). if (!spec || nextmapoverride) { - if (nextmap >= 0 && nextmap < NUMMAPS) + if (nextmap >= 0 && nextmap < numgamemaps) { INT16 cm = nextmap; UINT32 tolflag = G_TOLFlag(gametype_to_use); - UINT8 visitedmap[(NUMMAPS+7)/8]; - - memset(visitedmap, 0, sizeof (visitedmap)); + UINT8 *visitedmap = Z_Calloc(((numgamemaps+7)/8) * sizeof(UINT8), PU_STATIC, NULL); while (!mapheaderinfo[cm] || !(mapheaderinfo[cm]->typeoflevel & tolflag)) { @@ -4078,12 +4247,12 @@ static void G_DoCompleted(void) else cm = (INT16)(mapheaderinfo[cm]->nextlevel-1); - if (cm >= NUMMAPS || cm < 0) // out of range (either 1100ish or error) + if (cm >= numgamemaps || cm < 0) // out of range (either 1100ish or error) { cm = nextmap; //Start the loop again so that the error checking below is executed. //Make sure the map actually exists before you try to go to it! - if ((W_CheckNumForName(G_BuildMapName(cm + 1)) == LUMPERROR)) + if (!G_MapFileExists(G_BuildMapName(cm + 1))) { CONS_Alert(CONS_ERROR, M_GetText("Next map given (MAP %d) doesn't exist! Reverting to MAP01.\n"), cm+1); cm = 0; @@ -4100,14 +4269,17 @@ static void G_DoCompleted(void) break; } } + + Z_Free(visitedmap); + nextmap = cm; } // wrap around in race - if (nextmap >= 1100-1 && nextmap <= 1102-1 && !(gametyperules & GTR_CAMPAIGN)) + if (G_IsGameEndMap(nextmap+1) && !(gametyperules & GTR_CAMPAIGN)) nextmap = (INT16)(spstage_start-1); - if (nextmap < 0 || (nextmap >= NUMMAPS && nextmap < 1100-1) || nextmap > 1103-1) + if (nextmap < 0 || (nextmap >= numgamemaps && !G_IsGameEndMap(nextmap+1))) I_Error("Followed map %d to invalid map %d\n", prevmap + 1, nextmap + 1); if (!spec) @@ -4149,7 +4321,7 @@ static void G_DoCompleted(void) // We are committed to this map now. // We may as well allocate its header if it doesn't exist // (That is, if it's a real map) - if (nextmap < NUMMAPS && !mapheaderinfo[nextmap]) + if (nextmap < numgamemaps && !mapheaderinfo[nextmap]) P_AllocMapHeader(nextmap); Y_DetermineIntermissionType(); @@ -4195,7 +4367,7 @@ void G_AfterIntermission(void) } else { - if (nextmap < 1100-1) + if (!G_IsGameEndMap(nextmap+1)) G_NextLevel(); else G_EndGame(); @@ -4315,17 +4487,17 @@ void G_EndGame(void) // Only do evaluation and credits in coop games. if (gametyperules & GTR_CUTSCENES) { - if (nextmap == 1103-1) // end game with ending + if (nextmap+1 == MAP_ENDING) // end game with ending { F_StartEnding(); return; } - if (nextmap == 1102-1) // end game with credits + else if (nextmap+1 == MAP_CREDITS) // end game with credits { F_StartCredits(); return; } - if (nextmap == 1101-1) // end game with evaluation + else if (nextmap+1 == MAP_EVALUATION) // end game with evaluation { F_StartGameEvaluation(); return; @@ -4356,6 +4528,62 @@ void G_LoadGameSettings(void) #define GAMEDATA_ID 0x86E4A27C // Change every major version, as usual #define COMPAT_GAMEDATA_ID 0xFCAFE211 // TODO: 2.3: Delete +#define EXTRA_DATA_MARKER 0x71B9F853 // TODO: 2.3: Refactor all related code, then delete this + +static boolean ReadMapVisited(gamedata_t *data, UINT16 i) +{ + if ((data->mapvisited[i] = READUINT8(save_p)) > MV_MAX) + return false; + + return true; +} + +static boolean ReadMainRecords(gamedata_t *data, UINT16 i) +{ + UINT32 recscore = READUINT32(save_p); + tic_t rectime = (tic_t)READUINT32(save_p); + UINT16 recrings = READUINT16(save_p); + save_p++; // compat + + if (recrings > 10000 || recscore > MAXSCORE) + return false; + + if (recscore || rectime || recrings) + { + G_AllocMainRecordData((INT16)i, data); + data->mainrecords[i]->score = recscore; + data->mainrecords[i]->time = rectime; + data->mainrecords[i]->rings = recrings; + } + + return true; +} + +static boolean ReadNightsRecords(gamedata_t *data, UINT16 i) +{ + UINT8 recmares; + + if ((recmares = READUINT8(save_p)) == 0) + return true; + + G_AllocNightsRecordData((INT16)i, data); + + for (INT32 curmare = 0; curmare < (recmares+1); ++curmare) + { + data->nightsrecords[i]->score[curmare] = READUINT32(save_p); + data->nightsrecords[i]->grade[curmare] = READUINT8(save_p); + data->nightsrecords[i]->time[curmare] = (tic_t)READUINT32(save_p); + + if (data->nightsrecords[i]->grade[curmare] > GRADE_S) + { + return false; + } + } + + data->nightsrecords[i]->nummares = recmares; + + return true; +} // G_LoadGameData // Loads the main data file, which stores information such as emblems found, etc. @@ -4367,14 +4595,6 @@ void G_LoadGameData(gamedata_t *data) UINT32 versionID; UINT8 rtemp; - //For records - UINT32 recscore; - tic_t rectime; - UINT16 recrings; - - UINT8 recmares; - INT32 curmare; - // Stop saving, until we successfully load it again. data->loaded = false; @@ -4482,9 +4702,12 @@ void G_LoadGameData(gamedata_t *data) } // TODO put another cipher on these things? meh, I don't care... - for (i = 0; i < NUMMAPS; i++) - if ((data->mapvisited[i] = READUINT8(save_p)) > MV_MAX) + // Read map visited flags + for (i = 0; i < NUMBASEMAPS; i++) + { + if (!ReadMapVisited(data, i)) goto datacorrupt; + } // To save space, use one bit per collected/achieved/unlocked flag for (i = 0; i < max_emblems;) @@ -4521,47 +4744,57 @@ void G_LoadGameData(gamedata_t *data) data->timesBeatenUltimate = READUINT32(save_p); // Main records - for (i = 0; i < NUMMAPS; ++i) + for (i = 0; i < NUMBASEMAPS; ++i) { - recscore = READUINT32(save_p); - rectime = (tic_t)READUINT32(save_p); - recrings = READUINT16(save_p); - save_p++; // compat - - if (recrings > 10000 || recscore > MAXSCORE) + if (!ReadMainRecords(data, i)) goto datacorrupt; - - if (recscore || rectime || recrings) - { - G_AllocMainRecordData((INT16)i, data); - data->mainrecords[i]->score = recscore; - data->mainrecords[i]->time = rectime; - data->mainrecords[i]->rings = recrings; - } } // Nights records - for (i = 0; i < NUMMAPS; ++i) + for (i = 0; i < NUMBASEMAPS; ++i) { - if ((recmares = READUINT8(save_p)) == 0) - continue; + if (!ReadNightsRecords(data, i)) + goto datacorrupt; + } + +#ifdef EXTRA_DATA_MARKER + // Read extra data + if (save_p < savebuffer+length && (length - (save_p-savebuffer)) >= 4) + { + UINT32 marker = READUINT32(save_p); + if (marker != EXTRA_DATA_MARKER) + goto datacorrupt; + + UINT8 extraID = READUINT8(save_p); + if (extraID != 0x00) + goto datacorrupt; - G_AllocNightsRecordData((INT16)i, data); + UINT16 nummaps = READUINT16(save_p); + if (nummaps >= MAXMAPS) + goto datacorrupt; - for (curmare = 0; curmare < (recmares+1); ++curmare) + // Read map visited flags + for (i = NUMBASEMAPS; i < nummaps; i++) { - data->nightsrecords[i]->score[curmare] = READUINT32(save_p); - data->nightsrecords[i]->grade[curmare] = READUINT8(save_p); - data->nightsrecords[i]->time[curmare] = (tic_t)READUINT32(save_p); + if (!ReadMapVisited(data, i)) + goto datacorrupt; + } - if (data->nightsrecords[i]->grade[curmare] > GRADE_S) - { + // Main records + for (i = NUMBASEMAPS; i < nummaps; i++) + { + if (!ReadMainRecords(data, i)) goto datacorrupt; - } } - data->nightsrecords[i]->nummares = recmares; + // Nights records + for (i = NUMBASEMAPS; i < nummaps; i++) + { + if (!ReadNightsRecords(data, i)) + goto datacorrupt; + } } +#endif // done Z_Free(savebuffer); @@ -4593,6 +4826,41 @@ void G_LoadGameData(gamedata_t *data) } } +static void WriteMainRecords(gamedata_t *data, UINT16 i) +{ + if (data->mainrecords[i]) + { + WRITEUINT32(save_p, data->mainrecords[i]->score); + WRITEUINT32(save_p, data->mainrecords[i]->time); + WRITEUINT16(save_p, data->mainrecords[i]->rings); + } + else + { + WRITEUINT32(save_p, 0); + WRITEUINT32(save_p, 0); + WRITEUINT16(save_p, 0); + } + WRITEUINT8(save_p, 0); // compat +} + +static void WriteNightsRecords(gamedata_t *data, UINT16 i) +{ + if (!data->nightsrecords[i] || !data->nightsrecords[i]->nummares) + { + WRITEUINT8(save_p, 0); + return; + } + + WRITEUINT8(save_p, data->nightsrecords[i]->nummares); + + for (INT32 curmare = 0; curmare < (data->nightsrecords[i]->nummares + 1); ++curmare) + { + WRITEUINT32(save_p, data->nightsrecords[i]->score[curmare]); + WRITEUINT8(save_p, data->nightsrecords[i]->grade[curmare]); + WRITEUINT32(save_p, data->nightsrecords[i]->time[curmare]); + } +} + // G_SaveGameData // Saves the main data file, which stores information such as emblems found, etc. void G_SaveGameData(gamedata_t *data) @@ -4601,8 +4869,6 @@ void G_SaveGameData(gamedata_t *data) INT32 i, j; UINT8 btemp; - INT32 curmare; - if (!data->loaded) return; // If never loaded (-nodata), don't save @@ -4628,7 +4894,7 @@ void G_SaveGameData(gamedata_t *data) WRITEUINT32(save_p, quickncasehash(timeattackfolder, sizeof timeattackfolder)); // TODO put another cipher on these things? meh, I don't care... - for (i = 0; i < NUMMAPS; i++) + for (i = 0; i < NUMBASEMAPS; i++) WRITEUINT8(save_p, (data->mapvisited[i] & MV_MAX)); // To save space, use one bit per collected/achieved/unlocked flag @@ -4670,41 +4936,35 @@ void G_SaveGameData(gamedata_t *data) WRITEUINT32(save_p, data->timesBeatenUltimate); // Main records - for (i = 0; i < NUMMAPS; i++) - { - if (data->mainrecords[i]) - { - WRITEUINT32(save_p, data->mainrecords[i]->score); - WRITEUINT32(save_p, data->mainrecords[i]->time); - WRITEUINT16(save_p, data->mainrecords[i]->rings); - } - else - { - WRITEUINT32(save_p, 0); - WRITEUINT32(save_p, 0); - WRITEUINT16(save_p, 0); - } - WRITEUINT8(save_p, 0); // compat - } + for (i = 0; i < NUMBASEMAPS; i++) + WriteMainRecords(data, i); // NiGHTS records - for (i = 0; i < NUMMAPS; i++) + for (i = 0; i < NUMBASEMAPS; i++) + WriteNightsRecords(data, i); + +#ifdef EXTRA_DATA_MARKER + if (numgamemaps > NUMBASEMAPS) { - if (!data->nightsrecords[i] || !data->nightsrecords[i]->nummares) - { - WRITEUINT8(save_p, 0); - continue; - } + // Write extra data + WRITEUINT32(save_p, EXTRA_DATA_MARKER); + WRITEUINT8(save_p, 0x00); - WRITEUINT8(save_p, data->nightsrecords[i]->nummares); + WRITEUINT16(save_p, numgamemaps); - for (curmare = 0; curmare < (data->nightsrecords[i]->nummares + 1); ++curmare) - { - WRITEUINT32(save_p, data->nightsrecords[i]->score[curmare]); - WRITEUINT8(save_p, data->nightsrecords[i]->grade[curmare]); - WRITEUINT32(save_p, data->nightsrecords[i]->time[curmare]); - } + // Write map visited flags + for (i = NUMBASEMAPS; i < numgamemaps; i++) + WRITEUINT8(save_p, (data->mapvisited[i] & MV_MAX)); + + // Main records + for (i = NUMBASEMAPS; i < numgamemaps; i++) + WriteMainRecords(data, i); + + // NiGHTS records + for (i = NUMBASEMAPS; i < numgamemaps; i++) + WriteNightsRecords(data, i); } +#endif length = save_p - savebuffer; @@ -5019,7 +5279,7 @@ void G_DeferedInitNew(boolean pultmode, const char *mapname, INT32 character, bo SetPlayerSkinByNum(consoleplayer, character); if (mapname) - D_MapChange(M_MapNumber(mapname[3], mapname[4]), gametype, pultmode, true, 1, false, FLS); + D_MapChange(G_GetMapNumber(mapname), gametype, pultmode, true, 1, false, FLS); } // @@ -5100,18 +5360,18 @@ void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean // (Looks a bit silly, but it works.) boolean reset_skin = netgame && mapheaderinfo[gamemap-1] && mapheaderinfo[gamemap-1]->forcecharacter[0] != '\0'; + gamemap = (INT16)G_GetMapNumber(mapname); // get xx out of MAPxx + // internal game map // well this check is useless because it is done before (d_netcmd.c::command_map_f) // but in case of for demos.... - if (W_CheckNumForName(mapname) == LUMPERROR) + if (gamemap == 0) { I_Error("Internal game map '%s' not found\n", mapname); Command_ExitGame_f(); return; } - gamemap = (INT16)M_MapNumber(mapname[3], mapname[4]); // get xx out of MAPxx - // gamemap changed; we assume that its map header is always valid, // so make it so if(!mapheaderinfo[gamemap-1]) @@ -5162,7 +5422,6 @@ void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean } } - char *G_BuildMapTitle(INT32 mapnum) { char *title = NULL; @@ -5259,7 +5518,7 @@ INT32 G_FindMap(const char *mapname, char **foundmapnamep, mapnamelen = strlen(mapname); /* Count available maps; how ugly. */ - for (i = 0, freqc = 0; i < NUMMAPS; ++i) + for (i = 0, freqc = 0; i < numgamemaps; ++i) { if (mapheaderinfo[i]) freqc++; @@ -5270,7 +5529,7 @@ INT32 G_FindMap(const char *mapname, char **foundmapnamep, wanttable = !!( freqp ); freqc = 0; - for (i = 0, mapnum = 1; i < NUMMAPS; ++i, ++mapnum) + for (i = 0, mapnum = 1; i < numgamemaps; ++i, ++mapnum) if (mapheaderinfo[i]) { if (!( realmapname = G_BuildMapTitle(mapnum) )) @@ -5397,7 +5656,7 @@ INT32 G_FindMapByNameOrCode(const char *mapname, char **realmapnamep) { usemapcode = true; newmapnum = mapheaderinfo[gamemap-1]->nextlevel; - if (newmapnum < 1 || newmapnum > NUMMAPS) + if (newmapnum < 1 || newmapnum > numgamemaps) { CONS_Alert(CONS_ERROR, M_GetText("NextLevel (%d) is not a valid map.\n"), newmapnum); return 0; @@ -5414,6 +5673,11 @@ INT32 G_FindMapByNameOrCode(const char *mapname, char **realmapnamep) if (( newmapnum = M_MapNumber(mapname[3], mapname[4]) )) usemapcode = true; } + else + { + if (( newmapnum = G_GetMapNumber(mapname) )) + usemapcode = true; + } if (!usemapcode) { @@ -5421,7 +5685,7 @@ INT32 G_FindMapByNameOrCode(const char *mapname, char **realmapnamep) newmapnum = strtol(mapname, &p, 10); if (*p == '\0')/* we got it */ { - if (newmapnum < 1 || newmapnum > NUMMAPS) + if (newmapnum < 1 || newmapnum > numgamemaps) { CONS_Alert(CONS_ERROR, M_GetText("Invalid map number %d.\n"), newmapnum); return 0; @@ -5437,7 +5701,7 @@ INT32 G_FindMapByNameOrCode(const char *mapname, char **realmapnamep) if (usemapcode) { /* we can't check mapheaderinfo for this hahahaha */ - if (W_CheckNumForName(G_BuildMapName(newmapnum)) == LUMPERROR) + if (!G_MapFileExists(G_BuildMapName(newmapnum))) return 0; if (realmapnamep) diff --git a/src/g_game.h b/src/g_game.h index 2612224a1252266346c352aa0294fee28047fe15..6e59b2cd2473b416512d5775c7b5f4bb9e01ee33 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -113,8 +113,16 @@ INT32 Joy2Axis(joyaxis_e axissel); #define SLOWTURNTICS (6) // build an internal map name MAPxx from map number +const char *G_BuildClassicMapName(INT32 map); + const char *G_BuildMapName(INT32 map); +void G_InitMaps(void); +UINT16 G_GetMapNumber(const char *name); +UINT16 G_AddMap(const char *name); +boolean G_MapFileExists(const char *name); +boolean G_IsValidMapName(const char *name); + extern INT16 ticcmd_oldangleturn[2]; extern boolean ticcmd_centerviewdown[2]; // For simple controls, lock the camera behind the player extern mobj_t *ticcmd_ztargetfocus[2]; // Locking onto an object? @@ -141,6 +149,11 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps); void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean skipprecutscene, boolean FLS); char *G_BuildMapTitle(INT32 mapnum); +const char *G_GetMapThumbnail(INT16 map); +const char *G_GetMapThumbnailWide(INT16 map); +const char *G_GetDefaultMapMusic(INT16 map); +const char *G_GetMapMetalSonicReplay(INT16 map); +boolean G_IsGameEndMap(INT16 mapnum); struct searchdim { diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 9c723353b33ab6057fea4fc5b24de2499e607c50..87afc772c04a6c7fabce14de17ae4ad87a1d90df 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -1368,7 +1368,7 @@ static int lib_pPlayJingleMusic(lua_State *L) { player_t *player = NULL; const char *musnamearg = luaL_checkstring(L, 2); - char musname[7], *p = musname; + char musname[MAX_MUSIC_NAME+1], *p = musname; UINT16 musflags = luaL_optinteger(L, 3, 0); boolean looping = lua_opttrueboolean(L, 4); jingletype_t jingletype = luaL_optinteger(L, 5, JT_OTHER); @@ -1383,8 +1383,7 @@ static int lib_pPlayJingleMusic(lua_State *L) if (jingletype >= NUMJINGLES) return luaL_error(L, "jingletype %d out of range (0 - %d)", jingletype, NUMJINGLES-1); - musname[6] = '\0'; - strncpy(musname, musnamearg, 6); + strlcpy(musname, musnamearg, MAX_MUSIC_NAME+1); while (*p) { *p = tolower(*p); @@ -3828,10 +3827,34 @@ static int lib_gSetUsedCheats(lua_State *L) return 0; } +static int GetMapNameOrNumber(lua_State *L, int idx) +{ + if (lua_type(L, idx) == LUA_TSTRING) + { + const char *mapname = luaL_checkstring(L, idx); + INT16 mapnum = G_GetMapNumber(mapname); + if (mapnum == 0) + { + return luaL_error(L, + "%s is not a valid game map.", + mapname + ); + } + return mapnum; + } + else + return luaL_checkinteger(L, idx); +} + static int Lcheckmapnumber (lua_State *L, int idx, const char *fun) { if (ISINLEVEL) - return luaL_optinteger(L, idx, gamemap); + { + if (!lua_isnoneornil(L, idx)) + return GetMapNameOrNumber(L, idx); + else + return gamemap; + } else { if (lua_isnoneornil(L, idx)) @@ -3842,14 +3865,21 @@ static int Lcheckmapnumber (lua_State *L, int idx, const char *fun) ); } else - return luaL_checkinteger(L, idx); + return GetMapNameOrNumber(L, idx); } } static int lib_gBuildMapName(lua_State *L) { INT32 map = Lcheckmapnumber(L, 1, "G_BuildMapName"); - //HUDSAFE + if (map < 1 || map > numgamemaps) + { + return luaL_error(L, + "map number %d out of range (1 - %d)", + map, + numgamemaps + ); + } lua_pushstring(L, G_BuildMapName(map)); return 1; } @@ -3858,12 +3888,12 @@ static int lib_gBuildMapTitle(lua_State *L) { INT32 map = Lcheckmapnumber(L, 1, "G_BuildMapTitle"); char *name; - if (map < 1 || map > NUMMAPS) + if (map < 1 || map > numgamemaps) { return luaL_error(L, "map number %d out of range (1 - %d)", map, - NUMMAPS + numgamemaps ); } name = G_BuildMapTitle(map); @@ -3983,6 +4013,36 @@ static int lib_gFindMapByNameOrCode(lua_State *L) return 1; } +static int lib_gGetMapThumbnail(lua_State *L) +{ + INT32 map = Lcheckmapnumber(L, 1, "G_GetMapThumbnail"); + if (map < 1 || map > numgamemaps) + { + return luaL_error(L, + "map number %d out of range (1 - %d)", + map, + numgamemaps + ); + } + lua_pushstring(L, G_GetMapThumbnail(map)); + return 1; +} + +static int lib_gGetMapThumbnailWide(lua_State *L) +{ + INT32 map = Lcheckmapnumber(L, 1, "G_GetMapThumbnailWide"); + if (map < 1 || map > numgamemaps) + { + return luaL_error(L, + "map number %d out of range (1 - %d)", + map, + numgamemaps + ); + } + lua_pushstring(L, G_GetMapThumbnailWide(map)); + return 1; +} + static int lib_gDoReborn(lua_State *L) { INT32 playernum = luaL_checkinteger(L, 1); @@ -4016,7 +4076,19 @@ static int lib_gSetCustomExitVars(lua_State *L) if (n >= 1) { - nextmapoverride = (INT16)luaL_optinteger(L, 1, 0); + if (!lua_isnoneornil(L, 1)) + { + INT16 mapnum = GetMapNameOrNumber(L, 1); + if (mapnum < 1 || mapnum > numgamemaps) + { + return luaL_error(L, + "map number %d out of range (1 - %d)", + mapnum, + numgamemaps + ); + } + nextmapoverride = mapnum; + } skipstats = (INT16)luaL_optinteger(L, 2, 0); nextgametype = (INT16)luaL_optinteger(L, 3, -1); } @@ -4044,9 +4116,22 @@ static int lib_gExitLevel(lua_State *L) static int lib_gIsSpecialStage(lua_State *L) { - INT32 mapnum = luaL_optinteger(L, 1, gamemap); - //HUDSAFE + INT32 mapnum; INLEVEL + if (!lua_isnoneornil(L, 1)) + { + mapnum = GetMapNameOrNumber(L, 1); + if (mapnum < 1 || mapnum > numgamemaps) + { + return luaL_error(L, + "map number %d out of range (1 - %d)", + mapnum, + numgamemaps + ); + } + } + else + mapnum = gamemap; lua_pushboolean(L, G_IsSpecialStage(mapnum)); return 1; } @@ -4451,6 +4536,8 @@ static luaL_Reg lib[] = { {"G_BuildMapTitle",lib_gBuildMapTitle}, {"G_FindMap",lib_gFindMap}, {"G_FindMapByNameOrCode",lib_gFindMapByNameOrCode}, + {"G_GetMapThumbnail",lib_gGetMapThumbnail}, + {"G_GetMapThumbnailWide",lib_gGetMapThumbnailWide}, {"G_DoReborn",lib_gDoReborn}, {"G_SetCustomExitVars",lib_gSetCustomExitVars}, {"G_EnoughPlayersFinished",lib_gEnoughPlayersFinished}, diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index 38815a06cfa4558b8ad5659bcbe1cdba5705ca03..358bc82af425e193a25a08fdf93e92622f00dd69 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -1067,16 +1067,16 @@ static void update_music_name(struct MusicChange *musicchange) size_t length; const char * new = lua_tolstring(gL, -6, &length); - if (length < 7) + if (length <= MAX_MUSIC_NAME) { strcpy(musicchange->newname, new); lua_pushvalue(gL, -6);/* may as well keep it for next call */ } else { - memcpy(musicchange->newname, new, 6); - musicchange->newname[6] = '\0'; - lua_pushlstring(gL, new, 6); + memcpy(musicchange->newname, new, MAX_MUSIC_NAME); + musicchange->newname[MAX_MUSIC_NAME] = '\0'; + lua_pushlstring(gL, new, MAX_MUSIC_NAME); } lua_replace(gL, -7); diff --git a/src/lua_maplib.c b/src/lua_maplib.c index 0c4ba6fd3e24451d4b3144264bb5c357eb3eea35..d5cb0c2f054f10fe21c2dd8651d412bd80bd292a 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -2685,32 +2685,22 @@ static int vector3_get(lua_State *L) static int lib_getMapheaderinfo(lua_State *L) { // i -> mapheaderinfo[i-1] - - //int field; lua_settop(L, 2); lua_remove(L, 1); // dummy userdata table is unused. if (lua_isnumber(L, 1)) { size_t i = lua_tointeger(L, 1)-1; - if (i >= NUMMAPS) + if (i >= numgamemaps) return 0; LUA_PushUserdata(L, mapheaderinfo[i], META_MAPHEADER); - //CONS_Printf(mapheaderinfo[i]->lvlttl); - return 1; - }/* - field = luaL_checkoption(L, 1, NULL, array_opt); - switch(field) - { - case 0: // iterate - lua_pushcfunction(L, lib_iterateSubsectors); return 1; - }*/ + } return 0; } static int lib_nummapheaders(lua_State *L) { - lua_pushinteger(L, NUMMAPS); + lua_pushinteger(L, numgamemaps); return 1; } diff --git a/src/m_cond.c b/src/m_cond.c index 706a1b5106f487e4ed285880304a87335f7f716e..7fea86c65700126f81134134a3ff3253065b23c8 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -78,7 +78,7 @@ void M_CopyGameData(gamedata_t *dest, gamedata_t *src) memcpy(dest->mapvisited, src->mapvisited, sizeof(dest->mapvisited)); // Main records - for (i = 0; i < NUMMAPS; ++i) + for (i = 0; i < MAXMAPS; ++i) { if (!src->mainrecords[i]) continue; @@ -90,7 +90,7 @@ void M_CopyGameData(gamedata_t *dest, gamedata_t *src) } // Nights records - for (i = 0; i < NUMMAPS; ++i) + for (i = 0; i < MAXMAPS; ++i) { if (!src->nightsrecords[i] || !src->nightsrecords[i]->nummares) continue; @@ -574,7 +574,7 @@ UINT8 M_GotHighEnoughScore(INT32 tscore, gamedata_t *data) INT32 mscore = 0; INT32 i; - for (i = 0; i < NUMMAPS; ++i) + for (i = 0; i < numgamemaps; ++i) { if (!mapheaderinfo[i] || !(mapheaderinfo[i]->menuflags & LF2_RECORDATTACK)) continue; @@ -592,7 +592,7 @@ UINT8 M_GotLowEnoughTime(INT32 tictime, gamedata_t *data) INT32 curtics = 0; INT32 i; - for (i = 0; i < NUMMAPS; ++i) + for (i = 0; i < numgamemaps; ++i) { if (!mapheaderinfo[i] || !(mapheaderinfo[i]->menuflags & LF2_RECORDATTACK)) continue; @@ -610,7 +610,7 @@ UINT8 M_GotHighEnoughRings(INT32 trings, gamedata_t *data) INT32 mrings = 0; INT32 i; - for (i = 0; i < NUMMAPS; ++i) + for (i = 0; i < numgamemaps; ++i) { if (!mapheaderinfo[i] || !(mapheaderinfo[i]->menuflags & LF2_RECORDATTACK)) continue; diff --git a/src/m_cond.h b/src/m_cond.h index 2491a384c02aa5f34ba47933eba689811ac599d0..2efc6c530cb467b4bc2abd36da48951e56edf2a2 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -203,9 +203,9 @@ typedef struct boolean unlocked[MAXUNLOCKABLES]; // TIME ATTACK DATA - recorddata_t *mainrecords[NUMMAPS]; - nightsdata_t *nightsrecords[NUMMAPS]; - UINT8 mapvisited[NUMMAPS]; + recorddata_t *mainrecords[MAXMAPS]; + nightsdata_t *nightsrecords[MAXMAPS]; + UINT8 mapvisited[MAXMAPS]; // # OF TIMES THE GAME HAS BEEN BEATEN UINT32 timesBeaten; diff --git a/src/m_menu.c b/src/m_menu.c index 9aae59445382270c6d45445dfb113425fe52eee6..7dc5056ac221ecad45199ff23e87f87241d68e83 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -414,7 +414,7 @@ consvar_t cv_showfocuslost = CVAR_INIT ("showfocuslost", "Yes", CV_SAVE, CV_YesN static CV_PossibleValue_t map_cons_t[] = { {1,"MIN"}, - {NUMMAPS, "MAX"}, + {MAXMAPS, "MAX"}, {0,NULL} }; consvar_t cv_nextmap = CVAR_INIT ("nextmap", "1", CV_HIDEN|CV_CALL, map_cons_t, Nextmap_OnChange); @@ -2230,9 +2230,9 @@ void Nextmap_OnChange(void) { gamedata_t *data = clientGamedata; char *leveltitle; - char tabase[256]; + char tabase[4096]; #ifdef OLDNREPLAYNAME - char tabaseold[256]; + char tabaseold[4096]; #endif short i; boolean active; @@ -2498,13 +2498,13 @@ void M_InitMenuPresTables(void) menupres[i].muslooping = true; } if (i == MN_SP_TIMEATTACK) - strncpy(menupres[i].musname, "_recat", 7); + strlcpy(menupres[i].musname, "_recat", MAX_MUSIC_NAME+1); else if (i == MN_SP_NIGHTSATTACK) - strncpy(menupres[i].musname, "_nitat", 7); + strlcpy(menupres[i].musname, "_nitat", MAX_MUSIC_NAME+1); else if (i == MN_SP_MARATHON) - strncpy(menupres[i].musname, "spec8", 6); + strlcpy(menupres[i].musname, "spec8", MAX_MUSIC_NAME+1); else if (i == MN_SP_PLAYER || i == MN_SR_PLAYER) - strncpy(menupres[i].musname, "_chsel", 7); + strlcpy(menupres[i].musname, "_chsel", MAX_MUSIC_NAME+1); else if (i == MN_SR_SOUNDTEST) { *menupres[i].musname = '\0'; @@ -2530,7 +2530,7 @@ typedef boolean (*menutree_iterator)(UINT32, INT32, INT32 *, void **, boolean fr // a single input. Maybe someday use this struct program-wide. typedef struct { - char musname[7]; + char musname[MAX_MUSIC_NAME+1]; UINT16 mustrack; boolean muslooping; } menupresmusic_t; @@ -2741,8 +2741,7 @@ void M_ChangeMenuMusic(const char *defaultmusname, boolean defaultmuslooping) if (!defaultmusname) defaultmusname = ""; - strncpy(defaultmusic.musname, defaultmusname, 7); - defaultmusic.musname[6] = 0; + strlcpy(defaultmusic.musname, defaultmusname, MAX_MUSIC_NAME+1); defaultmusic.mustrack = 0; defaultmusic.muslooping = defaultmuslooping; @@ -5091,7 +5090,7 @@ static INT32 M_CountLevelsToShowOnPlatter(INT32 gt) { INT32 mapnum, count = 0; - for (mapnum = 0; mapnum < NUMMAPS; mapnum++) + for (mapnum = 0; mapnum < numgamemaps; mapnum++) if (M_CanShowLevelOnPlatter(mapnum, gt)) count++; @@ -5126,7 +5125,7 @@ static boolean M_GametypeHasLevels(INT32 gt) { INT32 mapnum; - for (mapnum = 0; mapnum < NUMMAPS; mapnum++) + for (mapnum = 0; mapnum < numgamemaps; mapnum++) if (M_CanShowLevelOnPlatter(mapnum, gt)) return true; @@ -5138,11 +5137,9 @@ static INT32 M_CountRowsToShowOnPlatter(INT32 gt) INT32 col = 0, rows = 0; INT32 mapIterate = 0; INT32 headingIterate = 0; - boolean mapAddedAlready[NUMMAPS]; + boolean *mapAddedAlready = Z_Calloc(numgamemaps*sizeof(boolean), PU_STATIC, NULL); - memset(mapAddedAlready, 0, sizeof mapAddedAlready); - - for (mapIterate = 0; mapIterate < NUMMAPS; mapIterate++) + for (mapIterate = 0; mapIterate < numgamemaps; mapIterate++) { boolean forceNewRow = true; @@ -5158,7 +5155,7 @@ static INT32 M_CountRowsToShowOnPlatter(INT32 gt) continue; } - for (headingIterate = mapIterate; headingIterate < NUMMAPS; headingIterate++) + for (headingIterate = mapIterate; headingIterate < numgamemaps; headingIterate++) { boolean wide = false; @@ -5205,6 +5202,8 @@ static INT32 M_CountRowsToShowOnPlatter(INT32 gt) rows++; } + Z_Free(mapAddedAlready); + return rows; } @@ -5236,11 +5235,13 @@ static boolean M_PrepareLevelPlatter(INT32 gt, boolean nextmappick) INT32 col = 0, row = 0, startrow = 0; INT32 mapIterate = 0; // First level of map loop -- find starting points for select headings INT32 headingIterate = 0; // Second level of map loop -- finding maps that match mapIterate's heading. - boolean mapAddedAlready[NUMMAPS]; + boolean *mapAddedAlready; if (!numrows) return false; + mapAddedAlready = Z_Calloc(numgamemaps*sizeof(boolean), PU_STATIC, NULL); + if (levelselect.rows) Z_Free(levelselect.rows); levelselect.rows = NULL; @@ -5253,8 +5254,6 @@ static boolean M_PrepareLevelPlatter(INT32 gt, boolean nextmappick) // done here so lsrow and lscol can be set if cv_nextmap is on the platter lsrow = lscol = lshli = lsoffs[0] = lsoffs[1] = 0; - memset(mapAddedAlready, 0, sizeof mapAddedAlready); - if (levellistmode == LLM_CREATESERVER) { sprintf(levelselect.rows[0].header, "Gametype"); @@ -5266,7 +5265,7 @@ static boolean M_PrepareLevelPlatter(INT32 gt, boolean nextmappick) char_notes = NULL; } - for (mapIterate = 0; mapIterate < NUMMAPS; mapIterate++) + for (mapIterate = 0; mapIterate < numgamemaps; mapIterate++) { INT32 headerRow = -1; boolean anyAvailable = false; @@ -5284,7 +5283,7 @@ static boolean M_PrepareLevelPlatter(INT32 gt, boolean nextmappick) continue; } - for (headingIterate = mapIterate; headingIterate < NUMMAPS; headingIterate++) + for (headingIterate = mapIterate; headingIterate < numgamemaps; headingIterate++) { UINT8 actnum = 0; boolean headingisname = false; @@ -5435,6 +5434,8 @@ static boolean M_PrepareLevelPlatter(INT32 gt, boolean nextmappick) } #endif + Z_Free(mapAddedAlready); + M_CacheLevelPlatter(); return true; @@ -5670,8 +5671,9 @@ static void M_DrawLevelPlatterWideMap(UINT8 row, UINT8 col, INT32 x, INT32 y, bo } else { - if (W_CheckNumForName(va("%sW", G_BuildMapName(map))) != LUMPERROR) - patch = W_CachePatchName(va("%sW", G_BuildMapName(map)), PU_PATCH); + const char *thumbnail = G_GetMapThumbnailWide(map); + if (W_CheckNumForLongName(thumbnail) != LUMPERROR) + patch = W_CachePatchLongName(thumbnail, PU_PATCH); else patch = levselp[1][2]; // don't static to indicate that it's just a normal level @@ -5701,8 +5703,9 @@ static void M_DrawLevelPlatterMap(UINT8 row, UINT8 col, INT32 x, INT32 y, boolea } else { - if (W_CheckNumForName(va("%sP", G_BuildMapName(map))) != LUMPERROR) - patch = W_CachePatchName(va("%sP", G_BuildMapName(map)), PU_PATCH); + const char *thumbnail = G_GetMapThumbnail(map); + if (W_CheckNumForLongName(thumbnail) != LUMPERROR) + patch = W_CachePatchLongName(thumbnail, PU_PATCH); else patch = levselp[0][2]; // don't static to indicate that it's just a normal level @@ -6025,7 +6028,7 @@ static INT32 M_GetFirstLevelInList(INT32 gt) { INT32 mapnum; - for (mapnum = 0; mapnum < NUMMAPS; mapnum++) + for (mapnum = 0; mapnum < numgamemaps; mapnum++) if (M_CanShowLevelInList(mapnum, gt)) return mapnum + 1; @@ -6905,12 +6908,9 @@ static boolean M_ExitPandorasBox(void) static void M_ChangeLevel(INT32 choice) { - char mapname[6]; - (void)choice; + const char *mapname = G_BuildMapName(cv_nextmap.value); - strlcpy(mapname, G_BuildMapName(cv_nextmap.value), sizeof (mapname)); - strlwr(mapname); - mapname[5] = '\0'; + (void)choice; M_ClearMenus(true); COM_BufAddText(va("map %s -gametype \"%s\"\n", mapname, cv_newgametype.string)); @@ -7075,7 +7075,7 @@ static void M_LevelSelectWarp(INT32 choice) { (void)choice; - if (W_CheckNumForName(G_BuildMapName(cv_nextmap.value)) == LUMPERROR) + if (!G_MapFileExists(G_BuildMapName(cv_nextmap.value))) { CONS_Alert(CONS_WARNING, "Internal game map '%s' not found\n", G_BuildMapName(cv_nextmap.value)); return; @@ -8438,7 +8438,7 @@ static void M_DrawLoadGameData(void) #ifdef PERFECTSAVE // disabled on request else if ((savegameinfo[savetodraw].skinnum == 1) && (savegameinfo[savetodraw].lives == 99) - && (savegameinfo[savetodraw].gamemap & 8192) + && (savegameinfo[savetodraw].flags & SAVE_GAME_COMPLETE_BIT) && (savegameinfo[savetodraw].numgameovers == 0) && (savegameinfo[savetodraw].numemeralds == ((1<<7) - 1))) // perfect save { @@ -8494,11 +8494,11 @@ static void M_DrawLoadGameData(void) else { patch_t *patch; - if (savegameinfo[savetodraw].gamemap & 8192) + if (savegameinfo[savetodraw].flags & SAVE_GAME_COMPLETE_BIT) patch = savselp[3]; else { - lumpnum_t lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName((savegameinfo[savetodraw].gamemap) & 8191))); + lumpnum_t lumpnum = W_CheckNumForLongName(G_GetMapThumbnail(savegameinfo[savetodraw].gamemap)); if (lumpnum != LUMPERROR) patch = W_CachePatchNum(lumpnum, PU_PATCH); else @@ -8513,7 +8513,7 @@ static void M_DrawLoadGameData(void) V_DrawRightAlignedThinString(x + 79, y, V_GRAYMAP, "NEW GAME"); else if (savegameinfo[savetodraw].lives == -666) V_DrawRightAlignedThinString(x + 79, y, V_REDMAP, "CAN'T LOAD!"); - else if (savegameinfo[savetodraw].gamemap & 8192) + else if (savegameinfo[savetodraw].flags & SAVE_GAME_COMPLETE_BIT) V_DrawRightAlignedThinString(x + 79, y, V_GREENMAP, "CLEAR!"); else V_DrawRightAlignedThinString(x + 79, y, V_YELLOWMAP, savegameinfo[savetodraw].levelname); @@ -8731,7 +8731,7 @@ static void M_LoadSelect(INT32 choice) // This slot is empty, so start a new game here. M_NewGame(); } - else if (savegameinfo[saveSlotSelected-1].gamemap & 8192) // Completed + else if (savegameinfo[saveSlotSelected-1].flags & SAVE_GAME_COMPLETE_BIT) // Completed M_LoadGameLevelSelect(0); else G_LoadGame((UINT32)saveSlotSelected, 0); @@ -8752,6 +8752,7 @@ static void M_ReadSavegameInfo(UINT32 slot) UINT8 *end_p; // buffer end point, don't read past here UINT8 *sav_p; INT32 fake; // Dummy variable + INT16 mapnum; char temp[sizeof(timeattackfolder)]; char vcheck[VERSIONSIZE]; #ifdef NEWSKINSAVES @@ -8786,19 +8787,44 @@ static void M_ReadSavegameInfo(UINT32 slot) CHECKPOS fake = READINT16(sav_p); - if (((fake-1) & 8191) >= NUMMAPS) BADSAVE +#ifdef NEWMAPSAVES + if (fake == NEWMAPSAVES) + { + char mapname[MAX_MAP_NAME_SIZE+1]; + + READSTRINGN(sav_p, mapname, MAX_MAP_NAME_SIZE); + + savegameinfo[slot].flags = READUINT8(sav_p); - if(!mapheaderinfo[(fake-1) & 8191]) + mapnum = G_GetMapNumber(mapname); + if (mapnum == 0) + BADSAVE + } + else +#endif + { + if (((fake-1) & 8191) >= NUMBASEMAPS) BADSAVE + + mapnum = (fake-1) & 8191; + mapnum++; + + if (fake & 8192) + savegameinfo[slot].flags = SAVE_GAME_COMPLETE_BIT; + else + savegameinfo[slot].flags = 0; + } + + if(!mapheaderinfo[mapnum-1]) savegameinfo[slot].levelname[0] = '\0'; - else if (V_ThinStringWidth(mapheaderinfo[(fake-1) & 8191]->lvlttl, 0) <= 78) - strlcpy(savegameinfo[slot].levelname, mapheaderinfo[(fake-1) & 8191]->lvlttl, 22); + else if (V_ThinStringWidth(mapheaderinfo[mapnum-1]->lvlttl, 0) <= 78) + strlcpy(savegameinfo[slot].levelname, mapheaderinfo[mapnum-1]->lvlttl, 22); else { - strlcpy(savegameinfo[slot].levelname, mapheaderinfo[(fake-1) & 8191]->lvlttl, 15); + strlcpy(savegameinfo[slot].levelname, mapheaderinfo[mapnum-1]->lvlttl, 15); strcat(savegameinfo[slot].levelname, "..."); } - savegameinfo[slot].gamemap = fake; + savegameinfo[slot].gamemap = mapnum; CHECKPOS savegameinfo[slot].numemeralds = READUINT16(sav_p)-357; // emeralds @@ -9608,7 +9634,8 @@ static void M_ChoosePlayer(INT32 choice) static INT32 statsLocation; static INT32 statsMax; -static INT16 statsMapList[NUMMAPS+1]; +static INT16 *statsMapList = NULL; +static size_t statsMapLength = 0; static void M_Statistics(INT32 choice) { @@ -9616,9 +9643,17 @@ static void M_Statistics(INT32 choice) (void)choice; - memset(statsMapList, 0, sizeof(statsMapList)); + size_t num_maps = (size_t)(numgamemaps+1); + + if (statsMapLength != num_maps) + { + statsMapLength = num_maps; + statsMapList = Z_Realloc(statsMapList, statsMapLength*sizeof(INT16), PU_STATIC, NULL); + } + + memset(statsMapList, 0, statsMapLength*sizeof(INT16)); - for (i = 0; i < NUMMAPS; i++) + for (i = 0; i < numgamemaps; i++) { if (!mapheaderinfo[i] || mapheaderinfo[i]->lvlttl[0] == '\0') continue; @@ -9754,7 +9789,7 @@ static void M_DrawLevelStats(void) G_TicsToMinutes(data->totalplaytime, false), G_TicsToSeconds(data->totalplaytime))); - for (i = 0; i < NUMMAPS; i++) + for (i = 0; i < numgamemaps; i++) { boolean mapunfinished = false; @@ -9965,10 +10000,10 @@ void M_DrawTimeAttackMenu(void) M_DrawLevelPlatterHeader(32-lsheadingheight/2, cv_nextmap.string, true, false); // A 160x100 image of the level as entry MAPxxP - lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(cv_nextmap.value))); + lumpnum = W_CheckNumForLongName(G_GetMapThumbnail(cv_nextmap.value)); if (lumpnum != LUMPERROR) - PictureOfLevel = W_CachePatchName(va("%sP", G_BuildMapName(cv_nextmap.value)), PU_PATCH); + PictureOfLevel = W_CachePatchLongName(G_GetMapThumbnail(cv_nextmap.value), PU_PATCH); else PictureOfLevel = W_CachePatchName("BLANKLVL", PU_PATCH); @@ -10229,10 +10264,10 @@ void M_DrawNightsAttackMenu(void) M_DrawLevelPlatterHeader(32-lsheadingheight/2, cv_nextmap.string, true, false); // A 160x100 image of the level as entry MAPxxP - lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(cv_nextmap.value))); + lumpnum = W_CheckNumForLongName(G_GetMapThumbnail(cv_nextmap.value)); if (lumpnum != LUMPERROR) - PictureOfLevel = W_CachePatchName(va("%sP", G_BuildMapName(cv_nextmap.value)), PU_PATCH); + PictureOfLevel = W_CachePatchLongName(G_GetMapThumbnail(cv_nextmap.value), PU_PATCH); else PictureOfLevel = W_CachePatchName("BLANKLVL", PU_PATCH); @@ -10366,7 +10401,8 @@ static void M_NightsAttack(INT32 choice) static void M_ChooseNightsAttack(INT32 choice) { char *gpath; - const size_t glen = strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1; + const char *mapname = G_BuildMapName(cv_nextmap.value); + const size_t glen = strlen("replay")+1+strlen(timeattackfolder)+1+strlen(mapname)+1; char nameofdemo[256]; (void)choice; emeralds = 0; @@ -10380,7 +10416,7 @@ static void M_ChooseNightsAttack(INT32 choice) if ((gpath = malloc(glen)) == NULL) I_Error("Out of memory for replay filepath\n"); - sprintf(gpath,"replay"PATHSEP"%s"PATHSEP"%s", timeattackfolder, G_BuildMapName(cv_nextmap.value)); + sprintf(gpath,"replay"PATHSEP"%s"PATHSEP"%s", timeattackfolder, mapname); snprintf(nameofdemo, sizeof nameofdemo, "%s-%s-last", gpath, skins[cv_chooseskin.value-1].name); if (!cv_autorecord.value) @@ -10395,7 +10431,8 @@ static void M_ChooseNightsAttack(INT32 choice) static void M_ChooseTimeAttack(INT32 choice) { char *gpath; - const size_t glen = strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1; + const char *mapname = G_BuildMapName(cv_nextmap.value); + const size_t glen = strlen("replay")+1+strlen(timeattackfolder)+1+strlen(mapname)+1; char nameofdemo[256]; (void)choice; emeralds = 0; @@ -10409,7 +10446,7 @@ static void M_ChooseTimeAttack(INT32 choice) if ((gpath = malloc(glen)) == NULL) I_Error("Out of memory for replay filepath\n"); - sprintf(gpath,"replay"PATHSEP"%s"PATHSEP"%s", timeattackfolder, G_BuildMapName(cv_nextmap.value)); + sprintf(gpath,"replay"PATHSEP"%s"PATHSEP"%s", timeattackfolder, mapname); snprintf(nameofdemo, sizeof nameofdemo, "%s-%s-last", gpath, skins[cv_chooseskin.value-1].name); if (!cv_autorecord.value) @@ -10741,7 +10778,7 @@ static void M_Marathon(INT32 choice) SP_MarathonMenu[marathonplayer].status = (skinset == MAXSKINS) ? IT_KEYHANDLER|IT_STRING : IT_NOTHING|IT_DISABLED; - while (mapnum < NUMMAPS) + while (mapnum < numgamemaps) { if (mapheaderinfo[mapnum]) { @@ -10751,7 +10788,7 @@ static void M_Marathon(INT32 choice) mapnum++; } - SP_MarathonMenu[marathoncutscenes].status = (mapnum < NUMMAPS) ? IT_CVAR|IT_STRING : IT_NOTHING|IT_DISABLED; + SP_MarathonMenu[marathoncutscenes].status = (mapnum < numgamemaps) ? IT_CVAR|IT_STRING : IT_NOTHING|IT_DISABLED; M_ChangeMenuMusic("spec8", true); @@ -11650,10 +11687,10 @@ static void M_DrawServerMenu(void) M_DrawLevelPlatterHeader(currentMenu->y + imgheight - 10 - lsheadingheight/2, (const char *)headerstr, true, false); // A 160x100 image of the level as entry MAPxxP - lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(cv_nextmap.value))); + lumpnum = W_CheckNumForLongName(G_GetMapThumbnail(cv_nextmap.value)); if (lumpnum != LUMPERROR) - PictureOfLevel = W_CachePatchName(va("%sP", G_BuildMapName(cv_nextmap.value)), PU_PATCH); + PictureOfLevel = W_CachePatchLongName(G_GetMapThumbnail(cv_nextmap.value), PU_PATCH); else PictureOfLevel = W_CachePatchName("BLANKLVL", PU_PATCH); diff --git a/src/m_menu.h b/src/m_menu.h index b8fe3b808928b81c86bf3c09731e557f4b113616..ed026a65df9ef612236245b3cb63c994466533cb 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -159,7 +159,7 @@ typedef struct INT16 ttloop; // # frame to loop; -1 means dont loop UINT16 tttics; // # of tics per frame - char musname[7]; ///< Music track to play. "" for no music. + char musname[MAX_MUSIC_NAME+1]; ///< Music track to play. "" for no music. UINT16 mustrack; ///< Subsong to play. Only really relevant for music modules and specific formats supported by GME. 0 to ignore. boolean muslooping; ///< Loop the music boolean musstop; ///< Don't play any music @@ -429,6 +429,7 @@ typedef struct INT32 lives; INT32 continuescore; INT32 gamemap; + UINT8 flags; } saveinfo_t; extern description_t description[MAXSKINS]; diff --git a/src/m_misc.c b/src/m_misc.c index ce332910dc8ccf78a8c751adfc96c28c3721aea4..ed5e1ebcdaa0e2fc64b084a742a879d6c360b579 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -2387,6 +2387,30 @@ boolean M_IsStringEmpty(const char *s) return true; } +const char *M_GetFilenameFromPath(const char *path) +{ + const char *slash = strrchr(path, '/'); + if (slash) + return slash + 1; + return path; +} + +const char *M_GetExtensionFromFilename(const char *filename) +{ + const char *dot = strrchr(filename, '.'); + if (dot) + return dot + 1; + return NULL; +} + +const char *M_CheckFilenameExtension(const char *filename, const char *ext) +{ + const char *dot = strrchr(filename, '.'); + if (dot && (strstr(dot, ext) || strstr(dot + 1, ext))) + return dot + 1; + return NULL; +} + // Rounds off floating numbers and checks for 0 - 255 bounds int M_RoundUp(double number) { diff --git a/src/m_misc.h b/src/m_misc.h index 753991e70465c075fa874ce7662d6aa6603e7b6a..7e6f18d4cd598490422c3b73d2698c3c6c5c00ae 100644 --- a/src/m_misc.h +++ b/src/m_misc.h @@ -109,6 +109,10 @@ const char * M_Ftrim (double); // Returns true if the string is empty. boolean M_IsStringEmpty(const char *s); +const char *M_GetFilenameFromPath(const char *path); +const char *M_GetExtensionFromFilename(const char *filename); +const char *M_CheckFilenameExtension(const char *filename, const char *ext); + // counting bits, for weapon ammo code, usually FUNCMATH UINT8 M_CountBits(UINT32 num, UINT8 size); diff --git a/src/netcode/d_netcmd.c b/src/netcode/d_netcmd.c index ef1ef9aeb1971d1a63b41944e59c161d8e05f676..a6b7b804d26bc222efe8a65b71deb5679b0680af 100644 --- a/src/netcode/d_netcmd.c +++ b/src/netcode/d_netcmd.c @@ -1720,7 +1720,7 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pultmode, boolean rese { UINT8 flags = 0; const char *mapname = G_BuildMapName(mapnum); - I_Assert(W_CheckNumForName(mapname) != LUMPERROR); + I_Assert(G_MapFileExists(mapname) == true); buf_p = buf; if (pultmode) flags |= 1; @@ -2022,8 +2022,8 @@ static void Command_Map_f(void) static void Got_Mapcmd(UINT8 **cp, INT32 playernum) { char mapname[MAX_WADPATH+1]; - UINT8 flags; - INT32 resetplayer = 1, lastgametype; + UINT8 flags, newgametype; + INT32 resetplayer = 1, lastgametype = gametype; UINT8 skipprecutscene, FLS; INT16 mapnumber; @@ -2039,6 +2039,12 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) chmappending--; flags = READUINT8(*cp); + newgametype = READUINT8(*cp); + READSTRINGN(*cp, mapname, MAX_WADPATH); + + mapnumber = G_GetMapNumber(mapname); + if (!mapnumber) // Not valid??? + return; ultimatemode = ((flags & 1) != 0); if (netgame || multiplayer) @@ -2046,13 +2052,8 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) resetplayer = ((flags & (1<<1)) == 0); - lastgametype = gametype; - gametype = READUINT8(*cp); - - if (gametype < 0 || gametype >= gametypecount) - gametype = lastgametype; - else - G_SetGametype(gametype); + if (newgametype < gametypecount) + G_SetGametype(newgametype); if (gametype != lastgametype) D_GameTypeChanged(lastgametype); // emulate consvar_t behavior for gametype @@ -2061,8 +2062,6 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) FLS = ((flags & (1<<3)) != 0); - READSTRINGN(*cp, mapname, MAX_WADPATH); - if (netgame) P_SetRandSeed(READUINT32(*cp)); @@ -2082,7 +2081,6 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) players[0].skincolor = skins[players[0].skin].prefcolor; } - mapnumber = M_MapNumber(mapname[3], mapname[4]); LUA_HookInt(mapnumber, HOOK(MapChange)); G_InitNew(ultimatemode, mapname, resetplayer, skipprecutscene, FLS); diff --git a/src/netcode/server_connection.c b/src/netcode/server_connection.c index bfbe30a08ed89aba1af4bb5ef6f2a51448d00c1c..2805824b53adff558e50b49f12ca7531a26a6557 100644 --- a/src/netcode/server_connection.c +++ b/src/netcode/server_connection.c @@ -121,7 +121,7 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime) netbuffer->u.serverinfo.flags = (dedicated ? SV_DEDICATED : 0); strncpy(netbuffer->u.serverinfo.servername, cv_servername.string, MAXSERVERNAME); - strncpy(netbuffer->u.serverinfo.mapname, G_BuildMapName(gamemap), 7); + strncpy(netbuffer->u.serverinfo.mapname, G_BuildMapName(gamemap), 7); // [mapnames] FIXME M_Memcpy(netbuffer->u.serverinfo.mapmd5, mapmd5, 16); diff --git a/src/p_enemy.c b/src/p_enemy.c index 819f0dc1d992f1251def75c6a82eb687d7c5e69c..a7492f0533d896824e766804db9b6548cf3214e6 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -4035,11 +4035,10 @@ static void P_DoBossVictory(mobj_t *mo) // Touching the egg trap button calls P_DoPlayerExit, which calls P_RestoreMusic. // So just park ourselves in the mapmus variables. // But don't change the mapmus variables if they were modified from their level header values (e.g., TUNES). - boolean changed = strnicmp(mapheaderinfo[gamemap-1]->musname, S_MusicName(), 7); - if (!strnicmp(mapheaderinfo[gamemap-1]->musname, mapmusname, 7)) + boolean changed = strnicmp(mapheaderinfo[gamemap-1]->musname, S_MusicName(), MAX_MUSIC_NAME); + if (!strnicmp(mapheaderinfo[gamemap-1]->musname, mapmusname, MAX_MUSIC_NAME)) { - strncpy(mapmusname, mapheaderinfo[gamemap-1]->muspostbossname, 7); - mapmusname[6] = 0; + strlcpy(mapmusname, mapheaderinfo[gamemap-1]->muspostbossname, MAX_MUSIC_NAME+1); mapmusflags = (mapheaderinfo[gamemap-1]->muspostbosstrack & MUSIC_TRACKMASK) | MUSIC_RELOADRESET; mapmusposition = mapheaderinfo[gamemap-1]->muspostbosspos; } diff --git a/src/p_local.h b/src/p_local.h index 84a0aace09b83b4a6f5bc71552ccb910a486ae43..1d53938b6d5c0220ac90c3dc5738c12ca09d2c87 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -258,7 +258,7 @@ typedef enum typedef struct { - char musname[7]; + char musname[MAX_MUSIC_NAME+1]; boolean looping; } jingle_t; diff --git a/src/p_saveg.c b/src/p_saveg.c index 8c74ebef4815cd535c16436b682efcdd769b5f42..f6c9134b2fe6e9461b05519b716dfe7e26cc387a 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -4355,24 +4355,59 @@ static void P_NetUnArchiveSpecials(void) // ======================================================================= // Misc // ======================================================================= -static inline void P_ArchiveMisc(INT16 mapnum) +static void P_ArchiveMisc(INT16 mapnum) { - //lastmapsaved = mapnum; lastmaploaded = mapnum; - if (gamecomplete) - mapnum |= 8192; +#ifdef NEWMAPSAVES + if (mapnum >= NUMBASEMAPS) + { + WRITEINT16(save_p, NEWMAPSAVES); + WRITESTRINGN(save_p, G_BuildMapName(mapnum), MAX_MAP_NAME_SIZE); + + UINT8 flags = 0; + if (gamecomplete) + flags |= SAVE_GAME_COMPLETE_BIT; + + WRITEUINT8(save_p, flags); + } + else +#endif + { + if (gamecomplete) + mapnum |= 8192; + + WRITEINT16(save_p, mapnum); + } - WRITEINT16(save_p, mapnum); WRITEUINT16(save_p, emeralds+357); WRITESTRINGN(save_p, timeattackfolder, sizeof(timeattackfolder)); } -static inline void P_UnArchiveSPGame(INT16 mapoverride) +static void P_UnArchiveSPGame(INT16 mapoverride) { char testname[sizeof(timeattackfolder)]; - gamemap = READINT16(save_p); + INT16 mapnum = READINT16(save_p); + +#ifdef NEWMAPSAVES + if (mapnum == NEWMAPSAVES) + { + char mapname[MAX_MAP_NAME_SIZE+1]; + + READSTRINGN(save_p, mapname, MAX_MAP_NAME_SIZE); + READUINT8(save_p); // flags + + mapnum = G_GetMapNumber(mapname); + if (mapnum == 0) + { + // If not valid, just load MAP01 instead. + mapnum = 1; + } + } +#endif + + gamemap = mapnum; if (mapoverride != 0) { @@ -4387,7 +4422,6 @@ static inline void P_UnArchiveSPGame(INT16 mapoverride) if(!mapheaderinfo[gamemap-1]) P_AllocMapHeader(gamemap-1); - //lastmapsaved = gamemap; lastmaploaded = gamemap; tokenlist = 0; @@ -4612,7 +4646,7 @@ static inline void P_NetArchiveEmblems(void) WRITEUINT32(save_p, data->totalplaytime); // TODO put another cipher on these things? meh, I don't care... - for (i = 0; i < NUMMAPS; i++) + for (i = 0; i < numgamemaps; i++) WRITEUINT8(save_p, (data->mapvisited[i] & MV_MAX)); // To save space, use one bit per collected/achieved/unlocked flag @@ -4654,7 +4688,7 @@ static inline void P_NetArchiveEmblems(void) WRITEUINT32(save_p, data->timesBeatenUltimate); // Main records - for (i = 0; i < NUMMAPS; i++) + for (i = 0; i < numgamemaps; i++) { if (data->mainrecords[i]) { @@ -4671,7 +4705,7 @@ static inline void P_NetArchiveEmblems(void) } // NiGHTS records - for (i = 0; i < NUMMAPS; i++) + for (i = 0; i < numgamemaps; i++) { if (!data->nightsrecords[i] || !data->nightsrecords[i]->nummares) { @@ -4747,7 +4781,7 @@ static inline void P_NetUnArchiveEmblems(void) data->totalplaytime = READUINT32(save_p); // TODO put another cipher on these things? meh, I don't care... - for (i = 0; i < NUMMAPS; i++) + for (i = 0; i < numgamemaps; i++) if ((data->mapvisited[i] = READUINT8(save_p)) > MV_MAX) I_Error("Bad $$$.sav dearchiving Emblems (invalid visit flags)"); @@ -4786,7 +4820,7 @@ static inline void P_NetUnArchiveEmblems(void) data->timesBeatenUltimate = READUINT32(save_p); // Main records - for (i = 0; i < NUMMAPS; ++i) + for (i = 0; i < numgamemaps; ++i) { recscore = READUINT32(save_p); rectime = (tic_t)READUINT32(save_p); @@ -4805,7 +4839,7 @@ static inline void P_NetUnArchiveEmblems(void) } // Nights records - for (i = 0; i < NUMMAPS; ++i) + for (i = 0; i < numgamemaps; ++i) { if ((recmares = READUINT8(save_p)) == 0) continue; diff --git a/src/p_saveg.h b/src/p_saveg.h index 545008e7efc6af656fe94864a4ebcf8ea28e5f27..7325980050aa21993042459041e4dbb9ec022c3a 100644 --- a/src/p_saveg.h +++ b/src/p_saveg.h @@ -18,7 +18,11 @@ #pragma interface #endif -#define NEWSKINSAVES (INT16_MAX) // TODO: 2.3: Delete (Purely for backwards compatibility) +#define SAVE_GAME_COMPLETE_BIT 0x01 + +// TODO: 2.3: Delete both of these (purely for backwards compatibility) +#define NEWSKINSAVES (INT16_MAX) +#define NEWMAPSAVES (INT16_MAX) // Persistent storage/archiving. // These are the load / save game routines. diff --git a/src/p_setup.c b/src/p_setup.c index 6f5ec17dcd59814ddae0032911704c3c9e4f6b16..40be9babab87d4c715874202df838634eefffd25 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -360,8 +360,7 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) mapheaderinfo[num]->ssspheres = 1; mapheaderinfo[num]->gravity = FRACUNIT/2; mapheaderinfo[num]->keywords[0] = '\0'; - snprintf(mapheaderinfo[num]->musname, 7, "%sM", G_BuildMapName(i)); - mapheaderinfo[num]->musname[6] = 0; + snprintf(mapheaderinfo[num]->musname, MAX_MUSIC_NAME+1, "%s", G_GetDefaultMapMusic(i)); mapheaderinfo[num]->mustrack = 0; mapheaderinfo[num]->muspos = 0; mapheaderinfo[num]->musinterfadeout = 0; @@ -7293,14 +7292,15 @@ static void P_ResetSpawnpoints(void) static void P_LoadRecordGhosts(void) { - const size_t glen = strlen(srb2home)+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1; + const char *mapname = G_BuildMapName(gamemap); + const size_t glen = strlen(srb2home)+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen(mapname)+1; char *gpath = malloc(glen); INT32 i; if (!gpath) return; - sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap)); + sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, mapname); // Best Score ghost if (cv_ghost_bestscore.value) @@ -7363,14 +7363,15 @@ static void P_LoadRecordGhosts(void) static void P_LoadNightsGhosts(void) { - const size_t glen = strlen(srb2home)+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1; + const char *mapname = G_BuildMapName(gamemap); + const size_t glen = strlen(srb2home)+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen(mapname)+1; char *gpath = malloc(glen); INT32 i; if (!gpath) return; - sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap)); + sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, mapname); // Best Score ghost if (cv_ghost_bestscore.value) @@ -7544,7 +7545,7 @@ static void P_RunSpecialStageWipe(void) // Fade music! Time it to S3KAF: 0.25 seconds is snappy. if (RESETMUSIC || strnicmp(S_MusicName(), - (mapmusflags & MUSIC_RELOADRESET) ? mapheaderinfo[gamemap - 1]->musname : mapmusname, 7)) + (mapmusflags & MUSIC_RELOADRESET) ? mapheaderinfo[gamemap - 1]->musname : mapmusname, MAX_MUSIC_NAME)) S_FadeOutStopMusic(MUSICRATE/4); //FixedMul(FixedDiv(F_GetWipeLength(wipedefs[wipe_speclevel_towhite])*NEWTICRATERATIO, NEWTICRATE), MUSICRATE) F_WipeStartScreen(); @@ -7812,7 +7813,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) // But don't halt the music! S_Start will take care of that. This dodges a MIDI crash bug. if (!(reloadinggamestate || titlemapinaction) && (RESETMUSIC || strnicmp(S_MusicName(), - (mapmusflags & MUSIC_RELOADRESET) ? mapheaderinfo[gamemap-1]->musname : mapmusname, 7))) + (mapmusflags & MUSIC_RELOADRESET) ? mapheaderinfo[gamemap-1]->musname : mapmusname, MAX_MUSIC_NAME))) { S_FadeMusic(0, FixedMul( FixedDiv((F_GetWipeLength(wipedefs[wipe_level_toblack])-2)*NEWTICRATERATIO, NEWTICRATE), MUSICRATE)); @@ -8118,6 +8119,80 @@ static lumpinfo_t* FindFolder(const char *folName, UINT16 *start, UINT16 *end, l return lumpinfo; } +void P_LoadMapsFromFile(UINT16 wadnum, boolean is_pwad) +{ + boolean mapsadded = false; + + lumpinfo_t *lumpinfo = wadfiles[wadnum]->lumpinfo; + + INT16 num; + const char *name; + + if (W_FileHasFolders(wadfiles[wadnum])) + { + UINT16 posStart = W_CheckNumForFolderStartPK3("Maps/", wadnum, 0); + if (posStart == INT16_MAX) + return; + + UINT16 posEnd = W_CheckNumForFolderEndPK3("Maps/", wadnum, posStart); + + lumpinfo += posStart; + + for (; posStart < posEnd; posStart++, lumpinfo++) + { + name = M_GetFilenameFromPath(lumpinfo->fullname); // Full lump name, with its extension + + if (!M_CheckFilenameExtension(name, "wad")) + { + // Extension must be .wad + continue; + } + + name = lumpinfo->longname; // Name without the extension + + num = G_AddMap(name); + + if (num == 0) + { + CONS_Alert(CONS_ERROR, "Too many maps loaded!\n"); + break; + } + //If you replaced the map you're on, end the level when done. + else if (num == gamemap) + replacedcurrentmap = true; + + if (is_pwad) + CONS_Printf("%s\n", name); + mapsadded = true; + } + } + else + { + UINT16 numlumps = wadfiles[wadnum]->numlumps; + for (size_t i = 0; i < numlumps; i++, lumpinfo++) + { + name = lumpinfo->name; + if (name[0] == 'M' && name[1] == 'A' && name[2] == 'P') // Ignore the headers + { + if (name[5]!='\0') + continue; + num = (INT16)M_MapNumber(name[3], name[4]); + + //If you replaced the map you're on, end the level when done. + if (num == gamemap) + replacedcurrentmap = true; + + if (is_pwad) + CONS_Printf("%s\n", name); + mapsadded = true; + } + } + } + + if (!mapsadded && is_pwad) + CONS_Printf(M_GetText("No maps added\n")); +} + // // Add a wadfile to the active wad files, // replace sounds, musics, patches, textures, sprites and maps @@ -8131,8 +8206,6 @@ static boolean P_LoadAddon(UINT16 numlumps) lumpinfo_t *lumpinfo; //boolean texturechange = false; ///\todo Useless; broken when back-frontporting PK3 changes? - boolean mapsadded = false; - boolean replacedcurrentmap = false; // Vars to help us with the position start and amount of each resource type. // Useful for PK3s since they use folders. @@ -8272,32 +8345,7 @@ static boolean P_LoadAddon(UINT16 numlumps) // S_LoadMusicDefs(wadnum); - // - // search for maps - // - lumpinfo = wadfiles[wadnum]->lumpinfo; - for (i = 0; i < numlumps; i++, lumpinfo++) - { - name = lumpinfo->name; - if (name[0] == 'M' && name[1] == 'A' && name[2] == 'P') // Ignore the headers - { - INT16 num; - if (name[5]!='\0') - continue; - num = (INT16)M_MapNumber(name[3], name[4]); - - //If you replaced the map you're on, end the level when done. - if (num == gamemap) - replacedcurrentmap = true; - - CONS_Printf("%s\n", name); - mapsadded = true; - } - } - if (!mapsadded) - CONS_Printf(M_GetText("No maps added\n")); - - R_LoadSpriteInfoLumps(wadnum, numlumps); + R_LoadSpriteInfoLumps(wadnum); #ifdef HWRENDER HWR_ReloadModels(); @@ -8311,11 +8359,16 @@ static boolean P_LoadAddon(UINT16 numlumps) if (modifiedgame && (cursaveslot > 0)) cursaveslot = 0; - if (replacedcurrentmap && gamestate == GS_LEVEL && (netgame || multiplayer)) + if (replacedcurrentmap) { - CONS_Printf(M_GetText("Current map %d replaced by added file, ending the level to ensure consistency.\n"), gamemap); - if (server) - D_SendExitLevel(false); + replacedcurrentmap = false; + + if (gamestate == GS_LEVEL && (netgame || multiplayer)) + { + CONS_Printf(M_GetText("Current map %d replaced by added file, ending the level to ensure consistency.\n"), gamemap); + if (server) + D_SendExitLevel(false); + } } return true; diff --git a/src/p_setup.h b/src/p_setup.h index c6f4f741c01c56fecfc5b0fa0fb267fb1c975b16..23c6d4b1c8883675e6100e4664ad3197097d40d4 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -107,6 +107,7 @@ boolean P_AddFolder(const char *folderpath); boolean P_RunSOC(const char *socfilename); void P_LoadSoundsRange(UINT16 wadnum, UINT16 first, UINT16 num); void P_LoadMusicsRange(UINT16 wadnum, UINT16 first, UINT16 num); +void P_LoadMapsFromFile(UINT16 wadnum, boolean is_pwad); //void P_WriteThings(void); size_t P_PrecacheLevelFlats(void); void P_AllocMapHeader(INT16 i); diff --git a/src/p_spec.c b/src/p_spec.c index 131a58d20c4a5b3d7f5800b2b3a2e4db93a229c7..594a11e7d3736960e22c099b28169af2ef8763e0 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -2522,7 +2522,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) // console player only unless TMM_ALLPLAYERS is set if ((line->args[0] & TMM_ALLPLAYERS) || (mo && mo->player && P_IsLocalPlayer(mo->player)) || titlemapinaction) { - boolean musicsame = (!line->stringargs[0] || !line->stringargs[0][0] || !strnicmp(line->stringargs[0], S_MusicName(), 7)); + boolean musicsame = (!line->stringargs[0] || !line->stringargs[0][0] || !strnicmp(line->stringargs[0], S_MusicName(), MAX_MUSIC_NAME)); UINT16 tracknum = (UINT16)max(line->args[6], 0); INT32 position = (INT32)max(line->args[1], 0); UINT32 prefadems = (UINT32)max(line->args[2], 0); @@ -2565,8 +2565,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) strcpy(mapmusname, ""); else { - strncpy(mapmusname, line->stringargs[0], 7); - mapmusname[6] = 0; + strlcpy(mapmusname, line->stringargs[0], MAX_MUSIC_NAME+1); } mapmusflags = tracknum & MUSIC_TRACKMASK; diff --git a/src/p_user.c b/src/p_user.c index 0c21a1cc15fdcf310276222879c0fb04e232a01e..d7a4de627a19262db9281bde3b96ff7d5523eb84 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1576,13 +1576,8 @@ void P_PlayJingle(player_t *player, jingletype_t jingletype) UINT16 musflags = 0; boolean looping = jingleinfo[jingletype].looping; - char newmusic[7]; - strncpy(newmusic, musname, 7); -#ifdef HAVE_LUA_MUSICPLUS - if(LUAh_MusicJingle(jingletype, newmusic, &musflags, &looping)) - return; -#endif - newmusic[6] = 0; + char newmusic[MAX_MUSIC_NAME]; + strlcpy(newmusic, musname, MAX_MUSIC_NAME); P_PlayJingleMusic(player, newmusic, musflags, looping, jingletype); } diff --git a/src/r_picformats.c b/src/r_picformats.c index 3e817f4a06199bb47c38f198c6ceb6cd447a6452..8f577e426102afc7de9022b497251a6a2318d5ea 100644 --- a/src/r_picformats.c +++ b/src/r_picformats.c @@ -1678,13 +1678,13 @@ void R_ParseSPRTINFOLump(UINT16 wadNum, UINT16 lumpNum) // // Load and read every SPRTINFO lump from the specified file. // -void R_LoadSpriteInfoLumps(UINT16 wadnum, UINT16 numlumps) +void R_LoadSpriteInfoLumps(UINT16 wadnum) { lumpinfo_t *lumpinfo = wadfiles[wadnum]->lumpinfo; UINT16 i; char *name; - for (i = 0; i < numlumps; i++, lumpinfo++) + for (i = 0; i < wadfiles[wadnum]->numlumps; i++, lumpinfo++) { name = lumpinfo->name; // Load SPRTINFO and SPR_ lumps as SpriteInfo diff --git a/src/r_picformats.h b/src/r_picformats.h index 4050a1b71dc01e8a60cbb14cbe017716c61038c3..c06d2d55ec0bfb8178f45caab6a01e21603c7898 100644 --- a/src/r_picformats.h +++ b/src/r_picformats.h @@ -122,7 +122,7 @@ boolean Picture_PNGDimensions(UINT8 *png, INT32 *width, INT32 *height, INT16 *to // SpriteInfo extern spriteinfo_t spriteinfo[NUMSPRITES]; -void R_LoadSpriteInfoLumps(UINT16 wadnum, UINT16 numlumps); +void R_LoadSpriteInfoLumps(UINT16 wadnum); void R_ParseSPRTINFOLump(UINT16 wadNum, UINT16 lumpNum); #endif // __R_PICFORMATS__ diff --git a/src/r_things.c b/src/r_things.c index 557e1681439cd13d6bd871f7c33a789a0d2ba2be..d3a5d960c63ebef9c7a0146914cd7991902a3e6d 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -583,7 +583,7 @@ void R_InitSprites(void) { R_AddSkins((UINT16)i, true); R_PatchSkins((UINT16)i, true); - R_LoadSpriteInfoLumps(i, wadfiles[i]->numlumps); + R_LoadSpriteInfoLumps(i); } ST_ReloadSkinFaceGraphics(); diff --git a/src/s_sound.c b/src/s_sound.c index a579292ff3aa791176b389d686901799c47c89a1..7b7268566a8ae362da65b1db3284ee520ba62365 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -1352,12 +1352,12 @@ void S_InitSfxChannels(INT32 sfxVolume) /// Music /// ------------------------ -static char music_name[7]; // up to 6-character name +static char music_name[MAX_MUSIC_NAME+1]; static void *music_data; static UINT16 music_flags; static boolean music_looping; -static char queue_name[7]; +static char queue_name[MAX_MUSIC_NAME+1]; static UINT16 queue_flags; static boolean queue_looping; static UINT32 queue_position; @@ -1568,9 +1568,8 @@ ReadMusicDefFields (UINT16 wadnum, int line, boolean fields, char *stoken, } else if (!stricmp(stoken, "soundtestpage")) { def->soundtestpage = (UINT8)i; } else if (!stricmp(stoken, "soundtestcond")) { - // Convert to map number - if (textline[0] >= 'A' && textline[0] <= 'Z' && textline[2] == '\0') - i = M_MapNumber(textline[0], textline[1]); + if (!i) + i = G_GetMapNumber(textline); def->soundtestcond = (INT16)i; } else if (!stricmp(stoken, "stoppingtime")) { double stoppingtime = atof(textline)*TICRATE; @@ -1778,8 +1777,8 @@ const char *S_MusicName(void) boolean S_MusicExists(const char *mname, boolean checkMIDI, boolean checkDigi) { return ( - (checkDigi ? W_CheckNumForName(va("O_%s", mname)) != LUMPERROR : false) - || (checkMIDI ? W_CheckNumForName(va("D_%s", mname)) != LUMPERROR : false) + (checkDigi ? W_CheckNumForLongName(va("O_%s", mname)) != LUMPERROR : false) + || (checkMIDI ? W_CheckNumForLongName(va("D_%s", mname)) != LUMPERROR : false) ); } @@ -1826,7 +1825,7 @@ UINT32 S_GetMusicPosition(void) /// In this section: mazmazz doesn't know how to do dynamic arrays or struct pointers! /// ------------------------ -char music_stack_nextmusname[7]; +char music_stack_nextmusname[MAX_MUSIC_NAME+1]; boolean music_stack_noposition = false; UINT32 music_stack_fadeout = 0; UINT32 music_stack_fadein = 0; @@ -1910,7 +1909,7 @@ static void S_AddMusicStackEntry(const char *mname, UINT16 mflags, boolean loopi if (!music_stacks) { music_stacks = Z_Calloc(sizeof (*mst), PU_MUSIC, NULL); - strncpy(music_stacks->musname, (status == JT_MASTER ? mname : (S_CheckQueue() ? queue_name : mapmusname)), 7); + strlcpy(music_stacks->musname, (status == JT_MASTER ? mname : (S_CheckQueue() ? queue_name : mapmusname)), MAX_MUSIC_NAME+1); music_stacks->musflags = (status == JT_MASTER ? mflags : (S_CheckQueue() ? queue_flags : mapmusflags)); music_stacks->looping = (status == JT_MASTER ? looping : (S_CheckQueue() ? queue_looping : true)); music_stacks->position = (status == JT_MASTER ? position : (S_CheckQueue() ? queue_position : S_GetMusicPosition())); @@ -1928,8 +1927,7 @@ static void S_AddMusicStackEntry(const char *mname, UINT16 mflags, boolean loopi // create our new entry new_mst = Z_Calloc(sizeof (*new_mst), PU_MUSIC, NULL); - strncpy(new_mst->musname, mname, 7); - new_mst->musname[6] = 0; + strlcpy(new_mst->musname, mname, MAX_MUSIC_NAME+1); new_mst->musflags = mflags; new_mst->looping = looping; new_mst->position = position; @@ -2033,13 +2031,13 @@ boolean S_RecallMusic(UINT16 status, boolean fromfirst) if (result) { *entry = *result; - strncpy(entry->musname, result->musname, 7); + strlcpy(entry->musname, result->musname, MAX_MUSIC_NAME+1); } // no result, just grab mapmusname if (!result || !entry->musname[0] || ((status == JT_MASTER || (music_stacks ? !music_stacks->status : false)) && !entry->status)) { - strncpy(entry->musname, mapmusname, 7); + strlcpy(entry->musname, mapmusname, MAX_MUSIC_NAME+1); entry->musflags = mapmusflags; entry->looping = true; entry->position = mapmusposition; @@ -2051,10 +2049,10 @@ boolean S_RecallMusic(UINT16 status, boolean fromfirst) if (entry->status == JT_MASTER) { - mapmuschanged = strnicmp(entry->musname, mapmusname, 7); + mapmuschanged = strnicmp(entry->musname, mapmusname, MAX_MUSIC_NAME); if (mapmuschanged) { - strncpy(entry->musname, mapmusname, 7); + strlcpy(entry->musname, mapmusname, MAX_MUSIC_NAME+1); entry->musflags = mapmusflags; entry->looping = true; entry->position = mapmusposition; @@ -2071,7 +2069,7 @@ boolean S_RecallMusic(UINT16 status, boolean fromfirst) return false; } - if (strncmp(entry->musname, S_MusicName(), 7) || // don't restart music if we're already playing it + if (strncmp(entry->musname, S_MusicName(), MAX_MUSIC_NAME) || // don't restart music if we're already playing it (midipref != currentmidi && S_PrefAvailable(midipref, entry->musname))) // but do if the user's preference has changed { if (music_stack_fadeout) @@ -2122,9 +2120,9 @@ static lumpnum_t S_GetMusicLumpNum(const char *mname) boolean midipref = cv_musicpref.value; if (S_PrefAvailable(midipref, mname)) - return W_GetNumForName(va(midipref ? "d_%s":"o_%s", mname)); + return W_GetNumForLongName(va(midipref ? "D_%s":"O_%s", mname)); else if (S_PrefAvailable(!midipref, mname)) - return W_GetNumForName(va(midipref ? "o_%s":"d_%s", mname)); + return W_GetNumForLongName(va(midipref ? "O_%s":"D_%s", mname)); else return LUMPERROR; } @@ -2141,18 +2139,16 @@ static boolean S_LoadMusic(const char *mname) if (mlumpnum == LUMPERROR) { - CONS_Alert(CONS_ERROR, "Music %.6s could not be loaded: lump not found!\n", mname); + CONS_Alert(CONS_ERROR, "Music %s could not be loaded: lump not found!\n", mname); return false; } // load & register it mdata = W_CacheLumpNum(mlumpnum, PU_MUSIC); - if (I_LoadSong(mdata, W_LumpLength(mlumpnum))) { - strncpy(music_name, mname, 7); - music_name[6] = 0; + strlcpy(music_name, mname, MAX_MUSIC_NAME+1); music_data = mdata; return true; } @@ -2213,7 +2209,7 @@ static boolean S_PlayMusic(boolean looping, UINT32 fadeinms) static void S_QueueMusic(const char *mmusic, UINT16 mflags, boolean looping, UINT32 position, UINT32 fadeinms) { - strncpy(queue_name, mmusic, 7); + strlcpy(queue_name, mmusic, MAX_MUSIC_NAME+1); queue_flags = mflags; queue_looping = looping; queue_position = position; @@ -2238,7 +2234,7 @@ static void S_ChangeMusicToQueue(void) void S_ChangeMusicEx(const char *mmusic, UINT16 mflags, boolean looping, UINT32 position, UINT32 prefadems, UINT32 fadeinms) { - char newmusic[7]; + char newmusic[MAX_MUSIC_NAME+1]; struct MusicChange hook_param = { newmusic, @@ -2255,10 +2251,9 @@ void S_ChangeMusicEx(const char *mmusic, UINT16 mflags, boolean looping, UINT32 if (S_MusicDisabled()) return; - strncpy(newmusic, mmusic, 7); + strlcpy(newmusic, mmusic, MAX_MUSIC_NAME+1); if (LUA_HookMusicChange(music_name, &hook_param)) return; - newmusic[6] = 0; // No Music (empty string) if (newmusic[0] == 0) @@ -2278,7 +2273,7 @@ void S_ChangeMusicEx(const char *mmusic, UINT16 mflags, boolean looping, UINT32 I_FadeSong(0, prefadems, S_ChangeMusicToQueue); return; } - else if (strnicmp(music_name, newmusic, 6) || (mflags & MUSIC_FORCERESET) || + else if (strnicmp(music_name, newmusic, MAX_MUSIC_NAME) || (mflags & MUSIC_FORCERESET) || (midipref != currentmidi && S_PrefAvailable(midipref, newmusic))) { CONS_Debug(DBG_DETAILED, "Now playing song %s\n", newmusic); @@ -2303,7 +2298,7 @@ void S_ChangeMusicEx(const char *mmusic, UINT16 mflags, boolean looping, UINT32 { I_SetSongPosition(position); I_FadeSong(100, fadeinms, NULL); -} + } else // reset volume to 100 with same music { I_StopFadingSong(); @@ -2433,8 +2428,7 @@ void S_StartEx(boolean reset) { if (mapmusflags & MUSIC_RELOADRESET) { - strncpy(mapmusname, mapheaderinfo[gamemap-1]->musname, 7); - mapmusname[6] = 0; + strlcpy(mapmusname, mapheaderinfo[gamemap-1]->musname, MAX_MUSIC_NAME+1); mapmusflags = (mapheaderinfo[gamemap-1]->mustrack & MUSIC_TRACKMASK); mapmusposition = mapheaderinfo[gamemap-1]->muspos; } @@ -2487,18 +2481,17 @@ static void Command_Tunes_f(void) track = mapheaderinfo[gamemap-1]->mustrack; } - if (strlen(tunearg) > 6) // This is automatic -- just show the error just in case - CONS_Alert(CONS_NOTICE, M_GetText("Music name too long - truncated to six characters.\n")); + if (strlen(tunearg) > MAX_MUSIC_NAME) // This is automatic -- just show the error just in case + CONS_Alert(CONS_NOTICE, M_GetText("Music name too long - truncated to %d characters.\n"), MAX_MUSIC_NAME); if (argc > 2) track = (UINT16)atoi(COM_Argv(2))-1; - strncpy(mapmusname, tunearg, 7); + strlcpy(mapmusname, tunearg, MAX_MUSIC_NAME+1); if (argc > 4) position = (UINT32)atoi(COM_Argv(4)); - mapmusname[6] = 0; mapmusflags = (track & MUSIC_TRACKMASK); mapmusposition = position; diff --git a/src/s_sound.h b/src/s_sound.h index 288859c8d233dc9696118ef1d93655f98be514b9..66cb80ff88e4044eb94641f006584d5db2ae3ed2 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -182,7 +182,7 @@ boolean S_SpeedMusic(float speed); // Music definitions typedef struct musicdef_s { - char name[7]; + char name[MAX_MUSIC_NAME+1]; char title[32]; char alttitle[64]; char authors[256]; @@ -238,7 +238,7 @@ UINT32 S_GetMusicPosition(void); typedef struct musicstack_s { - char musname[7]; + char musname[MAX_MUSIC_NAME+1]; UINT16 musflags; boolean looping; UINT32 position; @@ -251,7 +251,7 @@ typedef struct musicstack_s struct musicstack_s *next; } musicstack_t; -extern char music_stack_nextmusname[7]; +extern char music_stack_nextmusname[MAX_MUSIC_NAME+1]; extern boolean music_stack_noposition; extern UINT32 music_stack_fadeout; extern UINT32 music_stack_fadein; diff --git a/src/w_wad.c b/src/w_wad.c index 051469ef57285b28003b43569de8e625856ce5e8..13749f630078f27382a456d52b522eda1798f892 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -979,6 +979,9 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) // Read shaders from file W_ReadFileShaders(wadfile); + // Load maps from file + P_LoadMapsFromFile(numwadfiles - 1, !startup); + // TODO: HACK ALERT - Load Lua & SOC stuff right here. I feel like this should be out of this place, but... Let's stick with this for now. switch (wadfile->type) {