From 37c345c7eb37003d9b90a4d976971d5af4ce7e99 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 18 Oct 2020 18:49:38 -0700 Subject: [PATCH 01/60] Map lump names can be anything, map number is dynamically allocated --- src/d_main.c | 8 +--- src/d_netcmd.c | 13 +++--- src/dehacked.c | 112 ++++++++++++---------------------------------- src/doomdef.h | 2 +- src/doomstat.h | 3 +- src/f_finale.c | 3 -- src/g_demo.c | 2 +- src/g_game.c | 66 +++++++++++++++------------ src/g_game.h | 6 +-- src/lua_baselib.c | 1 + src/m_menu.c | 4 +- src/m_misc.c | 26 ----------- src/m_misc.h | 2 - src/p_saveg.c | 2 +- src/p_setup.c | 4 +- src/s_sound.c | 4 +- src/w_wad.c | 4 +- 17 files changed, 91 insertions(+), 171 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index db0f74fb2..e28dc1c5c 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -892,13 +892,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))); } } diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 6ff12ce3b..5c7705a42 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2347,8 +2347,7 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pencoremode, boolean r if (delay != 2) { UINT8 flags = 0; - const char *mapname = G_BuildMapName(mapnum); - I_Assert(W_CheckNumForName(mapname) != LUMPERROR); + I_Assert(W_CheckNumForName(G_BuildMapName(mapnum)) != LUMPERROR); buf_p = buf; if (pencoremode) flags |= 1; @@ -2363,7 +2362,7 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pencoremode, boolean r // new gametype value WRITEUINT8(buf_p, newgametype); - WRITESTRINGN(buf_p, mapname, MAX_WADPATH); + WRITEINT16(buf_p, mapnum); } if (delay == 1) @@ -2791,7 +2790,6 @@ 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 skipprecutscene, FLS; @@ -2833,7 +2831,7 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) FLS = ((flags & (1<<3)) != 0); - READSTRINGN(*cp, mapname, MAX_WADPATH); + mapnumber = READINT16(*cp); if (netgame) P_SetRandSeed(READUINT32(*cp)); @@ -2841,7 +2839,7 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) if (!skipprecutscene) { DEBFILE(va("Warping to %s [resetplayer=%d lastgametype=%d gametype=%d cpnd=%d]\n", - mapname, resetplayer, lastgametype, gametype, chmappending)); + G_BuildMapName(mapnumber), resetplayer, lastgametype, gametype, chmappending)); CON_LogMessage(M_GetText("Speeding off to level...\n")); } @@ -2861,13 +2859,12 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) CV_StealthSetValue(&cv_playercolor[0], players[0].skincolor); } - mapnumber = M_MapNumber(mapname[3], mapname[4]); LUAh_MapChange(mapnumber); demo.savemode = (cv_recordmultiplayerdemos.value == 2) ? DSM_WILLAUTOSAVE : DSM_NOTSAVING; demo.savebutton = 0; - G_InitNew(pencoremode, mapname, resetplayer, skipprecutscene, FLS); + G_InitNew(pencoremode, mapnumber, resetplayer, skipprecutscene, FLS); if (demo.playback && !demo.timing) precache = true; if (demo.timing) diff --git a/src/dehacked.c b/src/dehacked.c index a467543e9..1aaa2f2c8 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1684,7 +1684,7 @@ static const struct { #define MAXFLICKIES 64 -static void readlevelheader(MYFILE *f, INT32 num) +static void readlevelheader(MYFILE *f, char * name) { char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); char *word; @@ -1692,10 +1692,24 @@ static void readlevelheader(MYFILE *f, INT32 num) //char *word3; // Non-uppercase version of word2 char *tmp; INT32 i; + const INT32 num = G_MapNumber(name); + + if (num > NUMMAPS) + { + I_Error("Too many maps!"); + } + + if (mapheaderinfo[num-1]) + G_SetGameModified(multiplayer, true); // only mark as a major mod if it replaces an already-existing mapheaderinfo // Reset all previous map header information P_AllocMapHeader((INT16)(num-1)); + if (mapheaderinfo[num-1]->lumpname == NULL) + { + mapheaderinfo[num-1]->lumpname = Z_StrDup(name); + } + do { if (myfgets(s, MAXLINELEN, f)) @@ -1895,8 +1909,7 @@ static void readlevelheader(MYFILE *f, INT32 num) // 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 = G_MapNumber(word2); mapheaderinfo[num-1]->nextlevel = (INT16)i; } @@ -1911,8 +1924,7 @@ static void readlevelheader(MYFILE *f, INT32 num) // 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 = G_MapNumber(word2); mapheaderinfo[num-1]->marathonnext = (INT16)i; } @@ -3608,10 +3620,7 @@ static void reademblemdata(MYFILE *f, INT32 num) // 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]); - - emblemlocations[num-1].level = (INT16)value; + emblemlocations[num-1].level = (INT16)G_MapNumber(word2); } else if (fastcmp(word, "SPRITE")) { @@ -3836,10 +3845,7 @@ static void readunlockable(MYFILE *f, INT32 num) // 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]); - - unlockables[num].variable = (INT16)i; + unlockables[num].variable = (INT16)G_MapNumber(word2); } else deh_warning("Unlockable %d: unknown word '%s'", num+1, word); @@ -3930,11 +3936,7 @@ 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 - re = atoi(params[1]); + re = G_MapNumber(params[1]); if (re < 0 || re >= NUMMAPS) { @@ -3948,11 +3950,7 @@ static void readcondition(UINT8 set, UINT32 id, char *word2) ty = UC_MAPTIME; 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 - x1 = (INT16)atoi(params[1]); + x1 = (INT16)G_MapNumber(params[1]); if (x1 < 0 || x1 >= NUMMAPS) { @@ -4160,12 +4158,7 @@ static 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); - - spstage_start = spmarathon_start = (INT16)value; + spstage_start = spmarathon_start = (INT16)G_MapNumber(word2); } else if (fastcmp(word, "SPMARATHON_START")) { @@ -4173,12 +4166,7 @@ static 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); - - spmarathon_start = (INT16)value; + spmarathon_start = (INT16)G_MapNumber(word2); } else if (fastcmp(word, "SSTAGE_START")) { @@ -4186,12 +4174,7 @@ static 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); - - sstage_start = (INT16)value; + sstage_start = (INT16)G_MapNumber(word2); sstage_end = (INT16)(sstage_start+7); // 7 special stages total plus one weirdo } else if (fastcmp(word, "SMPSTAGE_START")) @@ -4200,12 +4183,7 @@ static 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); - - smpstage_start = (INT16)value; + smpstage_start = (INT16)G_MapNumber(word2); smpstage_end = (INT16)(smpstage_start+6); // 7 special stages total } else if (fastcmp(word, "REDTEAM")) @@ -4294,12 +4272,7 @@ static 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); - - titlemap = (INT16)value; + titlemap = (INT16)G_MapNumber(word2); titlechanged = true; } else if (fastcmp(word, "HIDETITLEPICS") || fastcmp(word, "TITLEPICSHIDE")) @@ -4440,12 +4413,7 @@ static 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); - - bootmap = (INT16)value; + bootmap = (INT16)G_MapNumber(word2); //titlechanged = true; } else if (fastcmp(word, "TUTORIALMAP")) @@ -4454,12 +4422,7 @@ static 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); - - tutorialmap = (INT16)value; + tutorialmap = (INT16)G_MapNumber(word2); } else deh_warning("Maincfg: unknown word '%s'", word); @@ -4859,24 +4822,7 @@ 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 (i > 0 && i <= NUMMAPS) - { - if (mapheaderinfo[i]) - G_SetGameModified(multiplayer, true); // only mark as a major mod if it replaces an already-existing mapheaderinfo - readlevelheader(f, i); - } - else - { - deh_warning("Level number %d out of range (1 - %d)", i, NUMMAPS); - ignorelines(f); - } + readlevelheader(f, word2); } else if (fastcmp(word, "GAMETYPE")) { diff --git a/src/doomdef.h b/src/doomdef.h index 9c4664135..5c89053cb 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -625,7 +625,7 @@ extern const char *compdate, *comptime, *comprevision, *compbranch; /// Backwards compatibility with musicslots. /// \note You should leave this enabled unless you're working with a future SRB2 version. -#define MUSICSLOT_COMPATIBILITY +//#define MUSICSLOT_COMPATIBILITY /// Experimental attempts at preventing MF_PAPERCOLLISION objects from getting stuck in walls. //#define PAPER_COLLISIONCORRECTION diff --git a/src/doomstat.h b/src/doomstat.h index 629e5cead..91ca7b0ea 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -324,7 +324,7 @@ typedef struct */ typedef struct { - // The original eight, plus one. + char * lumpname; ///< Lump name can be really long char lvlttl[22]; ///< Level name without "Zone". (21 character limit instead of 32, 21 characters can display on screen max anyway) char subttl[33]; ///< Subtitle for level char zonttl[22]; ///< "ZONE" replacement name @@ -415,6 +415,7 @@ typedef struct #define LF2_VISITNEEDED (1<<3) ///< Not available in Time Attack modes until you visit the level extern mapheader_t* mapheaderinfo[NUMMAPS]; +extern INT32 nummapheaders; // This could support more, but is that a good idea? // Keep in mind that it may encourage people making overly long cups just because they "can", and would be a waste of memory. diff --git a/src/f_finale.c b/src/f_finale.c index 4355cf231..d127a2359 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1837,9 +1837,6 @@ void F_StartTitleScreen(void) titlemapcameraref = NULL; gamemap = titlemap; - if (!mapheaderinfo[gamemap-1]) - P_AllocMapHeader(gamemap-1); - maptol = mapheaderinfo[gamemap-1]->typeoflevel; globalweather = mapheaderinfo[gamemap-1]->weather; diff --git a/src/g_demo.c b/src/g_demo.c index 50c53d1c3..a841afa9e 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -3021,7 +3021,7 @@ void G_DoPlayDemo(char *defdemoname) R_ExecuteSetViewSize(); P_SetRandSeed(randseed); - G_InitNew(demoflags & DF_ENCORE, G_BuildMapName(gamemap), true, true, false); // Doesn't matter whether you reset or not here, given changes to resetplayer. + G_InitNew(demoflags & DF_ENCORE, gamemap, true, true, false); // Doesn't matter whether you reset or not here, given changes to resetplayer. for (i = 0; i < MAXPLAYERS; i++) { diff --git a/src/g_game.c b/src/g_game.c index 0151783e9..bd6d7f713 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -185,6 +185,7 @@ struct quake quake; // Map Header Information mapheader_t* mapheaderinfo[NUMMAPS] = {NULL}; +INT32 nummapheaders; // Kart cup definitions cupheader_t *kartcupheaders = NULL; @@ -644,20 +645,14 @@ void G_SetGameModified(boolean silent, boolean major) Command_ExitGame_f(); } -/** Builds an original game map name from a map number. - * The complexity is due to MAPA0-MAPZZ. +/** Returns the map lump name for a map number. * * \param map Map number. - * \return Pointer to a static buffer containing the desired map name. - * \sa M_MapNumber + * \return Map name. + * \sa G_MapNumber */ const char *G_BuildMapName(INT32 map) { - static char mapname[10] = "MAPXX"; // internal map name (wad resource name) - - I_Assert(map >= 0); - I_Assert(map <= NUMMAPS); - if (map == 0) // hack??? { if (gamestate == GS_TITLESCREEN) @@ -669,19 +664,35 @@ const char *G_BuildMapName(INT32 map) map = G_RandMap(G_TOLFlag(cv_newgametype.value), map, false, 0, false, NULL)+1; } - if (map < 100) - sprintf(&mapname[3], "%.2d", map); + if (map > 0 && map <= NUMMAPS && mapheaderinfo[map - 1] != NULL) + { + return mapheaderinfo[map - 1]->lumpname; + } else { - mapname[3] = (char)('A' + (char)((map - 100) / 36)); - if ((map - 100) % 36 < 10) - mapname[4] = (char)('0' + (char)((map - 100) % 36)); - else - mapname[4] = (char)('A' + (char)((map - 100) % 36) - 10); - mapname[5] = '\0'; + return NULL; + } +} + +/** Returns the map number for map lump name. + * + * \param name Map name; + * \return Map number. + * \sa G_BuildMapName + */ +INT32 G_MapNumber(const char * name) +{ + INT32 map; + + for (map = 0; map < nummapheaders; ++map) + { + if (strcasecmp(mapheaderinfo[map]->lumpname, name) == 0) + { + break; + } } - return mapname; + return map + 1; } /** Clips the console player's mouse aiming to the current view. @@ -4318,7 +4329,7 @@ cleanup: // Can be called by the startup code or the menu task, // consoleplayer, displayplayers[], playeringame[] should be set. // -void G_DeferedInitNew(boolean pencoremode, const char *mapname, INT32 pickedchar, UINT8 ssplayers, boolean FLS) +void G_DeferedInitNew(boolean pencoremode, INT32 map, INT32 pickedchar, UINT8 ssplayers, boolean FLS) { INT32 i; UINT16 color = SKINCOLOR_NONE; @@ -4350,18 +4361,17 @@ void G_DeferedInitNew(boolean pencoremode, const char *mapname, INT32 pickedchar CV_StealthSetValue(&cv_playercolor[0], color); } - if (mapname) - { - D_MapChange(M_MapNumber(mapname[3], mapname[4]), gametype, pencoremode, true, 1, false, FLS); - } + D_MapChange(map, gametype, pencoremode, true, 1, false, FLS); } // // This is the map command interpretation something like Command_Map_f // // called at: map cmd execution, doloadgame, doplaydemo -void G_InitNew(UINT8 pencoremode, const char *mapname, boolean resetplayer, boolean skipprecutscene, boolean FLS) +void G_InitNew(UINT8 pencoremode, INT32 map, boolean resetplayer, boolean skipprecutscene, boolean FLS) { + const char * mapname = G_BuildMapName(map); + INT32 i; (void)FLS; @@ -4427,7 +4437,7 @@ void G_InitNew(UINT8 pencoremode, const char *mapname, boolean resetplayer, bool return; } - gamemap = (INT16)M_MapNumber(mapname[3], mapname[4]); // get xx out of MAPxx + gamemap = map; // gamemap changed; we assume that its map header is always valid, // so make it so @@ -4455,7 +4465,7 @@ void G_InitNew(UINT8 pencoremode, const char *mapname, boolean resetplayer, bool { char *title = G_BuildMapTitle(gamemap); - CON_LogMessage(va(M_GetText("Map is now \"%s"), G_BuildMapName(gamemap))); + CON_LogMessage(va(M_GetText("Map is now \"%s"), mapname)); if (title) { CON_LogMessage(va(": %s", title)); @@ -4705,12 +4715,12 @@ INT32 G_FindMapByNameOrCode(const char *mapname, char **realmapnamep) if (mapnamelen == 2)/* maybe two digit code */ { - if (( newmapnum = M_MapNumber(mapname[0], mapname[1]) )) + if (( newmapnum = G_MapNumber(mapname) )) usemapcode = true; } else if (mapnamelen == 5 && strnicmp(mapname, "MAP", 3) == 0) { - if (( newmapnum = M_MapNumber(mapname[3], mapname[4]) )) + if (( newmapnum = G_MapNumber(mapname) )) usemapcode = true; } diff --git a/src/g_game.h b/src/g_game.h index 78812a72c..78dddb1a3 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -81,8 +81,8 @@ extern consvar_t cv_resume; #define MAXPLMOVE (50) #define SLOWTURNTICS (6) -// build an internal map name MAPxx from map number const char *G_BuildMapName(INT32 map); +INT32 G_MapNumber(const char *mapname); void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer); @@ -123,7 +123,7 @@ extern INT32 localaiming[MAXSPLITSCREENPLAYERS]; // should be an angle_t but sig void G_ChangePlayerReferences(mobj_t *oldmo, mobj_t *newmo); void G_DoReborn(INT32 playernum); void G_PlayerReborn(INT32 player, boolean betweenmaps); -void G_InitNew(UINT8 pencoremode, const char *mapname, boolean resetplayer, +void G_InitNew(UINT8 pencoremode, INT32 map, boolean resetplayer, boolean skipprecutscene, boolean FLS); char *G_BuildMapTitle(INT32 mapnum); @@ -161,7 +161,7 @@ void G_SpawnPlayer(INT32 playernum); // Can be called by the startup code or M_Responder. // A normal game starts at map 1, but a warp test can start elsewhere -void G_DeferedInitNew(boolean pencoremode, const char *mapname, INT32 pickedchar, +void G_DeferedInitNew(boolean pencoremode, INT32 map, INT32 pickedchar, UINT8 ssplayers, boolean FLS); void G_DoLoadLevel(boolean resetplayer); diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 0ee1a7a02..8fe7a73f9 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -2387,6 +2387,7 @@ static int lib_sChangeMusic(lua_State *L) #else const char *music_name = luaL_checkstring(L, 1); + UINT32 position, prefadems, fadeinms; boolean looping = (boolean)lua_opttrueboolean(L, 2); player_t *player = NULL; UINT16 music_flags = 0; diff --git a/src/m_menu.c b/src/m_menu.c index 7f6f542c6..32d82f8f6 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -7767,7 +7767,7 @@ static void M_StartGrandPrix(INT32 choice) G_DeferedInitNew( false, - G_BuildMapName(grandprixinfo.cup->levellist[0] + 1), + grandprixinfo.cup->levellist[0] + 1, (UINT8)(cv_chooseskin.value - 1), (UINT8)(cv_splitplayers.value - 1), false @@ -8066,7 +8066,7 @@ static void M_ChooseTimeAttack(INT32 choice) else G_RecordDemo(nameofdemo); - G_DeferedInitNew(false, G_BuildMapName(cv_nextmap.value), (UINT8)(cv_chooseskin.value-1), 0, false); + G_DeferedInitNew(false, cv_nextmap.value, (UINT8)(cv_chooseskin.value-1), 0, false); } static void M_HandleStaffReplay(INT32 choice) diff --git a/src/m_misc.c b/src/m_misc.c index 4f9190b4c..cd8a35cba 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -168,32 +168,6 @@ boolean takescreenshot = false; // Take a screenshot this tic moviemode_t moviemode = MM_OFF; -/** Returns the map number for a map identified by the last two characters in - * its name. - * - * \param first The first character after MAP. - * \param second The second character after MAP. - * \return The map number, or 0 if no map corresponds to these characters. - * \sa G_BuildMapName - */ -INT32 M_MapNumber(char first, char second) -{ - if (isdigit(first)) - { - if (isdigit(second)) - return ((INT32)first - '0') * 10 + ((INT32)second - '0'); - return 0; - } - - if (!isalpha(first)) - return 0; - if (!isalnum(second)) - return 0; - - return 100 + ((INT32)tolower(first) - 'a') * 36 + (isdigit(second) ? ((INT32)second - '0') : - ((INT32)tolower(second) - 'a') + 10); -} - // ========================================================================== // FILE INPUT / OUTPUT // ========================================================================== diff --git a/src/m_misc.h b/src/m_misc.h index cfcd0f3f7..4e597adc2 100644 --- a/src/m_misc.h +++ b/src/m_misc.h @@ -42,8 +42,6 @@ void M_StopMovie(void); // the file where game vars and settings are saved #define CONFIGFILENAME "kartconfig.cfg" -INT32 M_MapNumber(char first, char second); - boolean FIL_WriteFile(char const *name, const void *source, size_t length); size_t FIL_ReadFileTag(char const *name, UINT8 **buffer, INT32 tag); #define FIL_ReadFile(n, b) FIL_ReadFileTag(n, b, PU_STATIC) diff --git a/src/p_saveg.c b/src/p_saveg.c index 0b083e42c..8f2575f07 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -4381,7 +4381,7 @@ boolean P_LoadGame(INT16 mapoverride) return false; // Only do this after confirming savegame is ok - G_DeferedInitNew(false, G_BuildMapName(gamemap), savedata.skin, 0, true); + G_DeferedInitNew(false, gamemap, savedata.skin, 0, true); COM_BufAddText("dummyconsvar 1\n"); // G_DeferedInitNew doesn't do this return true; diff --git a/src/p_setup.c b/src/p_setup.c index 50f39c5fa..4a50e2d08 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -427,8 +427,10 @@ void P_AllocMapHeader(INT16 i) if (!mapheaderinfo[i]) { mapheaderinfo[i] = Z_Malloc(sizeof(mapheader_t), PU_STATIC, NULL); + mapheaderinfo[i]->lumpname = NULL; mapheaderinfo[i]->flickies = NULL; mapheaderinfo[i]->grades = NULL; + nummapheaders++; } P_ClearSingleMapHeaderInfo(i + 1); } @@ -4473,7 +4475,7 @@ boolean P_AddWadFile(const char *wadfilename) INT16 num; if (name[5]!='\0') continue; - num = (INT16)M_MapNumber(name[3], name[4]); + num = (INT16)G_MapNumber(name); // we want to record whether this map exists. if it doesn't have a header, we can assume it's not relephant if (num <= NUMMAPS && mapheaderinfo[num-1]) diff --git a/src/s_sound.c b/src/s_sound.c index a7d45e160..f17d5bdd2 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -2665,8 +2665,8 @@ static void Command_Tunes_f(void) tunearg = mapheaderinfo[gamemap-1]->musname; track = mapheaderinfo[gamemap-1]->mustrack; } - else if (!tunearg[2] && toupper(tunearg[0]) >= 'A' && toupper(tunearg[0]) <= 'Z') - tunenum = (UINT16)M_MapNumber(tunearg[0], tunearg[1]); + else if (isalpha(tunearg[0])) + tunenum = (UINT16)G_MapNumber(tunearg); if (tunenum && tunenum >= 1036) { diff --git a/src/w_wad.c b/src/w_wad.c index 6de3cae6a..76f68d10f 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -65,7 +65,7 @@ #ifdef SCANTHINGS #include "p_setup.h" // P_ScanThings #endif -#include "m_misc.h" // M_MapNumber +#include "g_game.h" // G_MapNumber #ifdef HWRENDER #include "hardware/hw_main.h" @@ -278,7 +278,7 @@ static inline void W_LoadDehackedLumps(UINT16 wadnum, boolean mainfile) const char *name = lump_p->name; if (name[0] == 'M' && name[1] == 'A' && name[2] == 'P' && name[5]=='\0') { - INT16 mapnum = (INT16)M_MapNumber(name[3], name[4]); + INT16 mapnum = (INT16)G_MapNumber(name); P_ScanThings(mapnum, wadnum, lump + ML_THINGS); } } From 2520b87f7661a01ada48dcaf85af8544edc40427 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 18 Oct 2020 19:28:22 -0700 Subject: [PATCH 02/60] Fix map warp --- src/g_game.c | 55 +++++++++++++--------------------------------------- 1 file changed, 14 insertions(+), 41 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index bd6d7f713..c4c00aee0 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4703,55 +4703,28 @@ void G_FreeMapSearch(mapsearchfreq_t *freq, INT32 freqc) INT32 G_FindMapByNameOrCode(const char *mapname, char **realmapnamep) { - boolean usemapcode = false; - INT32 newmapnum; - size_t mapnamelen; - char *p; - mapnamelen = strlen(mapname); + /* Now detect map number in base 10, which no one asked for. */ + newmapnum = strtol(mapname, &p, 10); - if (mapnamelen == 2)/* maybe two digit code */ + if (*p == '\0')/* we got it */ { - if (( newmapnum = G_MapNumber(mapname) )) - usemapcode = true; - } - else if (mapnamelen == 5 && strnicmp(mapname, "MAP", 3) == 0) - { - if (( newmapnum = G_MapNumber(mapname) )) - usemapcode = true; - } - - if (!usemapcode) - { - /* Now detect map number in base 10, which no one asked for. */ - newmapnum = strtol(mapname, &p, 10); - if (*p == '\0')/* we got it */ - { - if (newmapnum < 1 || newmapnum > NUMMAPS) - { - CONS_Alert(CONS_ERROR, M_GetText("Invalid map number %d.\n"), newmapnum); - return 0; - } - usemapcode = true; - } - else - { - newmapnum = G_FindMap(mapname, realmapnamep, NULL, NULL); - } - } - - if (usemapcode) - { - /* we can't check mapheaderinfo for this hahahaha */ - if (W_CheckNumForName(G_BuildMapName(newmapnum)) == LUMPERROR) + if (newmapnum < 1 || newmapnum > nummapheaders) return 0; - - if (realmapnamep) - (*realmapnamep) = G_BuildMapTitle(newmapnum); } + else + { + newmapnum = G_MapNumber(mapname); + + if (newmapnum > nummapheaders) + return G_FindMap(mapname, realmapnamep, NULL, NULL); + } + + if (realmapnamep) + (*realmapnamep) = G_BuildMapTitle(newmapnum); return newmapnum; } From 6cda446f916399d8c97935bef050dad2261c171d Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 31 Oct 2020 17:44:24 -0700 Subject: [PATCH 03/60] Replace more instances of M_MapNumber in SOC --- src/dehacked.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 1aaa2f2c8..43065d8a5 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -2140,13 +2140,13 @@ static void readcupheader(MYFILE *f, cupheader_t *cup) tmp = strtok(word2,","); do { - INT32 map = atoi(tmp); + INT32 map = G_MapNumber(tmp); - if (tmp[0] >= 'A' && tmp[0] <= 'Z' && tmp[2] == '\0') - map = M_MapNumber(tmp[0], tmp[1]); - - if (!map) + if (map >= nummapheaders) + { + deh_warning("Unknown map name '%s'\n", tmp); break; + } if (cup->numlevels >= MAXLEVELLIST) { @@ -2161,16 +2161,12 @@ static void readcupheader(MYFILE *f, cupheader_t *cup) else if (fastcmp(word, "BONUSGAME")) { // Convert to map number - if (word2[0] >= 'A' && word2[0] <= 'Z' && word2[2] == '\0') - i = M_MapNumber(word2[0], word2[1]); - cup->bonusgame = (INT16)i - 1; + cup->bonusgame = (INT16)G_MapNumber(word2) - 1; } else if (fastcmp(word, "SPECIALSTAGE")) { // Convert to map number - if (word2[0] >= 'A' && word2[0] <= 'Z' && word2[2] == '\0') - i = M_MapNumber(word2[0], word2[1]); - cup->specialstage = (INT16)i - 1; + cup->specialstage = (INT16)G_MapNumber(word2) - 1; } else if (fastcmp(word, "EMERALDNUM")) { From 64b418cb2792bd3426250e8a8b88148e06fb1755 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 31 Oct 2020 18:14:25 -0700 Subject: [PATCH 04/60] Added W_CheckNumForMapPwad, both functions check long lump name, ignore case --- src/w_wad.c | 82 ++++++++++++++++++++++++++++++++++++++++------------- src/w_wad.h | 1 + 2 files changed, 64 insertions(+), 19 deletions(-) diff --git a/src/w_wad.c b/src/w_wad.c index 76f68d10f..3a38a136c 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -952,6 +952,39 @@ UINT16 W_FindNextEmptyInPwad(UINT16 wad, UINT16 startlump) return INT16_MAX; } +// Get a map marker for WADs, and a standalone WAD file lump inside PK3s. +UINT16 W_CheckNumForMapPwad(const char *name, UINT16 wad, UINT16 startlump) +{ + UINT16 i, end; + + if (wadfiles[wad]->type == RET_WAD) + { + for (i = startlump; i < wadfiles[wad]->numlumps; i++) + { + if (!strcasecmp(name, (wadfiles[wad]->lumpinfo + i)->name)) + return i; + } + } + else if (wadfiles[wad]->type == RET_PK3) + { + i = W_CheckNumForFolderStartPK3("maps/", wad, startlump); + + if (i != INT16_MAX) + { + end = W_CheckNumForFolderEndPK3("maps/", wad, i); + + // Now look for the specified map. + for (; i < end; i++) + { + if (!strcasecmp(name, (wadfiles[wad]->lumpinfo + i)->longname)) + return i; + } + } + } + + return INT16_MAX; +} + // // Same as the original, but checks in one pwad only. // wadid is a wad number @@ -1182,30 +1215,41 @@ lumpnum_t W_CheckNumForLongName(const char *name) // TODO: Make it search through cache first, maybe...? lumpnum_t W_CheckNumForMap(const char *name) { - UINT16 lumpNum, end; UINT32 i; - for (i = numwadfiles - 1; i < numwadfiles; i--) + lumpnum_t check = INT16_MAX; + + // Check the lumpnumcache first. Loop backwards so that we check + // most recent entries first + for (i = lumpnumcacheindex + LUMPNUMCACHESIZE; i > lumpnumcacheindex; i--) { - if (wadfiles[i]->type == RET_WAD) + if (strcasecmp(lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumpname, name) == 0) { - for (lumpNum = 0; lumpNum < wadfiles[i]->numlumps; lumpNum++) - if (!strncmp(name, (wadfiles[i]->lumpinfo + lumpNum)->name, 8)) - return (i<<16) + lumpNum; - } - else if (wadfiles[i]->type == RET_PK3) - { - lumpNum = W_CheckNumForFolderStartPK3("maps/", i, 0); - if (lumpNum != INT16_MAX) - end = W_CheckNumForFolderEndPK3("maps/", i, lumpNum); - else - continue; - // Now look for the specified map. - for (; lumpNum < end; lumpNum++) - if (!strnicmp(name, (wadfiles[i]->lumpinfo + lumpNum)->name, 8)) - return (i<<16) + lumpNum; + lumpnumcacheindex = i & (LUMPNUMCACHESIZE - 1); + return lumpnumcache[lumpnumcacheindex].lumpnum; } } - return LUMPERROR; + + for (i = numwadfiles - 1; i < numwadfiles; i--) + { + check = W_CheckNumForMapPwad(name,(UINT16)i,0); + if (check != INT16_MAX) + break; //found it + } + + if (check == INT16_MAX) return LUMPERROR; + else + { + if (strlen(name) < 32) + { + // Update the cache. + lumpnumcacheindex = (lumpnumcacheindex + 1) & (LUMPNUMCACHESIZE - 1); + memset(lumpnumcache[lumpnumcacheindex].lumpname, '\0', 32); + strlcpy(lumpnumcache[lumpnumcacheindex].lumpname, name, 32); + lumpnumcache[lumpnumcacheindex].lumpnum = (i << 16) + check; + } + + return (i << 16) + check; + } } // diff --git a/src/w_wad.h b/src/w_wad.h index 4797f4afd..19e60be49 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -160,6 +160,7 @@ const char *W_CheckNameForNum(lumpnum_t lumpnum); UINT16 W_FindNextEmptyInPwad(UINT16 wad, UINT16 startlump); // checks only in one pwad +UINT16 W_CheckNumForMapPwad(const char *name, UINT16 wad, UINT16 startlump); UINT16 W_CheckNumForNamePwad(const char *name, UINT16 wad, UINT16 startlump); // checks only in one pwad UINT16 W_CheckNumForLongNamePwad(const char *name, UINT16 wad, UINT16 startlump); From a669724217343b07b69c7f5081b2a289914e8b6b Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 31 Oct 2020 18:49:50 -0700 Subject: [PATCH 05/60] Kill alreadyExists, check for map replacement by going through the level headers and using W_CheckNumForMapPwad --- src/d_main.c | 53 +++++++------------------------------------------- src/doomstat.h | 3 --- src/g_demo.c | 2 +- src/p_setup.c | 34 +++++++++----------------------- 4 files changed, 17 insertions(+), 75 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index e28dc1c5c..ec4fe5425 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1132,9 +1132,9 @@ D_ConvertVersionNumbers (void) // void D_SRB2Main(void) { + INT32 numbasemapheaders; INT32 i; UINT16 wadnum; - lumpinfo_t *lumpinfo; char *name; INT32 p; @@ -1397,31 +1397,7 @@ void D_SRB2Main(void) #endif //ifndef DEVELOP - // - // search for maps - // - for (wadnum = 4; wadnum < 6; wadnum++) // fucking arbitrary numbers - { - lumpinfo = wadfiles[wadnum]->lumpinfo; - for (i = 0; i < wadfiles[wadnum]->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]); - - // we want to record whether this map exists. if it doesn't have a header, we can assume it's not relephant - if (num <= NUMMAPS && mapheaderinfo[num - 1]) - { - mapheaderinfo[num - 1]->alreadyExists = true; - } - } - } - } + numbasemapheaders = nummapheaders; CON_SetLoadingProgress(LOADED_IWAD); @@ -1430,32 +1406,17 @@ void D_SRB2Main(void) D_CleanFile(startuppwads); // - // search for maps... again. + // search for maps // for (wadnum = mainwads+1; wadnum < numwadfiles; wadnum++) { - lumpinfo = wadfiles[wadnum]->lumpinfo; - for (i = 0; i < wadfiles[wadnum]->numlumps; i++, lumpinfo++) + for (i = 0; i < numbasemapheaders; ++i) { - name = lumpinfo->name; + name = mapheaderinfo[i]->lumpname; - if (name[0] == 'M' && name[1] == 'A' && name[2] == 'P') // Ignore the headers + if (W_CheckNumForMapPwad(name, wadnum, 0) != INT16_MAX) { - INT16 num; - if (name[5] != '\0') - continue; - num = (INT16)M_MapNumber(name[3], name[4]); - - // we want to record whether this map exists. if it doesn't have a header, we can assume it's not relephant - if (num <= NUMMAPS && mapheaderinfo[num - 1]) - { - if (mapheaderinfo[num - 1]->alreadyExists != false) - { - G_SetGameModified(multiplayer, true); // oops, double-defined - no record attack privileges for you - } - - mapheaderinfo[num - 1]->alreadyExists = true; - } + G_SetGameModified(multiplayer, true); // oops, double-defined - no record attack privileges for you CONS_Printf("%s\n", name); } diff --git a/src/doomstat.h b/src/doomstat.h index 91ca7b0ea..7f9dcac93 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -395,9 +395,6 @@ typedef struct SINT8 musforcereset; ///< Force resetmusic (-1 for default; 0 for force off; 1 for force on) - // SRB2Kart: Keeps track of if a map lump exists, so we can tell when a map is being replaced. - boolean alreadyExists; - // Lua stuff. // (This is not ifdeffed so the map header structure can stay identical, just in case.) UINT8 numCustomOptions; ///< Internal. For Lua custom value support. diff --git a/src/g_demo.c b/src/g_demo.c index a841afa9e..89846d1a9 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -2840,7 +2840,7 @@ void G_DoPlayDemo(char *defdemoname) demo_p += 4; // Extrainfo location // ...*map* not loaded? - if (!gamemap || (gamemap > NUMMAPS) || !mapheaderinfo[gamemap-1] || !(mapheaderinfo[gamemap-1]->alreadyExists == true)) + if (!gamemap || (gamemap > NUMMAPS) || !mapheaderinfo[gamemap-1]) { snprintf(msg, 1024, M_GetText("%s features a course that is not currently loaded.\n"), pdemoname); CONS_Alert(CONS_ERROR, "%s", msg); diff --git a/src/p_setup.c b/src/p_setup.c index 4a50e2d08..d44b477bc 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -351,8 +351,6 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) { const INT16 num = (INT16)(i-1); - boolean exists = (mapheaderinfo[gamemap-1]->alreadyExists == true); - mapheaderinfo[num]->lvlttl[0] = '\0'; mapheaderinfo[num]->selectheading[0] = '\0'; mapheaderinfo[num]->subttl[0] = '\0'; @@ -411,9 +409,6 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) #endif P_DeleteGrades(num); - // see p_setup.c - prevents replacing maps in addons with different versions - mapheaderinfo[num]->alreadyExists = exists; - mapheaderinfo[num]->customopts = NULL; mapheaderinfo[num]->numCustomOptions = 0; } @@ -4317,6 +4312,8 @@ static lumpinfo_t* FindFolder(const char *folName, UINT16 *start, UINT16 *end, l boolean P_AddWadFile(const char *wadfilename) { size_t i, j, sreplaces = 0, mreplaces = 0, digmreplaces = 0; + INT32 numexistingmapheaders = nummapheaders; + INT32 map; UINT16 numlumps, wadnum; char *name; lumpinfo_t *lumpinfo; @@ -4466,36 +4463,23 @@ boolean P_AddWadFile(const char *wadfilename) // // search for maps // - lumpinfo = wadfiles[wadnum]->lumpinfo; - for (i = 0; i < numlumps; i++, lumpinfo++) + for (map = 0; map < numexistingmapheaders; ++map) { - name = lumpinfo->name; - if (name[0] == 'M' && name[1] == 'A' && name[2] == 'P') // Ignore the headers + name = mapheaderinfo[map]->lumpname; + + if (W_CheckNumForMapPwad(name, wadnum, 0) != INT16_MAX) { - INT16 num; - if (name[5]!='\0') - continue; - num = (INT16)G_MapNumber(name); - - // we want to record whether this map exists. if it doesn't have a header, we can assume it's not relephant - if (num <= NUMMAPS && mapheaderinfo[num-1]) - { - if (mapheaderinfo[num - 1]->alreadyExists != false) - { - G_SetGameModified(multiplayer, true); // oops, double-defined - no record attack privileges for you - } - - mapheaderinfo[num - 1]->alreadyExists = true; - } + G_SetGameModified(multiplayer, true); // oops, double-defined - no record attack privileges for you //If you replaced the map you're on, end the level when done. - if (num == gamemap) + if (map == gamemap - 1) replacedcurrentmap = true; CONS_Printf("%s\n", name); mapsadded = true; } } + if (!mapsadded) CONS_Printf(M_GetText("No maps added\n")); From d5b52d8ff385bac48651ff637a73f7c89f331ce6 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 31 Oct 2020 19:41:38 -0700 Subject: [PATCH 06/60] Use 2.2's version of the -warp parameter --- src/d_main.c | 73 ++++++++++++++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 37 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index ec4fe5425..e50a16c83 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1307,43 +1307,6 @@ void D_SRB2Main(void) if (M_CheckParm("-server") || dedicated) netgame = server = true; - if (M_CheckParm("-warp") && M_IsNextParm()) - { - const char *word = M_GetNextParm(); - char ch; // use this with sscanf to catch non-digits with - if (fastncmp(word, "MAP", 3)) // MAPxx name - pstartmap = M_MapNumber(word[3], word[4]); - else if (sscanf(word, "%d%c", &pstartmap, &ch) != 1) // a plain number - I_Error("Cannot warp to map %s (invalid map name)\n", word); - // Don't check if lump exists just yet because the wads haven't been loaded! - // Just do a basic range check here. - if (pstartmap < 1 || pstartmap > NUMMAPS) - I_Error("Cannot warp to map %d (out of range)\n", pstartmap); - else - { - if (!M_CheckParm("-server")) - { - G_SetGameModified(true, true); - - // Start up a "minor" grand prix session - memset(&grandprixinfo, 0, sizeof(struct grandprixinfo)); - - grandprixinfo.gamespeed = KARTSPEED_NORMAL; - grandprixinfo.encore = false; - grandprixinfo.masterbots = false; - - grandprixinfo.gp = true; - grandprixinfo.roundnum = 0; - grandprixinfo.cup = NULL; - grandprixinfo.wonround = false; - - grandprixinfo.initalize = true; - } - - autostart = true; - } - } - // adapt tables to SRB2's needs, including extra slots for dehacked file support P_PatchInfoTables(); @@ -1497,6 +1460,42 @@ void D_SRB2Main(void) //------------------------------------------------ COMMAND LINE PARAMS + // this must be done after loading gamedata, + // to avoid setting off the corrupted gamedata code in G_LoadGameData if a SOC with custom gamedata is added + // -- Monster Iestyn 20/02/20 + if (M_CheckParm("-warp") && M_IsNextParm()) + { + const char *word = M_GetNextParm(); + + pstartmap = G_FindMapByNameOrCode(word, 0); + + if (! pstartmap) + I_Error("Cannot find a map remotely named '%s'\n", word); + else + { + if (!M_CheckParm("-server")) + { + G_SetGameModified(true, true); + + // Start up a "minor" grand prix session + memset(&grandprixinfo, 0, sizeof(struct grandprixinfo)); + + grandprixinfo.gamespeed = KARTSPEED_NORMAL; + grandprixinfo.encore = false; + grandprixinfo.masterbots = false; + + grandprixinfo.gp = true; + grandprixinfo.roundnum = 0; + grandprixinfo.cup = NULL; + grandprixinfo.wonround = false; + + grandprixinfo.initalize = true; + } + + autostart = true; + } + } + // this must be done after loading gamedata, // to avoid setting off the corrupted gamedata code in G_LoadGameData if a SOC with custom gamedata is added // -- Monster Iestyn 20/02/20 From 8f68a21f2f93378e96d7837fe3b87785860e7bf4 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 31 Oct 2020 20:17:12 -0700 Subject: [PATCH 07/60] Fix many instances of G_BuildMapName Some things are gonna be busted. Fix it later, BYE. --- src/d_clisrv.c | 2 +- src/d_main.c | 5 +---- src/d_netcmd.c | 2 +- src/discord.c | 3 ++- src/f_finale.c | 12 +++++++++--- src/g_game.c | 7 ++++--- src/k_hud.c | 4 ++-- src/lua_hudlib.c | 4 ++-- src/m_cheat.c | 3 ++- src/m_menu.c | 21 ++++++++------------- src/m_misc.c | 4 +++- src/p_setup.c | 10 +++++----- src/p_spec.c | 3 +++ src/s_sound.c | 1 + src/y_inter.c | 4 ++-- 15 files changed, 46 insertions(+), 39 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 062cfd535..87509a98d 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1554,7 +1554,7 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime) CopyCaretColors(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); M_Memcpy(netbuffer->u.serverinfo.mapmd5, mapmd5, 16); diff --git a/src/d_main.c b/src/d_main.c index e50a16c83..9c84f19db 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1752,14 +1752,11 @@ void D_SRB2Main(void) if (server && !M_CheckParm("+map")) { - // Prevent warping to nonexistent levels - if (W_CheckNumForName(G_BuildMapName(pstartmap)) == LUMPERROR) - I_Error("Could not warp to %s (map not found)\n", G_BuildMapName(pstartmap)); // Prevent warping to locked levels // ... unless you're in a dedicated server. Yes, technically this means you can view any level by // running a dedicated server and joining it yourself, but that's better than making dedicated server's // lives hell. - else if (!dedicated && M_MapLocked(pstartmap)) + if (!dedicated && M_MapLocked(pstartmap)) I_Error("You need to unlock this level before you can warp to it!\n"); else { diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 5c7705a42..6d0bd002b 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2347,7 +2347,7 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pencoremode, boolean r if (delay != 2) { UINT8 flags = 0; - I_Assert(W_CheckNumForName(G_BuildMapName(mapnum)) != LUMPERROR); + //I_Assert(W_CheckNumForName(G_BuildMapName(mapnum)) != LUMPERROR); buf_p = buf; if (pencoremode) flags |= 1; diff --git a/src/discord.c b/src/discord.c index 42b4d91e4..9319095aa 100644 --- a/src/discord.c +++ b/src/discord.c @@ -576,7 +576,8 @@ void DRPC_UpdatePresence(void) if ((gamemap >= 1 && gamemap <= 60) // supported race maps || (gamemap >= 136 && gamemap <= 164)) // supported battle maps { - snprintf(mapimg, 8, "%s", G_BuildMapName(gamemap)); + //FIXME + //snprintf(mapimg, 8, "%s", G_BuildMapName(gamemap)); strlwr(mapimg); discordPresence.largeImageKey = mapimg; // Map image } diff --git a/src/f_finale.c b/src/f_finale.c index d127a2359..84afbdff4 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2104,6 +2104,7 @@ void F_TitleScreenTicker(boolean run) //static boolean use_netreplay = false; char dname[9]; + char *dname2 = dname; lumpnum_t l; const char *mapname; UINT8 numstaff; @@ -2146,7 +2147,7 @@ void F_TitleScreenTicker(boolean run) mapname = G_BuildMapName(G_RandMap(TOL_RACE, -2, false, 0, false, NULL)+1); numstaff = 1; - while (numstaff < 99 && (l = W_CheckNumForName(va("%sS%02u",mapname,numstaff+1))) != LUMPERROR) + while (numstaff < 99 && (l = W_CheckNumForLongName(va("%sS%02u",mapname,numstaff+1))) != LUMPERROR) numstaff++; #if 0 // turns out this isn't how we're gonna organise 'em @@ -2167,7 +2168,7 @@ void F_TitleScreenTicker(boolean run) #endif // Setup demo name - snprintf(dname, 9, "%sS%02u", mapname, numstaff); + dname2 = Z_StrDup(va("%sS%02u", mapname, numstaff)); /*if ((l = W_CheckNumForName(dname)) == LUMPERROR) -- we KNOW it exists now { @@ -2180,7 +2181,12 @@ loadreplay: demo.title = demo.fromtitle = true; demo.ignorefiles = true; demo.loadfiles = false; - G_DoPlayDemo(dname); + G_DoPlayDemo(dname2); + + if (dname2 != dname) + { + Z_Free(dname2); + } } } diff --git a/src/g_game.c b/src/g_game.c index c4c00aee0..65b6f1176 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1201,7 +1201,8 @@ void G_DoLoadLevel(boolean resetplayer) // cleanup if (titlemapinaction == TITLEMAP_LOADING) { - if (W_CheckNumForName(G_BuildMapName(gamemap)) == LUMPERROR) + //if (W_CheckNumForName(G_BuildMapName(gamemap)) == LUMPERROR) + if (gamemap < 1 || gamemap > nummapheaders) { titlemap = 0; // let's not infinite recursion ok Command_ExitGame_f(); @@ -3262,7 +3263,7 @@ tryagain: if (pprevmap == -2) // title demo hack { lumpnum_t l; - if ((l = W_CheckNumForName(va("%sS01",G_BuildMapName(ix+1)))) == LUMPERROR) + if ((l = W_CheckNumForLongName(va("%sS01",G_BuildMapName(ix+1)))) == LUMPERROR) continue; } @@ -3513,7 +3514,7 @@ static void G_DoCompleted(void) 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 (cm < 0 || cm >= nummapheaders) { CONS_Alert(CONS_ERROR, M_GetText("Next map given (MAP %d) doesn't exist! Reverting to MAP01.\n"), cm+1); cm = 0; diff --git a/src/k_hud.c b/src/k_hud.c index 42c7fd7c2..fb89de464 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -2761,10 +2761,10 @@ static void K_drawKartMinimap(void) if (stplyr != &players[displayplayers[0]]) return; - lumpnum = W_CheckNumForName(va("%sR", G_BuildMapName(gamemap))); + lumpnum = W_CheckNumForLongName(va("%sR", G_BuildMapName(gamemap))); if (lumpnum != -1) - AutomapPic = W_CachePatchName(va("%sR", G_BuildMapName(gamemap)), PU_HUDGFX); + AutomapPic = W_CachePatchNum(lumpnum, PU_HUDGFX); else return; // no pic, just get outta here diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 2180012b0..a60215537 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -815,10 +815,10 @@ static int libd_drawOnMinimap(lua_State *L) if (stplyr != &players[displayplayers[0]]) return 0; - lumpnum = W_CheckNumForName(va("%sR", G_BuildMapName(gamemap))); + lumpnum = W_CheckNumForLongName(va("%sR", G_BuildMapName(gamemap))); if (lumpnum != -1) - AutomapPic = W_CachePatchName(va("%sR", G_BuildMapName(gamemap)), PU_HUDGFX); + AutomapPic = W_CachePatchNum(lumpnum, PU_HUDGFX); else return 0; // no pic, just get outta here diff --git a/src/m_cheat.c b/src/m_cheat.c index ff5f86968..e929ba3d5 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -1165,7 +1165,8 @@ void Command_Writethings_f(void) REQUIRE_SINGLEPLAYER; REQUIRE_OBJECTPLACE; - P_WriteThings(W_GetNumForName(G_BuildMapName(gamemap)) + ML_THINGS); + //FIXME? + //P_WriteThings(W_GetNumForName(G_BuildMapName(gamemap)) + ML_THINGS); } void Command_ObjectPlace_f(void) diff --git a/src/m_menu.c b/src/m_menu.c index 32d82f8f6..9d01961ed 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -2218,7 +2218,7 @@ static void Dummystaff_OnChange(void) dummystaffname[0] = '\0'; - if ((l = W_CheckNumForName(va("%sS01",G_BuildMapName(cv_nextmap.value)))) == LUMPERROR) + if ((l = W_CheckNumForLongName(va("%sS01",G_BuildMapName(cv_nextmap.value)))) == LUMPERROR) { CV_StealthSetValue(&cv_dummystaff, 0); return; @@ -2227,7 +2227,7 @@ static void Dummystaff_OnChange(void) { char *temp = dummystaffname; UINT8 numstaff = 1; - while (numstaff < 99 && (l = W_CheckNumForName(va("%sS%02u",G_BuildMapName(cv_nextmap.value),numstaff+1))) != LUMPERROR) + while (numstaff < 99 && (l = W_CheckNumForLongName(va("%sS%02u",G_BuildMapName(cv_nextmap.value),numstaff+1))) != LUMPERROR) numstaff++; if (cv_dummystaff.value < 1) @@ -2235,7 +2235,7 @@ static void Dummystaff_OnChange(void) else if (cv_dummystaff.value > numstaff) CV_StealthSetValue(&cv_dummystaff, 1); - if ((l = W_CheckNumForName(va("%sS%02u",G_BuildMapName(cv_nextmap.value), cv_dummystaff.value))) == LUMPERROR) + if ((l = W_CheckNumForLongName(va("%sS%02u",G_BuildMapName(cv_nextmap.value), cv_dummystaff.value))) == LUMPERROR) return; // shouldn't happen but might as well check... G_UpdateStaffGhostName(l); @@ -5524,7 +5524,7 @@ static void DrawReplayHutReplayInfo(void) // A 160x100 image of the level as entry MAPxxP //CONS_Printf("%d %s\n", demolist[dir_on[menudepthleft]].map, G_BuildMapName(demolist[dir_on[menudepthleft]].map)); - lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(demolist[dir_on[menudepthleft]].map))); + lumpnum = W_CheckNumForLongName(va("%sP", G_BuildMapName(demolist[dir_on[menudepthleft]].map))); if (lumpnum != LUMPERROR) patch = W_CachePatchNum(lumpnum, PU_CACHE); else @@ -6187,15 +6187,10 @@ static boolean M_ExitPandorasBox(void) static void M_ChangeLevel(INT32 choice) { - char mapname[6]; (void)choice; - strlcpy(mapname, G_BuildMapName(cv_nextmap.value), sizeof (mapname)); - strlwr(mapname); - mapname[5] = '\0'; - M_ClearMenus(true); - COM_BufAddText(va("map %s -gametype \"%s\"\n", mapname, cv_newgametype.string)); + COM_BufAddText(va("map %d -gametype \"%s\"\n", cv_nextmap.value, cv_newgametype.string)); } static void M_ConfirmSpectate(INT32 choice) @@ -8878,7 +8873,7 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) // A 160x100 image of the level as entry MAPxxP if (cv_nextmap.value) { - lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(cv_nextmap.value))); + lumpnum = W_CheckNumForLongName(va("%sP", G_BuildMapName(cv_nextmap.value))); if (lumpnum != LUMPERROR) PictureOfLevel = W_CachePatchNum(lumpnum, PU_CACHE); else @@ -8944,7 +8939,7 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) // A 160x100 image of the level as entry MAPxxP if (i+1) { - lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(i+1))); + lumpnum = W_CheckNumForLongName(va("%sP", G_BuildMapName(i+1))); if (lumpnum != LUMPERROR) PictureOfLevel = W_CachePatchNum(lumpnum, PU_CACHE); else @@ -8982,7 +8977,7 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) // A 160x100 image of the level as entry MAPxxP if (i+1) { - lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(i+1))); + lumpnum = W_CheckNumForLongName(va("%sP", G_BuildMapName(i+1))); if (lumpnum != LUMPERROR) PictureOfLevel = W_CachePatchNum(lumpnum, PU_CACHE); else diff --git a/src/m_misc.c b/src/m_misc.c index cd8a35cba..177f2cd33 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -799,9 +799,11 @@ static void M_PNGText(png_structp png_ptr, png_infop png_info_ptr, PNG_CONST png break; } +#if 0 if (gamestate == GS_LEVEL) snprintf(maptext, 8, "%s", G_BuildMapName(gamemap)); else +#endif snprintf(maptext, 8, "Unknown"); if (gamestate == GS_LEVEL && mapheaderinfo[gamemap-1]->lvlttl[0] != '\0') @@ -2647,4 +2649,4 @@ const char * M_Ftrim (double f) dig[i + 1] = '\0'; return &dig[1];/* skip the 0 */ } -} \ No newline at end of file +} diff --git a/src/p_setup.c b/src/p_setup.c index d44b477bc..c0d7e4afa 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -367,7 +367,7 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) mapheaderinfo[num]->ssspheres = 1; mapheaderinfo[num]->gravity = DEFAULT_GRAVITY; mapheaderinfo[num]->keywords[0] = '\0'; - snprintf(mapheaderinfo[num]->musname, 7, "%sM", G_BuildMapName(i)); + sprintf(mapheaderinfo[num]->musname, "%.5sM", G_BuildMapName(i)); mapheaderinfo[num]->musname[6] = 0; mapheaderinfo[num]->mustrack = 0; mapheaderinfo[num]->muspos = 0; @@ -3671,7 +3671,7 @@ static void P_LoadRecordGhosts(void) { lumpnum_t l; UINT8 j = 1; - while (j <= 99 && (l = W_CheckNumForName(va("%sS%02u",G_BuildMapName(gamemap),j))) != LUMPERROR) + while (j <= 99 && (l = W_CheckNumForLongName(va("%sS%02u",G_BuildMapName(gamemap),j))) != LUMPERROR) { G_AddGhost(va("%sS%02u",G_BuildMapName(gamemap),j)); j++; @@ -3774,7 +3774,7 @@ static void P_InitGametype(void) { static char buf[256]; char *path; - sprintf(buf, "media"PATHSEP"replay"PATHSEP"online"PATHSEP"%d-%s", (int) (time(NULL)), G_BuildMapName(gamemap)); + snprintf(buf, sizeof buf, "media"PATHSEP"replay"PATHSEP"online"PATHSEP"%d-%s", (int) (time(NULL)), G_BuildMapName(gamemap)); path = va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"online", srb2home); M_MkdirEach(path, M_PathParts(path) - 4, 0755); @@ -4004,12 +4004,12 @@ boolean P_LoadLevel(boolean fromnetsave) // internal game map maplumpname = G_BuildMapName(gamemap); - lastloadedmaplumpnum = W_CheckNumForName(maplumpname); + lastloadedmaplumpnum = W_CheckNumForMap(maplumpname); if (lastloadedmaplumpnum == LUMPERROR) I_Error("Map %s not found.\n", maplumpname); R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette, - (encoremode ? W_CheckNumForName(va("%sE", maplumpname)) : LUMPERROR)); + (encoremode ? W_CheckNumForLongName(va("%sE", maplumpname)) : LUMPERROR)); CON_SetupBackColormap(); // SRB2 determines the sky texture to be used depending on the map header. diff --git a/src/p_spec.c b/src/p_spec.c index a86c54c07..b859d4588 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -2571,6 +2571,8 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) break; case 415: // Run a script + // FIXME: cursed +#if 0 if (cv_runscripts.value) { INT32 scrnum; @@ -2605,6 +2607,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) else COM_BufInsertText(W_CacheLumpNum(lumpnum, PU_CACHE)); } +#endif break; case 416: // Spawn adjustable fire flicker diff --git a/src/s_sound.c b/src/s_sound.c index f17d5bdd2..79c301e70 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -2627,6 +2627,7 @@ void S_StartEx(boolean reset) music_stack_fadein = JINGLEPOSTFADE; } +// TODO: fix this function, needs better support for map names static void Command_Tunes_f(void) { const char *tunearg; diff --git a/src/y_inter.c b/src/y_inter.c index 5f5bb5f05..34b58c4a7 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -1813,9 +1813,9 @@ void Y_StartVote(void) levelinfo[i].gts = NULL; // set up the pic - lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(votelevels[i][0]+1))); + lumpnum = W_CheckNumForLongName(va("%sP", G_BuildMapName(votelevels[i][0]+1))); if (lumpnum != LUMPERROR) - levelinfo[i].pic = W_CachePatchName(va("%sP", G_BuildMapName(votelevels[i][0]+1)), PU_STATIC); + levelinfo[i].pic = W_CachePatchNum(lumpnum, PU_STATIC); else levelinfo[i].pic = W_CachePatchName("BLANKLVL", PU_STATIC); } From fbca1b435a40bad0fbf5345b3268d92bc96f8a30 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 31 Oct 2020 20:26:25 -0700 Subject: [PATCH 08/60] Replaced level header does not mark game modified if from a main wad --- src/dehacked.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dehacked.c b/src/dehacked.c index 43065d8a5..11a94c12c 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1699,7 +1699,7 @@ static void readlevelheader(MYFILE *f, char * name) I_Error("Too many maps!"); } - if (mapheaderinfo[num-1]) + if (f->wad > mainwads && num <= nummapheaders) G_SetGameModified(multiplayer, true); // only mark as a major mod if it replaces an already-existing mapheaderinfo // Reset all previous map header information From 3eb278684afab90ed17c64cfeddf65dd1f27c3c4 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 31 Oct 2020 20:28:46 -0700 Subject: [PATCH 09/60] Fix mistake --- src/dehacked.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dehacked.c b/src/dehacked.c index 11a94c12c..44dda269b 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -2142,7 +2142,7 @@ static void readcupheader(MYFILE *f, cupheader_t *cup) do { INT32 map = G_MapNumber(tmp); - if (map >= nummapheaders) + if (map > nummapheaders) { deh_warning("Unknown map name '%s'\n", tmp); break; From 66f67267c773f914c2a736db01ddb1d92638ef19 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 31 Oct 2020 20:32:44 -0700 Subject: [PATCH 10/60] Remove duplicated code --- src/d_main.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 9c84f19db..c7f33d0db 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1496,23 +1496,6 @@ void D_SRB2Main(void) } } - // this must be done after loading gamedata, - // to avoid setting off the corrupted gamedata code in G_LoadGameData if a SOC with custom gamedata is added - // -- Monster Iestyn 20/02/20 - if (M_CheckParm("-warp") && M_IsNextParm()) - { - const char *word = M_GetNextParm(); - pstartmap = G_FindMapByNameOrCode(word, 0); - if (! pstartmap) - I_Error("Cannot find a map remotely named '%s'\n", word); - else - { - if (!M_CheckParm("-server")) - G_SetGameModified(multiplayer, true); - autostart = true; - } - } - if (M_CheckParm("-noupload")) COM_BufAddText("downloading 0\n"); From 481c178a15639aef31db691ba21893baea014cc8 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 1 Nov 2020 19:31:10 -0800 Subject: [PATCH 11/60] The lump is not needed for P_WriteThings (cherry picked from commit 972b0c084eeba679674095cfe2f41d8747e4097d) --- src/m_cheat.c | 3 +-- src/p_setup.c | 7 +------ src/p_setup.h | 2 +- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/m_cheat.c b/src/m_cheat.c index e929ba3d5..27aa5859b 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -1165,8 +1165,7 @@ void Command_Writethings_f(void) REQUIRE_SINGLEPLAYER; REQUIRE_OBJECTPLACE; - //FIXME? - //P_WriteThings(W_GetNumForName(G_BuildMapName(gamemap)) + ML_THINGS); + P_WriteThings(); } void Command_ObjectPlace_f(void) diff --git a/src/p_setup.c b/src/p_setup.c index c0d7e4afa..2f3f06024 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -870,16 +870,13 @@ static void P_SpawnMapThings(boolean spawnemblems) } // Experimental groovy write function! -void P_WriteThings(lumpnum_t lumpnum) +void P_WriteThings(void) { size_t i, length; mapthing_t *mt; - UINT8 *data; UINT8 *savebuffer, *savebuf_p; INT16 temp; - data = W_CacheLumpNum(lumpnum, PU_LEVEL); - savebuf_p = savebuffer = (UINT8 *)malloc(nummapthings * sizeof (mapthing_t)); if (!savebuf_p) @@ -901,8 +898,6 @@ void P_WriteThings(lumpnum_t lumpnum) WRITEUINT16(savebuf_p, mt->options); } - Z_Free(data); - length = savebuf_p - savebuffer; FIL_WriteFile(va("newthings%d.lmp", gamemap), savebuffer, length); diff --git a/src/p_setup.h b/src/p_setup.h index ac0f22caf..06139aa5c 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -105,7 +105,7 @@ boolean P_AddWadFile(const char *wadfilename); 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_WriteThings(lumpnum_t lump); +void P_WriteThings(void); void P_UpdateSegLightOffset(seg_t *li); size_t P_PrecacheLevelFlats(void); void P_AllocMapHeader(INT16 i); From 8a616fb26543ca92778dd683970cc0882c9f71c3 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 1 Nov 2020 19:40:59 -0800 Subject: [PATCH 12/60] P_WriteThings: use map name in file name --- src/p_setup.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index 2f3f06024..bc72af902 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -872,6 +872,7 @@ static void P_SpawnMapThings(boolean spawnemblems) // Experimental groovy write function! void P_WriteThings(void) { + const char * filename; size_t i, length; mapthing_t *mt; UINT8 *savebuffer, *savebuf_p; @@ -900,11 +901,13 @@ void P_WriteThings(void) length = savebuf_p - savebuffer; - FIL_WriteFile(va("newthings%d.lmp", gamemap), savebuffer, length); + filename = va("newthings-%s.lmp", G_BuildMapName(gamemap)); + + FIL_WriteFile(filename, savebuffer, length); free(savebuffer); savebuf_p = NULL; - CONS_Printf(M_GetText("newthings%d.lmp saved.\n"), gamemap); + CONS_Printf(M_GetText("%s saved.\n"), filename); } // From 1db88decce5730e10fdd6d84549639be89b3c7d3 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 1 Nov 2020 19:43:26 -0800 Subject: [PATCH 13/60] Put a run time warning that 415 doesn't work --- src/p_spec.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/p_spec.c b/src/p_spec.c index b859d4588..229d5f5c8 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -2572,6 +2572,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) case 415: // Run a script // FIXME: cursed + CONS_Alert(CONS_WARNING, "Linedef special 415 is currently broken! Fix it later, BYE.\n"); #if 0 if (cv_runscripts.value) { From de1f67b72a196bc228832ca848f54a34b03c36b0 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Fri, 9 Apr 2021 21:10:46 -0400 Subject: [PATCH 14/60] Use strings in the map header for next level, marathon next, thumbnails, minimaps, encoremaps, and tweakmaps --- src/d_main.c | 15 ++- src/d_netcmd.c | 7 +- src/deh_lua.c | 28 +---- src/deh_soc.c | 314 ++++++++++------------------------------------ src/deh_soc.h | 7 +- src/dehacked.c | 22 +--- src/doomdef.h | 4 - src/doomstat.h | 147 ++++++++++++---------- src/f_finale.c | 8 +- src/g_demo.c | 1 + src/g_game.c | 51 ++++++-- src/k_hud.c | 7 +- src/lua_baselib.c | 65 ---------- src/lua_hudlib.c | 7 +- src/lua_maplib.c | 4 +- src/lua_script.c | 6 +- src/m_cond.c | 27 +++- src/m_cond.h | 2 +- src/m_menu.c | 44 +++++-- src/p_setup.c | 64 +++++++++- src/s_sound.c | 22 ---- src/s_sound.h | 6 - src/y_inter.c | 8 +- 23 files changed, 355 insertions(+), 511 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index c623a0097..9f87bb59c 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1594,13 +1594,18 @@ void D_SRB2Main(void) // rei/miru: bootmap (Idea: starts the game on a predefined map) if (bootmap && !(M_CheckParm("-warp") && M_IsNextParm())) { - pstartmap = bootmap; + const INT32 bootMapNum = G_MapNumber(bootmap); - if (pstartmap < 1 || pstartmap > NUMMAPS) - I_Error("Cannot warp to map %d (out of range)\n", pstartmap); - else + if (mapheaderinfo[bootMapNum]) { - autostart = true; + pstartmap = bootMapNum; + + if (pstartmap < 1 || pstartmap > NUMMAPS) + I_Error("Cannot warp to map %d (out of range)\n", pstartmap); + else + { + autostart = true; + } } } diff --git a/src/d_netcmd.c b/src/d_netcmd.c index fbf205479..b56c6e18b 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2791,6 +2791,7 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) INT32 resetplayer = 1, lastgametype; UINT8 skipprecutscene, FLS; boolean pencoremode; + INT16 mapnumber; forceresetplayers = deferencoremode = false; @@ -2848,13 +2849,13 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) memset(&luabanks, 0, sizeof(luabanks)); } + demo.savemode = (cv_recordmultiplayerdemos.value == 2) ? DSM_WILLAUTOSAVE : DSM_NOTSAVING; + demo.savebutton = 0; + // Sal: Is this needed? // From experimenting with Lua scripts in vanilla I found a lot of annoying & potentially desync-y things with MapChange. LUAh_MapChange(mapnumber); - demo.savemode = (cv_recordmultiplayerdemos.value == 2) ? DSM_WILLAUTOSAVE : DSM_NOTSAVING; - demo.savebutton = 0; - G_InitNew(pencoremode, mapnumber, resetplayer, skipprecutscene, FLS); if (demo.playback && !demo.timing) precache = true; diff --git a/src/deh_lua.c b/src/deh_lua.c index c36ebc034..2154a1416 100644 --- a/src/deh_lua.c +++ b/src/deh_lua.c @@ -24,10 +24,7 @@ #include "dehacked.h" #include "deh_lua.h" #include "deh_tables.h" - -#ifdef MUSICSLOT_COMPATIBILITY -#include "deh_soc.h" // for get_mus -#endif +#include "deh_soc.h" // freeslotusage // freeslot takes a name (string only!) // and allocates it to the appropriate free slot. @@ -422,29 +419,6 @@ static inline int lib_getenum(lua_State *L) if (mathlib) return luaL_error(L, "sfx '%s' could not be found.\n", word); return 0; } -#ifdef MUSICSLOT_COMPATIBILITY - else if (!mathlib && fastncmp("mus_",word,4)) { - p = word+4; - if ((i = get_mus(p, false)) == 0) - return 0; - lua_pushinteger(L, i); - return 1; - } - else if (mathlib && fastncmp("MUS_",word,4)) { // SOCs are ALL CAPS! - p = word+4; - if ((i = get_mus(p, false)) == 0) - return luaL_error(L, "music '%s' could not be found.\n", word); - lua_pushinteger(L, i); - return 1; - } - else if (mathlib && (fastncmp("O_",word,2) || fastncmp("D_",word,2))) { - p = word+2; - if ((i = get_mus(p, false)) == 0) - return luaL_error(L, "music '%s' could not be found.\n", word); - lua_pushinteger(L, i); - return 1; - } -#endif else if (!mathlib && fastncmp("pw_",word,3)) { p = word+3; for (i = 0; i < NUMPOWERS; i++) diff --git a/src/deh_soc.c b/src/deh_soc.c index c6ad81b7b..774f5ffed 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -152,7 +152,10 @@ void clear_levels(void) // we may as well try to save some memory, right? for (i = 0; i < NUMMAPS; ++i) { - if (!mapheaderinfo[i] || i == (tutorialmap-1)) + if (!mapheaderinfo[i]) + continue; + + if (strcmp(mapheaderinfo[i]->lumpname, tutorialmap) == 0) // Sal: Is this needed...? continue; // Custom map header info @@ -1256,18 +1259,38 @@ void readgametype(MYFILE *f, char *gtname) CONS_Printf("Added gametype %s\n", Gametype_Names[newgtidx]); } -void readlevelheader(MYFILE *f, INT32 num) +void readlevelheader(MYFILE *f, char * name) { char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); + char *word; char *word2; //char *word3; // Non-uppercase version of word2 + char *tmp; INT32 i; + const INT32 num = G_MapNumber(name); + + if (num > NUMMAPS) + { + I_Error("Too many maps!"); + } + + if (f->wad > mainwads && num <= nummapheaders) + { + // only mark as a major mod if it replaces an already-existing mapheaderinfo + G_SetGameModified(multiplayer, true); + } + // Reset all previous map header information P_AllocMapHeader((INT16)(num-1)); + if (mapheaderinfo[num-1]->lumpname == NULL) + { + mapheaderinfo[num-1]->lumpname = Z_StrDup(name); + } + do { if (myfgets(s, MAXLINELEN, f)) @@ -1434,6 +1457,30 @@ void readlevelheader(MYFILE *f, INT32 num) } // Strings that can be truncated + else if (fastcmp(word, "THUMBNAIL")) + { + mapheaderinfo[num-1]->thumbnailLump = Z_StrDup(word2); + } + else if (fastcmp(word, "MINIMAP")) + { + mapheaderinfo[num-1]->minimapLump = Z_StrDup(word2); + } + else if (fastcmp(word, "ENCOREMAP")) + { + mapheaderinfo[num-1]->encoreLump = Z_StrDup(word2); + } + else if (fastcmp(word, "TWEAKMAP")) + { + mapheaderinfo[num-1]->tweakLump = Z_StrDup(word2); + } + else if (fastcmp(word, "NEXTLEVEL")) + { + mapheaderinfo[num-1]->nextlevel = Z_StrDup(word2); + } + else if (fastcmp(word, "MARATHONNEXT")) + { + mapheaderinfo[num-1]->marathonnext = Z_StrDup(word2); + } else if (fastcmp(word, "ZONETITLE")) { deh_strlcpy(mapheaderinfo[num-1]->zonttl, word2, @@ -1456,38 +1503,6 @@ void readlevelheader(MYFILE *f, INT32 num) else deh_warning("Level header %d: invalid act number %d", num, i); } - 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]); - - 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]); - - mapheaderinfo[num-1]->marathonnext = (INT16)i; - } else if (fastcmp(word, "TYPEOFLEVEL")) { if (i) // it's just a number @@ -1522,19 +1537,6 @@ void readlevelheader(MYFILE *f, INT32 num) sizeof(mapheaderinfo[num-1]->musname), va("Level header %d: music", num)); } } -#ifdef MUSICSLOT_COMPATIBILITY - else if (fastcmp(word, "MUSICSLOT")) - { - i = get_mus(word2, true); - if (i && i <= 1035) - snprintf(mapheaderinfo[num-1]->musname, 7, "%sM", G_BuildMapName(i)); - else if (i && i <= 1050) - strncpy(mapheaderinfo[num-1]->musname, compat_special_music_slots[i - 1036], 7); - else - mapheaderinfo[num-1]->musname[0] = 0; // becomes empty string - mapheaderinfo[num-1]->musname[6] = 0; - } -#endif else if (fastcmp(word, "MUSICTRACK")) mapheaderinfo[num-1]->mustrack = ((UINT16)i - 1); else if (fastcmp(word, "MUSICPOS")) @@ -1777,19 +1779,6 @@ static void readcutscenescene(MYFILE *f, INT32 num, INT32 scenenum) strncpy(cutscenes[num]->scene[scenenum].musswitch, word2, 7); cutscenes[num]->scene[scenenum].musswitch[6] = 0; } -#ifdef MUSICSLOT_COMPATIBILITY - else if (fastcmp(word, "MUSICSLOT")) - { - i = get_mus(word2, true); - if (i && i <= 1035) - snprintf(cutscenes[num]->scene[scenenum].musswitch, 7, "%sM", G_BuildMapName(i)); - else if (i && i <= 1050) - strncpy(cutscenes[num]->scene[scenenum].musswitch, compat_special_music_slots[i - 1036], 7); - else - cutscenes[num]->scene[scenenum].musswitch[0] = 0; // becomes empty string - cutscenes[num]->scene[scenenum].musswitch[6] = 0; - } -#endif else if (fastcmp(word, "MUSICTRACK")) { cutscenes[num]->scene[scenenum].musswitchflags = ((UINT16)i) & MUSIC_TRACKMASK; @@ -2052,19 +2041,6 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) strncpy(textprompts[num]->page[pagenum].musswitch, word2, 7); textprompts[num]->page[pagenum].musswitch[6] = 0; } -#ifdef MUSICSLOT_COMPATIBILITY - else if (fastcmp(word, "MUSICSLOT")) - { - i = get_mus(word2, true); - if (i && i <= 1035) - snprintf(textprompts[num]->page[pagenum].musswitch, 7, "%sM", G_BuildMapName(i)); - else if (i && i <= 1050) - strncpy(textprompts[num]->page[pagenum].musswitch, compat_special_music_slots[i - 1036], 7); - else - textprompts[num]->page[pagenum].musswitch[0] = 0; // becomes empty string - textprompts[num]->page[pagenum].musswitch[6] = 0; - } -#endif else if (fastcmp(word, "MUSICTRACK")) { textprompts[num]->page[pagenum].musswitchflags = ((UINT16)i) & MUSIC_TRACKMASK; @@ -2388,20 +2364,6 @@ void readmenu(MYFILE *f, INT32 num) menupres[num].musname[6] = 0; titlechanged = true; } -#ifdef MUSICSLOT_COMPATIBILITY - else if (fastcmp(word, "MUSICSLOT")) - { - value = get_mus(word2, true); - if (value && value <= 1035) - snprintf(menupres[num].musname, 7, "%sM", G_BuildMapName(value)); - else if (value && value <= 1050) - strncpy(menupres[num].musname, compat_special_music_slots[value - 1036], 7); - else - menupres[num].musname[0] = 0; // becomes empty string - menupres[num].musname[6] = 0; - titlechanged = true; - } -#endif else if (fastcmp(word, "MUSICTRACK")) { menupres[num].mustrack = ((UINT16)value - 1); @@ -2794,14 +2756,7 @@ 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]); - - emblemlocations[num-1].level = (INT16)value; + emblemlocations[num-1].level = Z_StrDup(word2); } else if (fastcmp(word, "SPRITE")) { @@ -3022,13 +2977,7 @@ void readunlockable(MYFILE *f, INT32 num) } else if (fastcmp(word, "VAR")) { - // 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]); - + // TODO: different field for level name string unlockables[num].variable = (INT16)i; } else @@ -3107,12 +3056,7 @@ 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 - re = atoi(params[1]); + re = G_MapNumber(params[1]); if (re < 0 || re >= NUMMAPS) { @@ -3125,12 +3069,7 @@ static void readcondition(UINT8 set, UINT32 id, char *word2) PARAMCHECK(2); ty = UC_MAPTIME; 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 - x1 = (INT16)atoi(params[1]); + x1 = G_MapNumber(params[1]); if (x1 < 0 || x1 >= NUMMAPS) { @@ -3333,56 +3272,23 @@ void readmaincfg(MYFILE *f) else if (fastcmp(word, "SPSTAGE_START")) { - // 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]); - else - value = get_number(word2); - - spstage_start = spmarathon_start = (INT16)value; + // TODO: Use map name string + // Haven't done it because of how special stage ends are handled + // Though, we likely won't be using these for Kart anyhow + spstage_start = spmarathon_start = (INT16)G_MapNumber(word2); } else if (fastcmp(word, "SPMARATHON_START")) { - // 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]); - else - value = get_number(word2); - - spmarathon_start = (INT16)value; + spmarathon_start = (INT16)G_MapNumber(word2); } else if (fastcmp(word, "SSTAGE_START")) { - // 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]); - else - value = get_number(word2); - - sstage_start = (INT16)value; + sstage_start = (INT16)G_MapNumber(word2); sstage_end = (INT16)(sstage_start+7); // 7 special stages total plus one weirdo } else if (fastcmp(word, "SMPSTAGE_START")) { - // 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]); - else - value = get_number(word2); - - smpstage_start = (INT16)value; + smpstage_start = (INT16)G_MapNumber(word2); smpstage_end = (INT16)(smpstage_start+6); // 7 special stages total } else if (fastcmp(word, "REDTEAM")) @@ -3467,16 +3373,7 @@ void readmaincfg(MYFILE *f) } else if (fastcmp(word, "TITLEMAP")) { - // 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]); - else - value = get_number(word2); - - titlemap = (INT16)value; + titlemap = Z_StrDup(word2); titlechanged = true; } else if (fastcmp(word, "HIDETITLEPICS") || fastcmp(word, "TITLEPICSHIDE")) @@ -3606,30 +3503,12 @@ void readmaincfg(MYFILE *f) } else if (fastcmp(word, "BOOTMAP")) { - // 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]); - else - value = get_number(word2); - - bootmap = (INT16)value; + bootmap = Z_StrDup(word2); //titlechanged = true; } else if (fastcmp(word, "TUTORIALMAP")) { - // 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]); - else - value = get_number(word2); - - tutorialmap = (INT16)value; + tutorialmap = Z_StrDup(word2); } else deh_warning("Maincfg: unknown word '%s'", word); @@ -3852,37 +3731,23 @@ void readcupheader(MYFILE *f, cupheader_t *cup) tmp = strtok(word2,","); do { - INT32 map = atoi(tmp); - - if (tmp[0] >= 'A' && tmp[0] <= 'Z' && tmp[2] == '\0') - map = M_MapNumber(tmp[0], tmp[1]); - - if (!map) - break; - if (cup->numlevels >= MAXLEVELLIST) { deh_warning("%s Cup: reached max levellist (%d)\n", cup->name, MAXLEVELLIST); break; } - cup->levellist[cup->numlevels] = map - 1; + cup->levellist[cup->numlevels] = Z_StrDup(word2); cup->numlevels++; } while((tmp = strtok(NULL,",")) != NULL); } else if (fastcmp(word, "BONUSGAME")) { - // Convert to map number - if (word2[0] >= 'A' && word2[0] <= 'Z' && word2[2] == '\0') - i = M_MapNumber(word2[0], word2[1]); - cup->bonusgame = (INT16)i - 1; + cup->bonusgame = Z_StrDup(word2); } else if (fastcmp(word, "SPECIALSTAGE")) { - // Convert to map number - if (word2[0] >= 'A' && word2[0] <= 'Z' && word2[2] == '\0') - i = M_MapNumber(word2[0], word2[1]); - cup->specialstage = (INT16)i - 1; + cup->specialstage = Z_StrDup(word2); } else if (fastcmp(word, "EMERALDNUM")) { @@ -4257,46 +4122,6 @@ sfxenum_t get_sfx(const char *word) return sfx_None; } -#ifdef MUSICSLOT_COMPATIBILITY -UINT16 get_mus(const char *word, UINT8 dehacked_mode) -{ // Returns the value of MUS_ enumerations - UINT16 i; - char lumptmp[4]; - - if (*word >= '0' && *word <= '9') - return atoi(word); - if (!word[2] && toupper(word[0]) >= 'A' && toupper(word[0]) <= 'Z') - return (UINT16)M_MapNumber(word[0], word[1]); - - if (fastncmp("MUS_",word,4)) - word += 4; // take off the MUS_ - else if (fastncmp("O_",word,2) || fastncmp("D_",word,2)) - word += 2; // take off the O_ or D_ - - strncpy(lumptmp, word, 4); - lumptmp[3] = 0; - if (fasticmp("MAP",lumptmp)) - { - word += 3; - if (toupper(word[0]) >= 'A' && toupper(word[0]) <= 'Z') - return (UINT16)M_MapNumber(word[0], word[1]); - else if ((i = atoi(word))) - return i; - - word -= 3; - if (dehacked_mode) - deh_warning("Couldn't find music named 'MUS_%s'",word); - return 0; - } - for (i = 0; compat_special_music_slots[i][0]; ++i) - if (fasticmp(word, compat_special_music_slots[i])) - return i + 1036; - if (dehacked_mode) - deh_warning("Couldn't find music named 'MUS_%s'",word); - return 0; -} -#endif - hudnum_t get_huditem(const char *word) { // Returns the value of HUD_ enumerations hudnum_t i; @@ -4527,13 +4352,6 @@ static fixed_t find_const(const char **rword) free(word); return r; } -#ifdef MUSICSLOT_COMPATIBILITY - else if (fastncmp("MUS_",word,4) || fastncmp("O_",word,2)) { - r = get_mus(word, true); - free(word); - return r; - } -#endif else if (fastncmp("PW_",word,3)) { r = get_power(word); free(word); diff --git a/src/deh_soc.h b/src/deh_soc.h index ee518c55b..cdc75975d 100644 --- a/src/deh_soc.h +++ b/src/deh_soc.h @@ -43,7 +43,7 @@ #include "info.h" #include "dehacked.h" -#include "doomdef.h" // MUSICSLOT_COMPATIBILITY, HWRENDER +#include "doomdef.h" // HWRENDER // Crazy word-reading stuff /// \todo Put these in a seperate file or something. @@ -52,9 +52,6 @@ statenum_t get_state(const char *word); spritenum_t get_sprite(const char *word); playersprite_t get_sprite2(const char *word); sfxenum_t get_sfx(const char *word); -#ifdef MUSICSLOT_COMPATIBILITY -UINT16 get_mus(const char *word, UINT8 dehacked_mode); -#endif hudnum_t get_huditem(const char *word); menutype_t get_menutype(const char *word); //INT16 get_gametype(const char *word); @@ -73,7 +70,7 @@ void readhuditem(MYFILE *f, INT32 num); void readmenu(MYFILE *f, INT32 num); void readtextprompt(MYFILE *f, INT32 num); void readcutscene(MYFILE *f, INT32 num); -void readlevelheader(MYFILE *f, INT32 num); +void readlevelheader(MYFILE *f, char * name); void readgametype(MYFILE *f, char *gtname); void readsprite2(MYFILE *f, INT32 num); void readspriteinfo(MYFILE *f, INT32 num, boolean sprite2); diff --git a/src/dehacked.c b/src/dehacked.c index 9b81a7c13..c4c15efd1 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -400,27 +400,7 @@ 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 (i > 0 && i <= NUMMAPS) - { - if (mapheaderinfo[i]) - { - G_SetGameModified(multiplayer, true); // Only a major mod if editing stuff that isn't your own! - } - - readlevelheader(f, i); - } - else - { - deh_warning("Level number %d out of range (1 - %d)", i, NUMMAPS); - ignorelines(f); - } + readlevelheader(f, word2); } else if (fastcmp(word, "GAMETYPE")) { diff --git a/src/doomdef.h b/src/doomdef.h index e0bd46ab8..0907df0ac 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -628,10 +628,6 @@ extern const char *compdate, *comptime, *comprevision, *compbranch; /// Experimental tweaks to analog mode. (Needs a lot of work before it's ready for primetime.) //#define REDSANALOG -/// Backwards compatibility with musicslots. -/// \note You should leave this enabled unless you're working with a future SRB2 version. -//#define MUSICSLOT_COMPATIBILITY - /// Experimental attempts at preventing MF_PAPERCOLLISION objects from getting stuck in walls. //#define PAPER_COLLISIONCORRECTION diff --git a/src/doomstat.h b/src/doomstat.h index 0854b3196..6169e8b0e 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -177,11 +177,11 @@ extern boolean splitscreen_partied[MAXPLAYERS]; extern INT16 spstage_start, spmarathon_start; extern INT16 sstage_start, sstage_end, smpstage_start, smpstage_end; -extern INT16 titlemap; +extern char * titlemap; extern boolean hidetitlepics; -extern INT16 bootmap; //bootmap for loading a map on startup +extern char * bootmap; //bootmap for loading a map on startup -extern INT16 tutorialmap; // map to load for tutorial +extern char * tutorialmap; // map to load for tutorial extern boolean tutorialmode; // are we in a tutorial right now? extern INT32 tutorialgcs; // which control scheme is loaded? @@ -326,81 +326,100 @@ typedef struct */ typedef struct { - char * lumpname; ///< Lump name can be really long - char lvlttl[22]; ///< Level name without "Zone". (21 character limit instead of 32, 21 characters can display on screen max anyway) - char subttl[33]; ///< Subtitle for level - char zonttl[22]; ///< "ZONE" replacement name - UINT8 actnum; ///< Act number or 0 for none. - UINT32 typeoflevel; ///< Combination of typeoflevel flags. - 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. - 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. - UINT8 weather; ///< 0 = sunny day, 1 = storm, 2 = snow, 3 = rain, 4 = blank, 5 = thunder w/o rain, 6 = rain w/o lightning, 7 = heat wave. - char skytexture[9]; ///< Sky texture to use. - INT16 skybox_scalex; ///< Skybox X axis scale. (0 = no movement, 1 = 1:1 movement, 16 = 16:1 slow movement, -4 = 1:4 fast movement, etc.) - INT16 skybox_scaley; ///< Skybox Y axis scale. - INT16 skybox_scalez; ///< Skybox Z axis scale. + char * lumpname; ///< Lump name can be really long + + char * thumbnailLump; ///< Lump name for the level select thumbnail. + char * minimapLump; ///< Lump name for the minimap graphic. + char * encoreLump; ///< Lump name for the Encore Mode remap. + char * tweakLump; ///< Lump name for the palette tweak remap. + + char lvlttl[22]; ///< Level name without "Zone". (21 character limit instead of 32, 21 characters can display on screen max anyway) + char subttl[33]; ///< Subtitle for level + char zonttl[22]; ///< "ZONE" replacement name + UINT8 actnum; ///< Act number or 0 for none. + + UINT32 typeoflevel; ///< Combination of typeoflevel flags. + + char * nextlevel; ///< Map name of next level. + char * marathonnext; ///< See nextlevel, but for Marathon mode. + + char keywords[33]; ///< Keywords separated by space to search for. 32 characters. + + char musname[7]; ///< 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. + + UINT8 weather; ///< 0 = sunny day, 1 = storm, 2 = snow, 3 = rain, 4 = blank, 5 = thunder w/o rain, 6 = rain w/o lightning, 7 = heat wave. + char skytexture[9]; ///< Sky texture to use. + INT16 skybox_scalex; ///< Skybox X axis scale. (0 = no movement, 1 = 1:1 movement, 16 = 16:1 slow movement, -4 = 1:4 fast movement, etc.) + INT16 skybox_scaley; ///< Skybox Y axis scale. + INT16 skybox_scalez; ///< Skybox Z axis scale. // Extra information. - char interscreen[8]; ///< 320x200 patch to display at intermission. - char runsoc[33]; ///< SOC to execute at start of level (32 character limit instead of 63) - char scriptname[33]; ///< Script to use when the map is switched to. (32 character limit instead of 191) - UINT8 precutscenenum; ///< Cutscene number to play BEFORE a level starts. - UINT8 cutscenenum; ///< Cutscene number to use, 0 for none. - INT16 countdown; ///< Countdown until level end? - UINT16 palette; ///< PAL lump to use on this map - UINT16 encorepal; ///< PAL for encore mode - UINT8 numlaps; ///< Number of laps in circuit mode, unless overridden. - SINT8 unlockrequired; ///< Is an unlockable required to play this level? -1 if no. - UINT8 levelselect; ///< Is this map available in the level select? If so, which map list is it available in? - SINT8 bonustype; ///< What type of bonus does this level have? (-1 for null.) - SINT8 maxbonuslives; ///< How many bonus lives to award at Intermission? (-1 for unlimited.) + char interscreen[8]; ///< 320x200 patch to display at intermission. - UINT16 levelflags; ///< LF_flags: merged booleans into one UINT16 for space, see below - UINT8 menuflags; ///< LF2_flags: options that affect record attack / nights mode menus + char runsoc[33]; ///< SOC to execute at start of level (32 character limit instead of 63) + char scriptname[33]; ///< Script to use when the map is switched to. (32 character limit instead of 191) - char selectheading[22]; ///< Level select heading. Allows for controllable grouping. - UINT16 startrings; ///< Number of rings players start with. - INT32 sstimer; ///< Timer for special stages. - UINT32 ssspheres; ///< Sphere requirement in special stages. - fixed_t gravity; ///< Map-wide gravity. + UINT8 precutscenenum; ///< Cutscene number to play BEFORE a level starts. + UINT8 cutscenenum; ///< Cutscene number to use, 0 for none. + + INT16 countdown; ///< Countdown until level end? + + UINT16 palette; ///< PAL lump to use on this map + UINT16 encorepal; ///< PAL for encore mode + + UINT8 numlaps; ///< Number of laps in circuit mode, unless overridden. + + SINT8 unlockrequired; ///< Is an unlockable required to play this level? -1 if no. + UINT8 levelselect; ///< Is this map available in the level select? If so, which map list is it available in? + + SINT8 bonustype; ///< What type of bonus does this level have? (-1 for null.) + SINT8 maxbonuslives; ///< How many bonus lives to award at Intermission? (-1 for unlimited.) + + UINT16 levelflags; ///< LF_flags: merged booleans into one UINT16 for space, see below + UINT16 menuflags; ///< LF2_flags: options that affect record attack / nights mode menus + + char selectheading[22]; ///< Level select heading. Allows for controllable grouping. + UINT16 startrings; ///< Number of rings players start with. + INT32 sstimer; ///< Timer for special stages. + UINT32 ssspheres; ///< Sphere requirement in special stages. + fixed_t gravity; ///< Map-wide gravity. // Title card. - char ltzzpatch[8]; ///< Zig zag patch. - char ltzztext[8]; ///< Zig zag text. - char ltactdiamond[8]; ///< Act diamond. + char ltzzpatch[8]; ///< Zig zag patch. + char ltzztext[8]; ///< Zig zag text. + char ltactdiamond[8]; ///< Act diamond. // Freed animals stuff. - UINT8 numFlickies; ///< Internal. For freed flicky support. - mobjtype_t *flickies; ///< List of freeable flickies in this level. Allocated dynamically for space reasons. Be careful. + UINT8 numFlickies; ///< Internal. For freed flicky support. + mobjtype_t *flickies; ///< List of freeable flickies in this level. Allocated dynamically for space reasons. Be careful. // NiGHTS stuff. - UINT8 numGradedMares; ///< Internal. For grade support. - nightsgrades_t *grades; ///< NiGHTS grades. Allocated dynamically for space reasons. Be careful. - - // SRB2kart - fixed_t mobj_scale; ///< Replacement for TOL_ERZ3 - fixed_t default_waypoint_radius; ///< 0 is a special value for DEFAULT_WAYPOINT_RADIUS, but scaled with mobjscale + UINT8 numGradedMares; ///< Internal. For grade support. + nightsgrades_t *grades; ///< NiGHTS grades. Allocated dynamically for space reasons. Be careful. // Music stuff. - UINT32 musinterfadeout; ///< Fade out level music on intermission screen in milliseconds - char musintername[7]; ///< Intermission screen music. + UINT32 musinterfadeout; ///< Fade out level music on intermission screen in milliseconds + char musintername[7]; ///< Intermission screen music. - char muspostbossname[7]; ///< Post-bossdeath music. - UINT16 muspostbosstrack; ///< Post-bossdeath track. - UINT32 muspostbosspos; ///< Post-bossdeath position - UINT32 muspostbossfadein; ///< Post-bossdeath fade-in milliseconds. + char muspostbossname[7]; ///< Post-bossdeath music. + UINT16 muspostbosstrack; ///< Post-bossdeath track. + UINT32 muspostbosspos; ///< Post-bossdeath position + UINT32 muspostbossfadein; ///< Post-bossdeath fade-in milliseconds. - SINT8 musforcereset; ///< Force resetmusic (-1 for default; 0 for force off; 1 for force on) + SINT8 musforcereset; ///< Force resetmusic (-1 for default; 0 for force off; 1 for force on) + + // SRB2kart + fixed_t mobj_scale; ///< Replacement for TOL_ERZ3 + fixed_t default_waypoint_radius; ///< 0 is a special value for DEFAULT_WAYPOINT_RADIUS, but scaled with mobjscale // Lua stuff. // (This is not ifdeffed so the map header structure can stay identical, just in case.) - UINT8 numCustomOptions; ///< Internal. For Lua custom value support. - customoption_t *customopts; ///< Custom options. Allocated dynamically for space reasons. Be careful. + UINT8 numCustomOptions; ///< Internal. For Lua custom value support. + customoption_t *customopts; ///< Custom options. Allocated dynamically for space reasons. Be careful. } mapheader_t; // level flags @@ -426,10 +445,10 @@ typedef struct cupheader_s UINT16 id; ///< Cup ID char name[15]; ///< Cup title (14 chars) char icon[9]; ///< Name of the icon patch - INT16 levellist[MAXLEVELLIST]; ///< List of levels that belong to this cup + char * levellist[MAXLEVELLIST]; ///< List of levels that belong to this cup UINT8 numlevels; ///< Number of levels defined in levellist - INT16 bonusgame; ///< Map number to use for bonus game - INT16 specialstage; ///< Map number to use for special stage + char * bonusgame; ///< Map number to use for bonus game + char * specialstage; ///< Map number to use for special stage UINT8 emeraldnum; ///< ID of Emerald to use for special stage (1-7 for Chaos Emeralds, 8-14 for Super Emeralds, 0 for no emerald) SINT8 unlockrequired; ///< An unlockable is required to select this cup. -1 for no unlocking required. struct cupheader_s *next; ///< Next cup in linked list diff --git a/src/f_finale.c b/src/f_finale.c index bfea19d24..f3e26c97c 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1812,6 +1812,8 @@ static void F_CacheTitleScreen(void) void F_StartTitleScreen(void) { + const INT32 titleMapNum = G_MapNumber(titlemap); + if (gamestate != GS_TITLESCREEN && gamestate != GS_WAITINGPLAYERS) { ttuser_count = 0; @@ -1821,20 +1823,20 @@ void F_StartTitleScreen(void) else wipegamestate = GS_TITLESCREEN; - if (titlemap) + if (mapheaderinfo[titleMapNum]) { mapthing_t *startpos; gamestate_t prevwipegamestate = wipegamestate; titlemapinaction = TITLEMAP_LOADING; titlemapcameraref = NULL; - gamemap = titlemap; + gamemap = titleMapNum; maptol = mapheaderinfo[gamemap-1]->typeoflevel; globalweather = mapheaderinfo[gamemap-1]->weather; G_DoLoadLevel(true); - if (!titlemap) + if (!titleMapNum) return; players[displayplayers[0]].playerstate = PST_DEAD; // Don't spawn the player in dummy (I'm still a filthy cheater) diff --git a/src/g_demo.c b/src/g_demo.c index 46e814634..b0f3c7a01 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -3467,6 +3467,7 @@ void G_DoPlayMetal(void) thinker_t *th; // it's an internal demo + // TODO: Use map header to determine lump name if ((l = W_CheckNumForName(va("%sMS",G_BuildMapName(gamemap)))) == LUMPERROR) { CONS_Alert(CONS_WARNING, M_GetText("No bot recording for this map.\n")); diff --git a/src/g_game.c b/src/g_game.c index d05266cd0..8589c4ebf 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -149,11 +149,11 @@ tic_t timeinmap; // Ticker for time spent in level (used for levelcard display) INT16 spstage_start, spmarathon_start; INT16 sstage_start, sstage_end, smpstage_start, smpstage_end; -INT16 titlemap = 0; +char * titlemap = NULL; boolean hidetitlepics = false; -INT16 bootmap; //bootmap for loading a map on startup +char * bootmap = NULL; //bootmap for loading a map on startup -INT16 tutorialmap = 0; // map to load for tutorial +char * tutorialmap = NULL; // map to load for tutorial boolean tutorialmode = false; // are we in a tutorial right now? INT32 tutorialgcs = gcs_custom; // which control scheme is loaded? @@ -3340,6 +3340,7 @@ tryagain: if (pprevmap == -2) // title demo hack { lumpnum_t l; + // TODO: Use map header to determine lump name if ((l = W_CheckNumForLongName(va("%sS01",G_BuildMapName(ix+1)))) == LUMPERROR) continue; } @@ -3529,7 +3530,12 @@ static void G_DoCompleted(void) } else if (marathonmode && mapheaderinfo[gamemap-1]->marathonnext) { - nextmap = (INT16)(mapheaderinfo[gamemap-1]->marathonnext-1); + const INT32 mNextNum = G_MapNumber(mapheaderinfo[gamemap-1]->marathonnext); + + if (mapheaderinfo[mNextNum]) + { + nextmap = (INT16)(mNextNum-1); + } } else if (grandprixinfo.gp == true) { @@ -3546,16 +3552,27 @@ static void G_DoCompleted(void) else { // Proceed to next map - nextmap = grandprixinfo.cup->levellist[grandprixinfo.roundnum]; + const INT32 cupLevelNum = G_MapNumber(grandprixinfo.cup->levellist[grandprixinfo.roundnum]); + + if (mapheaderinfo[cupLevelNum]) + { + nextmap = cupLevelNum; + } + grandprixinfo.roundnum++; } } } else { - nextmap = (INT16)(mapheaderinfo[gamemap-1]->nextlevel-1); - if (marathonmode && nextmap == spmarathon_start-1) - nextmap = 1100-1; // No infinite loop for you + const INT32 nextNum = G_MapNumber(mapheaderinfo[gamemap-1]->nextlevel); + + if (mapheaderinfo[nextNum]) + { + nextmap = (INT16)(nextNum-1); + if (marathonmode && nextmap == spmarathon_start-1) + nextmap = 1100-1; // No infinite loop for you + } } // Remember last map for when you come out of the special stage. @@ -3582,9 +3599,23 @@ static void G_DoCompleted(void) if (!mapheaderinfo[cm]) cm = -1; // guarantee error execution else if (marathonmode && mapheaderinfo[cm]->marathonnext) - cm = (INT16)(mapheaderinfo[cm]->marathonnext-1); + { + const INT32 mNextNum = G_MapNumber(mapheaderinfo[gamemap-1]->marathonnext); + + if (!mapheaderinfo[mNextNum]) + cm = -1; // guarantee error execution + else + cm = (INT16)(mNextNum-1); + } else - cm = (INT16)(mapheaderinfo[cm]->nextlevel-1); + { + const INT32 nextNum = G_MapNumber(mapheaderinfo[gamemap-1]->nextlevel); + + if (!mapheaderinfo[nextNum]) + cm = -1; // guarantee error execution + else + cm = (INT16)(nextNum-1); + } if (cm >= NUMMAPS || cm < 0) // out of range (either 1100ish or error) { diff --git a/src/k_hud.c b/src/k_hud.c index 6bf9b153b..1f2465152 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -3015,7 +3015,7 @@ static void K_drawKartMinimapIcon(fixed_t objx, fixed_t objy, INT32 hudx, INT32 static void K_drawKartMinimap(void) { - INT32 lumpnum; + INT32 lumpnum = LUMPERROR; patch_t *AutomapPic; INT32 i = 0; INT32 x, y; @@ -3037,7 +3037,10 @@ static void K_drawKartMinimap(void) if (stplyr != &players[displayplayers[0]]) return; - lumpnum = W_CheckNumForLongName(va("%sR", G_BuildMapName(gamemap))); + if (mapheaderinfo[gamemap-1]) + { + lumpnum = W_CheckNumForLongName(mapheaderinfo[gamemap-1]->minimapLump); + } if (lumpnum != -1) AutomapPic = W_CachePatchNum(lumpnum, PU_HUDGFX); diff --git a/src/lua_baselib.c b/src/lua_baselib.c index eb2411f20..4ccb4b841 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -2435,39 +2435,6 @@ static int lib_sStopSoundByID(lua_State *L) static int lib_sChangeMusic(lua_State *L) { -#ifdef MUSICSLOT_COMPATIBILITY - const char *music_name; - UINT32 music_num, position, prefadems, fadeinms; - char music_compat_name[7]; - - boolean looping; - player_t *player = NULL; - UINT16 music_flags = 0; - //NOHUD - - if (lua_isnumber(L, 1)) - { - music_num = (UINT32)luaL_checkinteger(L, 1); - music_flags = (UINT16)(music_num & 0x0000FFFF); - if (music_flags && music_flags <= 1035) - snprintf(music_compat_name, 7, "%sM", G_BuildMapName((INT32)music_flags)); - else if (music_flags && music_flags <= 1050) - strncpy(music_compat_name, compat_special_music_slots[music_flags - 1036], 7); - else - music_compat_name[0] = 0; // becomes empty string - music_compat_name[6] = 0; - music_name = (const char *)&music_compat_name; - music_flags = 0; - } - else - { - music_num = 0; - music_name = luaL_checkstring(L, 1); - } - - looping = (boolean)lua_opttrueboolean(L, 2); - -#else const char *music_name = luaL_checkstring(L, 1); UINT32 position, prefadems, fadeinms; boolean looping = (boolean)lua_opttrueboolean(L, 2); @@ -2475,7 +2442,6 @@ static int lib_sChangeMusic(lua_State *L) UINT16 music_flags = 0; //NOHUD -#endif if (!lua_isnone(L, 3) && lua_isuserdata(L, 3)) { player = *((player_t **)luaL_checkudata(L, 3, META_PLAYER)); @@ -2483,11 +2449,6 @@ static int lib_sChangeMusic(lua_State *L) return LUA_ErrInvalid(L, "player_t"); } -#ifdef MUSICSLOT_COMPATIBILITY - if (music_num) - music_flags = (UINT16)((music_num & 0x7FFF0000) >> 16); - else -#endif music_flags = (UINT16)luaL_optinteger(L, 4, 0); position = (UINT32)luaL_optinteger(L, 5, 0); @@ -2593,33 +2554,7 @@ static int lib_sMusicName(lua_State *L) static int lib_sMusicExists(lua_State *L) { -#ifdef MUSICSLOT_COMPATIBILITY - const char *music_name; - UINT32 music_num; - char music_compat_name[7]; - UINT16 music_flags = 0; - NOHUD - if (lua_isnumber(L, 1)) - { - music_num = (UINT32)luaL_checkinteger(L, 1); - music_flags = (UINT16)(music_num & 0x0000FFFF); - if (music_flags && music_flags <= 1035) - snprintf(music_compat_name, 7, "%sM", G_BuildMapName((INT32)music_flags)); - else if (music_flags && music_flags <= 1050) - strncpy(music_compat_name, compat_special_music_slots[music_flags - 1036], 7); - else - music_compat_name[0] = 0; // becomes empty string - music_compat_name[6] = 0; - music_name = (const char *)&music_compat_name; - } - else - { - music_num = 0; - music_name = luaL_checkstring(L, 1); - } -#else const char *music_name = luaL_checkstring(L, 1); -#endif NOHUD lua_pushboolean(L, S_MusicExists(music_name)); return 1; diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 78f273311..3610e54c7 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -652,7 +652,7 @@ static int libd_drawOnMinimap(lua_State *L) boolean centered; // the patch is centered and doesn't need readjusting on x/y coordinates. // variables used to replicate k_kart's mmap drawer: - INT32 lumpnum; + INT32 lumpnum = LUMPERROR; patch_t *AutomapPic; INT32 mx, my; INT32 splitflags, minimaptrans; @@ -738,7 +738,10 @@ static int libd_drawOnMinimap(lua_State *L) if (stplyr != &players[displayplayers[0]]) return 0; - lumpnum = W_CheckNumForLongName(va("%sR", G_BuildMapName(gamemap))); + if (mapheaderinfo[gamemap-1]) + { + lumpnum = W_CheckNumForLongName(mapheaderinfo[gamemap-1]->minimapLump); + } if (lumpnum != -1) AutomapPic = W_CachePatchNum(lumpnum, PU_HUDGFX); diff --git a/src/lua_maplib.c b/src/lua_maplib.c index e537160da..ec5f18127 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -2128,9 +2128,9 @@ static int mapheaderinfo_get(lua_State *L) else if (fastcmp(field,"typeoflevel")) lua_pushinteger(L, header->typeoflevel); else if (fastcmp(field,"nextlevel")) - lua_pushinteger(L, header->nextlevel); + lua_pushstring(L, header->nextlevel); else if (fastcmp(field,"marathonnext")) - lua_pushinteger(L, header->marathonnext); + lua_pushstring(L, header->marathonnext); else if (fastcmp(field,"keywords")) lua_pushstring(L, header->keywords); else if (fastcmp(field,"musname")) diff --git a/src/lua_script.c b/src/lua_script.c index 4d02ee413..d0e98a66e 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -230,16 +230,16 @@ int LUA_PushGlobals(lua_State *L, const char *word) lua_pushinteger(L, smpstage_end); return 1; } else if (fastcmp(word,"titlemap")) { - lua_pushinteger(L, titlemap); + lua_pushstring(L, titlemap); return 1; } else if (fastcmp(word,"titlemapinaction")) { lua_pushboolean(L, (titlemapinaction != TITLEMAP_OFF)); return 1; } else if (fastcmp(word,"bootmap")) { - lua_pushinteger(L, bootmap); + lua_pushstring(L, bootmap); return 1; } else if (fastcmp(word,"tutorialmap")) { - lua_pushinteger(L, tutorialmap); + lua_pushstring(L, tutorialmap); return 1; } else if (fastcmp(word,"tutorialmode")) { lua_pushboolean(L, tutorialmode); diff --git a/src/m_cond.c b/src/m_cond.c index d8194d4d1..b632aa267 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -283,10 +283,17 @@ UINT8 M_CheckLevelEmblems(void) // Update Score, Time, Rings emblems for (i = 0; i < numemblems; ++i) { + INT32 checkLevel; + if (emblemlocations[i].type < ET_TIME || emblemlocations[i].collected) continue; - levelnum = emblemlocations[i].level; + checkLevel = G_MapNumber(emblemlocations[i].level); + + if (!mapheaderinfo[checkLevel]) + continue; + + levelnum = checkLevel; valToReach = emblemlocations[i].var; switch (emblemlocations[i].type) @@ -316,10 +323,17 @@ UINT8 M_CompletionEmblems(void) // Bah! Duplication sucks, but it's for a separa for (i = 0; i < numemblems; ++i) { - if (emblemlocations[i].type != ET_MAP || emblemlocations[i].collected) + INT32 checkLevel; + + if (emblemlocations[i].type < ET_TIME || emblemlocations[i].collected) continue; - levelnum = emblemlocations[i].level; + checkLevel = G_MapNumber(emblemlocations[i].level); + + if (!mapheaderinfo[checkLevel]) + continue; + + levelnum = checkLevel; embtype = emblemlocations[i].var; flags = MV_BEATEN; @@ -472,7 +486,12 @@ emblem_t *M_GetLevelEmblems(INT32 mapnum) while (--i >= 0) { - if (emblemlocations[i].level == map) + INT32 checkLevel = G_MapNumber(emblemlocations[i].level); + + if (!mapheaderinfo[checkLevel]) + continue; + + if (checkLevel == map) return &emblemlocations[i]; } return NULL; diff --git a/src/m_cond.h b/src/m_cond.h index ed29fe326..323c84347 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -73,7 +73,7 @@ typedef struct { UINT8 type; ///< Emblem type INT16 tag; ///< Tag of emblem mapthing - INT16 level; ///< Level on which this emblem can be found. + char * level; ///< Level on which this emblem can be found. UINT8 sprite; ///< emblem sprite to use, 0 - 25 UINT16 color; ///< skincolor to use INT32 var; ///< If needed, specifies information on the target amount to achieve (or target skin) diff --git a/src/m_menu.c b/src/m_menu.c index 06985d923..4c1eca56b 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -2219,6 +2219,7 @@ static void Dummystaff_OnChange(void) dummystaffname[0] = '\0'; + // TODO: Use map header to determine lump name if ((l = W_CheckNumForLongName(va("%sS01",G_BuildMapName(cv_nextmap.value)))) == LUMPERROR) { CV_StealthSetValue(&cv_dummystaff, 0); @@ -5498,7 +5499,7 @@ static void M_HandleReplayHutList(INT32 choice) #define SCALEDVIEWHEIGHT (vid.height/vid.dupy) static void DrawReplayHutReplayInfo(void) { - lumpnum_t lumpnum; + lumpnum_t lumpnum = LUMPERROR; patch_t *patch; UINT8 *colormap; INT32 x, y, w, h; @@ -5525,7 +5526,12 @@ static void DrawReplayHutReplayInfo(void) // A 160x100 image of the level as entry MAPxxP //CONS_Printf("%d %s\n", demolist[dir_on[menudepthleft]].map, G_BuildMapName(demolist[dir_on[menudepthleft]].map)); - lumpnum = W_CheckNumForLongName(va("%sP", G_BuildMapName(demolist[dir_on[menudepthleft]].map))); + + if (mapheaderinfo[demolist[dir_on[menudepthleft]].map]) + { + lumpnum = W_CheckNumForLongName(mapheaderinfo[demolist[dir_on[menudepthleft]].map]->thumbnailLump); + } + if (lumpnum != LUMPERROR) patch = W_CachePatchNum(lumpnum, PU_CACHE); else @@ -6548,8 +6554,15 @@ static void M_DrawEmblemHints(void) for (i = 0; i < numemblems; i++) { + INT32 checkLevel; + emblem = &emblemlocations[i]; - if (emblem->level != gamemap || emblem->type != ET_GLOBAL) + if (emblem->type != ET_GLOBAL) + continue; + + checkLevel = G_MapNumber(emblem->level); + + if (!mapheaderinfo[checkLevel] || gamemap != checkLevel) continue; if (emblem->collected) @@ -7709,6 +7722,7 @@ static void M_GrandPrixTemp(INT32 choice) static void M_StartGrandPrix(INT32 choice) { cupheader_t *gpcup = kartcupheaders; + INT32 levelNum; (void)choice; @@ -7760,9 +7774,11 @@ static void M_StartGrandPrix(INT32 choice) grandprixinfo.initalize = true; + levelNum = G_MapNumber(grandprixinfo.cup->levellist[0]); + G_DeferedInitNew( false, - grandprixinfo.cup->levellist[0] + 1, + levelNum + 1, (UINT8)(cv_chooseskin.value - 1), (UINT8)(cv_splitplayers.value - 1), false @@ -8866,14 +8882,18 @@ static void M_StartServer(INT32 choice) static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) { - lumpnum_t lumpnum; + lumpnum_t lumpnum = LUMPERROR; patch_t *PictureOfLevel; INT32 x, y, w, i, oldval, trans, dupadjust = ((vid.width/vid.dupx) - BASEVIDWIDTH)>>1; // A 160x100 image of the level as entry MAPxxP if (cv_nextmap.value) { - lumpnum = W_CheckNumForLongName(va("%sP", G_BuildMapName(cv_nextmap.value))); + if (mapheaderinfo[cv_nextmap.value]) + { + lumpnum = W_CheckNumForLongName(mapheaderinfo[cv_nextmap.value]->thumbnailLump); + } + if (lumpnum != LUMPERROR) PictureOfLevel = W_CachePatchNum(lumpnum, PU_CACHE); else @@ -8939,7 +8959,11 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) // A 160x100 image of the level as entry MAPxxP if (i+1) { - lumpnum = W_CheckNumForLongName(va("%sP", G_BuildMapName(i+1))); + if (mapheaderinfo[i+1]) + { + lumpnum = W_CheckNumForLongName(mapheaderinfo[i+1]->thumbnailLump); + } + if (lumpnum != LUMPERROR) PictureOfLevel = W_CachePatchNum(lumpnum, PU_CACHE); else @@ -8977,7 +9001,11 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) // A 160x100 image of the level as entry MAPxxP if (i+1) { - lumpnum = W_CheckNumForLongName(va("%sP", G_BuildMapName(i+1))); + if (mapheaderinfo[i+1]) + { + lumpnum = W_CheckNumForLongName(mapheaderinfo[i+1]->thumbnailLump); + } + if (lumpnum != LUMPERROR) PictureOfLevel = W_CachePatchNum(lumpnum, PU_CACHE); else diff --git a/src/p_setup.c b/src/p_setup.c index df6fe3ecc..d587df732 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -354,6 +354,42 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) { const INT16 num = (INT16)(i-1); + if (mapheaderinfo[num]->thumbnailLump) + { + Z_Free(mapheaderinfo[num]->thumbnailLump); + mapheaderinfo[num]->thumbnailLump = NULL; + } + + if (mapheaderinfo[num]->minimapLump) + { + Z_Free(mapheaderinfo[num]->minimapLump); + mapheaderinfo[num]->minimapLump = NULL; + } + + if (mapheaderinfo[num]->encoreLump) + { + Z_Free(mapheaderinfo[num]->encoreLump); + mapheaderinfo[num]->encoreLump = NULL; + } + + if (mapheaderinfo[num]->tweakLump) + { + Z_Free(mapheaderinfo[num]->tweakLump); + mapheaderinfo[num]->tweakLump = NULL; + } + + if (mapheaderinfo[num]->nextlevel) + { + Z_Free(mapheaderinfo[num]->nextlevel); + mapheaderinfo[num]->nextlevel = NULL; + } + + if (mapheaderinfo[num]->marathonnext) + { + Z_Free(mapheaderinfo[num]->marathonnext); + mapheaderinfo[num]->marathonnext = NULL; + } + mapheaderinfo[num]->lvlttl[0] = '\0'; mapheaderinfo[num]->selectheading[0] = '\0'; mapheaderinfo[num]->subttl[0] = '\0'; @@ -363,8 +399,6 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) mapheaderinfo[num]->ltactdiamond[0] = '\0'; mapheaderinfo[num]->actnum = 0; mapheaderinfo[num]->typeoflevel = 0; - mapheaderinfo[num]->nextlevel = (INT16)(i + 1); - mapheaderinfo[num]->marathonnext = 0; mapheaderinfo[num]->startrings = 0; mapheaderinfo[num]->sstimer = 90; mapheaderinfo[num]->ssspheres = 1; @@ -426,6 +460,12 @@ void P_AllocMapHeader(INT16 i) { mapheaderinfo[i] = Z_Malloc(sizeof(mapheader_t), PU_STATIC, NULL); mapheaderinfo[i]->lumpname = NULL; + mapheaderinfo[i]->thumbnailLump = NULL; + mapheaderinfo[i]->minimapLump = NULL; + mapheaderinfo[i]->encoreLump = NULL; + mapheaderinfo[i]->tweakLump = NULL; + mapheaderinfo[i]->nextlevel = NULL; + mapheaderinfo[i]->marathonnext = NULL; mapheaderinfo[i]->flickies = NULL; mapheaderinfo[i]->grades = NULL; nummapheaders++; @@ -3713,6 +3753,7 @@ static void P_LoadRecordGhosts(void) { lumpnum_t l; UINT8 j = 1; + // TODO: Use map header to determine lump name while (j <= 99 && (l = W_CheckNumForLongName(va("%sS%02u",G_BuildMapName(gamemap),j))) != LUMPERROR) { G_AddGhost(va("%sS%02u",G_BuildMapName(gamemap),j)); @@ -4057,8 +4098,23 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) if (lastloadedmaplumpnum == LUMPERROR) I_Error("Map %s not found.\n", maplumpname); - R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette, - W_CheckNumForName(va("%s%c", maplumpname, (encoremode ? 'E' : 'T')))); + { + INT32 encoreLump = LUMPERROR; + + if (mapheaderinfo[gamemap-1]) + { + if (encoremode) + { + encoreLump = W_CheckNumForLongName(mapheaderinfo[gamemap-1]->encoreLump); + } + else + { + encoreLump = W_CheckNumForLongName(mapheaderinfo[gamemap-1]->tweakLump); + } + } + + R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette, encoreLump); + } CON_SetupBackColormap(); // SRB2 determines the sky texture to be used depending on the map header. diff --git a/src/s_sound.c b/src/s_sound.c index 4c36325c6..fa5726516 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -1557,28 +1557,6 @@ void S_InitSfxChannels(INT32 sfxVolume) /// Music /// ------------------------ -#ifdef MUSICSLOT_COMPATIBILITY -const char *compat_special_music_slots[16] = -{ - "_title", // 1036 title screen - "_intro", // 1037 intro - "_clear", // 1038 level clear - "_inv", // 1039 invincibility - "_shoes", // 1040 super sneakers - "_minv", // 1041 Mario invincibility - "_drown", // 1042 drowning - "_gover", // 1043 game over - "_1up", // 1044 extra life - "_conti", // 1045 continue screen - "_super", // 1046 Super Sonic - "_chsel", // 1047 character select - "_creds", // 1048 credits - "_inter", // 1049 Race Results - "_stjr", // 1050 Sonic Team Jr. Presents - "" -}; -#endif - static char music_name[7]; // up to 6-character name static void *music_data; static UINT16 music_flags; diff --git a/src/s_sound.h b/src/s_sound.h index 80a53fb3e..8d1fccee4 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -314,10 +314,4 @@ void S_StopSoundByNum(sfxenum_t sfxnum); #define S_StartScreamSound S_StartSound #endif -#ifdef MUSICSLOT_COMPATIBILITY -// For compatibility with code/scripts relying on older versions -// This is a list of all the "special" slot names and their associated numbers -extern const char *compat_special_music_slots[16]; -#endif - #endif diff --git a/src/y_inter.c b/src/y_inter.c index 40451a775..6174bf86d 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -1738,7 +1738,7 @@ void Y_StartVote(void) for (i = 0; i < 5; i++) { - lumpnum_t lumpnum; + lumpnum_t lumpnum = LUMPERROR; // set up the encore levelinfo[i].encore = (votelevels[i][1] & 0x80); @@ -1788,7 +1788,11 @@ void Y_StartVote(void) levelinfo[i].gts = NULL; // set up the pic - lumpnum = W_CheckNumForLongName(va("%sP", G_BuildMapName(votelevels[i][0]+1))); + if (mapheaderinfo[votelevels[i][0]+1]) + { + lumpnum = W_CheckNumForLongName(mapheaderinfo[votelevels[i][0]+1]->thumbnailLump); + } + if (lumpnum != LUMPERROR) levelinfo[i].pic = W_CachePatchNum(lumpnum, PU_STATIC); else From 111548668998d0bc65b572c632f54eda24e3d5ea Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Fri, 9 Apr 2021 23:15:44 -0400 Subject: [PATCH 15/60] Fix crashes & off-by-one errors --- src/k_hud.c | 10 ++++++---- src/lua_hudlib.c | 11 +++++++---- src/m_menu.c | 21 ++++++++++++--------- src/w_wad.c | 6 ++++++ src/y_inter.c | 2 +- 5 files changed, 32 insertions(+), 18 deletions(-) diff --git a/src/k_hud.c b/src/k_hud.c index 1f2465152..ce8538939 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -3015,7 +3015,7 @@ static void K_drawKartMinimapIcon(fixed_t objx, fixed_t objy, INT32 hudx, INT32 static void K_drawKartMinimap(void) { - INT32 lumpnum = LUMPERROR; + lumpnum_t lumpnum = LUMPERROR; patch_t *AutomapPic; INT32 i = 0; INT32 x, y; @@ -3042,10 +3042,12 @@ static void K_drawKartMinimap(void) lumpnum = W_CheckNumForLongName(mapheaderinfo[gamemap-1]->minimapLump); } - if (lumpnum != -1) - AutomapPic = W_CachePatchNum(lumpnum, PU_HUDGFX); - else + if (lumpnum == LUMPERROR) + { return; // no pic, just get outta here + } + + AutomapPic = W_CachePatchNum(lumpnum, PU_HUDGFX); x = MINI_X - (AutomapPic->width/2); y = MINI_Y - (AutomapPic->height/2); diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 3610e54c7..ef32b56a6 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -644,6 +644,7 @@ static int libd_drawStretched(lua_State *L) } // KART: draw patch on minimap from x, y coordinates on the map +// Sal: Let's please just merge the relevant info into the actual function, and have Lua call that... static int libd_drawOnMinimap(lua_State *L) { fixed_t x, y, scale; // coordinates of the object @@ -652,7 +653,7 @@ static int libd_drawOnMinimap(lua_State *L) boolean centered; // the patch is centered and doesn't need readjusting on x/y coordinates. // variables used to replicate k_kart's mmap drawer: - INT32 lumpnum = LUMPERROR; + lumpnum_t lumpnum = LUMPERROR; patch_t *AutomapPic; INT32 mx, my; INT32 splitflags, minimaptrans; @@ -743,10 +744,12 @@ static int libd_drawOnMinimap(lua_State *L) lumpnum = W_CheckNumForLongName(mapheaderinfo[gamemap-1]->minimapLump); } - if (lumpnum != -1) - AutomapPic = W_CachePatchNum(lumpnum, PU_HUDGFX); - else + if (lumpnum == LUMPERROR) + { return 0; // no pic, just get outta here + } + + AutomapPic = W_CachePatchNum(lumpnum, PU_HUDGFX); mx = MM_X - (AutomapPic->width/2); my = MM_Y - (AutomapPic->height/2); diff --git a/src/m_menu.c b/src/m_menu.c index 4c1eca56b..434efea54 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -5527,9 +5527,9 @@ static void DrawReplayHutReplayInfo(void) // A 160x100 image of the level as entry MAPxxP //CONS_Printf("%d %s\n", demolist[dir_on[menudepthleft]].map, G_BuildMapName(demolist[dir_on[menudepthleft]].map)); - if (mapheaderinfo[demolist[dir_on[menudepthleft]].map]) + if (mapheaderinfo[demolist[dir_on[menudepthleft]].map - 1]) { - lumpnum = W_CheckNumForLongName(mapheaderinfo[demolist[dir_on[menudepthleft]].map]->thumbnailLump); + lumpnum = W_CheckNumForLongName(mapheaderinfo[demolist[dir_on[menudepthleft]].map - 1]->thumbnailLump); } if (lumpnum != LUMPERROR) @@ -8882,16 +8882,17 @@ static void M_StartServer(INT32 choice) static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) { - lumpnum_t lumpnum = LUMPERROR; + lumpnum_t lumpnum; patch_t *PictureOfLevel; INT32 x, y, w, i, oldval, trans, dupadjust = ((vid.width/vid.dupx) - BASEVIDWIDTH)>>1; // A 160x100 image of the level as entry MAPxxP if (cv_nextmap.value) { - if (mapheaderinfo[cv_nextmap.value]) + lumpnum = LUMPERROR; + if (mapheaderinfo[cv_nextmap.value-1]) { - lumpnum = W_CheckNumForLongName(mapheaderinfo[cv_nextmap.value]->thumbnailLump); + lumpnum = W_CheckNumForLongName(mapheaderinfo[cv_nextmap.value-1]->thumbnailLump); } if (lumpnum != LUMPERROR) @@ -8959,9 +8960,10 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) // A 160x100 image of the level as entry MAPxxP if (i+1) { - if (mapheaderinfo[i+1]) + lumpnum = LUMPERROR; + if (mapheaderinfo[i]) { - lumpnum = W_CheckNumForLongName(mapheaderinfo[i+1]->thumbnailLump); + lumpnum = W_CheckNumForLongName(mapheaderinfo[i]->thumbnailLump); } if (lumpnum != LUMPERROR) @@ -9001,9 +9003,10 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) // A 160x100 image of the level as entry MAPxxP if (i+1) { - if (mapheaderinfo[i+1]) + lumpnum = LUMPERROR; + if (mapheaderinfo[i]) { - lumpnum = W_CheckNumForLongName(mapheaderinfo[i+1]->thumbnailLump); + lumpnum = W_CheckNumForLongName(mapheaderinfo[i]->thumbnailLump); } if (lumpnum != LUMPERROR) diff --git a/src/w_wad.c b/src/w_wad.c index 1b79b0a45..e7fa8c668 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -1135,6 +1135,9 @@ lumpnum_t W_CheckNumForName(const char *name) INT32 i; lumpnum_t check = INT16_MAX; + if (name == NULL) + return LUMPERROR; + if (!*name) // some doofus gave us an empty string? return LUMPERROR; @@ -1182,6 +1185,9 @@ lumpnum_t W_CheckNumForLongName(const char *name) INT32 i; lumpnum_t check = INT16_MAX; + if (name == NULL) + return LUMPERROR; + if (!*name) // some doofus gave us an empty string? return LUMPERROR; diff --git a/src/y_inter.c b/src/y_inter.c index 6174bf86d..c6a2edfe2 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -1790,7 +1790,7 @@ void Y_StartVote(void) // set up the pic if (mapheaderinfo[votelevels[i][0]+1]) { - lumpnum = W_CheckNumForLongName(mapheaderinfo[votelevels[i][0]+1]->thumbnailLump); + lumpnum = W_CheckNumForLongName(mapheaderinfo[votelevels[i][0]]->thumbnailLump); } if (lumpnum != LUMPERROR) From 524eff9fde114c988960a453099068d8fece4b7b Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 10 Sep 2022 16:01:47 -0400 Subject: [PATCH 16/60] Update new menus to use long names --- src/doomstat.h | 6 +++--- src/k_menudraw.c | 34 ++++++++++++++++++++++++++-------- src/k_menufunc.c | 10 +++++++--- 3 files changed, 36 insertions(+), 14 deletions(-) diff --git a/src/doomstat.h b/src/doomstat.h index 09922d2e8..32b48eb27 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -460,10 +460,10 @@ typedef struct cupheader_s UINT16 id; ///< Cup ID char name[15]; ///< Cup title (14 chars) char icon[9]; ///< Name of the icon patch - char * levellist[MAXLEVELLIST]; ///< List of levels that belong to this cup + char *levellist[MAXLEVELLIST]; ///< List of levels that belong to this cup UINT8 numlevels; ///< Number of levels defined in levellist - char * bonusgame; ///< Map number to use for bonus game - char * specialstage; ///< Map number to use for special stage + char *bonusgame; ///< Map name to use for bonus game + char *specialstage; ///< Map name to use for special stage UINT8 emeraldnum; ///< ID of Emerald to use for special stage (1-7 for Chaos Emeralds, 8-14 for Super Emeralds, 0 for no emerald) SINT8 unlockrequired; ///< An unlockable is required to select this cup. -1 for no unlocking required. struct cupheader_s *next; ///< Next cup in linked list diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 76a001544..657b6a379 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -1846,10 +1846,15 @@ static void M_DrawCupPreview(INT16 y, cupheader_t *cup) i = (cupgrid.previewanim / 82) % cup->numlevels; while (x < BASEVIDWIDTH + pad) { - lumpnum_t lumpnum; + INT32 cupLevelNum = G_MapNumber(cup->levellist[i]); + lumpnum_t lumpnum = LUMPERROR; patch_t *PictureOfLevel; - lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(cup->levellist[i]+1))); + if (mapheaderinfo[cupLevelNum]) + { + lumpnum = W_CheckNumForLongName(mapheaderinfo[cupLevelNum]->thumbnailLump); + } + if (lumpnum != LUMPERROR) PictureOfLevel = W_CachePatchNum(lumpnum, PU_CACHE); else @@ -2073,14 +2078,18 @@ static void M_DrawHighLowLevelTitle(INT16 x, INT16 y, INT16 map) static void M_DrawLevelSelectBlock(INT16 x, INT16 y, INT16 map, boolean redblink, boolean greyscale) { - lumpnum_t lumpnum; + lumpnum_t lumpnum = LUMPERROR; patch_t *PictureOfLevel; UINT8 *colormap = NULL; if (greyscale) colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_GREY, GTC_MENUCACHE); - lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(map+1))); + if (mapheaderinfo[map]) + { + lumpnum = W_CheckNumForLongName(mapheaderinfo[map]->thumbnailLump); + } + if (lumpnum != LUMPERROR) PictureOfLevel = W_CachePatchNum(lumpnum, PU_CACHE); else @@ -2146,7 +2155,7 @@ void M_DrawTimeAttack(void) INT16 rightedge = 149+t+155; INT16 opty = 140; INT32 w; - lumpnum_t lumpnum; + lumpnum_t lumpnum = LUMPERROR; UINT8 i; consvar_t *cv; @@ -2158,7 +2167,11 @@ void M_DrawTimeAttack(void) if (currentMenu == &PLAY_TimeAttackDef) { - lumpnum = W_CheckNumForName(va("%sR", G_BuildMapName(map+1))); + if (mapheaderinfo[map]) + { + lumpnum = W_CheckNumForName(mapheaderinfo[map]->minimapLump); + } + if (lumpnum != LUMPERROR) V_DrawScaledPatch(24-t, 82, 0, W_CachePatchNum(lumpnum, PU_CACHE)); @@ -3825,7 +3838,7 @@ void M_DrawPlaybackMenu(void) #define SCALEDVIEWHEIGHT (vid.height/vid.dupy) void M_DrawReplayHutReplayInfo(void) { - lumpnum_t lumpnum; + lumpnum_t lumpnum = LUMPERROR; patch_t *patch; UINT8 *colormap; INT32 x, y, w, h; @@ -3852,7 +3865,12 @@ void M_DrawReplayHutReplayInfo(void) // A 160x100 image of the level as entry MAPxxP //CONS_Printf("%d %s\n", extrasmenu.demolist[dir_on[menudepthleft]].map, G_BuildMapName(extrasmenu.demolist[dir_on[menudepthleft]].map)); - lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(extrasmenu.demolist[dir_on[menudepthleft]].map))); + + if (mapheaderinfo[extrasmenu.demolist[dir_on[menudepthleft]].map]) + { + lumpnum = W_CheckNumForName(mapheaderinfo[extrasmenu.demolist[dir_on[menudepthleft]].map]->thumbnailLump); + } + if (lumpnum != LUMPERROR) patch = W_CachePatchNum(lumpnum, PU_CACHE); else diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 753a9b767..0df40ab4c 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -3208,7 +3208,9 @@ boolean M_CanShowLevelInList(INT16 mapnum, UINT8 gt) for (i = 0; i < levellist.selectedcup->numlevels; i++) { - if (mapnum == levellist.selectedcup->levellist[i]) + const INT32 cupLevelNum = G_MapNumber(levellist.selectedcup->levellist[i]); + + if (mapnum == cupLevelNum) break; } @@ -3414,7 +3416,7 @@ void M_CupSelectHandler(INT32 choice) if (cupgrid.grandprix == true) { - + INT32 levelNum; UINT8 ssplayers = cv_splitplayers.value-1; S_StartSound(NULL, sfx_s3k63); @@ -3458,8 +3460,10 @@ void M_CupSelectHandler(INT32 choice) netgame = levellist.netgame; // ^ ditto. } + levelNum = G_MapNumber(grandprixinfo.cup->levellist[0]); + D_MapChange( - grandprixinfo.cup->levellist[0] + 1, + levelNum + 1, GT_RACE, grandprixinfo.encore, true, From 430f357f873c87bee64722e99b7fc69ef782289f Mon Sep 17 00:00:00 2001 From: SteelT Date: Sun, 11 Sep 2022 19:36:34 -0400 Subject: [PATCH 17/60] Fix title screen crash --- src/f_finale.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index 2e998f467..877d1892b 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1836,8 +1836,6 @@ static void F_CacheTitleScreen(void) void F_StartTitleScreen(void) { - const INT32 titleMapNum = G_MapNumber(titlemap); - setup_numplayers = 0; if (gamestate != GS_TITLESCREEN && gamestate != GS_WAITINGPLAYERS) @@ -1849,10 +1847,11 @@ void F_StartTitleScreen(void) else wipegamestate = GS_TITLESCREEN; - if (mapheaderinfo[titleMapNum]) + if (titlemap) { mapthing_t *startpos; + const INT32 titleMapNum = G_MapNumber(titlemap); gamestate_t prevwipegamestate = wipegamestate; titlemapinaction = TITLEMAP_LOADING; titlemapcameraref = NULL; From e1ad0bef7c13f4dc16b97f63a9baf9c1b3fdf421 Mon Sep 17 00:00:00 2001 From: SteelT Date: Mon, 12 Sep 2022 12:40:24 -0400 Subject: [PATCH 18/60] Comment out some things for now Just so I can get in-game without crashing during testing --- src/k_hud.c | 3 ++- src/p_setup.c | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/k_hud.c b/src/k_hud.c index 29aa49b3e..0b2504ae5 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -3418,11 +3418,12 @@ static void K_drawKartMinimap(void) // Maybe move this somewhere else where this won't be a concern? if (stplyr != &players[displayplayers[0]]) return; - +#if 0 if (mapheaderinfo[gamemap-1]) { lumpnum = W_CheckNumForLongName(mapheaderinfo[gamemap-1]->minimapLump); } +#endif if (lumpnum == LUMPERROR) { diff --git a/src/p_setup.c b/src/p_setup.c index beb391297..124c5c541 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -4358,6 +4358,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) { INT32 encoreLump = LUMPERROR; +#if 0 if (mapheaderinfo[gamemap-1]) { if (encoremode) @@ -4371,6 +4372,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) } R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette, encoreLump); +#endif } CON_SetupBackColormap(); From 556aa1c4c0301844be4efe96593d70cb986d0380 Mon Sep 17 00:00:00 2001 From: SteelT Date: Mon, 12 Sep 2022 12:51:31 -0400 Subject: [PATCH 19/60] Add patch support from a virtual lump --- src/w_wad.c | 69 ++++++++++++++++++++++++++++++++++++++++++++--------- src/w_wad.h | 2 ++ 2 files changed, 60 insertions(+), 11 deletions(-) diff --git a/src/w_wad.c b/src/w_wad.c index 498f98d8e..714928978 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -1771,6 +1771,26 @@ void *W_CacheLumpName(const char *name, INT32 tag) // Cache a patch into heap memory, convert the patch format as necessary // +static void MakePatch(void *lumpdata, size_t size, INT32 tag, void *cache) +{ + void *ptr, *dest; + size_t len = size; + + ptr = lumpdata; + +#ifndef NO_PNG_LUMPS + if (Picture_IsLumpPNG((UINT8 *)lumpdata, len)) + { + ptr = Picture_PNGConvert((UINT8 *)lumpdata, PICFMT_DOOMPATCH, NULL, NULL, NULL, NULL, len, &len, 0); + } +#endif + + dest = Z_Calloc(sizeof(patch_t), tag, cache); + Patch_Create(ptr, len, dest); + + Z_Free(ptr); +} + void *W_CacheSoftwarePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag) { lumpcache_t *lumpcache = NULL; @@ -1783,21 +1803,12 @@ void *W_CacheSoftwarePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag) if (!lumpcache[lump]) { size_t len = W_LumpLengthPwad(wad, lump); - void *ptr, *dest, *lumpdata = Z_Malloc(len, PU_STATIC, NULL); + void *lumpdata = Z_Malloc(len, PU_STATIC, NULL); // read the lump in full W_ReadLumpHeaderPwad(wad, lump, lumpdata, 0, 0); - ptr = lumpdata; -#ifndef NO_PNG_LUMPS - if (Picture_IsLumpPNG((UINT8 *)lumpdata, len)) - ptr = Picture_PNGConvert((UINT8 *)lumpdata, PICFMT_DOOMPATCH, NULL, NULL, NULL, NULL, len, &len, 0); -#endif - - dest = Z_Calloc(sizeof(patch_t), tag, &lumpcache[lump]); - Patch_Create(ptr, len, dest); - - Z_Free(ptr); + MakePatch(lumpdata, len, tag, &lumpcache[lump]); } else Z_ChangeTag(lumpcache[lump], tag); @@ -2278,6 +2289,7 @@ virtres_t* vres_GetMap(lumpnum_t lumpnum) vlumps[i].name[8] = '\0'; vlumps[i].data = Z_Malloc(vlumps[i].size, PU_LEVEL, NULL); // This is memory inefficient, sorry about that. memcpy(vlumps[i].data, wadData + (fileinfo + i)->filepos, vlumps[i].size); + vlumps[i].cache = NULL; } Z_Free(wadData); @@ -2298,6 +2310,7 @@ virtres_t* vres_GetMap(lumpnum_t lumpnum) memcpy(vlumps[i].name, W_CheckNameForNum(lumpnum), 8); vlumps[i].name[8] = '\0'; vlumps[i].data = W_CacheLumpNum(lumpnum, PU_LEVEL); + vlumps[i].cache = NULL; } } vres = Z_Malloc(sizeof(virtres_t), PU_LEVEL, NULL); @@ -2345,3 +2358,37 @@ virtlump_t* vres_Find(const virtres_t* vres, const char* name) return &vres->vlumps[i]; return NULL; } + +/** \brief Gets patch from given virtual lump + * + * \param Virtual lump + * \return Patch data + * + */ +void *vres_GetPatch(virtlump_t *vlump, INT32 tag) +{ + patch_t *patch; + + if (!vlump) + return NULL; + + if (!vlump->cache) + { + MakePatch(vlump->data, vlump->size, tag, &vlump->cache); + } + else + Z_ChangeTag(vlump->cache, tag); + + patch = vlump->cache; + +#ifdef HWRENDER + // Software-only compile cache the data without conversion + if (rendermode == render_soft || rendermode == render_none) +#endif + return (void *)patch; + +#ifdef HWRENDER + Patch_CreateGL(patch); + return (void *)patch; +#endif +} \ No newline at end of file diff --git a/src/w_wad.h b/src/w_wad.h index d81c07d7d..71f46f46b 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -82,6 +82,7 @@ typedef struct { char name[9]; UINT8* data; size_t size; + void *cache; } virtlump_t; typedef struct { @@ -92,6 +93,7 @@ typedef struct { virtres_t* vres_GetMap(lumpnum_t); void vres_Free(virtres_t*); virtlump_t* vres_Find(const virtres_t*, const char*); +void* vres_GetPatch(virtlump_t *vlump, INT32 tag); // ========================================================================= // DYNAMIC WAD LOADING From c64f36309a7db398805a66313b1f2c50d51a2e07 Mon Sep 17 00:00:00 2001 From: SteelT Date: Mon, 12 Sep 2022 17:29:15 -0400 Subject: [PATCH 20/60] Support reading PICTURE/MINIMAP/ENCORE/TWEAKMAP lumps from a map resource This supersedes the header-based method of fetching those lumps. --- src/d_main.c | 22 +++++++++- src/deh_soc.c | 16 -------- src/doomstat.h | 12 ++++-- src/k_hud.c | 13 ++---- src/k_menudraw.c | 35 ++++++---------- src/lua_hudlib.c | 10 +---- src/p_setup.c | 102 +++++++++++++++++++++++++++-------------------- src/r_data.c | 6 +-- src/r_data.h | 2 +- src/w_wad.c | 24 +++++------ src/w_wad.h | 3 +- src/y_inter.c | 9 ++--- 12 files changed, 126 insertions(+), 128 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 6eafb88cf..307baa90c 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -353,7 +353,7 @@ static void D_Display(void) if (gamestate != GS_LEVEL && rendermode != render_none) { V_SetPaletteLump("PLAYPAL"); // Reset the palette - R_ReInitColormaps(0, LUMPERROR); + R_ReInitColormaps(0, NULL, 0); } F_WipeStartScreen(); @@ -1194,6 +1194,8 @@ void D_SRB2Main(void) INT32 i; UINT16 wadnum; char *name; + virtres_t *virtmap; + virtlump_t *minimap, *thumbnailPic; INT32 p; @@ -1455,6 +1457,24 @@ void D_SRB2Main(void) for (i = 0; i < numbasemapheaders; ++i) { name = mapheaderinfo[i]->lumpname; + mapheaderinfo[i]->lumpnum = W_CheckNumForMap(name); + + // Get map thumbnail and minimap + virtmap = vres_GetMap(mapheaderinfo[i]->lumpnum); + thumbnailPic = vres_Find(virtmap, "PICTURE"); + minimap = vres_Find(virtmap, "MINIMAP"); + + if (thumbnailPic) + { + mapheaderinfo[i]->thumbnailPic = vres_GetPatch(thumbnailPic, PU_CACHE); + } + + if (minimap) + { + mapheaderinfo[i]->minimapPic = vres_GetPatch(minimap, PU_HUDGFX); + } + + vres_Free(virtmap); if (W_CheckNumForMapPwad(name, wadnum, 0) != INT16_MAX) { diff --git a/src/deh_soc.c b/src/deh_soc.c index 7bdf8b35f..e574b0c5e 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -1275,22 +1275,6 @@ void readlevelheader(MYFILE *f, char * name) } // Strings that can be truncated - else if (fastcmp(word, "THUMBNAIL")) - { - mapheaderinfo[num-1]->thumbnailLump = Z_StrDup(word2); - } - else if (fastcmp(word, "MINIMAP")) - { - mapheaderinfo[num-1]->minimapLump = Z_StrDup(word2); - } - else if (fastcmp(word, "ENCOREMAP")) - { - mapheaderinfo[num-1]->encoreLump = Z_StrDup(word2); - } - else if (fastcmp(word, "TWEAKMAP")) - { - mapheaderinfo[num-1]->tweakLump = Z_StrDup(word2); - } else if (fastcmp(word, "NEXTLEVEL")) { mapheaderinfo[num-1]->nextlevel = Z_StrDup(word2); diff --git a/src/doomstat.h b/src/doomstat.h index 32b48eb27..9c48985e6 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -25,6 +25,9 @@ // We need the player data structure as well. #include "d_player.h" +// For lumpnum_t. +#include "w_wad.h" + // ============================= // Selected map etc. // ============================= @@ -338,11 +341,12 @@ typedef struct typedef struct { char * lumpname; ///< Lump name can be really long + lumpnum_t lumpnum; ///< Lump number for the map, used by vres_GetMap - char * thumbnailLump; ///< Lump name for the level select thumbnail. - char * minimapLump; ///< Lump name for the minimap graphic. - char * encoreLump; ///< Lump name for the Encore Mode remap. - char * tweakLump; ///< Lump name for the palette tweak remap. + void * thumbnailPic; ///< Lump data for the level select thumbnail. + void * minimapPic; ///< Lump data for the minimap graphic. + void * encoreLump; ///< Lump data for the Encore Mode remap. + void * tweakLump; ///< Lump data for the palette tweak remap. char lvlttl[22]; ///< Level name without "Zone". (21 character limit instead of 32, 21 characters can display on screen max anyway) char subttl[33]; ///< Subtitle for level diff --git a/src/k_hud.c b/src/k_hud.c index 0b2504ae5..de22f42a9 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -3395,7 +3395,6 @@ static void K_drawKartMinimapIcon(fixed_t objx, fixed_t objy, INT32 hudx, INT32 static void K_drawKartMinimap(void) { - lumpnum_t lumpnum = LUMPERROR; patch_t *AutomapPic; INT32 i = 0; INT32 x, y; @@ -3418,20 +3417,14 @@ static void K_drawKartMinimap(void) // Maybe move this somewhere else where this won't be a concern? if (stplyr != &players[displayplayers[0]]) return; -#if 0 - if (mapheaderinfo[gamemap-1]) - { - lumpnum = W_CheckNumForLongName(mapheaderinfo[gamemap-1]->minimapLump); - } -#endif - if (lumpnum == LUMPERROR) + AutomapPic = mapheaderinfo[gamemap-1]->minimapPic; + + if (!AutomapPic) { return; // no pic, just get outta here } - AutomapPic = W_CachePatchNum(lumpnum, PU_HUDGFX); - if (r_splitscreen < 2) // 1/2P right aligned { splitflags = (V_SLIDEIN|V_SNAPTORIGHT); diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 657b6a379..a780b364e 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -1847,17 +1847,14 @@ static void M_DrawCupPreview(INT16 y, cupheader_t *cup) while (x < BASEVIDWIDTH + pad) { INT32 cupLevelNum = G_MapNumber(cup->levellist[i]); - lumpnum_t lumpnum = LUMPERROR; - patch_t *PictureOfLevel; + patch_t *PictureOfLevel = NULL; if (mapheaderinfo[cupLevelNum]) { - lumpnum = W_CheckNumForLongName(mapheaderinfo[cupLevelNum]->thumbnailLump); + PictureOfLevel = mapheaderinfo[cupLevelNum]->thumbnailPic; } - if (lumpnum != LUMPERROR) - PictureOfLevel = W_CachePatchNum(lumpnum, PU_CACHE); - else + if (!PictureOfLevel) PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE); V_DrawSmallScaledPatch(x + 1, y+2, 0, PictureOfLevel); @@ -2078,8 +2075,7 @@ static void M_DrawHighLowLevelTitle(INT16 x, INT16 y, INT16 map) static void M_DrawLevelSelectBlock(INT16 x, INT16 y, INT16 map, boolean redblink, boolean greyscale) { - lumpnum_t lumpnum = LUMPERROR; - patch_t *PictureOfLevel; + patch_t *PictureOfLevel = NULL; UINT8 *colormap = NULL; if (greyscale) @@ -2087,12 +2083,10 @@ static void M_DrawLevelSelectBlock(INT16 x, INT16 y, INT16 map, boolean redblink if (mapheaderinfo[map]) { - lumpnum = W_CheckNumForLongName(mapheaderinfo[map]->thumbnailLump); + PictureOfLevel = mapheaderinfo[map]->thumbnailPic; } - if (lumpnum != LUMPERROR) - PictureOfLevel = W_CachePatchNum(lumpnum, PU_CACHE); - else + if (!PictureOfLevel) PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE); if (redblink) @@ -2155,7 +2149,7 @@ void M_DrawTimeAttack(void) INT16 rightedge = 149+t+155; INT16 opty = 140; INT32 w; - lumpnum_t lumpnum = LUMPERROR; + patch_t *minimap = NULL; UINT8 i; consvar_t *cv; @@ -2169,11 +2163,11 @@ void M_DrawTimeAttack(void) { if (mapheaderinfo[map]) { - lumpnum = W_CheckNumForName(mapheaderinfo[map]->minimapLump); + minimap = mapheaderinfo[map]->minimapPic; } - if (lumpnum != LUMPERROR) - V_DrawScaledPatch(24-t, 82, 0, W_CachePatchNum(lumpnum, PU_CACHE)); + if (!minimap) + V_DrawScaledPatch(24-t, 82, 0, minimap); V_DrawRightAlignedString(rightedge-12, 82, highlightflags, "BEST LAP:"); K_drawKartTimestamp(0, 162+t, 88, 0, 2); @@ -3838,8 +3832,7 @@ void M_DrawPlaybackMenu(void) #define SCALEDVIEWHEIGHT (vid.height/vid.dupy) void M_DrawReplayHutReplayInfo(void) { - lumpnum_t lumpnum = LUMPERROR; - patch_t *patch; + patch_t *patch = NULL; UINT8 *colormap; INT32 x, y, w, h; @@ -3868,12 +3861,10 @@ void M_DrawReplayHutReplayInfo(void) if (mapheaderinfo[extrasmenu.demolist[dir_on[menudepthleft]].map]) { - lumpnum = W_CheckNumForName(mapheaderinfo[extrasmenu.demolist[dir_on[menudepthleft]].map]->thumbnailLump); + patch = mapheaderinfo[extrasmenu.demolist[dir_on[menudepthleft]].map]->thumbnailPic; } - if (lumpnum != LUMPERROR) - patch = W_CachePatchNum(lumpnum, PU_CACHE); - else + if (!patch) patch = W_CachePatchName("M_NOLVL", PU_CACHE); if (!(extrasmenu.demolist[dir_on[menudepthleft]].kartspeed & DF_ENCORE)) diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index db22c6b2c..6ce41dea5 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -600,7 +600,6 @@ static int libd_drawOnMinimap(lua_State *L) huddrawlist_h list; // variables used to replicate k_kart's mmap drawer: - lumpnum_t lumpnum = LUMPERROR; patch_t *AutomapPic; INT32 mx, my; INT32 splitflags, minimaptrans; @@ -686,18 +685,13 @@ static int libd_drawOnMinimap(lua_State *L) if (stplyr != &players[displayplayers[0]]) return 0; - if (mapheaderinfo[gamemap-1]) - { - lumpnum = W_CheckNumForLongName(mapheaderinfo[gamemap-1]->minimapLump); - } + AutomapPic = mapheaderinfo[gamemap-1]->minimapPic; - if (lumpnum == LUMPERROR) + if (!AutomapPic) { return 0; // no pic, just get outta here } - AutomapPic = W_CachePatchNum(lumpnum, PU_HUDGFX); - mx = MM_X - (AutomapPic->width/2); my = MM_Y - (AutomapPic->height/2); diff --git a/src/p_setup.c b/src/p_setup.c index 124c5c541..bc2df7862 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -134,6 +134,8 @@ boolean stoppedclock; boolean levelloading; UINT8 levelfadecol; +virtres_t *curmapvirt; + // BLOCKMAP // Created from axis aligned bounding box // of the map, a rectangular array of @@ -361,28 +363,16 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) { const INT16 num = (INT16)(i-1); - if (mapheaderinfo[num]->thumbnailLump) + if (mapheaderinfo[num]->thumbnailPic) { - Z_Free(mapheaderinfo[num]->thumbnailLump); - mapheaderinfo[num]->thumbnailLump = NULL; + Z_Free(mapheaderinfo[num]->thumbnailPic); + mapheaderinfo[num]->thumbnailPic = NULL; } - if (mapheaderinfo[num]->minimapLump) + if (mapheaderinfo[num]->minimapPic) { - Z_Free(mapheaderinfo[num]->minimapLump); - mapheaderinfo[num]->minimapLump = NULL; - } - - if (mapheaderinfo[num]->encoreLump) - { - Z_Free(mapheaderinfo[num]->encoreLump); - mapheaderinfo[num]->encoreLump = NULL; - } - - if (mapheaderinfo[num]->tweakLump) - { - Z_Free(mapheaderinfo[num]->tweakLump); - mapheaderinfo[num]->tweakLump = NULL; + Z_Free(mapheaderinfo[num]->minimapPic); + mapheaderinfo[num]->minimapPic = NULL; } if (mapheaderinfo[num]->nextlevel) @@ -469,11 +459,10 @@ void P_AllocMapHeader(INT16 i) if (!mapheaderinfo[i]) { mapheaderinfo[i] = Z_Malloc(sizeof(mapheader_t), PU_STATIC, NULL); + mapheaderinfo[i]->lumpnum = LUMPERROR; mapheaderinfo[i]->lumpname = NULL; - mapheaderinfo[i]->thumbnailLump = NULL; - mapheaderinfo[i]->minimapLump = NULL; - mapheaderinfo[i]->encoreLump = NULL; - mapheaderinfo[i]->tweakLump = NULL; + mapheaderinfo[i]->thumbnailPic = NULL; + mapheaderinfo[i]->minimapPic = NULL; mapheaderinfo[i]->nextlevel = NULL; mapheaderinfo[i]->marathonnext = NULL; mapheaderinfo[i]->flickies = NULL; @@ -3600,15 +3589,14 @@ static void P_MakeMapMD5(virtres_t *virt, void *dest) static boolean P_LoadMapFromFile(void) { - virtres_t *virt = vres_GetMap(lastloadedmaplumpnum); - virtlump_t *textmap = vres_Find(virt, "TEXTMAP"); + virtlump_t *textmap = vres_Find(curmapvirt, "TEXTMAP"); size_t i; udmf = textmap != NULL; - if (!P_LoadMapData(virt)) + if (!P_LoadMapData(curmapvirt)) return false; - P_LoadMapBSP(virt); - P_LoadMapLUT(virt); + P_LoadMapBSP(curmapvirt); + P_LoadMapLUT(curmapvirt); P_LinkMapData(); @@ -3633,9 +3621,9 @@ static boolean P_LoadMapFromFile(void) if (sectors[i].tags.count) spawnsectors[i].tags.tags = memcpy(Z_Malloc(sectors[i].tags.count*sizeof(mtag_t), PU_LEVEL, NULL), sectors[i].tags.tags, sectors[i].tags.count*sizeof(mtag_t)); - P_MakeMapMD5(virt, &mapmd5); + P_MakeMapMD5(curmapvirt, &mapmd5); - vres_Free(virt); + vres_Free(curmapvirt); return true; } @@ -4129,6 +4117,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) // Map header should always be in place at this point INT32 i, ranspecialwipe = 0; sector_t *ss; + virtlump_t *encoreLump = NULL; levelloading = true; @@ -4355,24 +4344,27 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) if (lastloadedmaplumpnum == LUMPERROR) I_Error("Map %s not found.\n", maplumpname); + curmapvirt = vres_GetMap(lastloadedmaplumpnum); + + if (mapheaderinfo[gamemap-1]) { - INT32 encoreLump = LUMPERROR; - -#if 0 - if (mapheaderinfo[gamemap-1]) + if (encoremode) { - if (encoremode) - { - encoreLump = W_CheckNumForLongName(mapheaderinfo[gamemap-1]->encoreLump); - } - else - { - encoreLump = W_CheckNumForLongName(mapheaderinfo[gamemap-1]->tweakLump); - } + encoreLump = vres_Find(curmapvirt, "ENCORE"); } + else + { + encoreLump = vres_Find(curmapvirt, "TWEAKMAP"); + } + } - R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette, encoreLump); -#endif + if (encoreLump) + { + R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette, encoreLump->data, encoreLump->size); + } + else + { + R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette, NULL, 0); } CON_SetupBackColormap(); @@ -4677,6 +4669,8 @@ boolean P_AddWadFile(const char *wadfilename) UINT16 numlumps, wadnum; char *name; lumpinfo_t *lumpinfo; + virtres_t *virtmap; + virtlump_t *minimap, *thumbnailPic; //boolean texturechange = false; ///\todo Useless; broken when back-frontporting PK3 changes? boolean mapsadded = false; @@ -4834,6 +4828,28 @@ boolean P_AddWadFile(const char *wadfilename) { name = mapheaderinfo[map]->lumpname; + if (mapheaderinfo[i]->lumpnum != W_CheckNumForMap(name)) + { + mapheaderinfo[i]->lumpnum = W_CheckNumForMap(name); + + // Get map thumbnail and minimap + virtmap = vres_GetMap(mapheaderinfo[i]->lumpnum); + thumbnailPic = vres_Find(virtmap, "PICTURE"); + minimap = vres_Find(virtmap, "MINIMAP"); + + if (thumbnailPic) + { + mapheaderinfo[i]->thumbnailPic = vres_GetPatch(thumbnailPic, PU_CACHE); + } + + if (minimap) + { + mapheaderinfo[i]->minimapPic = vres_GetPatch(minimap, PU_HUDGFX); + } + + vres_Free(virtmap); + } + if (W_CheckNumForMapPwad(name, wadnum, 0) != INT16_MAX) { G_SetGameModified(multiplayer, true); // oops, double-defined - no record attack privileges for you diff --git a/src/r_data.c b/src/r_data.c index ddeb5e3b5..353a9bbf5 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -286,7 +286,7 @@ void R_InitColormaps(void) #endif } -void R_ReInitColormaps(UINT16 num, lumpnum_t newencoremap) +void R_ReInitColormaps(UINT16 num, void *newencoremap, size_t encoremapsize) { char colormap[9] = "COLORMAP"; lumpnum_t lump; @@ -309,13 +309,13 @@ void R_ReInitColormaps(UINT16 num, lumpnum_t newencoremap) W_ReadLumpHeader(lump, colormaps, W_LumpLength(basecolormaplump), 0U); // Encore mode. - if (newencoremap != LUMPERROR) + if (newencoremap) { lighttable_t *colormap_p, *colormap_p2; size_t p, i; encoremap = Z_MallocAlign(256 + 10, PU_LEVEL, NULL, 8); - W_ReadLump(newencoremap, encoremap); + M_Memcpy(encoremap, newencoremap, encoremapsize); colormap_p = colormap_p2 = colormaps; colormap_p += COLORMAP_REMAPOFFSET; diff --git a/src/r_data.h b/src/r_data.h index 3c8908a59..da3f81163 100644 --- a/src/r_data.h +++ b/src/r_data.h @@ -55,7 +55,7 @@ extern size_t flatmemory, spritememory, texturememory; //#define COLORMAPREVERSELIST void R_InitColormaps(void); -void R_ReInitColormaps(UINT16 num, lumpnum_t newencoremap); +void R_ReInitColormaps(UINT16 num, void *newencoremap, size_t encoremapsize); void R_ClearColormaps(void); extracolormap_t *R_CreateDefaultColormap(boolean lighttable); extracolormap_t *R_GetDefaultColormap(void); diff --git a/src/w_wad.c b/src/w_wad.c index 714928978..3bcd805c4 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -1771,7 +1771,7 @@ void *W_CacheLumpName(const char *name, INT32 tag) // Cache a patch into heap memory, convert the patch format as necessary // -static void MakePatch(void *lumpdata, size_t size, INT32 tag, void *cache) +static void *MakePatch(void *lumpdata, size_t size, INT32 tag, void *cache) { void *ptr, *dest; size_t len = size; @@ -1786,9 +1786,10 @@ static void MakePatch(void *lumpdata, size_t size, INT32 tag, void *cache) #endif dest = Z_Calloc(sizeof(patch_t), tag, cache); + Patch_Create(ptr, len, dest); - Z_Free(ptr); + return dest; } void *W_CacheSoftwarePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag) @@ -1809,6 +1810,7 @@ void *W_CacheSoftwarePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag) W_ReadLumpHeaderPwad(wad, lump, lumpdata, 0, 0); MakePatch(lumpdata, len, tag, &lumpcache[lump]); + Z_Free(lumpdata); } else Z_ChangeTag(lumpcache[lump], tag); @@ -2289,7 +2291,6 @@ virtres_t* vres_GetMap(lumpnum_t lumpnum) vlumps[i].name[8] = '\0'; vlumps[i].data = Z_Malloc(vlumps[i].size, PU_LEVEL, NULL); // This is memory inefficient, sorry about that. memcpy(vlumps[i].data, wadData + (fileinfo + i)->filepos, vlumps[i].size); - vlumps[i].cache = NULL; } Z_Free(wadData); @@ -2310,7 +2311,6 @@ virtres_t* vres_GetMap(lumpnum_t lumpnum) memcpy(vlumps[i].name, W_CheckNameForNum(lumpnum), 8); vlumps[i].name[8] = '\0'; vlumps[i].data = W_CacheLumpNum(lumpnum, PU_LEVEL); - vlumps[i].cache = NULL; } } vres = Z_Malloc(sizeof(virtres_t), PU_LEVEL, NULL); @@ -2327,7 +2327,12 @@ virtres_t* vres_GetMap(lumpnum_t lumpnum) void vres_Free(virtres_t* vres) { while (vres->numlumps--) - Z_Free(vres->vlumps[vres->numlumps].data); + { + if (vres->vlumps[vres->numlumps].data) + { + Z_Free(vres->vlumps[vres->numlumps].data); + } + } Z_Free(vres->vlumps); Z_Free(vres); } @@ -2372,14 +2377,7 @@ void *vres_GetPatch(virtlump_t *vlump, INT32 tag) if (!vlump) return NULL; - if (!vlump->cache) - { - MakePatch(vlump->data, vlump->size, tag, &vlump->cache); - } - else - Z_ChangeTag(vlump->cache, tag); - - patch = vlump->cache; + patch = MakePatch(vlump->data, vlump->size, tag, NULL); #ifdef HWRENDER // Software-only compile cache the data without conversion diff --git a/src/w_wad.h b/src/w_wad.h index 71f46f46b..310e87203 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -82,7 +82,6 @@ typedef struct { char name[9]; UINT8* data; size_t size; - void *cache; } virtlump_t; typedef struct { @@ -93,7 +92,7 @@ typedef struct { virtres_t* vres_GetMap(lumpnum_t); void vres_Free(virtres_t*); virtlump_t* vres_Find(const virtres_t*, const char*); -void* vres_GetPatch(virtlump_t *vlump, INT32 tag); +void* vres_GetPatch(virtlump_t *vlump, INT32); // ========================================================================= // DYNAMIC WAD LOADING diff --git a/src/y_inter.c b/src/y_inter.c index bb788d509..08bd9bb92 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -1490,8 +1490,6 @@ void Y_StartVote(void) for (i = 0; i < 4; i++) { - lumpnum_t lumpnum = LUMPERROR; - // set up the encore levelinfo[i].encore = (votelevels[i][1] & 0x80); votelevels[i][1] &= ~0x80; @@ -1534,13 +1532,14 @@ void Y_StartVote(void) levelinfo[i].gts = NULL; // set up the pic + patch_t *thumbnailPic = NULL; if (mapheaderinfo[votelevels[i][0]+1]) { - lumpnum = W_CheckNumForLongName(mapheaderinfo[votelevels[i][0]]->thumbnailLump); + thumbnailPic = mapheaderinfo[votelevels[i][0]]->thumbnailPic; } - if (lumpnum != LUMPERROR) - levelinfo[i].pic = W_CachePatchNum(lumpnum, PU_STATIC); + if (thumbnailPic) + levelinfo[i].pic = thumbnailPic; else levelinfo[i].pic = W_CachePatchName("BLANKLVL", PU_STATIC); } From ae38b7091a07a44aab9eacc7bf056b5e4e80b19b Mon Sep 17 00:00:00 2001 From: SteelT Date: Mon, 12 Sep 2022 17:37:50 -0400 Subject: [PATCH 21/60] Fix function prototype --- src/w_wad.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/w_wad.h b/src/w_wad.h index 310e87203..5e23ff0a7 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -92,7 +92,7 @@ typedef struct { virtres_t* vres_GetMap(lumpnum_t); void vres_Free(virtres_t*); virtlump_t* vres_Find(const virtres_t*, const char*); -void* vres_GetPatch(virtlump_t *vlump, INT32); +void* vres_GetPatch(virtlump_t *vlump, INT32 tag); // ========================================================================= // DYNAMIC WAD LOADING From 46441092dc63d7e48545faf183ae8ce467b6cf2e Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 16 Sep 2022 15:01:49 +0100 Subject: [PATCH 22/60] Address initial review comments + associated cleanup - Grab thumbnail and minimap pictures even for base game maps - Repair modified game event for replacement map load - PU_STATIC thumbnail and minimap, freed on new file load lump discovery - Fix W_CheckNumForMap to not SIGSEGV if no match - Reduce the number of pointless map lump hunts, we've already got it stored - Prevent use-after-free for map pictures on voting screen - Cache "BLANKLVL" patch once - Draw minimap on the time attack menu Unfortunately cups are still broken and I'm not sure where to start on that, or if it's just not having a sample wad to test with that includes cups --- src/d_main.c | 49 ++++------------- src/g_game.c | 17 +----- src/hu_stuff.c | 3 ++ src/k_menudraw.c | 10 ++-- src/p_setup.c | 136 ++++++++++++++++++++++++++++++----------------- src/p_setup.h | 5 ++ src/r_defs.h | 1 + src/w_wad.c | 2 +- src/y_inter.c | 66 ++++++++++------------- 9 files changed, 140 insertions(+), 149 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 307baa90c..6d9c84a43 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1190,15 +1190,10 @@ D_ConvertVersionNumbers (void) // void D_SRB2Main(void) { - INT32 numbasemapheaders; - INT32 i; - UINT16 wadnum; - char *name; - virtres_t *virtmap; - virtlump_t *minimap, *thumbnailPic; - INT32 p; + INT32 numbasemapheaders; + INT32 pstartmap = 1; boolean autostart = false; @@ -1441,6 +1436,11 @@ void D_SRB2Main(void) #endif //ifndef DEVELOP + // + // search for mainwad maps + // + P_InitMapData(0); + numbasemapheaders = nummapheaders; CON_SetLoadingProgress(LOADED_IWAD); @@ -1450,40 +1450,9 @@ void D_SRB2Main(void) D_CleanFile(startuppwads); // - // search for maps + // search for pwad maps // - for (wadnum = mainwads+1; wadnum < numwadfiles; wadnum++) - { - for (i = 0; i < numbasemapheaders; ++i) - { - name = mapheaderinfo[i]->lumpname; - mapheaderinfo[i]->lumpnum = W_CheckNumForMap(name); - - // Get map thumbnail and minimap - virtmap = vres_GetMap(mapheaderinfo[i]->lumpnum); - thumbnailPic = vres_Find(virtmap, "PICTURE"); - minimap = vres_Find(virtmap, "MINIMAP"); - - if (thumbnailPic) - { - mapheaderinfo[i]->thumbnailPic = vres_GetPatch(thumbnailPic, PU_CACHE); - } - - if (minimap) - { - mapheaderinfo[i]->minimapPic = vres_GetPatch(minimap, PU_HUDGFX); - } - - vres_Free(virtmap); - - if (W_CheckNumForMapPwad(name, wadnum, 0) != INT16_MAX) - { - G_SetGameModified(multiplayer, true); // oops, double-defined - no record attack privileges for you - - CONS_Printf("%s\n", name); - } - } - } + P_InitMapData(numbasemapheaders); CON_SetLoadingProgress(LOADED_PWAD); diff --git a/src/g_game.c b/src/g_game.c index d74839495..c8fb69f46 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -597,20 +597,7 @@ void G_SetGameModified(boolean silent, boolean major) */ const char *G_BuildMapName(INT32 map) { -#if 0 - if (map == 0) // hack??? - { - if (gamestate == GS_TITLESCREEN) - map = -1; - else if (gamestate == GS_LEVEL) - map = gamemap-1; - else - map = prevmap; - map = G_RandMap(G_TOLFlag(cv_newgametype.value), map, 0, 0, false, NULL)+1; - } -#endif - - if (map > 0 && map <= NUMMAPS && mapheaderinfo[map - 1] != NULL) + if (map > 0 && map <= nummapheaders && mapheaderinfo[map - 1] != NULL) { return mapheaderinfo[map - 1]->lumpname; } @@ -4612,7 +4599,7 @@ void G_InitNew(UINT8 pencoremode, INT32 map, boolean resetplayer, boolean skippr // 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 (mapheaderinfo[map-1]->lumpnum == LUMPERROR) { I_Error("Internal game map '%s' not found\n", mapname); Command_ExitGame_f(); diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 19e016ae7..e4f090ffb 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -93,6 +93,7 @@ static char hu_tick; //------------------------------------------- patch_t *missingpat; +patch_t *blanklvl; // song credits static patch_t *songcreditbg; @@ -180,6 +181,8 @@ void HU_LoadGraphics(void) Font_Load(); + HU_UpdatePatch(&blanklvl, "BLANKLVL"); + HU_UpdatePatch(&songcreditbg, "K_SONGCR"); // cache ping gfx: diff --git a/src/k_menudraw.c b/src/k_menudraw.c index a780b364e..e1dbc5bc9 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -1855,7 +1855,7 @@ static void M_DrawCupPreview(INT16 y, cupheader_t *cup) } if (!PictureOfLevel) - PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE); + PictureOfLevel = blanklvl; V_DrawSmallScaledPatch(x + 1, y+2, 0, PictureOfLevel); i = (i+1) % cup->numlevels; @@ -2087,7 +2087,7 @@ static void M_DrawLevelSelectBlock(INT16 x, INT16 y, INT16 map, boolean redblink } if (!PictureOfLevel) - PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE); + PictureOfLevel = blanklvl; if (redblink) V_DrawScaledPatch(3+x, y, 0, W_CachePatchName("LVLSEL2", PU_CACHE)); @@ -2163,12 +2163,10 @@ void M_DrawTimeAttack(void) { if (mapheaderinfo[map]) { - minimap = mapheaderinfo[map]->minimapPic; + if ((minimap = mapheaderinfo[map]->minimapPic)) + V_DrawScaledPatch(24-t, 82, 0, minimap); } - if (!minimap) - V_DrawScaledPatch(24-t, 82, 0, minimap); - V_DrawRightAlignedString(rightedge-12, 82, highlightflags, "BEST LAP:"); K_drawKartTimestamp(0, 162+t, 88, 0, 2); diff --git a/src/p_setup.c b/src/p_setup.c index bc2df7862..958e1c638 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -365,13 +365,13 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) if (mapheaderinfo[num]->thumbnailPic) { - Z_Free(mapheaderinfo[num]->thumbnailPic); + Patch_Free(mapheaderinfo[num]->thumbnailPic); mapheaderinfo[num]->thumbnailPic = NULL; } if (mapheaderinfo[num]->minimapPic) { - Z_Free(mapheaderinfo[num]->minimapPic); + Patch_Free(mapheaderinfo[num]->minimapPic); mapheaderinfo[num]->minimapPic = NULL; } @@ -4339,8 +4339,8 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) } // internal game map - maplumpname = G_BuildMapName(gamemap); - lastloadedmaplumpnum = W_CheckNumForMap(maplumpname); + maplumpname = mapheaderinfo[gamemap-1]->lumpname; + lastloadedmaplumpnum = mapheaderinfo[gamemap-1]->lumpnum; if (lastloadedmaplumpnum == LUMPERROR) I_Error("Map %s not found.\n", maplumpname); @@ -4655,6 +4655,87 @@ static lumpinfo_t* FindFolder(const char *folName, UINT16 *start, UINT16 *end, l return lumpinfo; } +// Initialising map data (and catching replacements)... +UINT8 P_InitMapData(INT32 numexistingmapheaders) +{ + UINT8 ret = 0; + INT32 i; + lumpnum_t maplump; + virtres_t *virtmap; + virtlump_t *minimap, *thumbnailPic; + char *name; + + for (i = 0; i < nummapheaders; ++i) + { + name = mapheaderinfo[i]->lumpname; + maplump = W_CheckNumForMap(name); + + // Doesn't exist? + if (maplump == INT16_MAX) + { +#ifndef DEVELOP + if (!numexistingmapheaders) + { + I_Error("P_InitMapData: Base map %s has a header but no level\n", name); + } +#endif + continue; + } + + // No change? + if (mapheaderinfo[i]->lumpnum == maplump) + continue; + + // Okay, it does... + { + ret |= MAPRET_ADDED; + CONS_Printf("%s\n", name); + + if (numexistingmapheaders && mapheaderinfo[i]->lumpnum != LUMPERROR) + { + G_SetGameModified(multiplayer, true); // oops, double-defined - no record attack privileges for you + + //If you replaced the map you're on, end the level when done. + if (i == gamemap - 1) + ret |= MAPRET_CURRENTREPLACED; + } + + mapheaderinfo[i]->lumpnum = maplump; + + // Get map thumbnail and minimap + virtmap = vres_GetMap(mapheaderinfo[i]->lumpnum); + thumbnailPic = vres_Find(virtmap, "PICTURE"); + minimap = vres_Find(virtmap, "MINIMAP"); + + // Clear out existing graphics... + if (mapheaderinfo[i]->thumbnailPic) + { + Patch_Free(mapheaderinfo[i]->thumbnailPic); + } + + if (mapheaderinfo[i]->minimapPic) + { + Patch_Free(mapheaderinfo[i]->minimapPic); + } + + // Now apply the new ones! + if (thumbnailPic) + { + mapheaderinfo[i]->thumbnailPic = vres_GetPatch(thumbnailPic, PU_STATIC); + } + + if (minimap) + { + mapheaderinfo[i]->minimapPic = vres_GetPatch(minimap, PU_STATIC); + } + + vres_Free(virtmap); + } + } + + return ret; +} + UINT16 p_adding_file = INT16_MAX; // @@ -4665,16 +4746,12 @@ boolean P_AddWadFile(const char *wadfilename) { size_t i, j, sreplaces = 0, mreplaces = 0, digmreplaces = 0; INT32 numexistingmapheaders = nummapheaders; - INT32 map; UINT16 numlumps, wadnum; char *name; lumpinfo_t *lumpinfo; - virtres_t *virtmap; - virtlump_t *minimap, *thumbnailPic; //boolean texturechange = false; ///\todo Useless; broken when back-frontporting PK3 changes? - boolean mapsadded = false; - boolean replacedcurrentmap = false; + UINT8 mapsadded = 0; // Vars to help us with the position start and amount of each resource type. // Useful for PK3s since they use folders. @@ -4824,44 +4901,7 @@ boolean P_AddWadFile(const char *wadfilename) // // search for maps // - for (map = 0; map < numexistingmapheaders; ++map) - { - name = mapheaderinfo[map]->lumpname; - - if (mapheaderinfo[i]->lumpnum != W_CheckNumForMap(name)) - { - mapheaderinfo[i]->lumpnum = W_CheckNumForMap(name); - - // Get map thumbnail and minimap - virtmap = vres_GetMap(mapheaderinfo[i]->lumpnum); - thumbnailPic = vres_Find(virtmap, "PICTURE"); - minimap = vres_Find(virtmap, "MINIMAP"); - - if (thumbnailPic) - { - mapheaderinfo[i]->thumbnailPic = vres_GetPatch(thumbnailPic, PU_CACHE); - } - - if (minimap) - { - mapheaderinfo[i]->minimapPic = vres_GetPatch(minimap, PU_HUDGFX); - } - - vres_Free(virtmap); - } - - if (W_CheckNumForMapPwad(name, wadnum, 0) != INT16_MAX) - { - G_SetGameModified(multiplayer, true); // oops, double-defined - no record attack privileges for you - - //If you replaced the map you're on, end the level when done. - if (map == gamemap - 1) - replacedcurrentmap = true; - - CONS_Printf("%s\n", name); - mapsadded = true; - } - } + mapsadded = P_InitMapData(numexistingmapheaders); if (!mapsadded) CONS_Printf(M_GetText("No maps added\n")); @@ -4880,7 +4920,7 @@ boolean P_AddWadFile(const char *wadfilename) if (cursaveslot > 0) cursaveslot = 0; - if (replacedcurrentmap && gamestate == GS_LEVEL && (netgame || multiplayer)) + if ((mapsadded & MAPRET_CURRENTREPLACED) && 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) diff --git a/src/p_setup.h b/src/p_setup.h index 7a8a8c18f..b36451dfb 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -108,6 +108,11 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate); void HWR_LoadLevel(void); #endif boolean P_AddWadFile(const char *wadfilename); + +#define MAPRET_ADDED (1) +#define MAPRET_CURRENTREPLACED (1<<1) +UINT8 P_InitMapData(INT32 numexistingmapheaders); + boolean P_RunSOC(const char *socfilename); void P_LoadSoundsRange(UINT16 wadnum, UINT16 first, UINT16 num); void P_LoadMusicsRange(UINT16 wadnum, UINT16 first, UINT16 num); diff --git a/src/r_defs.h b/src/r_defs.h index 8be91fc9b..ca2f5152d 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -698,6 +698,7 @@ typedef struct } patch_t; extern patch_t *missingpat; +extern patch_t *blanklvl; #if defined(_MSC_VER) #pragma pack(1) diff --git a/src/w_wad.c b/src/w_wad.c index 3bcd805c4..490954dd4 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -1274,7 +1274,7 @@ lumpnum_t W_CheckNumForMap(const char *name) } } - for (i = numwadfiles - 1; i < numwadfiles; i--) + for (i = numwadfiles - 1; i >= 0; i--) { check = W_CheckNumForMapPwad(name, (UINT16)i, 0); diff --git a/src/y_inter.c b/src/y_inter.c index 08bd9bb92..61ebc20d5 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -111,7 +111,6 @@ typedef struct char str[62]; UINT8 gtc; const char *gts; - patch_t *pic; boolean encore; } y_votelvlinfo; @@ -1010,7 +1009,18 @@ void Y_VoteDrawer(void) else { str = levelinfo[i].str; - pic = levelinfo[i].pic; + + pic = NULL; + + if (mapheaderinfo[votelevels[i][0]]) + { + pic = mapheaderinfo[votelevels[i][0]]->thumbnailPic; + } + + if (!pic) + { + pic = blanklvl; + } } if (selected[i]) @@ -1130,9 +1140,23 @@ void Y_VoteDrawer(void) patch_t *pic; if (votes[i] >= 3 && (i != pickedvote || voteendtic == -1)) + { pic = randomlvl; + } else - pic = levelinfo[votes[i]].pic; + { + pic = NULL; + + if (mapheaderinfo[votelevels[votes[i]][0]]) + { + pic = mapheaderinfo[votelevels[votes[i]][0]]->thumbnailPic; + } + + if (!pic) + { + pic = blanklvl; + } + } if (!timer && i == voteclient.ranim) { @@ -1530,18 +1554,6 @@ void Y_StartVote(void) levelinfo[i].gts = Gametype_Names[votelevels[i][1]]; else levelinfo[i].gts = NULL; - - // set up the pic - patch_t *thumbnailPic = NULL; - if (mapheaderinfo[votelevels[i][0]+1]) - { - thumbnailPic = mapheaderinfo[votelevels[i][0]]->thumbnailPic; - } - - if (thumbnailPic) - levelinfo[i].pic = thumbnailPic; - else - levelinfo[i].pic = W_CachePatchName("BLANKLVL", PU_STATIC); } voteclient.loaded = true; @@ -1561,8 +1573,6 @@ void Y_EndVote(void) // static void Y_UnloadVoteData(void) { - UINT8 i; - voteclient.loaded = false; if (rendermode != render_soft) @@ -1577,28 +1587,6 @@ static void Y_UnloadVoteData(void) UNLOAD(cursor4); UNLOAD(randomlvl); UNLOAD(rubyicon); - - // to prevent double frees... - for (i = 0; i < 4; i++) - { - // I went to all the trouble of doing this, - // but literally nowhere else frees level pics. -#if 0 - UINT8 j; - - if (!levelinfo[i].pic) - continue; - - for (j = i+1; j < 4; j++) - { - if (levelinfo[j].pic == levelinfo[i].pic) - levelinfo[j].pic = NULL; - } - UNLOAD(levelinfo[i].pic); -#else - CLEANUP(levelinfo[i].pic); -#endif - } } // From 4f1bb14732fc458808a673ed7eff2b0fb08d7943 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 16 Sep 2022 15:07:12 +0100 Subject: [PATCH 23/60] Extra catch to prevent SIGSEGV --- src/g_game.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/g_game.c b/src/g_game.c index c8fb69f46..b020179fa 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4599,6 +4599,12 @@ void G_InitNew(UINT8 pencoremode, INT32 map, boolean resetplayer, boolean skippr // 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 (!mapname) + { + I_Error("Internal game map with ID %d not found\n", map); + Command_ExitGame_f(); + return; + } if (mapheaderinfo[map-1]->lumpnum == LUMPERROR) { I_Error("Internal game map '%s' not found\n", mapname); From 04e5cfd33863b42b699729070b022fb404a2e8e9 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 16 Sep 2022 22:51:02 +0100 Subject: [PATCH 24/60] Fix cups. * Required an adjustment of everywhere using G_MapNumber to return the raw header number, instead of off-by-one ala gamemap. * Fixing gamemap is a viable improvement for a future commit, but this commit is already pretty big. * Remove SCANTHINGS, since it used G_MapNumber and didn't work with long map names OR virtres anyways. * Support freeing new information in CLEAR LEVELS maincfg event, since I tried to use that to test cups. * Make Patch_Free's usability match Z_Free -- passing NULL is permitted and a no-op. --- src/d_main.c | 2 +- src/deh_soc.c | 205 ++++++++++++++++++++++++++----------------------- src/f_finale.c | 2 +- src/g_game.c | 12 +-- src/p_setup.c | 91 ++-------------------- src/p_setup.h | 3 - src/r_patch.c | 2 +- src/w_wad.c | 19 ----- 8 files changed, 125 insertions(+), 211 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 6d9c84a43..d74f42378 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1709,7 +1709,7 @@ void D_SRB2Main(void) // rei/miru: bootmap (Idea: starts the game on a predefined map) if (bootmap && !(M_CheckParm("-warp") && M_IsNextParm())) { - const INT32 bootMapNum = G_MapNumber(bootmap); + const INT32 bootMapNum = G_MapNumber(bootmap)+1; if (mapheaderinfo[bootMapNum]) { diff --git a/src/deh_soc.c b/src/deh_soc.c index e574b0c5e..023a7648a 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -159,12 +159,22 @@ void clear_levels(void) P_DeleteFlickies(i); P_DeleteGrades(i); + Patch_Free(mapheaderinfo[i]->thumbnailPic); + Patch_Free(mapheaderinfo[i]->minimapPic); + Z_Free(mapheaderinfo[i]->nextlevel); + Z_Free(mapheaderinfo[i]->marathonnext); + + Z_Free(mapheaderinfo[i]->lumpname); + Z_Free(mapheaderinfo[i]); mapheaderinfo[i] = NULL; } - // Realloc the one for the current gamemap as a safeguard - P_AllocMapHeader(gamemap-1); + nummapheaders = 0; + + // Realloc the one for the current gamemap as a safeguard -- TODO: BAD + if (Playing()) + P_AllocMapHeader(gamemap-1); } // TODO: Figure out how to do undolines for this.... @@ -1090,23 +1100,23 @@ void readlevelheader(MYFILE *f, char * name) const INT32 num = G_MapNumber(name); - if (num > NUMMAPS) + if (num >= NUMMAPS) { I_Error("Too many maps!"); } - if (f->wad > mainwads && num <= nummapheaders) + if (f->wad > mainwads && num < nummapheaders) { // only mark as a major mod if it replaces an already-existing mapheaderinfo G_SetGameModified(multiplayer, true); } // Reset all previous map header information - P_AllocMapHeader((INT16)(num-1)); + P_AllocMapHeader((INT16)(num)); - if (mapheaderinfo[num-1]->lumpname == NULL) + if (mapheaderinfo[num]->lumpname == NULL) { - mapheaderinfo[num-1]->lumpname = Z_StrDup(name); + mapheaderinfo[num]->lumpname = Z_StrDup(name); } do @@ -1145,16 +1155,16 @@ void readlevelheader(MYFILE *f, char * name) if (fastcmp(word, "LEVELNAME")) { - deh_strlcpy(mapheaderinfo[num-1]->lvlttl, word2, - sizeof(mapheaderinfo[num-1]->lvlttl), va("Level header %d: levelname", num)); - strlcpy(mapheaderinfo[num-1]->selectheading, word2, sizeof(mapheaderinfo[num-1]->selectheading)); // not deh_ so only complains once + deh_strlcpy(mapheaderinfo[num]->lvlttl, word2, + sizeof(mapheaderinfo[num]->lvlttl), va("Level header %d: levelname", num)); + strlcpy(mapheaderinfo[num]->selectheading, word2, sizeof(mapheaderinfo[num]->selectheading)); // not deh_ so only complains once continue; } // CHEAP HACK: move this over here for lowercase subtitles if (fastcmp(word, "SUBTITLE")) { - deh_strlcpy(mapheaderinfo[num-1]->subttl, word2, - sizeof(mapheaderinfo[num-1]->subttl), va("Level header %d: subtitle", num)); + deh_strlcpy(mapheaderinfo[num]->subttl, word2, + sizeof(mapheaderinfo[num]->subttl), va("Level header %d: subtitle", num)); continue; } @@ -1176,19 +1186,19 @@ void readlevelheader(MYFILE *f, char * name) } // Sanity limit of 128 params - if (mapheaderinfo[num-1]->numCustomOptions == 128) + if (mapheaderinfo[num]->numCustomOptions == 128) { deh_warning("Level header %d: too many custom parameters", num); continue; } - j = mapheaderinfo[num-1]->numCustomOptions++; + j = mapheaderinfo[num]->numCustomOptions++; - mapheaderinfo[num-1]->customopts = - Z_Realloc(mapheaderinfo[num-1]->customopts, - sizeof(customoption_t) * mapheaderinfo[num-1]->numCustomOptions, PU_STATIC, NULL); + mapheaderinfo[num]->customopts = + Z_Realloc(mapheaderinfo[num]->customopts, + sizeof(customoption_t) * mapheaderinfo[num]->numCustomOptions, PU_STATIC, NULL); // Newly allocated - modoption = &mapheaderinfo[num-1]->customopts[j]; + modoption = &mapheaderinfo[num]->customopts[j]; strncpy(modoption->option, word, 31); modoption->option[31] = '\0'; @@ -1204,33 +1214,33 @@ void readlevelheader(MYFILE *f, char * name) if (fastcmp(word, "FLICKYLIST") || fastcmp(word, "ANIMALLIST")) { if (fastcmp(word2, "NONE")) - P_DeleteFlickies(num-1); + P_DeleteFlickies(num); else if (fastcmp(word2, "DEMO")) - P_SetDemoFlickies(num-1); + P_SetDemoFlickies(num); else if (fastcmp(word2, "ALL")) { mobjtype_t tmpflickies[MAXFLICKIES]; - for (mapheaderinfo[num-1]->numFlickies = 0; - ((mapheaderinfo[num-1]->numFlickies < MAXFLICKIES) && FLICKYTYPES[mapheaderinfo[num-1]->numFlickies].type); - mapheaderinfo[num-1]->numFlickies++) - tmpflickies[mapheaderinfo[num-1]->numFlickies] = FLICKYTYPES[mapheaderinfo[num-1]->numFlickies].type; + for (mapheaderinfo[num]->numFlickies = 0; + ((mapheaderinfo[num]->numFlickies < MAXFLICKIES) && FLICKYTYPES[mapheaderinfo[num]->numFlickies].type); + mapheaderinfo[num]->numFlickies++) + tmpflickies[mapheaderinfo[num]->numFlickies] = FLICKYTYPES[mapheaderinfo[num]->numFlickies].type; - if (mapheaderinfo[num-1]->numFlickies) // just in case... + if (mapheaderinfo[num]->numFlickies) // just in case... { - size_t newsize = sizeof(mobjtype_t) * mapheaderinfo[num-1]->numFlickies; - mapheaderinfo[num-1]->flickies = Z_Realloc(mapheaderinfo[num-1]->flickies, newsize, PU_STATIC, NULL); - M_Memcpy(mapheaderinfo[num-1]->flickies, tmpflickies, newsize); + size_t newsize = sizeof(mobjtype_t) * mapheaderinfo[num]->numFlickies; + mapheaderinfo[num]->flickies = Z_Realloc(mapheaderinfo[num]->flickies, newsize, PU_STATIC, NULL); + M_Memcpy(mapheaderinfo[num]->flickies, tmpflickies, newsize); } } else { mobjtype_t tmpflickies[MAXFLICKIES]; - mapheaderinfo[num-1]->numFlickies = 0; + mapheaderinfo[num]->numFlickies = 0; tmp = strtok(word2,","); // get up to the first MAXFLICKIES flickies do { - if (mapheaderinfo[num-1]->numFlickies == MAXFLICKIES) // never going to get above that number + if (mapheaderinfo[num]->numFlickies == MAXFLICKIES) // never going to get above that number { deh_warning("Level header %d: too many flickies\n", num); break; @@ -1244,7 +1254,7 @@ void readlevelheader(MYFILE *f, char * name) //deh_warning("Level header %d: unknown flicky mobj type %s\n", num, tmp); -- no need for this line as get_mobjtype complains too continue; } - tmpflickies[mapheaderinfo[num-1]->numFlickies] = i; + tmpflickies[mapheaderinfo[num]->numFlickies] = i; } else // ...or a quick, limited selection of default flickies! { @@ -1257,17 +1267,17 @@ void readlevelheader(MYFILE *f, char * name) deh_warning("Level header %d: unknown flicky selection %s\n", num, tmp); continue; } - tmpflickies[mapheaderinfo[num-1]->numFlickies] = FLICKYTYPES[i].type; + tmpflickies[mapheaderinfo[num]->numFlickies] = FLICKYTYPES[i].type; } - mapheaderinfo[num-1]->numFlickies++; + mapheaderinfo[num]->numFlickies++; } while ((tmp = strtok(NULL,",")) != NULL); - if (mapheaderinfo[num-1]->numFlickies) + if (mapheaderinfo[num]->numFlickies) { - size_t newsize = sizeof(mobjtype_t) * mapheaderinfo[num-1]->numFlickies; - mapheaderinfo[num-1]->flickies = Z_Realloc(mapheaderinfo[num-1]->flickies, newsize, PU_STATIC, NULL); + size_t newsize = sizeof(mobjtype_t) * mapheaderinfo[num]->numFlickies; + mapheaderinfo[num]->flickies = Z_Realloc(mapheaderinfo[num]->flickies, newsize, PU_STATIC, NULL); // now we add them to the list! - M_Memcpy(mapheaderinfo[num-1]->flickies, tmpflickies, newsize); + M_Memcpy(mapheaderinfo[num]->flickies, tmpflickies, newsize); } else deh_warning("Level header %d: no valid flicky types found\n", num); @@ -1277,38 +1287,38 @@ void readlevelheader(MYFILE *f, char * name) // Strings that can be truncated else if (fastcmp(word, "NEXTLEVEL")) { - mapheaderinfo[num-1]->nextlevel = Z_StrDup(word2); + mapheaderinfo[num]->nextlevel = Z_StrDup(word2); } else if (fastcmp(word, "MARATHONNEXT")) { - mapheaderinfo[num-1]->marathonnext = Z_StrDup(word2); + mapheaderinfo[num]->marathonnext = Z_StrDup(word2); } else if (fastcmp(word, "ZONETITLE")) { - deh_strlcpy(mapheaderinfo[num-1]->zonttl, word2, - sizeof(mapheaderinfo[num-1]->zonttl), va("Level header %d: zonetitle", num)); + deh_strlcpy(mapheaderinfo[num]->zonttl, word2, + sizeof(mapheaderinfo[num]->zonttl), va("Level header %d: zonetitle", num)); } else if (fastcmp(word, "SCRIPTNAME")) { - deh_strlcpy(mapheaderinfo[num-1]->scriptname, word2, - sizeof(mapheaderinfo[num-1]->scriptname), va("Level header %d: scriptname", num)); + deh_strlcpy(mapheaderinfo[num]->scriptname, word2, + sizeof(mapheaderinfo[num]->scriptname), va("Level header %d: scriptname", num)); } else if (fastcmp(word, "RUNSOC")) { - deh_strlcpy(mapheaderinfo[num-1]->runsoc, word2, - sizeof(mapheaderinfo[num-1]->runsoc), va("Level header %d: runsoc", num)); + deh_strlcpy(mapheaderinfo[num]->runsoc, word2, + sizeof(mapheaderinfo[num]->runsoc), va("Level header %d: runsoc", num)); } else if (fastcmp(word, "ACT")) { if (i >= 0 && i <= 99) // 0 for no act number - mapheaderinfo[num-1]->actnum = (UINT8)i; + mapheaderinfo[num]->actnum = (UINT8)i; else deh_warning("Level header %d: invalid act number %d", num, i); } else if (fastcmp(word, "TYPEOFLEVEL")) { if (i) // it's just a number - mapheaderinfo[num-1]->typeoflevel = (UINT32)i; + mapheaderinfo[num]->typeoflevel = (UINT32)i; else { UINT32 tol = 0; @@ -1321,152 +1331,152 @@ void readlevelheader(MYFILE *f, char * name) deh_warning("Level header %d: unknown typeoflevel flag %s\n", num, tmp); tol |= TYPEOFLEVEL[i].flag; } while((tmp = strtok(NULL,",")) != NULL); - mapheaderinfo[num-1]->typeoflevel = tol; + mapheaderinfo[num]->typeoflevel = tol; } } else if (fastcmp(word, "KEYWORDS")) { - deh_strlcpy(mapheaderinfo[num-1]->keywords, word2, - sizeof(mapheaderinfo[num-1]->keywords), va("Level header %d: keywords", num)); + deh_strlcpy(mapheaderinfo[num]->keywords, word2, + sizeof(mapheaderinfo[num]->keywords), va("Level header %d: keywords", num)); } else if (fastcmp(word, "MUSIC")) { if (fastcmp(word2, "NONE")) - mapheaderinfo[num-1]->musname[0] = 0; // becomes empty string + mapheaderinfo[num]->musname[0] = 0; // becomes empty string else { - deh_strlcpy(mapheaderinfo[num-1]->musname, word2, - sizeof(mapheaderinfo[num-1]->musname), va("Level header %d: music", num)); + deh_strlcpy(mapheaderinfo[num]->musname, word2, + sizeof(mapheaderinfo[num]->musname), va("Level header %d: music", num)); } } else if (fastcmp(word, "MUSICSLOT")) deh_warning("Level header %d: MusicSlot parameter is deprecated and will be removed.\nUse \"Music\" instead.", num); else if (fastcmp(word, "MUSICTRACK")) - mapheaderinfo[num-1]->mustrack = ((UINT16)i - 1); + mapheaderinfo[num]->mustrack = ((UINT16)i - 1); else if (fastcmp(word, "MUSICPOS")) - mapheaderinfo[num-1]->muspos = (UINT32)get_number(word2); + mapheaderinfo[num]->muspos = (UINT32)get_number(word2); else if (fastcmp(word, "FORCECHARACTER")) { - strlcpy(mapheaderinfo[num-1]->forcecharacter, word2, SKINNAMESIZE+1); - strlwr(mapheaderinfo[num-1]->forcecharacter); // skin names are lowercase + strlcpy(mapheaderinfo[num]->forcecharacter, word2, SKINNAMESIZE+1); + strlwr(mapheaderinfo[num]->forcecharacter); // skin names are lowercase } else if (fastcmp(word, "WEATHER")) - mapheaderinfo[num-1]->weather = get_precip(word2); + mapheaderinfo[num]->weather = get_precip(word2); else if (fastcmp(word, "SKYTEXTURE")) - deh_strlcpy(mapheaderinfo[num-1]->skytexture, word2, - sizeof(mapheaderinfo[num-1]->skytexture), va("Level header %d: sky texture", num)); + deh_strlcpy(mapheaderinfo[num]->skytexture, word2, + sizeof(mapheaderinfo[num]->skytexture), va("Level header %d: sky texture", num)); else if (fastcmp(word, "PRECUTSCENENUM")) - mapheaderinfo[num-1]->precutscenenum = (UINT8)i; + mapheaderinfo[num]->precutscenenum = (UINT8)i; else if (fastcmp(word, "CUTSCENENUM")) - mapheaderinfo[num-1]->cutscenenum = (UINT8)i; + mapheaderinfo[num]->cutscenenum = (UINT8)i; else if (fastcmp(word, "PALETTE")) - mapheaderinfo[num-1]->palette = (UINT16)i; + mapheaderinfo[num]->palette = (UINT16)i; else if (fastcmp(word, "ENCOREPAL")) - mapheaderinfo[num-1]->encorepal = (UINT16)i; + mapheaderinfo[num]->encorepal = (UINT16)i; else if (fastcmp(word, "NUMLAPS")) - mapheaderinfo[num-1]->numlaps = (UINT8)i; + mapheaderinfo[num]->numlaps = (UINT8)i; else if (fastcmp(word, "UNLOCKABLE")) { if (i >= 0 && i <= MAXUNLOCKABLES) // 0 for no unlock required, anything else requires something - mapheaderinfo[num-1]->unlockrequired = (SINT8)i - 1; + mapheaderinfo[num]->unlockrequired = (SINT8)i - 1; else deh_warning("Level header %d: invalid unlockable number %d", num, i); } else if (fastcmp(word, "SKYBOXSCALE")) - mapheaderinfo[num-1]->skybox_scalex = mapheaderinfo[num-1]->skybox_scaley = mapheaderinfo[num-1]->skybox_scalez = (INT16)i; + mapheaderinfo[num]->skybox_scalex = mapheaderinfo[num]->skybox_scaley = mapheaderinfo[num]->skybox_scalez = (INT16)i; else if (fastcmp(word, "SKYBOXSCALEX")) - mapheaderinfo[num-1]->skybox_scalex = (INT16)i; + mapheaderinfo[num]->skybox_scalex = (INT16)i; else if (fastcmp(word, "SKYBOXSCALEY")) - mapheaderinfo[num-1]->skybox_scaley = (INT16)i; + mapheaderinfo[num]->skybox_scaley = (INT16)i; else if (fastcmp(word, "SKYBOXSCALEZ")) - mapheaderinfo[num-1]->skybox_scalez = (INT16)i; + mapheaderinfo[num]->skybox_scalez = (INT16)i; else if (fastcmp(word, "LEVELFLAGS")) - mapheaderinfo[num-1]->levelflags = get_number(word2); + mapheaderinfo[num]->levelflags = get_number(word2); else if (fastcmp(word, "MENUFLAGS")) - mapheaderinfo[num-1]->menuflags = get_number(word2); + mapheaderinfo[num]->menuflags = get_number(word2); // SRB2Kart else if (fastcmp(word, "MOBJSCALE")) - mapheaderinfo[num-1]->mobj_scale = get_number(word2); + mapheaderinfo[num]->mobj_scale = get_number(word2); else if (fastcmp(word, "DEFAULTWAYPOINTRADIUS")) - mapheaderinfo[num-1]->default_waypoint_radius = get_number(word2); + mapheaderinfo[num]->default_waypoint_radius = get_number(word2); else if (fastcmp(word, "LIGHTCONTRAST")) { - mapheaderinfo[num-1]->light_contrast = (UINT8)i; + mapheaderinfo[num]->light_contrast = (UINT8)i; } else if (fastcmp(word, "LIGHTANGLE")) { if (fastcmp(word2, "EVEN")) { - mapheaderinfo[num-1]->use_light_angle = false; - mapheaderinfo[num-1]->light_angle = 0; + mapheaderinfo[num]->use_light_angle = false; + mapheaderinfo[num]->light_angle = 0; } else { - mapheaderinfo[num-1]->use_light_angle = true; - mapheaderinfo[num-1]->light_angle = FixedAngle(FloatToFixed(atof(word2))); + mapheaderinfo[num]->use_light_angle = true; + mapheaderinfo[num]->light_angle = FixedAngle(FloatToFixed(atof(word2))); } } // Individual triggers for level flags, for ease of use (and 2.0 compatibility) else if (fastcmp(word, "SCRIPTISFILE")) { if (i || word2[0] == 'T' || word2[0] == 'Y') - mapheaderinfo[num-1]->levelflags |= LF_SCRIPTISFILE; + mapheaderinfo[num]->levelflags |= LF_SCRIPTISFILE; else - mapheaderinfo[num-1]->levelflags &= ~LF_SCRIPTISFILE; + mapheaderinfo[num]->levelflags &= ~LF_SCRIPTISFILE; } else if (fastcmp(word, "NOZONE")) { if (i || word2[0] == 'T' || word2[0] == 'Y') - mapheaderinfo[num-1]->levelflags |= LF_NOZONE; + mapheaderinfo[num]->levelflags |= LF_NOZONE; else - mapheaderinfo[num-1]->levelflags &= ~LF_NOZONE; + mapheaderinfo[num]->levelflags &= ~LF_NOZONE; } else if (fastcmp(word, "SECTIONRACE")) { if (i || word2[0] == 'T' || word2[0] == 'Y') - mapheaderinfo[num-1]->levelflags |= LF_SECTIONRACE; + mapheaderinfo[num]->levelflags |= LF_SECTIONRACE; else - mapheaderinfo[num-1]->levelflags &= ~LF_SECTIONRACE; + mapheaderinfo[num]->levelflags &= ~LF_SECTIONRACE; } else if (fastcmp(word, "SUBTRACTNUM")) { if (i || word2[0] == 'T' || word2[0] == 'Y') - mapheaderinfo[num-1]->levelflags |= LF_SUBTRACTNUM; + mapheaderinfo[num]->levelflags |= LF_SUBTRACTNUM; else - mapheaderinfo[num-1]->levelflags &= ~LF_SUBTRACTNUM; + mapheaderinfo[num]->levelflags &= ~LF_SUBTRACTNUM; } // Individual triggers for menu flags else if (fastcmp(word, "HIDDEN")) { if (i || word2[0] == 'T' || word2[0] == 'Y') - mapheaderinfo[num-1]->menuflags |= LF2_HIDEINMENU; + mapheaderinfo[num]->menuflags |= LF2_HIDEINMENU; else - mapheaderinfo[num-1]->menuflags &= ~LF2_HIDEINMENU; + mapheaderinfo[num]->menuflags &= ~LF2_HIDEINMENU; } else if (fastcmp(word, "HIDEINSTATS")) { if (i || word2[0] == 'T' || word2[0] == 'Y') - mapheaderinfo[num-1]->menuflags |= LF2_HIDEINSTATS; + mapheaderinfo[num]->menuflags |= LF2_HIDEINSTATS; else - mapheaderinfo[num-1]->menuflags &= ~LF2_HIDEINSTATS; + mapheaderinfo[num]->menuflags &= ~LF2_HIDEINSTATS; } else if (fastcmp(word, "TIMEATTACK") || fastcmp(word, "RECORDATTACK")) { // RECORDATTACK is an accepted alias if (i || word2[0] == 'T' || word2[0] == 'Y') - mapheaderinfo[num-1]->menuflags &= ~LF2_NOTIMEATTACK; + mapheaderinfo[num]->menuflags &= ~LF2_NOTIMEATTACK; else - mapheaderinfo[num-1]->menuflags |= LF2_NOTIMEATTACK; + mapheaderinfo[num]->menuflags |= LF2_NOTIMEATTACK; } else if (fastcmp(word, "VISITNEEDED")) { if (i || word2[0] == 'T' || word2[0] == 'Y') - mapheaderinfo[num-1]->menuflags |= LF2_VISITNEEDED; + mapheaderinfo[num]->menuflags |= LF2_VISITNEEDED; else - mapheaderinfo[num-1]->menuflags &= ~LF2_VISITNEEDED; + mapheaderinfo[num]->menuflags &= ~LF2_VISITNEEDED; } else if (fastcmp(word, "GRAVITY")) - mapheaderinfo[num-1]->gravity = FLOAT_TO_FIXED(atof(word2)); + mapheaderinfo[num]->gravity = FLOAT_TO_FIXED(atof(word2)); else deh_warning("Level header %d: unknown word '%s'", num, word); } @@ -3319,8 +3329,9 @@ void readcupheader(MYFILE *f, cupheader_t *cup) break; } - cup->levellist[cup->numlevels] = Z_StrDup(word2); + cup->levellist[cup->numlevels] = Z_StrDup(tmp); cup->numlevels++; + CONS_Printf("tmp = %s\n", tmp); } while((tmp = strtok(NULL,",")) != NULL); } else if (fastcmp(word, "BONUSGAME")) diff --git a/src/f_finale.c b/src/f_finale.c index 877d1892b..ec70678b0 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1851,7 +1851,7 @@ void F_StartTitleScreen(void) { mapthing_t *startpos; - const INT32 titleMapNum = G_MapNumber(titlemap); + const INT32 titleMapNum = G_MapNumber(titlemap)+1; gamestate_t prevwipegamestate = wipegamestate; titlemapinaction = TITLEMAP_LOADING; titlemapcameraref = NULL; diff --git a/src/g_game.c b/src/g_game.c index b020179fa..6333326c9 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -625,7 +625,7 @@ INT32 G_MapNumber(const char * name) } } - return map + 1; + return map; } /** Clips the console player's mouse aiming to the current view. @@ -3610,7 +3610,7 @@ static void G_DoCompleted(void) if (mapheaderinfo[mNextNum]) { - nextmap = (INT16)(mNextNum-1); + nextmap = (INT16)mNextNum; } } else if (grandprixinfo.gp == true) @@ -3645,7 +3645,7 @@ static void G_DoCompleted(void) if (mapheaderinfo[nextNum]) { - nextmap = (INT16)(nextNum-1); + nextmap = (INT16)nextNum; if (marathonmode && nextmap == spmarathon_start-1) nextmap = 1100-1; // No infinite loop for you } @@ -3681,7 +3681,7 @@ static void G_DoCompleted(void) if (!mapheaderinfo[mNextNum]) cm = -1; // guarantee error execution else - cm = (INT16)(mNextNum-1); + cm = (INT16)mNextNum; } else { @@ -3690,7 +3690,7 @@ static void G_DoCompleted(void) if (!mapheaderinfo[nextNum]) cm = -1; // guarantee error execution else - cm = (INT16)(nextNum-1); + cm = (INT16)nextNum; } if (cm >= NUMMAPS || cm < 0) // out of range (either 1100ish or error) @@ -4892,7 +4892,7 @@ INT32 G_FindMapByNameOrCode(const char *mapname, char **realmapnamep) } else { - newmapnum = G_MapNumber(mapname); + newmapnum = G_MapNumber(mapname)+1; if (newmapnum > nummapheaders) return G_FindMap(mapname, realmapnamep, NULL, NULL); diff --git a/src/p_setup.c b/src/p_setup.c index 958e1c638..5aa38aa99 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -363,29 +363,17 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) { const INT16 num = (INT16)(i-1); - if (mapheaderinfo[num]->thumbnailPic) - { - Patch_Free(mapheaderinfo[num]->thumbnailPic); - mapheaderinfo[num]->thumbnailPic = NULL; - } + Patch_Free(mapheaderinfo[num]->thumbnailPic); + mapheaderinfo[num]->thumbnailPic = NULL; - if (mapheaderinfo[num]->minimapPic) - { - Patch_Free(mapheaderinfo[num]->minimapPic); - mapheaderinfo[num]->minimapPic = NULL; - } + Patch_Free(mapheaderinfo[num]->minimapPic); + mapheaderinfo[num]->minimapPic = NULL; - if (mapheaderinfo[num]->nextlevel) - { - Z_Free(mapheaderinfo[num]->nextlevel); - mapheaderinfo[num]->nextlevel = NULL; - } + Z_Free(mapheaderinfo[num]->nextlevel); + mapheaderinfo[num]->nextlevel = NULL; - if (mapheaderinfo[num]->marathonnext) - { - Z_Free(mapheaderinfo[num]->marathonnext); - mapheaderinfo[num]->marathonnext = NULL; - } + Z_Free(mapheaderinfo[num]->marathonnext); + mapheaderinfo[num]->marathonnext = NULL; mapheaderinfo[num]->lvlttl[0] = '\0'; mapheaderinfo[num]->selectheading[0] = '\0'; @@ -762,69 +750,6 @@ void P_ReloadRings(void) } } -#ifdef SCANTHINGS -void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum) -{ - size_t i, n; - UINT8 *data, *datastart; - UINT16 type, maprings; - INT16 tol; - UINT32 flags; - - tol = mapheaderinfo[mapnum-1]->typeoflevel; - flags = mapheaderinfo[mapnum-1]->levelflags; - - n = W_LumpLengthPwad(wadnum, lumpnum) / (5 * sizeof (INT16)); - //CONS_Printf("%u map things found!\n", n); - - maprings = 0; - data = datastart = W_CacheLumpNumPwad(wadnum, lumpnum, PU_STATIC); - for (i = 0; i < n; i++) - { - data += 3 * sizeof (INT16); // skip x y position, angle - type = READUINT16(data) & 4095; - data += sizeof (INT16); // skip options - - if (mt->type == mobjinfo[MT_RANDOMITEM].doomednum) - { - nummapboxes++; - } - else if (mt->type == mobjinfo[MT_BATTLECAPSULE].doomednum) - { - maptargets++; - } - else if (mt->type == mobjinfo[MT_RING].doomednum) - { - maprings++; - } - else - { - switch (type) - { - case 603: // 10 diagonal rings - maprings += 10; - break; - case 600: // 5 vertical rings - case 601: // 5 vertical rings - case 602: // 5 diagonal rings - maprings += 5; - break; - case 604: // 8 circle rings - maprings += 8; - break; - case 605: // 16 circle rings - maprings += 16; - break; - } - } - } - Z_Free(datastart); - - if (maprings) - CONS_Printf("%s has %u rings\n", G_BuildMapName(mapnum), maprings); -} -#endif - static void P_SpawnMapThings(boolean spawnemblems) { size_t i; diff --git a/src/p_setup.h b/src/p_setup.h index b36451dfb..4eaf46105 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -99,9 +99,6 @@ extern mapthing_t *mapthings; extern UINT16 p_adding_file; void P_SetupLevelSky(const char *skytexname, boolean global); -#ifdef SCANTHINGS -void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum); -#endif void P_RespawnThings(void); boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate); #ifdef HWRENDER diff --git a/src/r_patch.c b/src/r_patch.c index 544c15ae8..8cf89fa3d 100644 --- a/src/r_patch.c +++ b/src/r_patch.c @@ -101,7 +101,7 @@ static void Patch_FreeData(patch_t *patch) void Patch_Free(patch_t *patch) { - if (patch == missingpat) + if (!patch || patch == missingpat) return; Patch_FreeData(patch); Z_Free(patch); diff --git a/src/w_wad.c b/src/w_wad.c index 490954dd4..3c739493c 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -64,9 +64,6 @@ #include "i_system.h" #include "md5.h" #include "lua_script.h" -#ifdef SCANTHINGS -#include "p_setup.h" // P_ScanThings -#endif #include "g_game.h" // G_SetGameModified #include "k_terrain.h" @@ -274,22 +271,6 @@ static inline void W_LoadDehackedLumps(UINT16 wadnum, boolean mainfile) DEH_LoadDehackedLumpPwad(wadnum, lump, mainfile); } } - -#ifdef SCANTHINGS - // Scan maps for emblems 'n shit - { - lumpinfo_t *lump_p = wadfiles[wadnum]->lumpinfo; - for (lump = 0; lump < wadfiles[wadnum]->numlumps; lump++, lump_p++) - { - const char *name = lump_p->name; - if (name[0] == 'M' && name[1] == 'A' && name[2] == 'P' && name[5]=='\0') - { - INT16 mapnum = (INT16)G_MapNumber(name); - P_ScanThings(mapnum, wadnum, lump + ML_THINGS); - } - } - } -#endif } /** Compute MD5 message digest for bytes read from STREAM of this filname. From 6bd29a51b142feaafb6249101bbc37e9bb69d2fb Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 16 Sep 2022 23:13:54 +0100 Subject: [PATCH 25/60] Remove test strtok print --- src/deh_soc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index 023a7648a..8d988968b 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -3331,7 +3331,6 @@ void readcupheader(MYFILE *f, cupheader_t *cup) cup->levellist[cup->numlevels] = Z_StrDup(tmp); cup->numlevels++; - CONS_Printf("tmp = %s\n", tmp); } while((tmp = strtok(NULL,",")) != NULL); } else if (fastcmp(word, "BONUSGAME")) From dcd63aece977a24b672b31259c9292c0271f7214 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 16 Sep 2022 23:40:42 +0100 Subject: [PATCH 26/60] Repair bootmap. We're not even going to use this feature, but it showed up as nonsensical while reviewing, and would take more work to strip out --- src/d_main.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index d74f42378..d4c003a89 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1709,19 +1709,14 @@ void D_SRB2Main(void) // rei/miru: bootmap (Idea: starts the game on a predefined map) if (bootmap && !(M_CheckParm("-warp") && M_IsNextParm())) { - const INT32 bootMapNum = G_MapNumber(bootmap)+1; + pstartmap = G_MapNumber(bootmap)+1; - if (mapheaderinfo[bootMapNum]) + if (pstartmap == nummapheaders) { - pstartmap = bootMapNum; - - if (pstartmap < 1 || pstartmap > NUMMAPS) - I_Error("Cannot warp to map %d (out of range)\n", pstartmap); - else - { - autostart = true; - } + I_Error("Cannot warp to map %s (not found)\n", bootmap); } + + autostart = true; } if (autostart || netgame) From acc92ba4c95fda76c6cf905a503363fd99add8a6 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 17 Sep 2022 00:02:54 +0100 Subject: [PATCH 27/60] Catch some areas that previously checked for map lump, but stopped doing so for a bit. --- src/g_demo.c | 2 +- src/g_game.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/g_demo.c b/src/g_demo.c index 08e685621..a0d7ccbd6 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -2918,7 +2918,7 @@ void G_DoPlayDemo(char *defdemoname) demo_p += 4; // Extrainfo location // ...*map* not loaded? - if (!gamemap || (gamemap > NUMMAPS) || !mapheaderinfo[gamemap-1]) + if (!gamemap || (gamemap > NUMMAPS) || !mapheaderinfo[gamemap-1] || mapheaderinfo[gamemap-1]->lumpnum == LUMPERROR) { snprintf(msg, 1024, M_GetText("%s features a course that is not currently loaded.\n"), pdemoname); CONS_Alert(CONS_ERROR, "%s", msg); diff --git a/src/g_game.c b/src/g_game.c index 6333326c9..85c2264e4 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3698,9 +3698,9 @@ static void G_DoCompleted(void) 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 (cm < 0 || cm >= nummapheaders) + if (cm < 0 || cm >= nummapheaders || mapheaderinfo[cm]->lumpnum == LUMPERROR) { - CONS_Alert(CONS_ERROR, M_GetText("Next map given (MAP %d) doesn't exist! Reverting to MAP01.\n"), cm+1); + CONS_Alert(CONS_ERROR, M_GetText("Next map given (id %d) doesn't exist! Reverting to id 0.\n"), cm+1); cm = 0; break; } From 1fbd5655f585454ff1f40ae87c738d47b9ce7d0a Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 17 Sep 2022 00:03:49 +0100 Subject: [PATCH 28/60] Replay hut: Show nolvl if the user hasn't added the map, or blanklvl if they have. --- src/k_menudraw.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/k_menudraw.c b/src/k_menudraw.c index e1dbc5bc9..c51f9fdaa 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -3860,10 +3860,15 @@ void M_DrawReplayHutReplayInfo(void) if (mapheaderinfo[extrasmenu.demolist[dir_on[menudepthleft]].map]) { patch = mapheaderinfo[extrasmenu.demolist[dir_on[menudepthleft]].map]->thumbnailPic; + if (!patch) + { + patch = blanklvl; + } } - - if (!patch) + else if (!patch) + { patch = W_CachePatchName("M_NOLVL", PU_CACHE); + } if (!(extrasmenu.demolist[dir_on[menudepthleft]].kartspeed & DF_ENCORE)) V_DrawSmallScaledPatch(x, y, V_SNAPTOTOP, patch); From accb88869d7478272bbd434f3e01075939ec6fc7 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 17 Sep 2022 00:43:26 +0100 Subject: [PATCH 29/60] Don't strip previous thumbnail/minimap information on header replace, since the lumpnum will remain the same otherwise --- src/p_setup.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index 5aa38aa99..a0c97d9e8 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -363,12 +363,6 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) { const INT16 num = (INT16)(i-1); - Patch_Free(mapheaderinfo[num]->thumbnailPic); - mapheaderinfo[num]->thumbnailPic = NULL; - - Patch_Free(mapheaderinfo[num]->minimapPic); - mapheaderinfo[num]->minimapPic = NULL; - Z_Free(mapheaderinfo[num]->nextlevel); mapheaderinfo[num]->nextlevel = NULL; From 7e17f5456cd31fb8f2b31fa404493eb2021d734b Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 17 Sep 2022 13:07:48 +0100 Subject: [PATCH 30/60] I_Error in all situations where mapheaders were previously allocated outside of SOC. Also: - improved error prints for SOC condition definitions - improved bounds checking to use `nummapheaders` for iterating over mapheaderinfo There are still situations that use NUMMAPS like mapvisited, randmapbuffer, etc, which need to be addressed before merger. --- src/command.c | 36 ----------------------------- src/d_netcmd.c | 20 +++++++++++----- src/deh_soc.c | 58 +++++++++++++++++++++++------------------------ src/g_demo.c | 2 +- src/g_game.c | 45 ++++++++++++------------------------ src/k_menudraw.c | 4 ++-- src/k_menufunc.c | 10 ++++---- src/lua_baselib.c | 6 ++--- src/lua_maplib.c | 6 ++--- src/p_saveg.c | 8 +++---- src/y_inter.c | 4 ++-- 11 files changed, 77 insertions(+), 122 deletions(-) diff --git a/src/command.c b/src/command.c index 1439463c1..ec56ad20f 100644 --- a/src/command.c +++ b/src/command.c @@ -1961,42 +1961,6 @@ void CV_AddValue(consvar_t *var, INT32 increment) if (var->PossibleValue) { - /* - if (var == &cv_nextmap) - { - // Special case for the nextmap variable, used only directly from the menu - INT32 oldvalue = var->value - 1, gt; - gt = cv_newgametype.value; - { - newvalue = var->value - 1; - do - { - if(increment > 0) // Going up! - { - if (++newvalue == NUMMAPS) - newvalue = -1; - } - else // Going down! - { - if (--newvalue == -2) - newvalue = NUMMAPS-1; - } - - if (newvalue == oldvalue) - break; // don't loop forever if there's none of a certain gametype - - if(!mapheaderinfo[newvalue]) - continue; // Don't allocate the header. That just makes memory usage skyrocket. - - } while (!M_CanShowLevelInList(newvalue, gt)); - - var->value = newvalue + 1; - var->func(); - return; - } - } - else - */ #define MINVAL 0 #define MAXVAL 1 if (var->PossibleValue[MINVAL].strvalue && !strcmp(var->PossibleValue[MINVAL].strvalue, "MIN")) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index b2333902b..ab56fc296 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -4905,8 +4905,9 @@ static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum) { INT32 i; UINT8 gt, secondgt; + INT16 tempvotelevels[4][2]; - if (playernum != serverplayer && !IsPlayerAdmin(playernum)) + if (playernum != serverplayer) // admin shouldn't be able to set up vote... { CONS_Alert(CONS_WARNING, M_GetText("Illegal vote setup received from %s\n"), player_names[playernum]); if (server) @@ -4919,13 +4920,20 @@ static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum) for (i = 0; i < 4; i++) { - votelevels[i][0] = (UINT16)READUINT16(*cp); - votelevels[i][1] = gt; - if (!mapheaderinfo[votelevels[i][0]]) - P_AllocMapHeader(votelevels[i][0]); + tempvotelevels[i][0] = (UINT16)READUINT16(*cp); + tempvotelevels[i][1] = gt; + if (tempvotelevels[i][0] < nummapheaders && mapheaderinfo[tempvotelevels[i][0]]) + continue; + + if (server) + I_Error("Got_SetupVotecmd: Internal map ID %d not found (nummapheaders = %d)", tempvotelevels[i][0], nummapheaders); + CONS_Alert(CONS_WARNING, M_GetText("Vote setup with bad map ID %d received from %s\n"), tempvotelevels[i][0], player_names[playernum]); + return; } - votelevels[2][1] = secondgt; + tempvotelevels[2][1] = secondgt; + + memcpy(votelevels, tempvotelevels, sizeof(votelevels)); G_SetGamestate(GS_VOTING); Y_StartVote(); diff --git a/src/deh_soc.c b/src/deh_soc.c index 8d988968b..b060ae538 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -140,41 +140,39 @@ void clear_conditionsets(void) void clear_levels(void) { - INT16 i; - // 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) + while (nummapheaders > 0) { - if (!mapheaderinfo[i]) + nummapheaders--; + + if (!mapheaderinfo[nummapheaders]) continue; - if (strcmp(mapheaderinfo[i]->lumpname, tutorialmap) == 0) // Sal: Is this needed...? + if (strcmp(mapheaderinfo[nummapheaders]->lumpname, tutorialmap) == 0) // Sal: Is this needed...? continue; // Custom map header info // (no need to set num to 0, we're freeing the entire header shortly) - Z_Free(mapheaderinfo[i]->customopts); + Z_Free(mapheaderinfo[nummapheaders]->customopts); - P_DeleteFlickies(i); - P_DeleteGrades(i); + P_DeleteFlickies(nummapheaders); + P_DeleteGrades(nummapheaders); - Patch_Free(mapheaderinfo[i]->thumbnailPic); - Patch_Free(mapheaderinfo[i]->minimapPic); - Z_Free(mapheaderinfo[i]->nextlevel); - Z_Free(mapheaderinfo[i]->marathonnext); + Patch_Free(mapheaderinfo[nummapheaders]->thumbnailPic); + Patch_Free(mapheaderinfo[nummapheaders]->minimapPic); + Z_Free(mapheaderinfo[nummapheaders]->nextlevel); + Z_Free(mapheaderinfo[nummapheaders]->marathonnext); - Z_Free(mapheaderinfo[i]->lumpname); + Z_Free(mapheaderinfo[nummapheaders]->lumpname); - Z_Free(mapheaderinfo[i]); - mapheaderinfo[i] = NULL; + Z_Free(mapheaderinfo[nummapheaders]); + mapheaderinfo[nummapheaders] = NULL; } - nummapheaders = 0; - - // Realloc the one for the current gamemap as a safeguard -- TODO: BAD + // Realloc the one for the current gamemap as a safeguard if (Playing()) - P_AllocMapHeader(gamemap-1); + COM_BufAddText("exitgame"); // Command_ExitGame_f() but delayed } // TODO: Figure out how to do undolines for this.... @@ -2610,7 +2608,7 @@ static void readcondition(UINT8 set, UINT32 id, char *word2) if (!params[0]) { - deh_warning("condition line is empty"); + deh_warning("condition line is empty for condition ID %d", id); return; } @@ -2630,7 +2628,7 @@ static void readcondition(UINT8 set, UINT32 id, char *word2) if (x1 < 0 || x1 >= PWRLV_NUMTYPES) { - deh_warning("Power level type %d out of range (0 - %d)", x1, PWRLV_NUMTYPES-1); + deh_warning("Power level type %d out of range (0 - %d) for condition ID %d", x1, PWRLV_NUMTYPES-1, id); return; } } @@ -2652,9 +2650,9 @@ static void readcondition(UINT8 set, UINT32 id, char *word2) ty = UC_MAPVISITED + offset; re = G_MapNumber(params[1]); - if (re < 0 || re >= NUMMAPS) + if (re == nummapheaders) { - deh_warning("Level number %d out of range (1 - %d)", re, NUMMAPS); + deh_warning("Invalid level %s for condition ID %d", params[1], id); return; } } @@ -2665,9 +2663,9 @@ static void readcondition(UINT8 set, UINT32 id, char *word2) re = atoi(params[2]); x1 = G_MapNumber(params[1]); - if (x1 < 0 || x1 >= NUMMAPS) + if (x1 == nummapheaders) { - deh_warning("Level number %d out of range (1 - %d)", x1, NUMMAPS); + deh_warning("Invalid level %s for condition ID %d", params[1], id); return; } } @@ -2680,7 +2678,7 @@ static void readcondition(UINT8 set, UINT32 id, char *word2) // constrained by 32 bits if (re < 0 || re > 31) { - deh_warning("Trigger ID %d out of range (0 - 31)", re); + deh_warning("Trigger ID %d out of range (0 - 31) for condition ID %d", re, id); return; } } @@ -2698,7 +2696,7 @@ static void readcondition(UINT8 set, UINT32 id, char *word2) if (re <= 0 || re > MAXEMBLEMS) { - deh_warning("Emblem %d out of range (1 - %d)", re, MAXEMBLEMS); + deh_warning("Emblem %d out of range (1 - %d) for condition ID %d", re, MAXEMBLEMS, id); return; } } @@ -2710,7 +2708,7 @@ static void readcondition(UINT8 set, UINT32 id, char *word2) if (re <= 0 || re > MAXEXTRAEMBLEMS) { - deh_warning("Extra emblem %d out of range (1 - %d)", re, MAXEXTRAEMBLEMS); + deh_warning("Extra emblem %d out of range (1 - %d) for condition ID %d", re, MAXEXTRAEMBLEMS, id); return; } } @@ -2722,13 +2720,13 @@ static void readcondition(UINT8 set, UINT32 id, char *word2) if (re <= 0 || re > MAXCONDITIONSETS) { - deh_warning("Condition set %d out of range (1 - %d)", re, MAXCONDITIONSETS); + deh_warning("Condition set %d out of range (1 - %d) for condition ID %d", re, MAXCONDITIONSETS, id); return; } } else { - deh_warning("Invalid condition name %s", params[0]); + deh_warning("Invalid condition name %s for condition ID %d", params[0], id); return; } diff --git a/src/g_demo.c b/src/g_demo.c index a0d7ccbd6..59b943d97 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -2918,7 +2918,7 @@ void G_DoPlayDemo(char *defdemoname) demo_p += 4; // Extrainfo location // ...*map* not loaded? - if (!gamemap || (gamemap > NUMMAPS) || !mapheaderinfo[gamemap-1] || mapheaderinfo[gamemap-1]->lumpnum == LUMPERROR) + if (!gamemap || (gamemap > nummapheaders) || !mapheaderinfo[gamemap-1] || mapheaderinfo[gamemap-1]->lumpnum == LUMPERROR) { snprintf(msg, 1024, M_GetText("%s features a course that is not currently loaded.\n"), pdemoname); CONS_Alert(CONS_ERROR, "%s", msg); diff --git a/src/g_game.c b/src/g_game.c index 85c2264e4..1cdcaaae4 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3292,13 +3292,13 @@ UINT32 G_TOLFlag(INT32 pgametype) return gametypetol[pgametype]; } -static UINT32 TOLMaps(UINT32 tolflags) +static INT32 TOLMaps(UINT32 tolflags) { - UINT32 num = 0; - UINT32 i; + INT32 num = 0; + INT32 i; // Find all the maps that are ok and and put them in an array. - for (i = 0; i < NUMMAPS; i++) + for (i = 0; i < nummapheaders; i++) { if (!mapheaderinfo[i]) continue; @@ -3330,7 +3330,7 @@ INT16 G_RandMap(UINT32 tolflags, INT16 pprevmap, UINT8 ignorebuffer, UINT8 maphe if (!okmaps) { //CONS_Printf("(making okmaps)\n"); - okmaps = Z_Malloc(NUMMAPS * sizeof(INT16), PU_STATIC, NULL); + okmaps = Z_Malloc(nummapheaders * sizeof(INT16), PU_STATIC, NULL); } if (extbuffer != NULL) @@ -3347,7 +3347,7 @@ tryagain: usehellmaps = (maphell == 0 ? false : (maphell == 2 || M_RandomChance(FRACUNIT/100))); // 1% chance of Hell // Find all the maps that are ok and and put them in an array. - for (ix = 0; ix < NUMMAPS; ix++) + for (ix = 0; ix < nummapheaders; ix++) { boolean isokmap = true; @@ -3456,7 +3456,7 @@ tryagain: void G_AddMapToBuffer(INT16 map) { - INT16 bufx, refreshnum = max(0, ((INT32)TOLMaps(G_TOLFlag(gametype)))-3); + INT16 bufx, refreshnum = max(0, (TOLMaps(G_TOLFlag(gametype)))-3); // Add the map to the buffer. for (bufx = NUMMAPS-1; bufx > 0; bufx--) @@ -3665,7 +3665,7 @@ static void G_DoCompleted(void) { register INT16 cm = nextmap; UINT32 tolflag = G_TOLFlag(gametype); - UINT8 visitedmap[(NUMMAPS+7)/8]; + UINT8 visitedmap[(nummapheaders+7)/8]; memset(visitedmap, 0, sizeof (visitedmap)); @@ -3693,7 +3693,7 @@ static void G_DoCompleted(void) cm = (INT16)nextNum; } - if (cm >= NUMMAPS || cm < 0) // out of range (either 1100ish or error) + if (cm >= nummapheaders || cm < 0) // out of range (either 1100ish or error) { cm = nextmap; //Start the loop again so that the error checking below is executed. @@ -3722,7 +3722,7 @@ static void G_DoCompleted(void) if (nextmap >= 1100-1 && nextmap <= 1102-1 && !(gametyperules & GTR_CAMPAIGN)) nextmap = (INT16)(spstage_start-1); - if (nextmap < 0 || (nextmap >= NUMMAPS && nextmap < 1100-1) || nextmap > 1103-1) + if (nextmap < 0 || (nextmap >= nummapheaders && nextmap < 1100-1) || nextmap > 1103-1) I_Error("Followed map %d to invalid map %d\n", prevmap + 1, nextmap + 1); if (!spec) @@ -3747,7 +3747,7 @@ static void G_DoCompleted(void) // 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]) - P_AllocMapHeader(nextmap); + I_Error("G_DoCompleted: Internal map ID %d not found (nummapheaders = %d)\n", nextmap, nummapheaders); // Set up power level gametype scrambles K_SetPowerLevelScrambles(powertype); @@ -4614,11 +4614,6 @@ void G_InitNew(UINT8 pencoremode, INT32 map, boolean resetplayer, boolean skippr gamemap = map; - // gamemap changed; we assume that its map header is always valid, - // so make it so - if(!mapheaderinfo[gamemap-1]) - P_AllocMapHeader(gamemap-1); - maptol = mapheaderinfo[gamemap-1]->typeoflevel; globalweather = mapheaderinfo[gamemap-1]->weather; @@ -4655,11 +4650,8 @@ char *G_BuildMapTitle(INT32 mapnum) { char *title = NULL; - if (mapnum == 0) - return Z_StrDup("Random"); - - if (!mapheaderinfo[mapnum-1]) - P_AllocMapHeader(mapnum-1); + if (!mapnum || mapnum > nummapheaders || !mapheaderinfo[mapnum-1]) + I_Error("G_BuildMapTitle: Internal map ID %d not found (nummapheaders = %d)", mapnum-1, nummapheaders); if (strcmp(mapheaderinfo[mapnum-1]->lvlttl, "")) { @@ -4755,19 +4747,12 @@ INT32 G_FindMap(const char *mapname, char **foundmapnamep, mapnamelen = strlen(mapname); - /* Count available maps; how ugly. */ - for (i = 0, freqc = 0; i < NUMMAPS; ++i) - { - if (mapheaderinfo[i]) - freqc++; - } - - freq = ZZ_Calloc(freqc * sizeof (mapsearchfreq_t)); + freq = ZZ_Calloc(nummapheaders * sizeof (mapsearchfreq_t)); wanttable = !!( freqp ); freqc = 0; - for (i = 0, mapnum = 1; i < NUMMAPS; ++i, ++mapnum) + for (i = 0, mapnum = 1; i < nummapheaders; ++i, ++mapnum) if (mapheaderinfo[i]) { if (!( realmapname = G_BuildMapTitle(mapnum) )) diff --git a/src/k_menudraw.c b/src/k_menudraw.c index c51f9fdaa..54513b105 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -2117,10 +2117,10 @@ void M_DrawLevelSelect(void) { INT16 lvlx = t, lvly = y; - while (!M_CanShowLevelInList(map, levellist.newgametype) && map < NUMMAPS) + while (!M_CanShowLevelInList(map, levellist.newgametype) && map < nummapheaders) map++; - if (map >= NUMMAPS) + if (map >= nummapheaders) break; if (i == levellist.cursor && tatransition) diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 0df40ab4c..f930b1dfa 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -3229,7 +3229,7 @@ INT16 M_CountLevelsToShowInList(UINT8 gt) { INT16 mapnum, count = 0; - for (mapnum = 0; mapnum < NUMMAPS; mapnum++) + for (mapnum = 0; mapnum < nummapheaders; mapnum++) if (M_CanShowLevelInList(mapnum, gt)) count++; @@ -3240,7 +3240,7 @@ INT16 M_GetFirstLevelInList(UINT8 gt) { INT16 mapnum; - for (mapnum = 0; mapnum < NUMMAPS; mapnum++) + for (mapnum = 0; mapnum < nummapheaders; mapnum++) if (M_CanShowLevelInList(mapnum, gt)) return mapnum; @@ -3549,16 +3549,16 @@ void M_LevelSelectHandler(INT32 choice) { map++; - while (!M_CanShowLevelInList(map, levellist.newgametype) && map < NUMMAPS) + while (!M_CanShowLevelInList(map, levellist.newgametype) && map < nummapheaders) map++; - if (map >= NUMMAPS) + if (map >= nummapheaders) break; add--; } - if (map >= NUMMAPS) + if (map >= nummapheaders) { // This shouldn't happen return; diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 41768b3da..1219c7ba9 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -3046,12 +3046,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 > nummapheaders) { return luaL_error(L, - "map number %d out of range (1 - %d)", + "map ID %d out of range (1 - %d)", map, - NUMMAPS + nummapheaders ); } name = G_BuildMapTitle(map); diff --git a/src/lua_maplib.c b/src/lua_maplib.c index ec5f18127..863821a9b 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -2085,8 +2085,8 @@ static int lib_getMapheaderinfo(lua_State *L) 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) + INT32 i = lua_tointeger(L, 1)-1; + if (i < 0 || i >= nummapheaders) return 0; LUA_PushUserdata(L, mapheaderinfo[i], META_MAPHEADER); //CONS_Printf(mapheaderinfo[i]->lvlttl); @@ -2104,7 +2104,7 @@ static int lib_getMapheaderinfo(lua_State *L) static int lib_nummapheaders(lua_State *L) { - lua_pushinteger(L, NUMMAPS); + lua_pushinteger(L, nummapheaders); return 1; } diff --git a/src/p_saveg.c b/src/p_saveg.c index b50175ee1..eaab7e899 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -4396,8 +4396,8 @@ static inline void P_UnArchiveSPGame(INT16 mapoverride) // gamemap changed; we assume that its map header is always valid, // so make it so - if(!mapheaderinfo[gamemap-1]) - P_AllocMapHeader(gamemap-1); + if (!gamemap || gamemap > nummapheaders || !mapheaderinfo[gamemap-1]) + I_Error("P_UnArchiveSPGame: Internal map ID %d not found (nummapheaders = %d)", gamemap-1, nummapheaders); //lastmapsaved = gamemap; lastmaploaded = gamemap; @@ -4568,8 +4568,8 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading) // gamemap changed; we assume that its map header is always valid, // so make it so - if(!mapheaderinfo[gamemap-1]) - P_AllocMapHeader(gamemap-1); + if (!gamemap || gamemap > nummapheaders || !mapheaderinfo[gamemap-1]) + I_Error("P_NetUnArchiveMisc: Internal map ID %d not found (nummapheaders = %d)", gamemap-1, nummapheaders); // tell the sound code to reset the music since we're skipping what // normally sets this flag diff --git a/src/y_inter.c b/src/y_inter.c index 61ebc20d5..ac6767f35 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -833,8 +833,8 @@ void Y_StartIntermission(void) //if (dedicated) return; // This should always exist, but just in case... - if (!mapheaderinfo[prevmap]) - P_AllocMapHeader(prevmap); + if (prevmap >= nummapheaders || !mapheaderinfo[prevmap]) + I_Error("Y_StartIntermission: Internal map ID %d not found (nummapheaders = %d)", prevmap, nummapheaders); switch (intertype) { From d42812d5b56c9929feb9e7c600cd9220e4f5a76a Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 17 Sep 2022 14:08:11 +0100 Subject: [PATCH 31/60] Don't select a map - whether random (voting screen, randommap command, etc) or specific (map command) if it has no associated lump. --- src/g_game.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 7bff448a5..b27e5e6cc 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3401,7 +3401,7 @@ tryagain: { boolean isokmap = true; - if (!mapheaderinfo[ix]) + if (!mapheaderinfo[ix] || mapheaderinfo[ix]->lumpnum == LUMPERROR) continue; if ((mapheaderinfo[ix]->typeoflevel & tolflags) != tolflags @@ -4803,8 +4803,10 @@ INT32 G_FindMap(const char *mapname, char **foundmapnamep, freqc = 0; for (i = 0, mapnum = 1; i < nummapheaders; ++i, ++mapnum) - if (mapheaderinfo[i]) { + if (!mapheaderinfo[i] || mapheaderinfo[i]->lumpnum == LUMPERROR) + continue; + if (!( realmapname = G_BuildMapTitle(mapnum) )) continue; @@ -4924,6 +4926,8 @@ INT32 G_FindMapByNameOrCode(const char *mapname, char **realmapnamep) { if (newmapnum < 1 || newmapnum > nummapheaders) return 0; + if (!mapheaderinfo[newmapnum-1] || mapheaderinfo[newmapnum-1]->lumpnum == LUMPERROR) + return 0; } else { From 8ea80d64efcc29372c0647aadd4049bffead765b Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 17 Sep 2022 16:13:50 +0100 Subject: [PATCH 32/60] Randmapbuffer now prepared for infinite maps - Now a struct with zone-allocated buffer member - Instead of bunging it on the end of the buffer, the time for G_SometimesGetDifferentGametype is its own struct member --- src/g_game.c | 84 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 59 insertions(+), 25 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index b27e5e6cc..90f8f68b1 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -331,7 +331,25 @@ boolean legitimateexit; // Did this client actually finish the match? boolean comebackshowninfo; // Have you already seen the "ATTACK OR PROTECT" message? tic_t curlap; // Current lap time tic_t bestlap; // Best lap time -static INT16 randmapbuffer[NUMMAPS+1]; // Buffer for maps RandMap is allowed to roll + +typedef struct +{ + INT16 *mapbuffer; // Pointer to zone memory + INT32 lastnummapheaders; // Reset if nummapheaders != this + UINT8 counttogametype; // Time to gametype change event +} randmaps_t; +static randmaps_t randmaps = {NULL, 0, 0}; + +static void G_ResetRandMapBuffer(void) +{ + INT32 i; + Z_Free(randmaps.mapbuffer); + randmaps.lastnummapheaders = nummapheaders; + randmaps.mapbuffer = Z_Malloc(randmaps.lastnummapheaders * sizeof(INT16), PU_STATIC, NULL); + for (i = 0; i < randmaps.lastnummapheaders; i++) + randmaps.mapbuffer[i] = -1; + //intentionally not resetting randmaps.counttogametype here +} // Grading UINT32 timesBeaten; @@ -3251,6 +3269,10 @@ INT16 G_SometimesGetDifferentGametype(UINT8 prefgametype) && ((gametyperules|gametypedefaultrules[prefgametype]) & GTR_CIRCUIT)); UINT8 encoremodifier = 0; + // -- the below is only necessary if you want to use randmaps.mapbuffer here + //if (randmaps.lastnummapheaders != nummapheaders) + //G_ResetRandMapBuffer(); + if (encorepossible) { if (encorescramble != -1) @@ -3281,21 +3303,21 @@ INT16 G_SometimesGetDifferentGametype(UINT8 prefgametype) if (!cv_kartvoterulechanges.value) // never return (gametype|encoremodifier); - if (randmapbuffer[NUMMAPS] > 0 && (cv_kartvoterulechanges.value != 3)) + if (randmaps.counttogametype > 0 && (cv_kartvoterulechanges.value != 3)) { - randmapbuffer[NUMMAPS]--; + randmaps.counttogametype--; return (gametype|encoremodifier); } switch (cv_kartvoterulechanges.value) // okay, we're having a gametype change! when's the next one, luv? { case 1: // sometimes - randmapbuffer[NUMMAPS] = 5; // per "cup" + randmaps.counttogametype = 5; // per "cup" break; default: // fallthrough - happens when clearing buffer, but needs a reasonable countdown if cvar is modified case 2: // frequent - randmapbuffer[NUMMAPS] = 2; // ...every 1/2th-ish cup? + randmaps.counttogametype = 2; // ...every 1/2th-ish cup? break; } @@ -3377,6 +3399,9 @@ INT16 G_RandMap(UINT32 tolflags, INT16 pprevmap, UINT8 ignorebuffer, UINT8 maphe UINT16 extbufsize = 0; boolean usehellmaps; // Only consider Hell maps in this pick + if (randmaps.lastnummapheaders != nummapheaders) + G_ResetRandMapBuffer(); + if (!okmaps) { //CONS_Printf("(making okmaps)\n"); @@ -3429,11 +3454,11 @@ tryagain: continue; } - for (bufx = 0; bufx < (maphell ? 3 : NUMMAPS); bufx++) + for (bufx = 0; bufx < (maphell ? 3 : randmaps.lastnummapheaders); bufx++) { - if (randmapbuffer[bufx] == -1) // Rest of buffer SHOULD be empty + if (randmaps.mapbuffer[bufx] == -1) // Rest of buffer SHOULD be empty break; - if (ix == randmapbuffer[bufx]) + if (ix == randmaps.mapbuffer[bufx]) { isokmap = false; break; @@ -3459,15 +3484,15 @@ tryagain: { if (!ignorebuffer) { - if (randmapbuffer[3] == -1) // Is the buffer basically empty? + if (randmaps.mapbuffer[3] == -1) // Is the buffer basically empty? { ignorebuffer = 1; // This will probably only help in situations where there's very few maps, but it's folly not to at least try it //CONS_Printf("RANDMAP - ignoring buffer\n"); goto tryagain; } - for (bufx = 3; bufx < NUMMAPS; bufx++) // Let's clear all but the three most recent maps... - randmapbuffer[bufx] = -1; + for (bufx = 3; bufx < randmaps.lastnummapheaders; bufx++) // Let's clear all but the three most recent maps... + randmaps.mapbuffer[bufx] = -1; //CONS_Printf("RANDMAP - emptying randmapbuffer\n"); goto tryagain; } @@ -3484,8 +3509,8 @@ tryagain: if (ignorebuffer == 1) { //CONS_Printf("(emptying randmapbuffer entirely)\n"); - for (bufx = 0; bufx < NUMMAPS; bufx++) - randmapbuffer[bufx] = -1; // if we're having trouble finding a map we should probably clear it + for (bufx = 0; bufx < randmaps.lastnummapheaders; bufx++) + randmaps.mapbuffer[bufx] = -1; // if we're having trouble finding a map we should probably clear it } } else @@ -3506,19 +3531,30 @@ tryagain: void G_AddMapToBuffer(INT16 map) { - INT16 bufx, refreshnum = max(0, (TOLMaps(G_TOLFlag(gametype)))-3); + INT16 bufx; + INT16 refreshnum = (TOLMaps(G_TOLFlag(gametype)))-3; - // Add the map to the buffer. - for (bufx = NUMMAPS-1; bufx > 0; bufx--) - randmapbuffer[bufx] = randmapbuffer[bufx-1]; - randmapbuffer[0] = map; + if (refreshnum < 0) + refreshnum = 3; + + if (nummapheaders != randmaps.lastnummapheaders) + { + G_ResetRandMapBuffer(); + } + else + { + for (bufx = randmaps.lastnummapheaders-1; bufx > 0; bufx--) + randmaps.mapbuffer[bufx] = randmaps.mapbuffer[bufx-1]; + } + + randmaps.mapbuffer[0] = map; // We're getting pretty full, so lets flush this for future usage. - if (randmapbuffer[refreshnum] != -1) + if (randmaps.mapbuffer[refreshnum] != -1) { // Clear all but the five most recent maps. - for (bufx = 5; bufx < NUMMAPS; bufx++) // bufx < refreshnum? Might not handle everything for gametype switches, though. - randmapbuffer[bufx] = -1; + for (bufx = 5; bufx < randmaps.lastnummapheaders; bufx++) + randmaps.mapbuffer[bufx] = -1; //CONS_Printf("Random map buffer has been flushed.\n"); } } @@ -4556,7 +4592,6 @@ cleanup: // void G_DeferedInitNew(boolean pencoremode, INT32 map, INT32 pickedchar, UINT8 ssplayers, boolean FLS) { - INT32 i; UINT16 color = SKINCOLOR_NONE; paused = false; @@ -4566,8 +4601,7 @@ void G_DeferedInitNew(boolean pencoremode, INT32 map, INT32 pickedchar, UINT8 ss G_FreeGhosts(); // TODO: do we actually need to do this? - for (i = 0; i < NUMMAPS+1; i++) - randmapbuffer[i] = -1; + G_ResetRandMapBuffer(); // this leave the actual game if needed SV_StartSinglePlayerServer(); @@ -4607,7 +4641,7 @@ void G_InitNew(UINT8 pencoremode, INT32 map, boolean resetplayer, boolean skippr S_ResumeAudio(); } - prevencoremode = ((gamestate == GS_TITLESCREEN) ? false : encoremode); + prevencoremode = ((!Playing()) ? false : encoremode); encoremode = pencoremode; legitimateexit = false; // SRB2Kart From b68710faf2dba1ec92e68a8fba96443acca12d30 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 17 Sep 2022 19:10:04 +0100 Subject: [PATCH 33/60] Rework special nextmap events. - G_MapNumber now handles special NEXTMAP_ nextmapspecial_t constants that exist at the end of the available type. - Cleanup of G_DoCompleted - Add bounds checking to the various SOC maincfg map starts (spstage_start, etc) - Add lump checking to titlemap behaviour --- src/d_main.c | 2 +- src/deh_soc.c | 28 +++++++++---- src/f_finale.c | 13 +++--- src/g_game.c | 105 +++++++++++++++++++++++++---------------------- src/g_game.h | 12 ++++++ src/k_menudraw.c | 2 +- src/m_cond.c | 8 ++-- 7 files changed, 101 insertions(+), 69 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index d4c003a89..c69850aa8 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1711,7 +1711,7 @@ void D_SRB2Main(void) { pstartmap = G_MapNumber(bootmap)+1; - if (pstartmap == nummapheaders) + if (pstartmap > nummapheaders) { I_Error("Cannot warp to map %s (not found)\n", bootmap); } diff --git a/src/deh_soc.c b/src/deh_soc.c index b060ae538..596926287 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -2650,7 +2650,7 @@ static void readcondition(UINT8 set, UINT32 id, char *word2) ty = UC_MAPVISITED + offset; re = G_MapNumber(params[1]); - if (re == nummapheaders) + if (re >= nummapheaders) { deh_warning("Invalid level %s for condition ID %d", params[1], id); return; @@ -2663,7 +2663,7 @@ static void readcondition(UINT8 set, UINT32 id, char *word2) re = atoi(params[2]); x1 = G_MapNumber(params[1]); - if (x1 == nummapheaders) + if (x1 >= nummapheaders) { deh_warning("Invalid level %s for condition ID %d", params[1], id); return; @@ -2867,21 +2867,33 @@ void readmaincfg(MYFILE *f) // TODO: Use map name string // Haven't done it because of how special stage ends are handled // Though, we likely won't be using these for Kart anyhow - spstage_start = spmarathon_start = (INT16)G_MapNumber(word2); + INT16 maptmp = G_MapNumber(word2)+1; + if (maptmp <= nummapheaders) + spstage_start = spmarathon_start = maptmp; } else if (fastcmp(word, "SPMARATHON_START")) { - spmarathon_start = (INT16)G_MapNumber(word2); + INT16 maptmp = G_MapNumber(word2)+1; + if (maptmp <= nummapheaders) + spmarathon_start = maptmp; } else if (fastcmp(word, "SSTAGE_START")) { - sstage_start = (INT16)G_MapNumber(word2); - sstage_end = (INT16)(sstage_start+7); // 7 special stages total plus one weirdo + INT16 maptmp = G_MapNumber(word2)+1; + if (maptmp <= nummapheaders) + { + sstage_start = maptmp; + sstage_end = (sstage_start+13); // 14 special stages + } } else if (fastcmp(word, "SMPSTAGE_START")) { - smpstage_start = (INT16)G_MapNumber(word2); - smpstage_end = (INT16)(smpstage_start+6); // 7 special stages total + INT16 maptmp = G_MapNumber(word2)+1; + if (maptmp <= nummapheaders) + { + smpstage_start = maptmp; + smpstage_end = (smpstage_start+13); // 14 special stages + } } else if (fastcmp(word, "REDTEAM")) { diff --git a/src/f_finale.c b/src/f_finale.c index 8da3564d7..3a77e3ec5 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1837,6 +1837,7 @@ static void F_CacheTitleScreen(void) void F_StartTitleScreen(void) { + INT32 titleMapNum; setup_numplayers = 0; if (gamestate != GS_TITLESCREEN && gamestate != GS_WAITINGPLAYERS) @@ -1848,18 +1849,20 @@ void F_StartTitleScreen(void) else wipegamestate = GS_TITLESCREEN; - if (titlemap) + if (titlemap + && ((titleMapNum = G_MapNumber(titlemap)) < nummapheaders) + && mapheaderinfo[titleMapNum] + && mapheaderinfo[titleMapNum]->lumpnum != LUMPERROR) { mapthing_t *startpos; - const INT32 titleMapNum = G_MapNumber(titlemap)+1; gamestate_t prevwipegamestate = wipegamestate; titlemapinaction = TITLEMAP_LOADING; titlemapcameraref = NULL; - gamemap = titleMapNum; + gamemap = titleMapNum+1; - maptol = mapheaderinfo[gamemap-1]->typeoflevel; - globalweather = mapheaderinfo[gamemap-1]->weather; + maptol = mapheaderinfo[titleMapNum]->typeoflevel; + globalweather = mapheaderinfo[titleMapNum]->weather; G_DoLoadLevel(true); if (!titleMapNum) diff --git a/src/g_game.c b/src/g_game.c index 90f8f68b1..fbfc3512a 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -659,21 +659,35 @@ const char *G_BuildMapName(INT32 map) * * \param name Map name; * \return Map number. - * \sa G_BuildMapName + * \sa G_BuildMapName, nextmapspecial_t */ INT32 G_MapNumber(const char * name) { - INT32 map; - - for (map = 0; map < nummapheaders; ++map) + if (strncasecmp("NEXTMAP_", name, 8) != 0) { - if (strcasecmp(mapheaderinfo[map]->lumpname, name) == 0) + INT32 map; + + for (map = 0; map < nummapheaders; ++map) { - break; + if (strcasecmp(mapheaderinfo[map]->lumpname, name) == 0) + { + break; + } } + + return map; } - return map; + name += 8; + + if (strcasecmp("EVALUATION", name) == 0) + return NEXTMAP_EVALUATION; + if (strcasecmp("CREDITS", name) == 0) + return NEXTMAP_CREDITS; + if (strcasecmp("CEREMONY", name) == 0) + return NEXTMAP_CEREMONY; + //if (strcasecmp("TITLE", name) == 0) + return NEXTMAP_TITLE; } /** Clips the console player's mouse aiming to the current view. @@ -3709,17 +3723,21 @@ static void G_DoCompleted(void) { if (grandprixinfo.roundnum >= grandprixinfo.cup->numlevels) // On final map { - nextmap = 1101; // ceremonymap + nextmap = NEXTMAP_CEREMONY; // ceremonymap } else { // Proceed to next map const INT32 cupLevelNum = G_MapNumber(grandprixinfo.cup->levellist[grandprixinfo.roundnum]); - if (mapheaderinfo[cupLevelNum]) + if (cupLevelNum < nummapheaders && mapheaderinfo[cupLevelNum]) { nextmap = cupLevelNum; } + else + { + nextmap = prevmap; // Prevent uninitialised use + } grandprixinfo.roundnum++; } @@ -3733,7 +3751,7 @@ static void G_DoCompleted(void) { nextmap = (INT16)nextNum; if (marathonmode && nextmap == spmarathon_start-1) - nextmap = 1100-1; // No infinite loop for you + nextmap = NEXTMAP_TITLE; // No infinite loop for you } } @@ -3745,48 +3763,46 @@ static void G_DoCompleted(void) // a map of the proper gametype -- skip levels that don't support // the current gametype. (Helps avoid playing boss levels in Race, // for instance). - if (!modeattacking && grandprixinfo.gp == false && bossinfo.boss == false) + if (K_CanChangeRules()) { - if (nextmap >= 0 && nextmap < NUMMAPS) + if (cv_advancemap.value == 0) // Stay on same map. + { + nextmap = prevmap; + } + else if (cv_advancemap.value == 2) // Go to random map. + { + nextmap = G_RandMap(G_TOLFlag(gametype), prevmap, 0, 0, false, NULL); + } + else if (nextmap < NEXTMAP_SPECIAL) { register INT16 cm = nextmap; UINT32 tolflag = G_TOLFlag(gametype); - UINT8 visitedmap[(nummapheaders+7)/8]; + UINT8* visitedmap; - memset(visitedmap, 0, sizeof (visitedmap)); + visitedmap = Z_Calloc(((nummapheaders+7)/8)*sizeof(UINT8), PU_STATIC, NULL); - while (!mapheaderinfo[cm] || !(mapheaderinfo[cm]->typeoflevel & tolflag)) + while (!mapheaderinfo[cm] || mapheaderinfo[cm]->lumpnum == LUMPERROR || !(mapheaderinfo[cm]->typeoflevel & tolflag)) { visitedmap[cm/8] |= (1<<(cm&7)); if (!mapheaderinfo[cm]) cm = -1; // guarantee error execution else if (marathonmode && mapheaderinfo[cm]->marathonnext) { - const INT32 mNextNum = G_MapNumber(mapheaderinfo[gamemap-1]->marathonnext); - - if (!mapheaderinfo[mNextNum]) - cm = -1; // guarantee error execution - else - cm = (INT16)mNextNum; + cm = G_MapNumber(mapheaderinfo[cm]->marathonnext); } else { - const INT32 nextNum = G_MapNumber(mapheaderinfo[gamemap-1]->nextlevel); - - if (!mapheaderinfo[nextNum]) - cm = -1; // guarantee error execution - else - cm = (INT16)nextNum; + cm = G_MapNumber(mapheaderinfo[cm]->nextlevel); } - if (cm >= nummapheaders || cm < 0) // out of range (either 1100ish or error) + if (cm >= nummapheaders) // out of range (either NEXTMAP_SPECIAL 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 (cm < 0 || cm >= nummapheaders || mapheaderinfo[cm]->lumpnum == LUMPERROR) + if (cm >= nummapheaders || mapheaderinfo[cm]->lumpnum == LUMPERROR) { - CONS_Alert(CONS_ERROR, M_GetText("Next map given (id %d) doesn't exist! Reverting to id 0.\n"), cm+1); + CONS_Alert(CONS_ERROR, M_GetText("Next map given (ID %d) doesn't exist! Reverting to id 0.\n"), cm+1); cm = 0; break; } @@ -3797,28 +3813,17 @@ static void G_DoCompleted(void) // We got stuck in a loop, came back to the map we started on // without finding one supporting the current gametype. // Thus, print a warning, and just use this map anyways. - CONS_Alert(CONS_WARNING, M_GetText("Can't find a compatible map after map %d; using map %d anyway\n"), prevmap+1, cm+1); + CONS_Alert(CONS_WARNING, M_GetText("Can't find a compatible map after ID %d; using ID %d anyway\n"), prevmap, cm); break; } } + Z_Free(visitedmap); nextmap = cm; } - - // wrap around in race - if (nextmap >= 1100-1 && nextmap <= 1102-1 && !(gametyperules & GTR_CAMPAIGN)) + // wrap around + else if (!(gametyperules & GTR_CAMPAIGN)) nextmap = (INT16)(spstage_start-1); - if (nextmap < 0 || (nextmap >= nummapheaders && nextmap < 1100-1) || nextmap > 1103-1) - I_Error("Followed map %d to invalid map %d\n", prevmap + 1, nextmap + 1); - - if (!spec) - lastmap = nextmap; // Remember last map for when you come out of the special stage. - } - - automapactive = false; - - if (!(gametyperules & GTR_CAMPAIGN)) - { if (cv_advancemap.value == 0) // Stay on same map. { nextmap = prevmap; @@ -3832,7 +3837,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 < NEXTMAP_SPECIAL && (nextmap >= nummapheaders || !mapheaderinfo[nextmap] || mapheaderinfo[nextmap]->lumpnum == LUMPERROR)) I_Error("G_DoCompleted: Internal map ID %d not found (nummapheaders = %d)\n", nextmap, nummapheaders); // Set up power level gametype scrambles @@ -3899,7 +3904,7 @@ void G_AfterIntermission(void) F_StartCustomCutscene(mapheaderinfo[gamemap-1]->cutscenenum-1, false, false); else { - if (nextmap < 1100-1) + if (nextmap < NEXTMAP_SPECIAL) G_NextLevel(); else G_EndGame(); @@ -4043,17 +4048,17 @@ void G_EndGame(void) // Only do evaluation and credits in coop games. if (gametyperules & GTR_CAMPAIGN) { - if (nextmap == 1103-1) // end game with ending + if (nextmap == NEXTMAP_CEREMONY) // end game with ending { F_StartEnding(); return; } - if (nextmap == 1102-1) // end game with credits + if (nextmap == NEXTMAP_CREDITS) // end game with credits { F_StartCredits(); return; } - if (nextmap == 1101-1) // end game with evaluation + if (nextmap == NEXTMAP_EVALUATION) // end game with evaluation { F_StartGameEvaluation(); return; diff --git a/src/g_game.h b/src/g_game.h index 9da38f681..18ef96ad8 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -36,6 +36,18 @@ extern tic_t levelstarttic; // for modding? extern INT16 prevmap, nextmap; + +// see also G_MapNumber +typedef enum +{ + NEXTMAP_RESERVED = INT16_MAX, // so nextmap+1 doesn't roll over -- remove when gamemap is made 0-indexed + NEXTMAP_TITLE = INT16_MAX-1, + NEXTMAP_EVALUATION = INT16_MAX-2, + NEXTMAP_CREDITS = INT16_MAX-3, + NEXTMAP_CEREMONY = INT16_MAX-4, + NEXTMAP_SPECIAL = NEXTMAP_CEREMONY +} nextmapspecial_t; + extern INT32 gameovertics; extern UINT8 ammoremovaltics; extern tic_t timeinmap; // Ticker for time spent in level (used for levelcard display) diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 54513b105..8a1e368d3 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -1849,7 +1849,7 @@ static void M_DrawCupPreview(INT16 y, cupheader_t *cup) INT32 cupLevelNum = G_MapNumber(cup->levellist[i]); patch_t *PictureOfLevel = NULL; - if (mapheaderinfo[cupLevelNum]) + if (cupLevelNum < nummapheaders && mapheaderinfo[cupLevelNum]) { PictureOfLevel = mapheaderinfo[cupLevelNum]->thumbnailPic; } diff --git a/src/m_cond.c b/src/m_cond.c index b54e40388..cf2c41c3f 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -305,7 +305,7 @@ UINT8 M_CheckLevelEmblems(void) checkLevel = G_MapNumber(emblemlocations[i].level); - if (!mapheaderinfo[checkLevel]) + if (checkLevel >= nummapheaders || !mapheaderinfo[checkLevel]) continue; levelnum = checkLevel; @@ -345,7 +345,7 @@ UINT8 M_CompletionEmblems(void) // Bah! Duplication sucks, but it's for a separa checkLevel = G_MapNumber(emblemlocations[i].level); - if (!mapheaderinfo[checkLevel]) + if (checkLevel >= nummapheaders || !mapheaderinfo[checkLevel]) continue; levelnum = checkLevel; @@ -472,7 +472,7 @@ UINT8 M_GotLowEnoughTime(INT32 tictime) INT32 curtics = 0; INT32 i; - for (i = 0; i < NUMMAPS; ++i) + for (i = 0; i < nummapheaders; ++i) { if (!mapheaderinfo[i] || (mapheaderinfo[i]->menuflags & LF2_NOTIMEATTACK)) continue; @@ -508,7 +508,7 @@ emblem_t *M_GetLevelEmblems(INT32 mapnum) { INT32 checkLevel = G_MapNumber(emblemlocations[i].level); - if (!mapheaderinfo[checkLevel]) + if (checkLevel >= nummapheaders || !mapheaderinfo[checkLevel]) continue; if (checkLevel == map) From 7d990c4f1526d1a15d60de5c20c9c3501ff0b684 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 18 Sep 2022 20:00:28 +0100 Subject: [PATCH 34/60] Rework nextmap to be automatic - Refactor significantly (now has its own func, `G_GetNextMap`) - If gametype uses cups, iterate through cups to find the current level, then grab the next valid level - If not, get the next valid mapheader for your gametype - SOC `nextmap`/`marathonnext` is not just deprecated but REMOVED - Hide the NEXTMAP_ constants again, but leave support dummied out for if we have them publically accessible again - Also get rid of a bunch of OTHER mapheader stuff we're never gonna use - NiGHTS Grades? NOPE - Vanilla titlecard patches? NOPE - Boss music fadeout/replacement? NOPE - Select Heading? NOPE - You've been blocked. - Don't show maps without lumps on the level select list - this is me being petty, but making it NOTIMEATTACK in SOC instead of TIMEATTACK so we can reconsider the maps with/without them. --- src/d_main.c | 16 +- src/deh_lua.c | 12 -- src/deh_soc.c | 31 +--- src/deh_tables.c | 11 -- src/deh_tables.h | 1 - src/doomstat.h | 53 ------- src/f_finale.c | 2 +- src/g_game.c | 389 +++++++++++++++++++++++++++-------------------- src/g_game.h | 1 + src/k_menufunc.c | 23 +-- src/lua_maplib.c | 29 ---- src/p_enemy.c | 22 --- src/p_setup.c | 120 --------------- src/p_setup.h | 5 - src/p_user.c | 7 - 15 files changed, 250 insertions(+), 472 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index c69850aa8..87057a22f 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -939,14 +939,16 @@ void D_StartTitle(void) if (netgame) { - if (gametyperules & GTR_CAMPAIGN) - { - G_SetGamestate(GS_WAITINGPLAYERS); // hack to prevent a command repeat + G_SetGamestate(GS_WAITINGPLAYERS); // hack to prevent a command repeat - if (server) - { - COM_BufAddText(va("map %s\n", G_BuildMapName(spstage_start))); - } + if (server) + { + INT16 mapnum = G_GetFirstMapOfGametype(gametype)+1; + + if (i > nummapheaders) + I_Error("D_StartTitle: No valid map ID found!?"); + + COM_BufAddText(va("map %s\n", G_BuildMapName(mapnum))); } return; diff --git a/src/deh_lua.c b/src/deh_lua.c index 8e6e88360..9c407dbda 100644 --- a/src/deh_lua.c +++ b/src/deh_lua.c @@ -475,18 +475,6 @@ static inline int lib_getenum(lua_State *L) } return luaL_error(L, "skincolor '%s' could not be found.\n", word); } - else if (fastncmp("GRADE_",word,6)) - { - p = word+6; - for (i = 0; NIGHTSGRADE_LIST[i]; i++) - if (*p == NIGHTSGRADE_LIST[i]) - { - lua_pushinteger(L, i); - return 1; - } - if (mathlib) return luaL_error(L, "NiGHTS grade '%s' could not be found.\n", word); - return 0; - } else if (fastncmp("PRECIP_",word,7)) { p = word+7; for (i = 0; i < MAXPRECIP; i++) diff --git a/src/deh_soc.c b/src/deh_soc.c index 596926287..103579cb1 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -157,12 +157,9 @@ void clear_levels(void) Z_Free(mapheaderinfo[nummapheaders]->customopts); P_DeleteFlickies(nummapheaders); - P_DeleteGrades(nummapheaders); Patch_Free(mapheaderinfo[nummapheaders]->thumbnailPic); Patch_Free(mapheaderinfo[nummapheaders]->minimapPic); - Z_Free(mapheaderinfo[nummapheaders]->nextlevel); - Z_Free(mapheaderinfo[nummapheaders]->marathonnext); Z_Free(mapheaderinfo[nummapheaders]->lumpname); @@ -1155,7 +1152,6 @@ void readlevelheader(MYFILE *f, char * name) { deh_strlcpy(mapheaderinfo[num]->lvlttl, word2, sizeof(mapheaderinfo[num]->lvlttl), va("Level header %d: levelname", num)); - strlcpy(mapheaderinfo[num]->selectheading, word2, sizeof(mapheaderinfo[num]->selectheading)); // not deh_ so only complains once continue; } // CHEAP HACK: move this over here for lowercase subtitles @@ -1283,14 +1279,6 @@ void readlevelheader(MYFILE *f, char * name) } // Strings that can be truncated - else if (fastcmp(word, "NEXTLEVEL")) - { - mapheaderinfo[num]->nextlevel = Z_StrDup(word2); - } - else if (fastcmp(word, "MARATHONNEXT")) - { - mapheaderinfo[num]->marathonnext = Z_StrDup(word2); - } else if (fastcmp(word, "ZONETITLE")) { deh_strlcpy(mapheaderinfo[num]->zonttl, word2, @@ -1459,12 +1447,12 @@ void readlevelheader(MYFILE *f, char * name) else mapheaderinfo[num]->menuflags &= ~LF2_HIDEINSTATS; } - else if (fastcmp(word, "TIMEATTACK") || fastcmp(word, "RECORDATTACK")) + else if (fastcmp(word, "NOTIMEATTACK") || fastcmp(word, "NORECORDATTACK")) { // RECORDATTACK is an accepted alias if (i || word2[0] == 'T' || word2[0] == 'Y') - mapheaderinfo[num]->menuflags &= ~LF2_NOTIMEATTACK; - else mapheaderinfo[num]->menuflags |= LF2_NOTIMEATTACK; + else + mapheaderinfo[num]->menuflags &= ~LF2_NOTIMEATTACK; } else if (fastcmp(word, "VISITNEEDED")) { @@ -4060,19 +4048,6 @@ static fixed_t find_const(const char **rword) free(word); return 0; } - else if (fastncmp("GRADE_",word,6)) - { - char *p = word+6; - for (i = 0; NIGHTSGRADE_LIST[i]; i++) - if (*p == NIGHTSGRADE_LIST[i]) - { - free(word); - return i; - } - const_warning("NiGHTS grade",word); - free(word); - return 0; - } for (i = 0; INT_CONST[i].n; i++) if (fastcmp(word,INT_CONST[i].n)) { free(word); diff --git a/src/deh_tables.c b/src/deh_tables.c index 5fe950e9e..dc8c29e29 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -32,17 +32,6 @@ char *FREE_MOBJS[NUMMOBJFREESLOTS]; char *FREE_SKINCOLORS[NUMCOLORFREESLOTS]; UINT8 used_spr[(NUMSPRITEFREESLOTS / 8) + 1]; // Bitwise flag for sprite freeslot in use! I would use ceil() here if I could, but it only saves 1 byte of memory anyway. -const char NIGHTSGRADE_LIST[] = { - 'F', // GRADE_F - 'E', // GRADE_E - 'D', // GRADE_D - 'C', // GRADE_C - 'B', // GRADE_B - 'A', // GRADE_A - 'S', // GRADE_S - '\0' -}; - struct flickytypes_s FLICKYTYPES[] = { {"BLUEBIRD", MT_FLICKY_01}, // Flicky (Flicky) {"RABBIT", MT_FLICKY_02}, // Pocky (1) diff --git a/src/deh_tables.h b/src/deh_tables.h index 294e6452a..05fb38d67 100644 --- a/src/deh_tables.h +++ b/src/deh_tables.h @@ -53,7 +53,6 @@ struct int_const_s { lua_Integer v; }; -extern const char NIGHTSGRADE_LIST[]; extern struct flickytypes_s FLICKYTYPES[]; extern actionpointer_t actionpointers[]; // Array mapping action names to action functions. extern const char *const STATE_LIST[]; diff --git a/src/doomstat.h b/src/doomstat.h index f99797abc..b47f9a4d2 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -322,12 +322,6 @@ extern struct quake fixed_t radius, intensity; } quake; -// NiGHTS grades -typedef struct -{ - UINT32 grade[6]; // D, C, B, A, S, X (F: failed to reach any of these) -} nightsgrades_t; - // Custom Lua values // (This is not ifdeffed so the map header structure can stay identical, just in case.) typedef struct @@ -355,9 +349,6 @@ typedef struct UINT32 typeoflevel; ///< Combination of typeoflevel flags. - char * nextlevel; ///< Map name of next level. - char * marathonnext; ///< See nextlevel, but for Marathon mode. - char keywords[33]; ///< Keywords separated by space to search for. 32 characters. char musname[7]; ///< Music track to play. "" for no music. @@ -391,46 +382,22 @@ typedef struct SINT8 unlockrequired; ///< Is an unlockable required to play this level? -1 if no. UINT8 levelselect; ///< Is this map available in the level select? If so, which map list is it available in? - SINT8 bonustype; ///< What type of bonus does this level have? (-1 for null.) - SINT8 maxbonuslives; ///< How many bonus lives to award at Intermission? (-1 for unlimited.) - UINT16 levelflags; ///< LF_flags: merged booleans into one UINT16 for space, see below UINT16 menuflags; ///< LF2_flags: options that affect record attack / nights mode menus - char selectheading[22]; ///< Level select heading. Allows for controllable grouping. UINT16 startrings; ///< Number of rings players start with. INT32 sstimer; ///< Timer for special stages. UINT32 ssspheres; ///< Sphere requirement in special stages. fixed_t gravity; ///< Map-wide gravity. - // Title card. - char ltzzpatch[8]; ///< Zig zag patch. - char ltzztext[8]; ///< Zig zag text. - char ltactdiamond[8]; ///< Act diamond. - // Freed animals stuff. UINT8 numFlickies; ///< Internal. For freed flicky support. mobjtype_t *flickies; ///< List of freeable flickies in this level. Allocated dynamically for space reasons. Be careful. - // NiGHTS stuff. - UINT8 numGradedMares; ///< Internal. For grade support. - nightsgrades_t *grades; ///< NiGHTS grades. Allocated dynamically for space reasons. Be careful. - UINT8 light_contrast; ///< Range of wall lighting. 0 is no lighting. boolean use_light_angle; ///< When false, wall lighting is evenly distributed. When true, wall lighting is directional. angle_t light_angle; ///< Angle of directional wall lighting. - // Music stuff. - UINT32 musinterfadeout; ///< Fade out level music on intermission screen in milliseconds - char musintername[7]; ///< Intermission screen music. - - char muspostbossname[7]; ///< Post-bossdeath music. - UINT16 muspostbosstrack; ///< Post-bossdeath track. - UINT32 muspostbosspos; ///< Post-bossdeath position - UINT32 muspostbossfadein; ///< Post-bossdeath fade-in milliseconds. - - SINT8 musforcereset; ///< Force resetmusic (-1 for default; 0 for force off; 1 for force on) - // SRB2kart fixed_t mobj_scale; ///< Replacement for TOL_ERZ3 fixed_t default_waypoint_radius; ///< 0 is a special value for DEFAULT_WAYPOINT_RADIUS, but scaled with mobjscale @@ -606,26 +573,6 @@ typedef struct //UINT16 rings; ///< Rings when the level was finished. } recorddata_t; -/** Setup for one NiGHTS map. - * These are dynamically allocated because I am insane - */ -#define GRADE_F 0 -#define GRADE_E 1 -#define GRADE_D 2 -#define GRADE_C 3 -#define GRADE_B 4 -#define GRADE_A 5 -#define GRADE_S 6 - -/*typedef struct -{ - // 8 mares, 1 overall (0) - UINT8 nummares; - UINT32 score[9]; - UINT8 grade[9]; - tic_t time[9]; -} nightsdata_t;*/ - //extern nightsdata_t *nightsrecords[NUMMAPS]; extern recorddata_t *mainrecords[NUMMAPS]; diff --git a/src/f_finale.c b/src/f_finale.c index 3a77e3ec5..05457f5dd 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2416,7 +2416,7 @@ void F_EndCutScene(void) F_StartGameEvaluation(); else if (cutnum == introtoplay-1) D_StartTitle(); - else if (nextmap < 1100-1) + else if (nextmap < NEXTMAP_SPECIAL) G_NextLevel(); else G_EndGame(); diff --git a/src/g_game.c b/src/g_game.c index fbfc3512a..027a96011 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -663,7 +663,9 @@ const char *G_BuildMapName(INT32 map) */ INT32 G_MapNumber(const char * name) { +#ifdef NEXTMAPINSOC if (strncasecmp("NEXTMAP_", name, 8) != 0) +#endif { INT32 map; @@ -678,6 +680,7 @@ INT32 G_MapNumber(const char * name) return map; } +#ifdef NEXTMAPINSOC name += 8; if (strcasecmp("EVALUATION", name) == 0) @@ -688,6 +691,7 @@ INT32 G_MapNumber(const char * name) return NEXTMAP_CEREMONY; //if (strcasecmp("TITLE", name) == 0) return NEXTMAP_TITLE; +#endif } /** Clips the console player's mouse aiming to the current view. @@ -2994,7 +2998,7 @@ const char *Gametype_ConstantNames[NUMGAMETYPES] = UINT32 gametypedefaultrules[NUMGAMETYPES] = { // Race - GTR_CIRCUIT|GTR_BOTS, + GTR_CAMPAIGN|GTR_CIRCUIT|GTR_BOTS, // Battle GTR_SPHERES|GTR_BUMPERS|GTR_PAPERITEMS|GTR_KARMA|GTR_ITEMARROWS|GTR_CAPSULES|GTR_BATTLESTARTS|GTR_POINTLIMIT|GTR_TIMELIMIT|GTR_OVERTIME }; @@ -3378,20 +3382,54 @@ UINT32 G_TOLFlag(INT32 pgametype) return gametypetol[pgametype]; } -static INT32 TOLMaps(UINT32 tolflags) +INT16 G_GetFirstMapOfGametype(UINT8 pgametype) +{ + INT16 mapnum = nummapheaders; + + if ((gametypedefaultrules[pgametype] & GTR_CAMPAIGN) && kartcupheaders) + { + mapnum = G_MapNumber(kartcupheaders->levellist[0]); + } + + if (mapnum >= nummapheaders) + { + UINT32 tolflag = G_TOLFlag(pgametype); + for (mapnum = 0; mapnum < nummapheaders; mapnum++) + { + if (!mapheaderinfo[mapnum]) + continue; + if (mapheaderinfo[mapnum]->lumpnum == LUMPERROR) + continue; + if (!(mapheaderinfo[mapnum]->typeoflevel & tolflag)) + continue; + if (mapheaderinfo[mapnum]->menuflags & LF2_HIDEINMENU) + continue; + break; + } + } + + return mapnum; +} + +static INT32 TOLMaps(UINT8 pgametype) { INT32 num = 0; INT32 i; - // Find all the maps that are ok and and put them in an array. + UINT32 tolflag = G_TOLFlag(pgametype); + + // Find all the maps that are ok for (i = 0; i < nummapheaders; i++) { if (!mapheaderinfo[i]) continue; + if (mapheaderinfo[i]->lumpnum == LUMPERROR) + continue; + if (!(mapheaderinfo[i]->typeoflevel & tolflag)) + continue; if (mapheaderinfo[i]->menuflags & LF2_HIDEINMENU) // Don't include Map Hell continue; - if ((mapheaderinfo[i]->typeoflevel & tolflags) == tolflags) - num++; + num++; } return num; @@ -3546,7 +3584,7 @@ tryagain: void G_AddMapToBuffer(INT16 map) { INT16 bufx; - INT16 refreshnum = (TOLMaps(G_TOLFlag(gametype)))-3; + INT16 refreshnum = (TOLMaps(gametype))-3; if (refreshnum < 0) refreshnum = 3; @@ -3612,7 +3650,7 @@ static boolean CanSaveLevel(INT32 mapnum) static void G_HandleSaveLevel(void) { // do this before running the intermission or custom cutscene, mostly for the sake of marathon mode but it also massively reduces redundant file save events in f_finale.c - if (nextmap >= 1100-1) + if (nextmap >= NEXTMAP_SPECIAL) { if (!gamecomplete) gamecomplete = 2; // special temporary mode to prevent using SP level select in pause menu until the intermission is over without restricting it in every intermission @@ -3635,6 +3673,167 @@ static void G_HandleSaveLevel(void) G_SaveGame((UINT32)cursaveslot, lastmap+1); // not nextmap+1 to route around special stages } +static void G_GetNextMap(void) +{ + INT32 i; + + // go to next level + // nextmap is 0-based, unlike gamemap + if (nextmapoverride != 0) + { + nextmap = (INT16)(nextmapoverride-1); + } + else if (grandprixinfo.gp == true) + { + if (grandprixinfo.roundnum == 0 || grandprixinfo.cup == NULL) // Single session + { + nextmap = prevmap; // Same map + } + else + { + if (grandprixinfo.roundnum >= grandprixinfo.cup->numlevels) // On final map + { + nextmap = NEXTMAP_CEREMONY; // ceremonymap + } + else + { + // Proceed to next map + const INT32 cupLevelNum = G_MapNumber(grandprixinfo.cup->levellist[grandprixinfo.roundnum]); + + if (cupLevelNum < nummapheaders && mapheaderinfo[cupLevelNum]) + { + nextmap = cupLevelNum; + } + else + { + nextmap = prevmap; // Prevent uninitialised use + } + + grandprixinfo.roundnum++; + } + } + } + else if (bossinfo.boss == true) + { + nextmap = NEXTMAP_TITLE; // temporary + } + else + { + UINT32 tolflag = G_TOLFlag(gametype); + + if (gametyperules & GTR_CAMPAIGN) + { + register INT16 cm; + cupheader_t *cup = kartcupheaders; + UINT8 gettingresult = 0; + + // While this can't produce an infinite loop IN THE ITERATION, it + // is technically possible for you to keep cycling inside a lousy + // cul-de-sac of the same maps over and over while marathonning + // them all, if the same map is present in the cup list multiple + // times. There is no good solution. Don't dupe maps between cups! + while (cup) + { + for (i = 0; i < cup->numlevels; i++) + { + cm = G_MapNumber(cup->levellist[i]); + + // Not valid? + if (cm >= nummapheaders + || !mapheaderinfo[cm] + || mapheaderinfo[cm]->lumpnum == LUMPERROR + || !(mapheaderinfo[cm]->typeoflevel & tolflag)) + continue; + + // Grab the first valid after the map you're on + if (gettingresult) + { + nextmap = cm; + gettingresult = 2; + break; + } + + // Not the map you're on? + if (cm != prevmap) + { + continue; + } + + // Ok, this is the current map, time to get the next + gettingresult = 1; + } + + // We have a good nextmap? + if (gettingresult == 2) + { + break; + } + + // Ok, iterate to the next + cup = cup->next; + } + + // Didn't get a nextmap before reaching the end? + if (gettingresult != 2) + { + if (marathonmode) + { + nextmap = NEXTMAP_CEREMONY; // ceremonymap + } + else + { + nextmap = NEXTMAP_TITLE; + } + } + } + else + { + i = prevmap; + if (++i >= nummapheaders) + i = 0; + + while (i != prevmap) + { + if (!mapheaderinfo[i] + || mapheaderinfo[i]->lumpnum == LUMPERROR + || !(mapheaderinfo[i]->typeoflevel & tolflag) + || (mapheaderinfo[i]->menuflags & LF2_HIDEINMENU)) + { + if (++i >= nummapheaders) + i = 0; + continue; + } + + break; + } + + nextmap = i; + } + + if (!marathonmode) + { + if (cv_advancemap.value == 0) // Stay on same map. + { + nextmap = prevmap; + } + else if (cv_advancemap.value == 2) // Go to random map. + { + nextmap = G_RandMap(G_TOLFlag(gametype), prevmap, 0, 0, false, NULL); + } + else if (nextmap >= NEXTMAP_SPECIAL) // Loop back around + { + nextmap = G_GetFirstMapOfGametype(gametype); + } + } + } + + // 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 < NEXTMAP_SPECIAL && (nextmap >= nummapheaders || !mapheaderinfo[nextmap] || mapheaderinfo[nextmap]->lumpnum == LUMPERROR)) + I_Error("G_GetNextMap: Internal map ID %d not found (nummapheaders = %d)\n", nextmap, nummapheaders); +} + // // G_DoCompleted // @@ -3696,154 +3895,17 @@ static void G_DoCompleted(void) prevmap = (INT16)(gamemap-1); - if (demo.playback) goto demointermission; - - // go to next level - // nextmap is 0-based, unlike gamemap - if (nextmapoverride != 0) + if (!demo.playback) { - nextmap = (INT16)(nextmapoverride-1); + G_GetNextMap(); + + // Remember last map for when you come out of the special stage. + if (!spec) + lastmap = nextmap; + + // Set up power level gametype scrambles + K_SetPowerLevelScrambles(powertype); } - else if (marathonmode && mapheaderinfo[gamemap-1]->marathonnext) - { - const INT32 mNextNum = G_MapNumber(mapheaderinfo[gamemap-1]->marathonnext); - - if (mapheaderinfo[mNextNum]) - { - nextmap = (INT16)mNextNum; - } - } - else if (grandprixinfo.gp == true) - { - if (grandprixinfo.roundnum == 0 || grandprixinfo.cup == NULL) // Single session - { - nextmap = prevmap; // Same map - } - else - { - if (grandprixinfo.roundnum >= grandprixinfo.cup->numlevels) // On final map - { - nextmap = NEXTMAP_CEREMONY; // ceremonymap - } - else - { - // Proceed to next map - const INT32 cupLevelNum = G_MapNumber(grandprixinfo.cup->levellist[grandprixinfo.roundnum]); - - if (cupLevelNum < nummapheaders && mapheaderinfo[cupLevelNum]) - { - nextmap = cupLevelNum; - } - else - { - nextmap = prevmap; // Prevent uninitialised use - } - - grandprixinfo.roundnum++; - } - } - } - else - { - const INT32 nextNum = G_MapNumber(mapheaderinfo[gamemap-1]->nextlevel); - - if (mapheaderinfo[nextNum]) - { - nextmap = (INT16)nextNum; - if (marathonmode && nextmap == spmarathon_start-1) - nextmap = NEXTMAP_TITLE; // No infinite loop for you - } - } - - // Remember last map for when you come out of the special stage. - if (!spec) - lastmap = nextmap; - - // If nextmap is actually going to get used, make sure it points to - // a map of the proper gametype -- skip levels that don't support - // the current gametype. (Helps avoid playing boss levels in Race, - // for instance). - if (K_CanChangeRules()) - { - if (cv_advancemap.value == 0) // Stay on same map. - { - nextmap = prevmap; - } - else if (cv_advancemap.value == 2) // Go to random map. - { - nextmap = G_RandMap(G_TOLFlag(gametype), prevmap, 0, 0, false, NULL); - } - else if (nextmap < NEXTMAP_SPECIAL) - { - register INT16 cm = nextmap; - UINT32 tolflag = G_TOLFlag(gametype); - UINT8* visitedmap; - - visitedmap = Z_Calloc(((nummapheaders+7)/8)*sizeof(UINT8), PU_STATIC, NULL); - - while (!mapheaderinfo[cm] || mapheaderinfo[cm]->lumpnum == LUMPERROR || !(mapheaderinfo[cm]->typeoflevel & tolflag)) - { - visitedmap[cm/8] |= (1<<(cm&7)); - if (!mapheaderinfo[cm]) - cm = -1; // guarantee error execution - else if (marathonmode && mapheaderinfo[cm]->marathonnext) - { - cm = G_MapNumber(mapheaderinfo[cm]->marathonnext); - } - else - { - cm = G_MapNumber(mapheaderinfo[cm]->nextlevel); - } - - if (cm >= nummapheaders) // out of range (either NEXTMAP_SPECIAL 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 (cm >= nummapheaders || mapheaderinfo[cm]->lumpnum == LUMPERROR) - { - CONS_Alert(CONS_ERROR, M_GetText("Next map given (ID %d) doesn't exist! Reverting to id 0.\n"), cm+1); - cm = 0; - break; - } - } - - if (visitedmap[cm/8] & (1<<(cm&7))) // smells familiar - { - // We got stuck in a loop, came back to the map we started on - // without finding one supporting the current gametype. - // Thus, print a warning, and just use this map anyways. - CONS_Alert(CONS_WARNING, M_GetText("Can't find a compatible map after ID %d; using ID %d anyway\n"), prevmap, cm); - break; - } - } - Z_Free(visitedmap); - nextmap = cm; - } - // wrap around - else if (!(gametyperules & GTR_CAMPAIGN)) - nextmap = (INT16)(spstage_start-1); - - if (cv_advancemap.value == 0) // Stay on same map. - { - nextmap = prevmap; - } - else if (cv_advancemap.value == 2) // Go to random map. - { - nextmap = G_RandMap(G_TOLFlag(gametype), prevmap, 0, 0, false, NULL); - } - } - - // 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 < NEXTMAP_SPECIAL && (nextmap >= nummapheaders || !mapheaderinfo[nextmap] || mapheaderinfo[nextmap]->lumpnum == LUMPERROR)) - I_Error("G_DoCompleted: Internal map ID %d not found (nummapheaders = %d)\n", nextmap, nummapheaders); - - // Set up power level gametype scrambles - K_SetPowerLevelScrambles(powertype); - -demointermission: // If the current gametype has no intermission screen set, then don't start it. Y_DetermineIntermissionType(); @@ -3866,17 +3928,10 @@ demointermission: // See also F_EndCutscene, the only other place which handles intra-map/ending transitions void G_AfterIntermission(void) { - if (modeattacking) - { - M_EndModeAttackRun(); - return; - } - if (gamecomplete == 2) // special temporary mode to prevent using SP level select in pause menu until the intermission is over without restricting it in every intermission gamecomplete = 1; HU_ClearCEcho(); - //G_NextLevel(); if (demo.playback) { @@ -3900,8 +3955,8 @@ void G_AfterIntermission(void) return; } - if ((gametyperules & GTR_CAMPAIGN) && mapheaderinfo[gamemap-1]->cutscenenum && !modeattacking && skipstats <= 1 && (gamecomplete || !(marathonmode & MA_NOCUTSCENES))) // Start a custom cutscene. - F_StartCustomCutscene(mapheaderinfo[gamemap-1]->cutscenenum-1, false, false); + if ((gametyperules & GTR_CAMPAIGN) && mapheaderinfo[prevmap]->cutscenenum && !modeattacking && skipstats <= 1 && (gamecomplete || !(marathonmode & MA_NOCUTSCENES))) // Start a custom cutscene. + F_StartCustomCutscene(mapheaderinfo[prevmap]->cutscenenum-1, false, false); else { if (nextmap < NEXTMAP_SPECIAL) @@ -4045,12 +4100,12 @@ void G_EndGame(void) if (demo.recording && (modeattacking || demo.savemode != DSM_NOTSAVING)) G_SaveDemo(); - // Only do evaluation and credits in coop games. - if (gametyperules & GTR_CAMPAIGN) + // Only do evaluation and credits in singleplayer contexts + if (!netgame && (gametyperules & GTR_CAMPAIGN)) { - if (nextmap == NEXTMAP_CEREMONY) // end game with ending + if (nextmap == NEXTMAP_CEREMONY) // end game with ceremony { - F_StartEnding(); + D_StartTitle(); //F_StartEnding(); -- temporary return; } if (nextmap == NEXTMAP_CREDITS) // end game with credits @@ -4065,7 +4120,7 @@ void G_EndGame(void) } } - // 1100 or competitive multiplayer, so go back to title screen. + // direct or competitive multiplayer, so go back to title screen. D_StartTitle(); } diff --git a/src/g_game.h b/src/g_game.h index 18ef96ad8..b0a0e7320 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -256,6 +256,7 @@ FUNCMATH INT32 G_TicsToMilliseconds(tic_t tics); // Don't split up TOL handling UINT32 G_TOLFlag(INT32 pgametype); +INT16 G_GetFirstMapOfGametype(UINT8 pgametype); INT16 G_RandMap(UINT32 tolflags, INT16 pprevmap, UINT8 ignorebuffer, UINT8 maphell, boolean callagainsoon, INT16 *extbuffer); void G_AddMapToBuffer(INT16 map); diff --git a/src/k_menufunc.c b/src/k_menufunc.c index f930b1dfa..c119cfe7d 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -3178,6 +3178,8 @@ void M_SetupDifficultySelect(INT32 choice) // boolean M_CanShowLevelInList(INT16 mapnum, UINT8 gt) { + UINT32 tolflag = G_TOLFlag(gt); + // Does the map exist? if (!mapheaderinfo[mapnum]) return false; @@ -3186,21 +3188,26 @@ boolean M_CanShowLevelInList(INT16 mapnum, UINT8 gt) if (!mapheaderinfo[mapnum]->lvlttl[0]) return false; + // Does the map have a LUMP? + if (mapheaderinfo[mapnum]->lumpnum == LUMPERROR) + return false; + if (M_MapLocked(mapnum+1)) return false; // not unlocked + // Check for TOL + if (!(mapheaderinfo[mapnum]->typeoflevel & tolflag)) + return false; + // Should the map be hidden? - if (mapheaderinfo[mapnum]->menuflags & LF2_HIDEINMENU /*&& mapnum+1 != gamemap*/) + if (mapheaderinfo[mapnum]->menuflags & LF2_HIDEINMENU) return false; // I don't know why, but some may have exceptions. if (levellist.timeattack && (mapheaderinfo[mapnum]->menuflags & LF2_NOTIMEATTACK)) return false; - if (gt == GT_BATTLE && (mapheaderinfo[mapnum]->typeoflevel & TOL_BATTLE)) - return true; - - if (gt == GT_RACE && (mapheaderinfo[mapnum]->typeoflevel & TOL_RACE)) + if (gametypedefaultrules[gt] & GTR_CAMPAIGN) { if (levellist.selectedcup && levellist.selectedcup->numlevels) { @@ -3217,12 +3224,10 @@ boolean M_CanShowLevelInList(INT16 mapnum, UINT8 gt) if (i == levellist.selectedcup->numlevels) return false; } - - return true; } - // Hmm? Couldn't decide? - return false; + // Survived our checks. + return true; } INT16 M_CountLevelsToShowInList(UINT8 gt) diff --git a/src/lua_maplib.c b/src/lua_maplib.c index 863821a9b..b1bc68236 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -2127,10 +2127,6 @@ static int mapheaderinfo_get(lua_State *L) lua_pushinteger(L, header->actnum); else if (fastcmp(field,"typeoflevel")) lua_pushinteger(L, header->typeoflevel); - else if (fastcmp(field,"nextlevel")) - lua_pushstring(L, header->nextlevel); - else if (fastcmp(field,"marathonnext")) - lua_pushstring(L, header->marathonnext); else if (fastcmp(field,"keywords")) lua_pushstring(L, header->keywords); else if (fastcmp(field,"musname")) @@ -2139,20 +2135,6 @@ static int mapheaderinfo_get(lua_State *L) lua_pushinteger(L, header->mustrack); else if (fastcmp(field,"muspos")) lua_pushinteger(L, header->muspos); - else if (fastcmp(field,"musinterfadeout")) - lua_pushinteger(L, header->musinterfadeout); - else if (fastcmp(field,"musintername")) - lua_pushstring(L, header->musintername); - else if (fastcmp(field,"muspostbossname")) - lua_pushstring(L, header->muspostbossname); - else if (fastcmp(field,"muspostbosstrack")) - lua_pushinteger(L, header->muspostbosstrack); - else if (fastcmp(field,"muspostbosspos")) - lua_pushinteger(L, header->muspostbosspos); - else if (fastcmp(field,"muspostbossfadein")) - lua_pushinteger(L, header->muspostbossfadein); - else if (fastcmp(field,"musforcereset")) - lua_pushinteger(L, header->musforcereset); else if (fastcmp(field,"forcecharacter")) lua_pushstring(L, header->forcecharacter); else if (fastcmp(field,"weather")) @@ -2188,16 +2170,6 @@ static int mapheaderinfo_get(lua_State *L) lua_pushinteger(L, header->unlockrequired); else if (fastcmp(field,"levelselect")) lua_pushinteger(L, header->levelselect); - else if (fastcmp(field,"bonustype")) - lua_pushinteger(L, header->bonustype); - else if (fastcmp(field,"ltzzpatch")) - lua_pushstring(L, header->ltzzpatch); - else if (fastcmp(field,"ltzztext")) - lua_pushstring(L, header->ltzztext); - else if (fastcmp(field,"ltactdiamond")) - lua_pushstring(L, header->ltactdiamond); - else if (fastcmp(field,"maxbonuslives")) - lua_pushinteger(L, header->maxbonuslives); else if (fastcmp(field,"levelflags")) lua_pushinteger(L, header->levelflags); else if (fastcmp(field,"menuflags")) @@ -2212,7 +2184,6 @@ static int mapheaderinfo_get(lua_State *L) lua_pushinteger(L, header->ssspheres); else if (fastcmp(field, "gravity")) lua_pushfixed(L, header->gravity); - // TODO add support for reading numGradedMares and grades else { // Read custom vars now // (note: don't include the "LUA." in your lua scripts!) diff --git a/src/p_enemy.c b/src/p_enemy.c index d5f999624..2963cbae9 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -3460,28 +3460,6 @@ void A_BossDeath(mobj_t *mo) EV_DoElevator(&junk, elevateUp, false); Tag_FSet(&junk.tags, LE_CAPSULE2); EV_DoElevator(&junk, elevateHighest, false); - - if (mapheaderinfo[gamemap-1]->muspostbossname[0] && - S_MusicExists(mapheaderinfo[gamemap-1]->muspostbossname)) - { - // 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)) - { - strncpy(mapmusname, mapheaderinfo[gamemap-1]->muspostbossname, 7); - mapmusname[6] = 0; - mapmusflags = (mapheaderinfo[gamemap-1]->muspostbosstrack & MUSIC_TRACKMASK) | MUSIC_RELOADRESET; - mapmusposition = mapheaderinfo[gamemap-1]->muspostbosspos; - } - - // don't change if we're in another tune - // but in case we're in jingle, use our parked mapmus variables so the correct track restores - if (!changed) - S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, (1*MUSICRATE)+(MUSICRATE/2), - mapheaderinfo[gamemap-1]->muspostbossfadein); - } } bossjustdie: diff --git a/src/p_setup.c b/src/p_setup.c index 30f4d61cc..3aefd4e1a 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -363,19 +363,9 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) { const INT16 num = (INT16)(i-1); - Z_Free(mapheaderinfo[num]->nextlevel); - mapheaderinfo[num]->nextlevel = NULL; - - Z_Free(mapheaderinfo[num]->marathonnext); - mapheaderinfo[num]->marathonnext = NULL; - mapheaderinfo[num]->lvlttl[0] = '\0'; - mapheaderinfo[num]->selectheading[0] = '\0'; mapheaderinfo[num]->subttl[0] = '\0'; mapheaderinfo[num]->zonttl[0] = '\0'; - mapheaderinfo[num]->ltzzpatch[0] = '\0'; - mapheaderinfo[num]->ltzztext[0] = '\0'; - mapheaderinfo[num]->ltactdiamond[0] = '\0'; mapheaderinfo[num]->actnum = 0; mapheaderinfo[num]->typeoflevel = 0; mapheaderinfo[num]->startrings = 0; @@ -387,13 +377,6 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) mapheaderinfo[num]->musname[6] = 0; mapheaderinfo[num]->mustrack = 0; mapheaderinfo[num]->muspos = 0; - mapheaderinfo[num]->musinterfadeout = 0; - mapheaderinfo[num]->musintername[0] = 0; - mapheaderinfo[num]->muspostbossname[0] = 0; - mapheaderinfo[num]->muspostbosstrack = 0; - mapheaderinfo[num]->muspostbosspos = 0; - mapheaderinfo[num]->muspostbossfadein = 0; - mapheaderinfo[num]->musforcereset = -1; mapheaderinfo[num]->forcecharacter[0] = '\0'; mapheaderinfo[num]->weather = PRECIP_NONE; snprintf(mapheaderinfo[num]->skytexture, 5, "SKY1"); @@ -412,8 +395,6 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) mapheaderinfo[num]->numlaps = NUMLAPS_DEFAULT; mapheaderinfo[num]->unlockrequired = -1; mapheaderinfo[num]->levelselect = 0; - mapheaderinfo[num]->bonustype = 0; - mapheaderinfo[num]->maxbonuslives = -1; mapheaderinfo[num]->levelflags = 0; mapheaderinfo[num]->menuflags = 0; mapheaderinfo[num]->mobj_scale = FRACUNIT; @@ -426,7 +407,6 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) #else // equivalent to "FlickyList = NONE" P_DeleteFlickies(num); #endif - P_DeleteGrades(num); mapheaderinfo[num]->customopts = NULL; mapheaderinfo[num]->numCustomOptions = 0; @@ -445,112 +425,12 @@ void P_AllocMapHeader(INT16 i) mapheaderinfo[i]->lumpname = NULL; mapheaderinfo[i]->thumbnailPic = NULL; mapheaderinfo[i]->minimapPic = NULL; - mapheaderinfo[i]->nextlevel = NULL; - mapheaderinfo[i]->marathonnext = NULL; mapheaderinfo[i]->flickies = NULL; - mapheaderinfo[i]->grades = NULL; nummapheaders++; } P_ClearSingleMapHeaderInfo(i + 1); } -/** NiGHTS Grades are a special structure, - * we initialize them here. - * - * \param i Index of header to allocate grades for - * \param mare The mare we're adding grades for - * \param grades the string from DeHackEd, we work with it ourselves - */ -void P_AddGradesForMare(INT16 i, UINT8 mare, char *gtext) -{ - INT32 g; - char *spos = gtext; - - CONS_Debug(DBG_SETUP, "Map %d Mare %d: ", i+1, (UINT16)mare+1); - - if (mapheaderinfo[i]->numGradedMares < mare+1) - { - mapheaderinfo[i]->numGradedMares = mare+1; - mapheaderinfo[i]->grades = Z_Realloc(mapheaderinfo[i]->grades, sizeof(nightsgrades_t) * mapheaderinfo[i]->numGradedMares, PU_STATIC, NULL); - } - - for (g = 0; g < 6; ++g) - { - // Allow "partial" grading systems - if (spos != NULL) - { - mapheaderinfo[i]->grades[mare].grade[g] = atoi(spos); - CONS_Debug(DBG_SETUP, "%u ", atoi(spos)); - // Grab next comma - spos = strchr(spos, ','); - if (spos) - ++spos; - } - else - { - // Grade not reachable - mapheaderinfo[i]->grades[mare].grade[g] = UINT32_MAX; - } - } - - CONS_Debug(DBG_SETUP, "\n"); -} - -/** And this removes the grades safely. - * - * \param i The header to remove grades from - */ -void P_DeleteGrades(INT16 i) -{ - if (mapheaderinfo[i]->grades) - Z_Free(mapheaderinfo[i]->grades); - - mapheaderinfo[i]->grades = NULL; - mapheaderinfo[i]->numGradedMares = 0; -} - -/** And this fetches the grades - * - * \param pscore The player's score. - * \param map The game map. - * \param mare The mare to test. - */ -UINT8 P_GetGrade(UINT32 pscore, INT16 map, UINT8 mare) -{ - INT32 i; - - // Determining the grade - if (mapheaderinfo[map-1] && mapheaderinfo[map-1]->grades && mapheaderinfo[map-1]->numGradedMares >= mare + 1) - { - INT32 pgrade = 0; - for (i = 0; i < 6; ++i) - { - if (pscore >= mapheaderinfo[map-1]->grades[mare].grade[i]) - ++pgrade; - } - return (UINT8)pgrade; - } - return 0; -} - -UINT8 P_HasGrades(INT16 map, UINT8 mare) -{ - // Determining the grade - // Mare 0 is treated as overall and is true if ANY grades exist - if (mapheaderinfo[map-1] && mapheaderinfo[map-1]->grades - && (mare == 0 || mapheaderinfo[map-1]->numGradedMares >= mare)) - return true; - return false; -} - -UINT32 P_GetScoreForGrade(INT16 map, UINT8 mare, UINT8 grade) -{ - // Get the score for the grade... if it exists - if (grade == GRADE_F || grade > GRADE_S || !P_HasGrades(map, mare)) return 0; - - return mapheaderinfo[map-1]->grades[mare].grade[grade-1]; -} - // // levelflats // diff --git a/src/p_setup.h b/src/p_setup.h index 4eaf46105..3db26a7ba 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -125,10 +125,5 @@ void P_DeleteFlickies(INT16 i); // Needed for NiGHTS void P_ReloadRings(void); -void P_DeleteGrades(INT16 i); -void P_AddGradesForMare(INT16 i, UINT8 mare, char *gtext); -UINT8 P_GetGrade(UINT32 pscore, INT16 map, UINT8 mare); -UINT8 P_HasGrades(INT16 map, UINT8 mare); -UINT32 P_GetScoreForGrade(INT16 map, UINT8 mare, UINT8 grade); #endif diff --git a/src/p_user.c b/src/p_user.c index 1e1cfcbcb..5ec02733a 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4265,14 +4265,7 @@ void P_PlayerThink(player_t *player) if (!player->spectator) P_PlayerInSpecialSector(player); - else if ( -#else - if (player->spectator && #endif - (gametyperules & GTR_LIVES)) - { - /*P_ConsiderAllGone()*/; - } if (player->playerstate == PST_DEAD) { From 0a48165d3a57cb8a1ce0f1bce267023a31cfd58a Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 18 Sep 2022 20:43:15 +0100 Subject: [PATCH 35/60] Disable hardcoded Discord API map icons for now, we can address this at release --- src/discord.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/discord.c b/src/discord.c index 32ca25f53..7c1b77a62 100644 --- a/src/discord.c +++ b/src/discord.c @@ -508,6 +508,7 @@ void DRPC_UpdatePresence(void) if ((gamestate == GS_LEVEL || gamestate == GS_INTERMISSION) // Map info && !(demo.playback && demo.title)) { +#if 0 if ((gamemap >= 1 && gamemap <= 60) // supported race maps || (gamemap >= 136 && gamemap <= 164)) // supported battle maps { @@ -516,7 +517,9 @@ void DRPC_UpdatePresence(void) strlwr(mapimg); discordPresence.largeImageKey = mapimg; // Map image } - else if (mapheaderinfo[gamemap-1]->menuflags & LF2_HIDEINMENU) + else +#endif + if (mapheaderinfo[gamemap-1]->menuflags & LF2_HIDEINMENU) { // Hell map, use the method that got you here :P discordPresence.largeImageKey = "miscdice"; From fc9697b2e1796a71e8e81774c8160cc5f24fbac6 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 21 Sep 2022 19:22:05 +0100 Subject: [PATCH 36/60] Repair D_StartTitle component of netgame title fallthrough prevention --- src/d_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 87057a22f..5b1b00a70 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -943,12 +943,12 @@ void D_StartTitle(void) if (server) { - INT16 mapnum = G_GetFirstMapOfGametype(gametype)+1; + i = G_GetFirstMapOfGametype(gametype)+1; if (i > nummapheaders) I_Error("D_StartTitle: No valid map ID found!?"); - COM_BufAddText(va("map %s\n", G_BuildMapName(mapnum))); + COM_BufAddText(va("map %s\n", G_BuildMapName(i))); } return; From b8f3e64ca1a8d8c022818a21c550e4ad60a808b8 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 21 Sep 2022 19:22:33 +0100 Subject: [PATCH 37/60] discord.c compilation warning --- src/discord.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/discord.c b/src/discord.c index 7c1b77a62..0e9cb35c9 100644 --- a/src/discord.c +++ b/src/discord.c @@ -405,7 +405,9 @@ void DRPC_UpdatePresence(void) { char detailstr[48+1]; +#ifdef USEMAPIMG char mapimg[8+1]; +#endif char mapname[5+21+21+2+1]; char charimg[4+SKINNAMESIZE+1]; @@ -508,7 +510,7 @@ void DRPC_UpdatePresence(void) if ((gamestate == GS_LEVEL || gamestate == GS_INTERMISSION) // Map info && !(demo.playback && demo.title)) { -#if 0 +#ifdef USEMAPIMG if ((gamemap >= 1 && gamemap <= 60) // supported race maps || (gamemap >= 136 && gamemap <= 164)) // supported battle maps { From 60355d9efd19fb9e185883eaa0703736c83b047f Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 21 Sep 2022 22:12:36 +0100 Subject: [PATCH 38/60] Move two of the three remaining NUMMAPS arrays part of the mapheader_t struct - mapvisited and recorddata_t (previously mainrecords) - Changed how gamedata is saved and loaded - Change the versioncheck (funny hex provided by chengi) AND call it `developringdata.dat` in develop builds - Fix a bunch of off-by-ones in condition and emblem data ALSO, for Time Attack: - Fix menu not showing off your times - Now save times even when gamedata modified, since the menu didn't care (come back to it?) - Don't save times or do intermission screen if the Capsule Attack ended because you lost all your bumpers - Fix a crash adding ghosts in Capsule Attack --- src/deh_soc.c | 2 +- src/doomstat.h | 42 ++++++------- src/g_demo.c | 2 +- src/g_game.c | 160 ++++++++++++++++++++++++++++------------------- src/g_game.h | 1 - src/k_battle.c | 3 +- src/k_menu.h | 9 +++ src/k_menudef.c | 1 + src/k_menudraw.c | 31 ++++++--- src/m_cond.c | 25 +++++--- src/p_setup.c | 9 ++- 11 files changed, 179 insertions(+), 106 deletions(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index 103579cb1..3e9855256 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -2334,7 +2334,7 @@ void reademblemdata(MYFILE *f, INT32 num) } else if (fastcmp(word, "TAG")) emblemlocations[num-1].tag = (INT16)value; - else if (fastcmp(word, "MAPNUM")) + else if (fastcmp(word, "MAPNAME")) { emblemlocations[num-1].level = Z_StrDup(word2); } diff --git a/src/doomstat.h b/src/doomstat.h index b47f9a4d2..a9d82419b 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -105,6 +105,23 @@ extern preciptype_t precip_freeslot; extern preciptype_t globalweather; extern preciptype_t curWeather; +/** Time attack information, currently a very small structure. + */ +typedef struct +{ + tic_t time; ///< Time in which the level was finished. + tic_t lap; ///< Best lap time for this level. + //UINT32 score; ///< Score when the level was finished. + //UINT16 rings; ///< Rings when the level was finished. +} recorddata_t; + +// mapvisited is now a set of flags that says what we've done in the map. +#define MV_VISITED (1) +#define MV_BEATEN (1<<1) +#define MV_ENCORE (1<<2) +#define MV_MAX (MV_VISITED|MV_BEATEN|MV_ENCORE) +#define MV_MP ((MV_MAX+1)<<1) + // Set if homebrew PWAD stuff has been added. extern boolean modifiedgame; extern boolean majormods; @@ -402,6 +419,10 @@ typedef struct fixed_t mobj_scale; ///< Replacement for TOL_ERZ3 fixed_t default_waypoint_radius; ///< 0 is a special value for DEFAULT_WAYPOINT_RADIUS, but scaled with mobjscale + // Record data (modified liberally, saved to gamedata) + UINT8 mapvisited; ///< A set of flags that says what we've done in the map. + recorddata_t *mainrecord; ///< Stores best time attack data + // Lua stuff. // (This is not ifdeffed so the map header structure can stay identical, just in case.) UINT8 numCustomOptions; ///< Internal. For Lua custom value support. @@ -563,27 +584,6 @@ extern INT32 luabanks[NUM_LUABANKS]; extern INT32 nummaprings; //keep track of spawned rings/coins -/** Time attack information, currently a very small structure. - */ -typedef struct -{ - tic_t time; ///< Time in which the level was finished. - tic_t lap; ///< Best lap time for this level. - //UINT32 score; ///< Score when the level was finished. - //UINT16 rings; ///< Rings when the level was finished. -} recorddata_t; - -//extern nightsdata_t *nightsrecords[NUMMAPS]; -extern recorddata_t *mainrecords[NUMMAPS]; - -// mapvisited is now a set of flags that says what we've done in the map. -#define MV_VISITED (1) -#define MV_BEATEN (1<<1) -#define MV_ENCORE (1<<2) -#define MV_MAX (MV_VISITED|MV_BEATEN|MV_ENCORE) -#define MV_MP ((MV_MAX+1)<<1) -extern UINT8 mapvisited[NUMMAPS]; - extern UINT32 token; ///< Number of tokens collected in a level extern UINT32 tokenlist; ///< List of tokens collected extern boolean gottoken; ///< Did you get a token? Used for end of act diff --git a/src/g_demo.c b/src/g_demo.c index 59b943d97..5313a1699 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -3358,7 +3358,7 @@ void G_AddGhost(char *defdemoname) ghosts = gh; gh->version = ghostversion; - mthing = playerstarts[0]; + mthing = playerstarts[0] ? playerstarts[0] : deathmatchstarts[0]; // todo not correct but out of scope I_Assert(mthing); { // A bit more complex than P_SpawnPlayer because ghosts aren't solid and won't just push themselves out of the ceiling. fixed_t z,f,c; diff --git a/src/g_game.c b/src/g_game.c index 027a96011..7a3e90676 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -75,7 +75,11 @@ JoyType_t Joystick[MAXSPLITSCREENPLAYERS]; #define SAVEGAMESIZE (1024) // SRB2kart -char gamedatafilename[64] = "ringdata.dat"; +char gamedatafilename[64] = +#ifdef DEVELOP + "develop" +#endif + "ringdata.dat"; char timeattackfolder[64] = "ringracers"; char customversionstring[32] = "\0"; @@ -215,12 +219,6 @@ tic_t totalplaytime; UINT32 matchesplayed; // SRB2Kart boolean gamedataloaded = false; -// Time attack data for levels -// These are dynamically allocated for space reasons now -recorddata_t *mainrecords[NUMMAPS] = {NULL}; -//nightsdata_t *nightsrecords[NUMMAPS] = {NULL}; -UINT8 mapvisited[NUMMAPS]; - // Temporary holding place for nights data for the current map //nightsdata_t ntemprecords; @@ -473,21 +471,23 @@ INT32 player_name_changes[MAXPLAYERS]; // Allocation for time and nights data void G_AllocMainRecordData(INT16 i) { - if (!mainrecords[i]) - mainrecords[i] = Z_Malloc(sizeof(recorddata_t), PU_STATIC, NULL); - memset(mainrecords[i], 0, sizeof(recorddata_t)); + if (i > nummapheaders || !mapheaderinfo[i]) + I_Error("G_AllocMainRecordData: Internal map ID %d not found (nummapheaders = %d)\n", i, nummapheaders); + if (!mapheaderinfo[i]->mainrecord) + mapheaderinfo[i]->mainrecord = Z_Malloc(sizeof(recorddata_t), PU_STATIC, NULL); + memset(mapheaderinfo[i]->mainrecord, 0, sizeof(recorddata_t)); } // MAKE SURE YOU SAVE DATA BEFORE CALLING THIS void G_ClearRecords(void) { INT16 i; - for (i = 0; i < NUMMAPS; ++i) + for (i = 0; i < nummapheaders; ++i) { - if (mainrecords[i]) + if (mapheaderinfo[i]->mainrecord) { - Z_Free(mainrecords[i]); - mainrecords[i] = NULL; + Z_Free(mapheaderinfo[i]->mainrecord); + mapheaderinfo[i]->mainrecord = NULL; } /*if (nightsrecords[i]) { @@ -500,20 +500,22 @@ void G_ClearRecords(void) // For easy retrieval of records tic_t G_GetBestTime(INT16 map) { - if (!mainrecords[map-1] || mainrecords[map-1]->time <= 0) + if (!mapheaderinfo[map] || !mapheaderinfo[map]->mainrecord || mapheaderinfo[map]->mainrecord->time <= 0) return (tic_t)UINT32_MAX; - return mainrecords[map-1]->time; + return mapheaderinfo[map]->mainrecord->time; } +// BE RIGHT BACK + // Not needed /* tic_t G_GetBestLap(INT16 map) { - if (!mainrecords[map-1] || mainrecords[map-1]->lap <= 0) + if (!mapheaderinfo[map] || !mapheaderinfo[map]->mainrecord || mapheaderinfo[map]->mainrecord->lap <= 0) return (tic_t)UINT32_MAX; - return mainrecords[map-1]->lap; + return mapheaderinfo[map]->mainrecord->lap; } */ @@ -530,7 +532,7 @@ static void G_UpdateRecordReplays(void) UINT8 earnedEmblems; // Record new best time - if (!mainrecords[gamemap-1]) + if (!mapheaderinfo[gamemap-1]->mainrecord) G_AllocMainRecordData(gamemap-1); if (players[consoleplayer].pflags & PF_NOCONTEST) @@ -538,20 +540,20 @@ static void G_UpdateRecordReplays(void) players[consoleplayer].realtime = UINT32_MAX; } - if (((mainrecords[gamemap-1]->time == 0) || (players[consoleplayer].realtime < mainrecords[gamemap-1]->time)) + if (((mapheaderinfo[gamemap-1]->mainrecord->time == 0) || (players[consoleplayer].realtime < mapheaderinfo[gamemap-1]->mainrecord->time)) && (players[consoleplayer].realtime < UINT32_MAX)) // DNF { - mainrecords[gamemap-1]->time = players[consoleplayer].realtime; + mapheaderinfo[gamemap-1]->mainrecord->time = players[consoleplayer].realtime; } if (modeattacking == ATTACKING_TIME) { - if ((mainrecords[gamemap-1]->lap == 0) || (bestlap < mainrecords[gamemap-1]->lap)) - mainrecords[gamemap-1]->lap = bestlap; + if ((mapheaderinfo[gamemap-1]->mainrecord->lap == 0) || (bestlap < mapheaderinfo[gamemap-1]->mainrecord->lap)) + mapheaderinfo[gamemap-1]->mainrecord->lap = bestlap; } else { - mainrecords[gamemap-1]->lap = 0; + mapheaderinfo[gamemap-1]->mainrecord->lap = 0; } // Save demo! @@ -3616,20 +3618,19 @@ void G_AddMapToBuffer(INT16 map) // static void G_UpdateVisited(void) { - boolean spec = G_IsSpecialStage(gamemap); // Update visitation flags? - if ((!modifiedgame || savemoddata) // Not modified - && !multiplayer && !demo.playback // SP/RA/NiGHTS mode - && !(spec && stagefailed)) // Not failed the special stage + if (/*(!majormods || savemoddata) // Not modified + &&*/ !multiplayer && !demo.playback // SP/RA/NiGHTS mode + && !(modeattacking && (players[consoleplayer].pflags & PF_NOCONTEST))) // Not failed { UINT8 earnedEmblems; // Update visitation flags - mapvisited[gamemap-1] |= MV_BEATEN; + mapheaderinfo[gamemap-1]->mapvisited |= MV_BEATEN; if (encoremode == true) { - mapvisited[gamemap-1] |= MV_ENCORE; + mapheaderinfo[gamemap-1]->mapvisited |= MV_ENCORE; } if (modeattacking) @@ -3910,7 +3911,9 @@ static void G_DoCompleted(void) // If the current gametype has no intermission screen set, then don't start it. Y_DetermineIntermissionType(); - if ((skipstats && !modeattacking) || (spec && modeattacking && stagefailed) || (intertype == int_none)) + if ((skipstats && !modeattacking) + || (modeattacking && (players[consoleplayer].pflags & PF_NOCONTEST)) + || (intertype == int_none)) { G_UpdateVisited(); G_HandleSaveLevel(); @@ -4142,18 +4145,19 @@ void G_LoadGameSettings(void) S_InitRuntimeSounds(); } +#define GD_VERSIONCHECK 0xBA5ED444 + // G_LoadGameData // Loads the main data file, which stores information such as emblems found, etc. void G_LoadGameData(void) { size_t length; - INT32 i, j; + UINT32 i, j; UINT8 modded = false; UINT8 rtemp; //For records - tic_t rectime; - tic_t reclap; + UINT32 numgamedatamapheaders; // Clear things so previously read gamedata doesn't transfer // to new gamedata @@ -4184,7 +4188,7 @@ void G_LoadGameData(void) save_p = savebuffer; // Version check - if (READUINT32(save_p) != 0xFCAFE211) + if (READUINT32(save_p) != GD_VERSIONCHECK) { const char *gdfolder = "the Ring Racers folder"; if (strcmp(srb2home,".")) @@ -4206,11 +4210,6 @@ void G_LoadGameData(void) else if (modded != true && modded != false) goto datacorrupt; - // TODO put another cipher on these things? meh, I don't care... - for (i = 0; i < NUMMAPS; i++) - if ((mapvisited[i] = READUINT8(save_p)) > MV_MAX) - goto datacorrupt; - // To save space, use one bit per collected/achieved/unlocked flag for (i = 0; i < MAXEMBLEMS;) { @@ -4244,16 +4243,44 @@ void G_LoadGameData(void) timesBeaten = READUINT32(save_p); // Main records - for (i = 0; i < NUMMAPS; ++i) + numgamedatamapheaders = READUINT32(save_p); + if (numgamedatamapheaders >= NEXTMAP_SPECIAL) + goto datacorrupt; + + for (i = 0; i < numgamedatamapheaders; i++) { + char mapname[255]; + INT16 mapnum; + tic_t rectime; + tic_t reclap; + + READSTRINGN(save_p, mapname, sizeof(mapname)); + mapnum = G_MapNumber(mapname); + + rtemp = READUINT8(save_p); rectime = (tic_t)READUINT32(save_p); reclap = (tic_t)READUINT32(save_p); - if (rectime || reclap) + if (mapnum < nummapheaders && mapheaderinfo[mapnum]) { - G_AllocMainRecordData((INT16)i); - mainrecords[i]->time = rectime; - mainrecords[i]->lap = reclap; + // Valid mapheader, time to populate with record data. + + if ((mapheaderinfo[mapnum]->mapvisited = rtemp) & ~MV_MAX) + goto datacorrupt; + + if (rectime || reclap) + { + G_AllocMainRecordData((INT16)i); + mapheaderinfo[i]->mainrecord->time = rectime; + mapheaderinfo[i]->mainrecord->lap = reclap; + CONS_Printf("ID %d, Time = %d, Lap = %d\n", i, rectime/35, reclap/35); + } + } + else + { + // Since it's not worth declaring the entire gamedata + // corrupt over extra maps, we report and move on. + CONS_Alert(CONS_WARNING, "Map with lumpname %s does not exist, time record data will be discarded", mapname); } } @@ -4291,7 +4318,10 @@ void G_SaveGameData(void) if (!gamedataloaded) return; // If never loaded (-nodata), don't save - save_p = savebuffer = (UINT8 *)malloc(GAMEDATASIZE); + length = (4+4+4+1+(MAXEMBLEMS)+MAXEXTRAEMBLEMS+MAXUNLOCKABLES+MAXCONDITIONSETS+4+4); + length += nummapheaders * (255+1+4+4); + + save_p = savebuffer = (UINT8 *)malloc(length); if (!save_p) { CONS_Alert(CONS_ERROR, M_GetText("No more free memory for saving game data\n")); @@ -4309,19 +4339,15 @@ void G_SaveGameData(void) #endif // Version test - WRITEUINT32(save_p, 0xFCAFE211); + WRITEUINT32(save_p, GD_VERSIONCHECK); // 4 - WRITEUINT32(save_p, totalplaytime); - WRITEUINT32(save_p, matchesplayed); + WRITEUINT32(save_p, totalplaytime); // 4 + WRITEUINT32(save_p, matchesplayed); // 4 - WRITEUINT8(save_p, (UINT8)savemoddata); - - // TODO put another cipher on these things? meh, I don't care... - for (i = 0; i < NUMMAPS; i++) - WRITEUINT8(save_p, (mapvisited[i] & MV_MAX)); + WRITEUINT8(save_p, (UINT8)savemoddata); // 1 // To save space, use one bit per collected/achieved/unlocked flag - for (i = 0; i < MAXEMBLEMS;) + for (i = 0; i < MAXEMBLEMS;) // MAXEMBLEMS * 1; { btemp = 0; for (j = 0; j < 8 && j+i < MAXEMBLEMS; ++j) @@ -4329,7 +4355,7 @@ void G_SaveGameData(void) WRITEUINT8(save_p, btemp); i += j; } - for (i = 0; i < MAXEXTRAEMBLEMS;) + for (i = 0; i < MAXEXTRAEMBLEMS;) // MAXEXTRAEMBLEMS * 1; { btemp = 0; for (j = 0; j < 8 && j+i < MAXEXTRAEMBLEMS; ++j) @@ -4337,7 +4363,7 @@ void G_SaveGameData(void) WRITEUINT8(save_p, btemp); i += j; } - for (i = 0; i < MAXUNLOCKABLES;) + for (i = 0; i < MAXUNLOCKABLES;) // MAXUNLOCKABLES * 1; { btemp = 0; for (j = 0; j < 8 && j+i < MAXUNLOCKABLES; ++j) @@ -4345,7 +4371,7 @@ void G_SaveGameData(void) WRITEUINT8(save_p, btemp); i += j; } - for (i = 0; i < MAXCONDITIONSETS;) + for (i = 0; i < MAXCONDITIONSETS;) // MAXCONDITIONSETS * 1; { btemp = 0; for (j = 0; j < 8 && j+i < MAXCONDITIONSETS; ++j) @@ -4354,22 +4380,28 @@ void G_SaveGameData(void) i += j; } - WRITEUINT32(save_p, timesBeaten); + WRITEUINT32(save_p, timesBeaten); // 4 // Main records - for (i = 0; i < NUMMAPS; i++) + WRITEUINT32(save_p, nummapheaders); // 4 + + for (i = 0; i < nummapheaders; i++) // nummapheaders * (255+1+4+4) { - if (mainrecords[i]) + // For figuring out which header to assing it to on load + WRITESTRINGN(save_p, mapheaderinfo[i]->lumpname, 255); + + WRITEUINT8(save_p, (mapheaderinfo[i]->mapvisited & MV_MAX)); + + if (mapheaderinfo[i]->mainrecord) { - WRITEUINT32(save_p, mainrecords[i]->time); - WRITEUINT32(save_p, mainrecords[i]->lap); + WRITEUINT32(save_p, mapheaderinfo[i]->mainrecord->time); + WRITEUINT32(save_p, mapheaderinfo[i]->mainrecord->lap); } else { WRITEUINT32(save_p, 0); WRITEUINT32(save_p, 0); } - WRITEUINT8(save_p, 0); // compat } length = save_p - savebuffer; diff --git a/src/g_game.h b/src/g_game.h index b0a0e7320..3cc0963cf 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -23,7 +23,6 @@ extern char gamedatafilename[64]; extern char timeattackfolder[64]; extern char customversionstring[32]; -#define GAMEDATASIZE (4*8192) extern char player_names[MAXPLAYERS][MAXPLAYERNAME+1]; extern INT32 player_name_changes[MAXPLAYERS]; diff --git a/src/k_battle.c b/src/k_battle.c index 14ecfabf5..e8afc580f 100644 --- a/src/k_battle.c +++ b/src/k_battle.c @@ -17,6 +17,7 @@ #include "s_sound.h" #include "m_random.h" #include "r_sky.h" // skyflatnum +#include "k_grandprix.h" // K_CanChangeRules // Battle overtime info struct battleovertime battleovertime; @@ -126,7 +127,7 @@ void K_CheckBumpers(void) winnerscoreadd -= players[i].roundscore; } - if (bossinfo.boss) + if (K_CanChangeRules() == false) { if (nobumpers) { diff --git a/src/k_menu.h b/src/k_menu.h index 415c54284..982d0bcf9 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -218,6 +218,15 @@ extern menu_t PLAY_LevelSelectDef; extern menuitem_t PLAY_TimeAttack[]; extern menu_t PLAY_TimeAttackDef; +typedef enum +{ + ta_replay = 0, + ta_guest, + ta_ghosts, + ta_spacer, + ta_start, +} ta_e; + extern menuitem_t PLAY_TAReplay[]; extern menu_t PLAY_TAReplayDef; diff --git a/src/k_menudef.c b/src/k_menudef.c index d97083509..903366c73 100644 --- a/src/k_menudef.c +++ b/src/k_menudef.c @@ -204,6 +204,7 @@ menu_t PLAY_LevelSelectDef = { NULL }; +// see ta_e menuitem_t PLAY_TimeAttack[] = { {IT_STRING | IT_SUBMENU, "Replay...", NULL, NULL, {.submenu = &PLAY_TAReplayDef}, 0, 0}, diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 8a1e368d3..598ad9b48 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -2159,19 +2159,34 @@ void M_DrawTimeAttack(void) V_DrawScaledPatch(149+t, 70, 0, W_CachePatchName("BESTTIME", PU_CACHE)); - if (currentMenu == &PLAY_TimeAttackDef) + if (currentMenu == &PLAY_TimeAttackDef && mapheaderinfo[map]) { - if (mapheaderinfo[map]) + tic_t timerec = 0; + tic_t laprec = 0; + UINT32 timeheight = 82; + + if ((minimap = mapheaderinfo[map]->minimapPic)) + V_DrawScaledPatch(24-t, 82, 0, minimap); + + if (mapheaderinfo[map]->mainrecord) { - if ((minimap = mapheaderinfo[map]->minimapPic)) - V_DrawScaledPatch(24-t, 82, 0, minimap); + timerec = mapheaderinfo[map]->mainrecord->time; + laprec = mapheaderinfo[map]->mainrecord->lap; } - V_DrawRightAlignedString(rightedge-12, 82, highlightflags, "BEST LAP:"); - K_drawKartTimestamp(0, 162+t, 88, 0, 2); + if (levellist.newgametype != GT_BATTLE) + { + V_DrawRightAlignedString(rightedge-12, timeheight, highlightflags, "BEST LAP:"); + K_drawKartTimestamp(laprec, 162+t, timeheight+6, 0, 2); + timeheight += 30; + } + else + { + timeheight += 15; + } - V_DrawRightAlignedString(rightedge-12, 112, highlightflags, "BEST TIME:"); - K_drawKartTimestamp(0, 162+t, 118, map, 1); + V_DrawRightAlignedString(rightedge-12, timeheight, highlightflags, "BEST TIME:"); + K_drawKartTimestamp(timerec, 162+t, timeheight+6, map, 1); } else opty = 80; diff --git a/src/m_cond.c b/src/m_cond.c index cf2c41c3f..94169936c 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -81,7 +81,10 @@ void M_ClearSecrets(void) { INT32 i; - memset(mapvisited, 0, sizeof(mapvisited)); + for (i = 0; i < nummapheaders; ++i) + { + mapheaderinfo[i]->mapvisited = 0; + } for (i = 0; i < MAXEMBLEMS; ++i) emblemlocations[i].collected = false; @@ -129,11 +132,19 @@ UINT8 M_CheckCondition(condition_t *cn) case UC_OVERALLTIME: // Requires overall time <= x return (M_GotLowEnoughTime(cn->requirement)); case UC_MAPVISITED: // Requires map x to be visited - return ((mapvisited[cn->requirement - 1] & MV_VISITED) == MV_VISITED); case UC_MAPBEATEN: // Requires map x to be beaten - return ((mapvisited[cn->requirement - 1] & MV_BEATEN) == MV_BEATEN); case UC_MAPENCORE: // Requires map x to be beaten in encore - return ((mapvisited[cn->requirement - 1] & MV_ENCORE) == MV_ENCORE); + { + UINT8 mvtype = MV_VISITED; + if (cn->type == UC_MAPBEATEN) + mvtype = MV_BEATEN; + else if (cn->type == UC_MAPENCORE) + mvtype = MV_ENCORE; + + return ((cn->requirement < nummapheaders) + && (mapheaderinfo[cn->requirement]) + && ((mapheaderinfo[cn->requirement]->mapvisited & mvtype) == mvtype)); + } case UC_MAPTIME: // Requires time on map <= x return (G_GetBestTime(cn->extrainfo1) <= (unsigned)cn->requirement); case UC_TRIGGER: // requires map trigger set @@ -355,7 +366,7 @@ UINT8 M_CompletionEmblems(void) // Bah! Duplication sucks, but it's for a separa if (embtype & ME_ENCORE) flags |= MV_ENCORE; - res = ((mapvisited[levelnum - 1] & flags) == flags); + res = ((mapheaderinfo[levelnum]->mapvisited & flags) == flags); emblemlocations[i].collected = res; if (res) @@ -477,9 +488,9 @@ UINT8 M_GotLowEnoughTime(INT32 tictime) if (!mapheaderinfo[i] || (mapheaderinfo[i]->menuflags & LF2_NOTIMEATTACK)) continue; - if (!mainrecords[i] || !mainrecords[i]->time) + if (!mapheaderinfo[i]->mainrecord || !mapheaderinfo[i]->mainrecord->time) return false; - else if ((curtics += mainrecords[i]->time) > tictime) + else if ((curtics += mapheaderinfo[i]->mainrecord->time) > tictime) return false; } return true; diff --git a/src/p_setup.c b/src/p_setup.c index 3aefd4e1a..a74d9c137 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -408,6 +408,10 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) P_DeleteFlickies(num); #endif + mapheaderinfo[num]->mapvisited = 0; + Z_Free(mapheaderinfo[num]->mainrecord); + mapheaderinfo[num]->mainrecord = NULL; + mapheaderinfo[num]->customopts = NULL; mapheaderinfo[num]->numCustomOptions = 0; } @@ -426,6 +430,7 @@ void P_AllocMapHeader(INT16 i) mapheaderinfo[i]->thumbnailPic = NULL; mapheaderinfo[i]->minimapPic = NULL; mapheaderinfo[i]->flickies = NULL; + mapheaderinfo[i]->mainrecord = NULL; nummapheaders++; } P_ClearSingleMapHeaderInfo(i + 1); @@ -4265,9 +4270,9 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) skipstats = 0; if (!(netgame || multiplayer || demo.playback) && !majormods) - mapvisited[gamemap-1] |= MV_VISITED; + mapheaderinfo[gamemap-1]->mapvisited |= MV_VISITED; else if (!demo.playback) - mapvisited[gamemap-1] |= MV_MP; // you want to record that you've been there this session, but not permanently + mapheaderinfo[gamemap-1]->mapvisited |= MV_MP; // you want to record that you've been there this session, but not permanently G_AddMapToBuffer(gamemap-1); From 5a813cd94d229155b3b4546f8a8bb950c781dde1 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 21 Sep 2022 22:19:51 +0100 Subject: [PATCH 39/60] Remove mapname buffer from serverinfo_pak --- src/d_clisrv.c | 1 - src/d_clisrv.h | 1 - src/d_net.c | 4 ++-- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index b8e4d7276..de29aa371 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -931,7 +931,6 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime) CopyCaretColors(netbuffer->u.serverinfo.servername, cv_servername.string, MAXSERVERNAME); - //strncpy(netbuffer->u.serverinfo.mapname, G_BuildMapName(gamemap), 7); M_Memcpy(netbuffer->u.serverinfo.mapmd5, mapmd5, 16); diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 72ce18a5c..664812ff8 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -279,7 +279,6 @@ typedef struct tic_t time; tic_t leveltime; char servername[MAXSERVERNAME]; - char mapname[8]; char maptitle[33]; unsigned char mapmd5[16]; UINT8 actnum; diff --git a/src/d_net.c b/src/d_net.c index 201920f73..4500057e9 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -911,9 +911,9 @@ static void DebugPrintpacket(const char *header) netbuffer->u.servercfg.modifiedgame); break; case PT_SERVERINFO: - fprintf(debugfile, " '%s' player %d/%d, map %s, filenum %d, time %u \n", + fprintf(debugfile, " '%s' player %d/%d, filenum %d, time %u \n", netbuffer->u.serverinfo.servername, netbuffer->u.serverinfo.numberofplayer, - netbuffer->u.serverinfo.maxplayer, netbuffer->u.serverinfo.mapname, + netbuffer->u.serverinfo.maxplayer, netbuffer->u.serverinfo.fileneedednum, (UINT32)LONG(netbuffer->u.serverinfo.time)); fprintfstringnewline((char *)netbuffer->u.serverinfo.fileneeded, From a12a29e1e5ca9a712bb723ba39318f6c037a7f07 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 21 Sep 2022 22:37:30 +0100 Subject: [PATCH 40/60] Demos now store map lumpname rather than mapheader ID This was the last thing we needed to do before infinite maps. Stay tuned. --- src/g_demo.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/g_demo.c b/src/g_demo.c index 5313a1699..c060762b5 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -1994,7 +1994,7 @@ void G_BeginRecording(void) // game data M_Memcpy(demo_p, "PLAY", 4); demo_p += 4; - WRITEINT16(demo_p,gamemap); + WRITESTRINGN(demo_p, mapheaderinfo[gamemap-1]->lumpname, 255); M_Memcpy(demo_p, mapmd5, 16); demo_p += 16; WRITEUINT8(demo_p, demoflags); @@ -2406,6 +2406,7 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname) UINT16 s ATTRUNUSED; UINT8 aflags = 0; boolean uselaps = false; + char discard[255]; // load the new file FIL_DefaultExtension(newname, ".lmp"); @@ -2426,7 +2427,7 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname) p += 16; // demo checksum I_Assert(!memcmp(p, "PLAY", 4)); p += 4; // PLAY - p += 2; // gamemap + READSTRINGN(p, discard, sizeof(discard)); // gamemap p += 16; // map md5 flags = READUINT8(p); // demoflags p++; // gametype @@ -2484,7 +2485,7 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname) Z_Free(buffer); return UINT8_MAX; } p += 4; // "PLAY" - p += 2; // gamemap + READSTRINGN(p, discard, sizeof(discard)); // gamemap p += 16; // mapmd5 flags = READUINT8(p); p++; // gametype @@ -2703,7 +2704,7 @@ void G_DoPlayDemo(char *defdemoname) { UINT8 i, p; lumpnum_t l; - char skin[17],color[MAXCOLORNAME+1],follower[17],*n,*pdemoname; + char skin[17],color[MAXCOLORNAME+1],follower[17],mapname[255],*n,*pdemoname; UINT8 version,subversion; UINT32 randseed; char msg[1024]; @@ -2824,7 +2825,8 @@ void G_DoPlayDemo(char *defdemoname) return; } demo_p += 4; // "PLAY" - gamemap = READINT16(demo_p); + READSTRINGN(demo_p, mapname, sizeof(mapname)); // gamemap + gamemap = G_MapNumber(mapname)+1; demo_p += 16; // mapmd5 demoflags = READUINT8(demo_p); @@ -3144,7 +3146,7 @@ void G_AddGhost(char *defdemoname) { INT32 i; lumpnum_t l; - char name[17],skin[17],color[MAXCOLORNAME+1],*n,*pdemoname,md5[16]; + char name[17],skin[17],color[MAXCOLORNAME+1],discard[255],*n,*pdemoname,md5[16]; demoghost *gh; UINT8 flags; UINT8 *buffer,*p; @@ -3233,7 +3235,7 @@ void G_AddGhost(char *defdemoname) } p += 4; // "PLAY" - p += 2; // gamemap + READSTRINGN(p, discard, sizeof(discard)); // gamemap p += 16; // mapmd5 (possibly check for consistency?) flags = READUINT8(p); @@ -3429,6 +3431,7 @@ void G_UpdateStaffGhostName(lumpnum_t l) UINT8 *buffer,*p; UINT16 ghostversion; UINT8 flags; + char discard[255]; buffer = p = W_CacheLumpNum(l, PU_CACHE); @@ -3462,7 +3465,7 @@ void G_UpdateStaffGhostName(lumpnum_t l) } p += 4; // "PLAY" - p += 2; // gamemap + READSTRINGN(p, discard, sizeof(discard)); // gamemap p += 16; // mapmd5 (possibly check for consistency?) flags = READUINT8(p); From 574cc6049ff0e005b67319294b1cbd68336470bd Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 21 Sep 2022 23:01:58 +0100 Subject: [PATCH 41/60] NUMMAPS is dead Dynamically allocated mapheaderinfo. 1035 reserved slots in a google doc is a thing of the past --- src/deh_soc.c | 5 ----- src/doomdata.h | 2 -- src/doomstat.h | 4 ++-- src/g_game.c | 4 ++-- src/p_setup.c | 34 ++++++++++++++++++++++++++++++++++ 5 files changed, 38 insertions(+), 11 deletions(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index 3e9855256..030b7f644 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -1095,11 +1095,6 @@ void readlevelheader(MYFILE *f, char * name) const INT32 num = G_MapNumber(name); - if (num >= NUMMAPS) - { - I_Error("Too many maps!"); - } - if (f->wad > mainwads && num < nummapheaders) { // only mark as a major mod if it replaces an already-existing mapheaderinfo diff --git a/src/doomdata.h b/src/doomdata.h index b891bc8a4..dbe7c1f84 100644 --- a/src/doomdata.h +++ b/src/doomdata.h @@ -218,8 +218,6 @@ typedef struct #define ZSHIFT 4 -#define NUMMAPS 1035 - /* slope thing types */ enum { diff --git a/src/doomstat.h b/src/doomstat.h index a9d82419b..807aec2d6 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -440,8 +440,8 @@ typedef struct #define LF2_NOTIMEATTACK (1<<2) ///< Hide this map in Time Attack modes #define LF2_VISITNEEDED (1<<3) ///< Not available in Time Attack modes until you visit the level -extern mapheader_t* mapheaderinfo[NUMMAPS]; -extern INT32 nummapheaders; +extern mapheader_t** mapheaderinfo; +extern INT32 nummapheaders, mapallocsize; // This could support more, but is that a good idea? // Keep in mind that it may encourage people making overly long cups just because they "can", and would be a waste of memory. diff --git a/src/g_game.c b/src/g_game.c index 7a3e90676..21e30df41 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -192,8 +192,8 @@ mapthing_t *bflagpoint; struct quake quake; // Map Header Information -mapheader_t* mapheaderinfo[NUMMAPS] = {NULL}; -INT32 nummapheaders; +mapheader_t** mapheaderinfo = {NULL}; +INT32 nummapheaders, mapallocsize = 0; // Kart cup definitions cupheader_t *kartcupheaders = NULL; diff --git a/src/p_setup.c b/src/p_setup.c index a74d9c137..ae3ca64b2 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -422,9 +422,43 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) */ void P_AllocMapHeader(INT16 i) { + if (i > nummapheaders) + I_Error("P_AllocMapHeader: Called on %d, should be %d", i, nummapheaders); + + if (i >= NEXTMAP_SPECIAL) + { + I_Error("P_AllocMapHeader: Too many maps!"); + } + + if (i >= mapallocsize) + { + if (!mapallocsize) + { + mapallocsize = 16; + } + else + { + mapallocsize *= 2; + } + + mapheaderinfo = Z_ReallocAlign( + (void*) mapheaderinfo, + sizeof(mapheader_t*) * mapallocsize, + PU_STATIC, + NULL, + sizeof(mapheader_t*) * 8 + ); + + if (!mapheaderinfo) + I_Error("P_AllocMapHeader: Not enough memory to realloc mapheaderinfo (size %d)", mapallocsize); + } + if (!mapheaderinfo[i]) { mapheaderinfo[i] = Z_Malloc(sizeof(mapheader_t), PU_STATIC, NULL); + if (!mapheaderinfo[i]) + I_Error("P_AllocMapHeader: Not enough memory to allocate new mapheader"); + mapheaderinfo[i]->lumpnum = LUMPERROR; mapheaderinfo[i]->lumpname = NULL; mapheaderinfo[i]->thumbnailPic = NULL; From 077b23929b1fa57700ddc41198b6fb429ea0d761 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 22 Sep 2022 12:47:59 +0100 Subject: [PATCH 42/60] Adjust P_AllocMapHeader and associated - Prints with more info - No weird increment/decrement --- src/p_setup.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index ae3ca64b2..0c9879370 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -359,10 +359,8 @@ void P_DeleteFlickies(INT16 i) * \param i Map number to clear header for. * \sa P_ClearMapHeaderInfo */ -static void P_ClearSingleMapHeaderInfo(INT16 i) +static void P_ClearSingleMapHeaderInfo(INT16 num) { - const INT16 num = (INT16)(i-1); - mapheaderinfo[num]->lvlttl[0] = '\0'; mapheaderinfo[num]->subttl[0] = '\0'; mapheaderinfo[num]->zonttl[0] = '\0'; @@ -457,7 +455,7 @@ void P_AllocMapHeader(INT16 i) { mapheaderinfo[i] = Z_Malloc(sizeof(mapheader_t), PU_STATIC, NULL); if (!mapheaderinfo[i]) - I_Error("P_AllocMapHeader: Not enough memory to allocate new mapheader"); + I_Error("P_AllocMapHeader: Not enough memory to allocate new mapheader (ID %d)", i); mapheaderinfo[i]->lumpnum = LUMPERROR; mapheaderinfo[i]->lumpname = NULL; @@ -467,7 +465,7 @@ void P_AllocMapHeader(INT16 i) mapheaderinfo[i]->mainrecord = NULL; nummapheaders++; } - P_ClearSingleMapHeaderInfo(i + 1); + P_ClearSingleMapHeaderInfo(i); } // From 48e9138ddaf91814f9265a420af539992a166e16 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 22 Sep 2022 17:14:41 +0100 Subject: [PATCH 43/60] Refactoring ahoy * Instead of doing constant G_MapNumbers when finding the relationship between maps and cups... * Add a cache of level IDs to cups, to go with the strings. * Add a cache of the cup pointer to maps, so we don't have to search through all cups to find our map. (done in P_InitMapData) * Pre-emptive work: G_IsSpecialStage and P_GetNextEmerald now reference cup data instead of a hardcoded ID set. * Remove a bunch of old stuff from mapheaderinfo_t/associated, and reorder what stays * Countdowntimer? :boom: * Startrings? :boom: * sstimer/ssspheres? :boom: * forcecharacter? :boom: (distinct from forceskin) * interscreen? :boom: * sstage_start/end and smpstage_start/end? :boom::boom::boom::boom: * You've been blocked * G_MapNumber now returns a special NEXTMAP_INVALID if not found, for more consistent reference. * Incorporate a good chunk of the `edit-headers` branch. Can't clear maps individually because of the new restrictions on sequential mapheaders, but we can add a "disable in vote screen, not even for map hell/archive" flag to a map at some future juncture for equivalent functionality... --- src/d_netcmd.c | 2 +- src/deh_soc.c | 58 +++++++++----------- src/doomstat.h | 140 ++++++++++++++++++++++------------------------- src/g_game.c | 60 +++++++------------- src/g_game.h | 3 +- src/k_menudraw.c | 2 +- src/k_menufunc.c | 25 +++------ src/lua_maplib.c | 18 +----- src/lua_script.c | 12 ---- src/p_mobj.c | 2 +- src/p_saveg.c | 10 ---- src/p_setup.c | 93 ++++++++++++------------------- src/p_spec.c | 9 --- src/p_user.c | 17 +++--- src/r_skins.c | 6 -- 15 files changed, 168 insertions(+), 289 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 5d76385f3..fdd6e75e4 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1394,7 +1394,7 @@ UINT8 CanChangeSkin(INT32 playernum) return true; // Force skin in effect. - if ((cv_forceskin.value != -1) || (mapheaderinfo[gamemap-1] && mapheaderinfo[gamemap-1]->forcecharacter[0] != '\0')) + if (cv_forceskin.value != -1) return false; // Can change skin in intermission and whatnot. diff --git a/src/deh_soc.c b/src/deh_soc.c index 030b7f644..ac22781ed 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -158,6 +158,8 @@ void clear_levels(void) P_DeleteFlickies(nummapheaders); + Z_Free(mapheaderinfo[nummapheaders]->mainrecord); + Patch_Free(mapheaderinfo[nummapheaders]->thumbnailPic); Patch_Free(mapheaderinfo[nummapheaders]->minimapPic); @@ -167,7 +169,22 @@ void clear_levels(void) mapheaderinfo[nummapheaders] = NULL; } - // Realloc the one for the current gamemap as a safeguard + // Clear out the cache + { + cupheader_t *cup = kartcupheaders; + UINT8 i; + + while (cup) + { + for (i = 0; i < CUPCACHE_MAX; i++) + { + cup->cachedlevels[i] = NEXTMAP_INVALID; + } + cup = cup->next; + } + } + + // Exit the current gamemap as a safeguard if (Playing()) COM_BufAddText("exitgame"); // Command_ExitGame_f() but delayed } @@ -1093,17 +1110,18 @@ void readlevelheader(MYFILE *f, char * name) char *tmp; INT32 i; - const INT32 num = G_MapNumber(name); + INT32 num = G_MapNumber(name); - if (f->wad > mainwads && num < nummapheaders) + if (num >= nummapheaders) + { + P_AllocMapHeader((INT16)(num = nummapheaders)); + } + else if (f->wad > mainwads) { // only mark as a major mod if it replaces an already-existing mapheaderinfo G_SetGameModified(multiplayer, true); } - // Reset all previous map header information - P_AllocMapHeader((INT16)(num)); - if (mapheaderinfo[num]->lumpname == NULL) { mapheaderinfo[num]->lumpname = Z_StrDup(name); @@ -1336,11 +1354,6 @@ void readlevelheader(MYFILE *f, char * name) mapheaderinfo[num]->mustrack = ((UINT16)i - 1); else if (fastcmp(word, "MUSICPOS")) mapheaderinfo[num]->muspos = (UINT32)get_number(word2); - else if (fastcmp(word, "FORCECHARACTER")) - { - strlcpy(mapheaderinfo[num]->forcecharacter, word2, SKINNAMESIZE+1); - strlwr(mapheaderinfo[num]->forcecharacter); // skin names are lowercase - } else if (fastcmp(word, "WEATHER")) mapheaderinfo[num]->weather = get_precip(word2); else if (fastcmp(word, "SKYTEXTURE")) @@ -2860,24 +2873,6 @@ void readmaincfg(MYFILE *f) if (maptmp <= nummapheaders) spmarathon_start = maptmp; } - else if (fastcmp(word, "SSTAGE_START")) - { - INT16 maptmp = G_MapNumber(word2)+1; - if (maptmp <= nummapheaders) - { - sstage_start = maptmp; - sstage_end = (sstage_start+13); // 14 special stages - } - } - else if (fastcmp(word, "SMPSTAGE_START")) - { - INT16 maptmp = G_MapNumber(word2)+1; - if (maptmp <= nummapheaders) - { - smpstage_start = maptmp; - smpstage_end = (smpstage_start+13); // 14 special stages - } - } else if (fastcmp(word, "REDTEAM")) { skincolor_redteam = (UINT16)get_number(word2); @@ -3323,16 +3318,17 @@ void readcupheader(MYFILE *f, cupheader_t *cup) } cup->levellist[cup->numlevels] = Z_StrDup(tmp); + cup->cachedlevels[cup->numlevels] = NEXTMAP_INVALID; cup->numlevels++; } while((tmp = strtok(NULL,",")) != NULL); } else if (fastcmp(word, "BONUSGAME")) { - cup->bonusgame = Z_StrDup(word2); + cup->levellist[CUPCACHE_BONUS] = Z_StrDup(word2); } else if (fastcmp(word, "SPECIALSTAGE")) { - cup->specialstage = Z_StrDup(word2); + cup->levellist[CUPCACHE_SPECIAL] = Z_StrDup(word2); } else if (fastcmp(word, "EMERALDNUM")) { diff --git a/src/doomstat.h b/src/doomstat.h index 807aec2d6..0ed88b1aa 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -207,7 +207,6 @@ extern boolean splitscreen_partied[MAXPLAYERS]; // Maps of special importance extern INT16 spstage_start, spmarathon_start; -extern INT16 sstage_start, sstage_end, smpstage_start, smpstage_end; extern char * titlemap; extern boolean hidetitlepics; @@ -221,8 +220,6 @@ extern boolean looptitle; // CTF colors. extern UINT16 skincolor_redteam, skincolor_blueteam, skincolor_redring, skincolor_bluering; -extern tic_t countdowntimer; -extern boolean countdowntimeup; extern boolean exitfadestarted; typedef struct @@ -313,8 +310,6 @@ extern textprompt_t *textprompts[MAX_PROMPTS]; extern INT16 nextmapoverride; extern UINT8 skipstats; -extern UINT32 ssspheres; // Total # of spheres in a level - // Fun extra stuff extern INT16 lastmap; // Last level you were at (returning from special stages). extern mobj_t *redflag, *blueflag; // Pointers to physical flags @@ -340,91 +335,108 @@ extern struct quake } quake; // Custom Lua values -// (This is not ifdeffed so the map header structure can stay identical, just in case.) typedef struct { char option[32]; // 31 usable characters char value[256]; // 255 usable characters. If this seriously isn't enough then wtf. } customoption_t; +// This could support more, but is that a good idea? +// Keep in mind that it may encourage people making overly long cups just because they "can", and would be a waste of memory. +#define MAXLEVELLIST 5 +#define CUPCACHE_BONUS MAXLEVELLIST +#define CUPCACHE_SPECIAL MAXLEVELLIST+1 +#define CUPCACHE_MAX CUPCACHE_SPECIAL+1 + +typedef struct cupheader_s +{ + UINT16 id; ///< Cup ID + char name[15]; ///< Cup title (14 chars) + char icon[9]; ///< Name of the icon patch + char *levellist[CUPCACHE_MAX]; ///< List of levels that belong to this cup + INT16 cachedlevels[CUPCACHE_MAX]; ///< IDs in levellist, bonusgame, and specialstage + UINT8 numlevels; ///< Number of levels defined in levellist + UINT8 emeraldnum; ///< ID of Emerald to use for special stage (1-7 for Chaos Emeralds, 8-14 for Super Emeralds, 0 for no emerald) + SINT8 unlockrequired; ///< An unlockable is required to select this cup. -1 for no unlocking required. + struct cupheader_s *next; ///< Next cup in linked list +} cupheader_t; + +extern cupheader_t *kartcupheaders; // Start of cup linked list +extern UINT16 numkartcupheaders; + /** Map header information. */ typedef struct { - char * lumpname; ///< Lump name can be really long - lumpnum_t lumpnum; ///< Lump number for the map, used by vres_GetMap + // Core game information, not user-modifiable directly + char *lumpname; ///< Lump name can be really long + lumpnum_t lumpnum; ///< Lump number for the map, used by vres_GetMap - void * thumbnailPic; ///< Lump data for the level select thumbnail. - void * minimapPic; ///< Lump data for the minimap graphic. - void * encoreLump; ///< Lump data for the Encore Mode remap. - void * tweakLump; ///< Lump data for the palette tweak remap. + void *thumbnailPic; ///< Lump data for the level select thumbnail. + void *minimapPic; ///< Lump data for the minimap graphic. + void *encoreLump; ///< Lump data for the Encore Mode remap. + void *tweakLump; ///< Lump data for the palette tweak remap. + UINT8 mapvisited; ///< A set of flags that says what we've done in the map. + recorddata_t *mainrecord; ///< Stores best time attack data + + cupheader_t *cup; ///< Cached cup + + // Titlecard information char lvlttl[22]; ///< Level name without "Zone". (21 character limit instead of 32, 21 characters can display on screen max anyway) char subttl[33]; ///< Subtitle for level char zonttl[22]; ///< "ZONE" replacement name UINT8 actnum; ///< Act number or 0 for none. - UINT32 typeoflevel; ///< Combination of typeoflevel flags. - + // Selection metadata char keywords[33]; ///< Keywords separated by space to search for. 32 characters. + SINT8 unlockrequired; ///< Is an unlockable required to play this level? -1 if no. + UINT8 levelselect; ///< Is this map available in the level select? If so, which map list is it available in? + UINT16 menuflags; ///< LF2_flags: options that affect record attack menus + + // Operational metadata + UINT16 levelflags; ///< LF_flags: merged booleans into one UINT16 for space, see below + UINT32 typeoflevel; ///< Combination of typeoflevel flags. + UINT8 numlaps; ///< Number of laps in circuit mode, unless overridden. + fixed_t gravity; ///< Map-wide gravity. + + // Music information char musname[7]; ///< 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. - - UINT8 weather; ///< 0 = sunny day, 1 = storm, 2 = snow, 3 = rain, 4 = blank, 5 = thunder w/o rain, 6 = rain w/o lightning, 7 = heat wave. + // Sky information + UINT8 weather; ///< See preciptype_t char skytexture[9]; ///< Sky texture to use. INT16 skybox_scalex; ///< Skybox X axis scale. (0 = no movement, 1 = 1:1 movement, 16 = 16:1 slow movement, -4 = 1:4 fast movement, etc.) INT16 skybox_scaley; ///< Skybox Y axis scale. INT16 skybox_scalez; ///< Skybox Z axis scale. - // Extra information. - char interscreen[8]; ///< 320x200 patch to display at intermission. - - char runsoc[33]; ///< SOC to execute at start of level (32 character limit instead of 63) - char scriptname[33]; ///< Script to use when the map is switched to. (32 character limit instead of 191) - - UINT8 precutscenenum; ///< Cutscene number to play BEFORE a level starts. - UINT8 cutscenenum; ///< Cutscene number to use, 0 for none. - - INT16 countdown; ///< Countdown until level end? + // Distance information + fixed_t mobj_scale; ///< Defines the size all object calculations are relative to + fixed_t default_waypoint_radius; ///< 0 is a special value for DEFAULT_WAYPOINT_RADIUS, but scaled with mobjscale + // Visual information UINT16 palette; ///< PAL lump to use on this map UINT16 encorepal; ///< PAL for encore mode + UINT8 light_contrast; ///< Range of wall lighting. 0 is no lighting. + boolean use_light_angle; ///< When false, wall lighting is evenly distributed. When true, wall lighting is directional. + angle_t light_angle; ///< Angle of directional wall lighting. - UINT8 numlaps; ///< Number of laps in circuit mode, unless overridden. - - SINT8 unlockrequired; ///< Is an unlockable required to play this level? -1 if no. - UINT8 levelselect; ///< Is this map available in the level select? If so, which map list is it available in? - - UINT16 levelflags; ///< LF_flags: merged booleans into one UINT16 for space, see below - UINT16 menuflags; ///< LF2_flags: options that affect record attack / nights mode menus - - UINT16 startrings; ///< Number of rings players start with. - INT32 sstimer; ///< Timer for special stages. - UINT32 ssspheres; ///< Sphere requirement in special stages. - fixed_t gravity; ///< Map-wide gravity. - - // Freed animals stuff. + // Freed animal information UINT8 numFlickies; ///< Internal. For freed flicky support. mobjtype_t *flickies; ///< List of freeable flickies in this level. Allocated dynamically for space reasons. Be careful. - UINT8 light_contrast; ///< Range of wall lighting. 0 is no lighting. - boolean use_light_angle; ///< When false, wall lighting is evenly distributed. When true, wall lighting is directional. - angle_t light_angle; ///< Angle of directional wall lighting. + // Script information + char runsoc[33]; ///< SOC to execute at start of level (32 character limit instead of 63) + char scriptname[33]; ///< Script to use when the map is switched to. (32 character limit instead of 191) - // SRB2kart - fixed_t mobj_scale; ///< Replacement for TOL_ERZ3 - fixed_t default_waypoint_radius; ///< 0 is a special value for DEFAULT_WAYPOINT_RADIUS, but scaled with mobjscale + // Cutscene information + UINT8 precutscenenum; ///< Cutscene number to play BEFORE a level starts. + UINT8 cutscenenum; ///< Cutscene number to use, 0 for none. - // Record data (modified liberally, saved to gamedata) - UINT8 mapvisited; ///< A set of flags that says what we've done in the map. - recorddata_t *mainrecord; ///< Stores best time attack data - - // Lua stuff. - // (This is not ifdeffed so the map header structure can stay identical, just in case.) + // Lua information UINT8 numCustomOptions; ///< Internal. For Lua custom value support. customoption_t *customopts; ///< Custom options. Allocated dynamically for space reasons. Be careful. } mapheader_t; @@ -443,27 +455,6 @@ typedef struct extern mapheader_t** mapheaderinfo; extern INT32 nummapheaders, mapallocsize; -// This could support more, but is that a good idea? -// Keep in mind that it may encourage people making overly long cups just because they "can", and would be a waste of memory. -#define MAXLEVELLIST 5 - -typedef struct cupheader_s -{ - UINT16 id; ///< Cup ID - char name[15]; ///< Cup title (14 chars) - char icon[9]; ///< Name of the icon patch - char *levellist[MAXLEVELLIST]; ///< List of levels that belong to this cup - UINT8 numlevels; ///< Number of levels defined in levellist - char *bonusgame; ///< Map name to use for bonus game - char *specialstage; ///< Map name to use for special stage - UINT8 emeraldnum; ///< ID of Emerald to use for special stage (1-7 for Chaos Emeralds, 8-14 for Super Emeralds, 0 for no emerald) - SINT8 unlockrequired; ///< An unlockable is required to select this cup. -1 for no unlocking required. - struct cupheader_s *next; ///< Next cup in linked list -} cupheader_t; - -extern cupheader_t *kartcupheaders; // Start of cup linked list -extern UINT16 numkartcupheaders; - // Gametypes #define NUMGAMETYPEFREESLOTS 128 @@ -588,7 +579,6 @@ extern UINT32 token; ///< Number of tokens collected in a level extern UINT32 tokenlist; ///< List of tokens collected extern boolean gottoken; ///< Did you get a token? Used for end of act extern INT32 tokenbits; ///< Used for setting token bits -extern INT32 sstimer; ///< Time allotted in the special stage extern UINT32 bluescore; ///< Blue Team Scores extern UINT32 redscore; ///< Red Team Scores diff --git a/src/g_game.c b/src/g_game.c index 21e30df41..7d75245e1 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -151,12 +151,10 @@ INT32 g_localplayers[MAXSPLITSCREENPLAYERS]; tic_t gametic; tic_t levelstarttic; // gametic at level start -UINT32 ssspheres; // old special stage INT16 lastmap; // last level you were at (returning from special stages) tic_t timeinmap; // Ticker for time spent in level (used for levelcard display) INT16 spstage_start, spmarathon_start; -INT16 sstage_start, sstage_end, smpstage_start, smpstage_end; char * titlemap = NULL; boolean hidetitlepics = false; @@ -172,8 +170,6 @@ UINT16 skincolor_blueteam = SKINCOLOR_BLUE; UINT16 skincolor_redring = SKINCOLOR_RASPBERRY; UINT16 skincolor_bluering = SKINCOLOR_PERIWINKLE; -tic_t countdowntimer = 0; -boolean countdowntimeup = false; boolean exitfadestarted = false; cutscene_t *cutscenes[128]; @@ -212,9 +208,6 @@ UINT32 tokenlist; // List of tokens collected boolean gottoken; // Did you get a token? Used for end of act INT32 tokenbits; // Used for setting token bits -// Old Special Stage -INT32 sstimer; // Time allotted in the special stage - tic_t totalplaytime; UINT32 matchesplayed; // SRB2Kart boolean gamedataloaded = false; @@ -673,13 +666,13 @@ INT32 G_MapNumber(const char * name) for (map = 0; map < nummapheaders; ++map) { - if (strcasecmp(mapheaderinfo[map]->lumpname, name) == 0) - { - break; - } + if (strcasecmp(mapheaderinfo[map]->lumpname, name) != 0) + continue; + + return map; } - return map; + return NEXTMAP_INVALID; } #ifdef NEXTMAPINSOC @@ -3201,18 +3194,15 @@ INT32 G_GetGametypeByName(const char *gametypestr) // boolean G_IsSpecialStage(INT32 mapnum) { -#if 1 - (void)mapnum; -#else - if (modeattacking == ATTACKING_TIME) - return false; - if (mapnum >= sstage_start && mapnum <= sstage_end) - return true; - if (mapnum >= smpstage_start && mapnum <= smpstage_end) - return true; -#endif + mapnum--; // gamemap-based to 0 indexed - return false; + if (mapnum > nummapheaders || !mapheaderinfo[mapnum]) + return false; + + if (!mapheaderinfo[mapnum]->cup || mapheaderinfo[mapnum]->cup->cachedlevels[CUPCACHE_SPECIAL] != mapnum) + return false; + + return true; } // @@ -3386,11 +3376,11 @@ UINT32 G_TOLFlag(INT32 pgametype) INT16 G_GetFirstMapOfGametype(UINT8 pgametype) { - INT16 mapnum = nummapheaders; + INT16 mapnum = NEXTMAP_INVALID; if ((gametypedefaultrules[pgametype] & GTR_CAMPAIGN) && kartcupheaders) { - mapnum = G_MapNumber(kartcupheaders->levellist[0]); + mapnum = kartcupheaders->cachedlevels[0]; } if (mapnum >= nummapheaders) @@ -3699,7 +3689,7 @@ static void G_GetNextMap(void) else { // Proceed to next map - const INT32 cupLevelNum = G_MapNumber(grandprixinfo.cup->levellist[grandprixinfo.roundnum]); + const INT32 cupLevelNum =grandprixinfo.cup->cachedlevels[grandprixinfo.roundnum]; if (cupLevelNum < nummapheaders && mapheaderinfo[cupLevelNum]) { @@ -3725,19 +3715,14 @@ static void G_GetNextMap(void) if (gametyperules & GTR_CAMPAIGN) { register INT16 cm; - cupheader_t *cup = kartcupheaders; + cupheader_t *cup = mapheaderinfo[gamemap-1]->cup; UINT8 gettingresult = 0; - // While this can't produce an infinite loop IN THE ITERATION, it - // is technically possible for you to keep cycling inside a lousy - // cul-de-sac of the same maps over and over while marathonning - // them all, if the same map is present in the cup list multiple - // times. There is no good solution. Don't dupe maps between cups! while (cup) { for (i = 0; i < cup->numlevels; i++) { - cm = G_MapNumber(cup->levellist[i]); + cm = cup->cachedlevels[i]; // Not valid? if (cm >= nummapheaders @@ -3829,9 +3814,7 @@ static void G_GetNextMap(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 < NEXTMAP_SPECIAL && (nextmap >= nummapheaders || !mapheaderinfo[nextmap] || mapheaderinfo[nextmap]->lumpnum == LUMPERROR)) + if (nextmap == NEXTMAP_INVALID || (nextmap < NEXTMAP_SPECIAL && (nextmap >= nummapheaders || !mapheaderinfo[nextmap] || mapheaderinfo[nextmap]->lumpnum == LUMPERROR))) I_Error("G_GetNextMap: Internal map ID %d not found (nummapheaders = %d)\n", nextmap, nummapheaders); } @@ -4135,11 +4118,6 @@ void G_LoadGameSettings(void) { // defaults spstage_start = spmarathon_start = 1; - sstage_start = 50; - sstage_end = 56; // 7 special stages in vanilla SRB2 - sstage_end++; // plus one weirdo - smpstage_start = 60; - smpstage_end = 66; // 7 multiplayer special stages too // initialize free sfx slots for skin sounds S_InitRuntimeSounds(); diff --git a/src/g_game.h b/src/g_game.h index 3cc0963cf..fbd423963 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -44,7 +44,8 @@ typedef enum NEXTMAP_EVALUATION = INT16_MAX-2, NEXTMAP_CREDITS = INT16_MAX-3, NEXTMAP_CEREMONY = INT16_MAX-4, - NEXTMAP_SPECIAL = NEXTMAP_CEREMONY + NEXTMAP_INVALID = INT16_MAX-5, // Always last (swap with NEXTMAP_RESERVED when removing that) + NEXTMAP_SPECIAL = NEXTMAP_INVALID } nextmapspecial_t; extern INT32 gameovertics; diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 598ad9b48..cd5fcbaf1 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -1846,7 +1846,7 @@ static void M_DrawCupPreview(INT16 y, cupheader_t *cup) i = (cupgrid.previewanim / 82) % cup->numlevels; while (x < BASEVIDWIDTH + pad) { - INT32 cupLevelNum = G_MapNumber(cup->levellist[i]); + INT32 cupLevelNum = cup->cachedlevels[i]; patch_t *PictureOfLevel = NULL; if (cupLevelNum < nummapheaders && mapheaderinfo[cupLevelNum]) diff --git a/src/k_menufunc.c b/src/k_menufunc.c index c119cfe7d..0fad3451a 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -3207,23 +3207,10 @@ boolean M_CanShowLevelInList(INT16 mapnum, UINT8 gt) if (levellist.timeattack && (mapheaderinfo[mapnum]->menuflags & LF2_NOTIMEATTACK)) return false; - if (gametypedefaultrules[gt] & GTR_CAMPAIGN) + if (gametypedefaultrules[gt] & GTR_CAMPAIGN && levellist.selectedcup) { - if (levellist.selectedcup && levellist.selectedcup->numlevels) - { - UINT8 i; - - for (i = 0; i < levellist.selectedcup->numlevels; i++) - { - const INT32 cupLevelNum = G_MapNumber(levellist.selectedcup->levellist[i]); - - if (mapnum == cupLevelNum) - break; - } - - if (i == levellist.selectedcup->numlevels) - return false; - } + if (mapheaderinfo[mapnum]->cup != levellist.selectedcup) + return false; } // Survived our checks. @@ -3413,7 +3400,9 @@ void M_CupSelectHandler(INT32 choice) { M_SetMenuDelay(pid); - if ((!newcup) || (newcup && newcup->unlockrequired != -1 && !unlockables[newcup->unlockrequired].unlocked)) + if ((!newcup) + || (newcup && newcup->unlockrequired != -1 && !unlockables[newcup->unlockrequired].unlocked) + || (newcup->cachedlevels[0] == NEXTMAP_INVALID)) { S_StartSound(NULL, sfx_s3kb2); return; @@ -3465,7 +3454,7 @@ void M_CupSelectHandler(INT32 choice) netgame = levellist.netgame; // ^ ditto. } - levelNum = G_MapNumber(grandprixinfo.cup->levellist[0]); + levelNum = grandprixinfo.cup->cachedlevels[0]; D_MapChange( levelNum + 1, diff --git a/src/lua_maplib.c b/src/lua_maplib.c index b1bc68236..16e26069f 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -2116,7 +2116,6 @@ static int mapheaderinfo_get(lua_State *L) { mapheader_t *header = *((mapheader_t **)luaL_checkudata(L, 1, META_MAPHEADER)); const char *field = luaL_checkstring(L, 2); - INT16 i; if (fastcmp(field,"lvlttl")) lua_pushstring(L, header->lvlttl); else if (fastcmp(field,"subttl")) @@ -2135,8 +2134,6 @@ static int mapheaderinfo_get(lua_State *L) lua_pushinteger(L, header->mustrack); else if (fastcmp(field,"muspos")) lua_pushinteger(L, header->muspos); - else if (fastcmp(field,"forcecharacter")) - lua_pushstring(L, header->forcecharacter); else if (fastcmp(field,"weather")) lua_pushinteger(L, header->weather); else if (fastcmp(field,"skytexture")) @@ -2147,12 +2144,7 @@ static int mapheaderinfo_get(lua_State *L) lua_pushinteger(L, header->skybox_scaley); else if (fastcmp(field,"skybox_scalez")) lua_pushinteger(L, header->skybox_scalez); - else if (fastcmp(field,"interscreen")) { - for (i = 0; i < 8; i++) - if (!header->interscreen[i]) - break; - lua_pushlstring(L, header->interscreen, i); - } else if (fastcmp(field,"runsoc")) + else if (fastcmp(field,"runsoc")) lua_pushstring(L, header->runsoc); else if (fastcmp(field,"scriptname")) lua_pushstring(L, header->scriptname); @@ -2160,8 +2152,6 @@ static int mapheaderinfo_get(lua_State *L) lua_pushinteger(L, header->precutscenenum); else if (fastcmp(field,"cutscenenum")) lua_pushinteger(L, header->cutscenenum); - else if (fastcmp(field,"countdown")) - lua_pushinteger(L, header->countdown); else if (fastcmp(field,"palette")) lua_pushinteger(L, header->palette); else if (fastcmp(field,"numlaps")) @@ -2176,12 +2166,6 @@ static int mapheaderinfo_get(lua_State *L) lua_pushinteger(L, header->menuflags); else if (fastcmp(field,"mobj_scale")) lua_pushfixed(L, header->mobj_scale); - else if (fastcmp(field,"startrings")) - lua_pushinteger(L, header->startrings); - else if (fastcmp(field, "sstimer")) - lua_pushinteger(L, header->sstimer); - else if (fastcmp(field, "ssspheres")) - lua_pushinteger(L, header->ssspheres); else if (fastcmp(field, "gravity")) lua_pushfixed(L, header->gravity); else { diff --git a/src/lua_script.c b/src/lua_script.c index 14c066bc0..33dbe9fc3 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -217,18 +217,6 @@ int LUA_PushGlobals(lua_State *L, const char *word) } else if (fastcmp(word,"spmarathon_start")) { lua_pushinteger(L, spmarathon_start); return 1; - } else if (fastcmp(word,"sstage_start")) { - lua_pushinteger(L, sstage_start); - return 1; - } else if (fastcmp(word,"sstage_end")) { - lua_pushinteger(L, sstage_end); - return 1; - } else if (fastcmp(word,"smpstage_start")) { - lua_pushinteger(L, smpstage_start); - return 1; - } else if (fastcmp(word,"smpstage_end")) { - lua_pushinteger(L, smpstage_end); - return 1; } else if (fastcmp(word,"titlemap")) { lua_pushstring(L, titlemap); return 1; diff --git a/src/p_mobj.c b/src/p_mobj.c index 28b596e2e..d2eeca805 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11281,7 +11281,7 @@ void P_SpawnPlayer(INT32 playernum) else if (p->bot) { /* - if (bonusgame || specialstage) + if (bonusgame || specialstage || boss) { // Bots should avoid p->spectator = true; diff --git a/src/p_saveg.c b/src/p_saveg.c index 5578814f4..337efd5a8 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -4476,7 +4476,6 @@ static void P_NetArchiveMisc(boolean resending) WRITEUINT8(save_p, encoremode); WRITEUINT32(save_p, leveltime); - WRITEUINT32(save_p, ssspheres); WRITEINT16(save_p, lastmap); WRITEUINT16(save_p, bossdisabled); @@ -4502,7 +4501,6 @@ static void P_NetArchiveMisc(boolean resending) } WRITEUINT32(save_p, token); - WRITEINT32(save_p, sstimer); WRITEUINT32(save_p, bluescore); WRITEUINT32(save_p, redscore); @@ -4531,9 +4529,6 @@ static void P_NetArchiveMisc(boolean resending) WRITEFIXED(save_p, gravity); WRITEFIXED(save_p, mapobjectscale); - WRITEUINT32(save_p, countdowntimer); - WRITEUINT8(save_p, countdowntimeup); - // SRB2kart WRITEINT32(save_p, numgotboxes); WRITEUINT8(save_p, numtargets); @@ -4642,7 +4637,6 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading) // get the time leveltime = READUINT32(save_p); - ssspheres = READUINT32(save_p); lastmap = READINT16(save_p); bossdisabled = READUINT16(save_p); @@ -4665,7 +4659,6 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading) } token = READUINT32(save_p); - sstimer = READINT32(save_p); bluescore = READUINT32(save_p); redscore = READUINT32(save_p); @@ -4694,9 +4687,6 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading) gravity = READFIXED(save_p); mapobjectscale = READFIXED(save_p); - countdowntimer = (tic_t)READUINT32(save_p); - countdowntimeup = (boolean)READUINT8(save_p); - // SRB2kart numgotboxes = READINT32(save_p); numtargets = READUINT8(save_p); diff --git a/src/p_setup.c b/src/p_setup.c index 0c9879370..fa4adff30 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -366,28 +366,22 @@ static void P_ClearSingleMapHeaderInfo(INT16 num) mapheaderinfo[num]->zonttl[0] = '\0'; mapheaderinfo[num]->actnum = 0; mapheaderinfo[num]->typeoflevel = 0; - mapheaderinfo[num]->startrings = 0; - mapheaderinfo[num]->sstimer = 90; - mapheaderinfo[num]->ssspheres = 1; mapheaderinfo[num]->gravity = DEFAULT_GRAVITY; mapheaderinfo[num]->keywords[0] = '\0'; - sprintf(mapheaderinfo[num]->musname, "%.5sM", G_BuildMapName(i)); + sprintf(mapheaderinfo[num]->musname, "%.5sM", G_BuildMapName(num)); mapheaderinfo[num]->musname[6] = 0; mapheaderinfo[num]->mustrack = 0; mapheaderinfo[num]->muspos = 0; - mapheaderinfo[num]->forcecharacter[0] = '\0'; mapheaderinfo[num]->weather = PRECIP_NONE; snprintf(mapheaderinfo[num]->skytexture, 5, "SKY1"); mapheaderinfo[num]->skytexture[4] = 0; mapheaderinfo[num]->skybox_scalex = 16; mapheaderinfo[num]->skybox_scaley = 16; mapheaderinfo[num]->skybox_scalez = 16; - mapheaderinfo[num]->interscreen[0] = '#'; mapheaderinfo[num]->runsoc[0] = '#'; mapheaderinfo[num]->scriptname[0] = '#'; mapheaderinfo[num]->precutscenenum = 0; mapheaderinfo[num]->cutscenenum = 0; - mapheaderinfo[num]->countdown = 0; mapheaderinfo[num]->palette = UINT16_MAX; mapheaderinfo[num]->encorepal = UINT16_MAX; mapheaderinfo[num]->numlaps = NUMLAPS_DEFAULT; @@ -461,8 +455,9 @@ void P_AllocMapHeader(INT16 i) mapheaderinfo[i]->lumpname = NULL; mapheaderinfo[i]->thumbnailPic = NULL; mapheaderinfo[i]->minimapPic = NULL; - mapheaderinfo[i]->flickies = NULL; + mapheaderinfo[i]->cup = NULL; mapheaderinfo[i]->mainrecord = NULL; + mapheaderinfo[i]->flickies = NULL; nummapheaders++; } P_ClearSingleMapHeaderInfo(i); @@ -3523,15 +3518,6 @@ static void P_InitLevelSettings(void) // emerald hunt hunt1 = hunt2 = hunt3 = NULL; - // map time limit - if (mapheaderinfo[gamemap-1]->countdown) - { - countdowntimer = mapheaderinfo[gamemap-1]->countdown * TICRATE; - } - else - countdowntimer = 0; - countdowntimeup = false; - // clear ctf pointers redflag = blueflag = NULL; rflagpoint = bflagpoint = NULL; @@ -3539,7 +3525,7 @@ static void P_InitLevelSettings(void) // circuit, race and competition stuff circuitmap = false; numstarposts = 0; - ssspheres = timeinmap = 0; + timeinmap = 0; // special stage stagefailed = true; // assume failed unless proven otherwise - P_GiveEmerald or emerald touchspecial @@ -3683,43 +3669,6 @@ static void P_RunLevelScript(const char *scriptname) COM_BufExecute(); // Run it! } -static void P_ForceCharacter(const char *forcecharskin) -{ - UINT8 i; - - if (netgame) - { - char skincmd[33]; - - for (i = 0; i <= splitscreen; i++) - { - const char *num = ""; - - if (i > 0) - num = va("%d", i+1); - - sprintf(skincmd, "skin%s %s\n", num, forcecharskin); - CV_Set(&cv_skin[i], forcecharskin); - } - - COM_BufAddText(skincmd); - } - else - { - for (i = 0; i <= splitscreen; i++) - { - SetPlayerSkin(g_localplayers[i], forcecharskin); - - // normal player colors in single player - if ((unsigned)cv_playercolor[i].value != skins[players[g_localplayers[i]].skin].prefcolor && !modeattacking) - { - CV_StealthSetValue(&cv_playercolor[i], skins[players[g_localplayers[i]].skin].prefcolor); - players[g_localplayers[i]].skincolor = skins[players[g_localplayers[i]].skin].prefcolor; - } - } - } -} - static void P_ResetSpawnpoints(void) { UINT8 i; @@ -3991,9 +3940,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) for (i = 0; i <= r_splitscreen; i++) postimgtype[i] = postimg_none; - if (mapheaderinfo[gamemap-1]->forcecharacter[0] != '\0') - P_ForceCharacter(mapheaderinfo[gamemap-1]->forcecharacter); - // Initial height of PointOfView // will be set by player think. players[consoleplayer].viewz = 1; @@ -4566,6 +4512,37 @@ UINT8 P_InitMapData(INT32 numexistingmapheaders) } vres_Free(virtmap); + + // Now associate it with a cup cache. + // (The core assumption is that cups < headers.) + if (i >= numexistingmapheaders) + { + cupheader_t *cup = kartcupheaders; + INT32 j; + while (cup) + { + for (j = 0; j < CUPCACHE_MAX; j++) + { + // Already discovered? + if (cup->cachedlevels[j] != NEXTMAP_INVALID) + continue; + + if (!cup->levellist[j] || strcasecmp(cup->levellist[j], name) != 0) + continue; + + // Only panic about back-reference for non-bonus material. + if (j < MAXLEVELLIST || j == CUPCACHE_SPECIAL) + { + if (mapheaderinfo[i]->cup) + I_Error("P_InitMapData: Map %s cannot appear in cups multiple times! (First in %s, now in %s)", name, mapheaderinfo[i]->cup->name, cup->name); + mapheaderinfo[i]->cup = cup; + } + + cup->cachedlevels[j] = i; + } + cup = cup->next; + } + } } } diff --git a/src/p_spec.c b/src/p_spec.c index e0ea77c63..859b35fe1 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -5931,10 +5931,6 @@ void P_InitSpecials(void) maplighting.directional = mapheaderinfo[gamemap-1]->use_light_angle; maplighting.angle = mapheaderinfo[gamemap-1]->light_angle; - // Defaults in case levels don't have them set. - sstimer = mapheaderinfo[gamemap-1]->sstimer*TICRATE + 6; - ssspheres = mapheaderinfo[gamemap-1]->ssspheres; - CheckForBustableBlocks = CheckForBouncySector = CheckForQuicksand = CheckForMarioBlocks = CheckForFloatBob = CheckForReverseGravity = false; // Set weather @@ -6026,11 +6022,6 @@ void P_SpawnSpecials(boolean fromnetsave) // Process Section 2 switch(GETSECSPECIAL(sector->special, 2)) { - case 10: // Time for special stage - sstimer = (sector->floorheight>>FRACBITS) * TICRATE + 6; // Time to finish - ssspheres = sector->ceilingheight>>FRACBITS; // Ring count for special stage - break; - case 11: // Custom global gravity! gravity = sector->floorheight/1000; break; diff --git a/src/p_user.c b/src/p_user.c index 1185c2033..53014038f 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -300,11 +300,15 @@ boolean P_PlayerMoving(INT32 pnum) // UINT8 P_GetNextEmerald(void) { - if (gamemap >= sstage_start && gamemap <= sstage_end) - return (UINT8)(gamemap - sstage_start); - if (gamemap >= smpstage_start || gamemap <= smpstage_end) - return (UINT8)(gamemap - smpstage_start); - return 0; + INT16 mapnum = gamemap-1; + + if (mapnum > nummapheaders || !mapheaderinfo[mapnum]) + return 0; + + if (!mapheaderinfo[mapnum]->cup || mapheaderinfo[mapnum]->cup->cachedlevels[CUPCACHE_SPECIAL] != mapnum) + return 0; + + return mapheaderinfo[mapnum]->cup->emeraldnum; } // @@ -2144,9 +2148,6 @@ void P_MovePlayer(player_t *player) fixed_t runspd; - if (countdowntimeup) - return; - cmd = &player->cmd; runspd = 14*player->mo->scale; //srb2kart diff --git a/src/r_skins.c b/src/r_skins.c index ae5e0363c..f8410c15f 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -191,12 +191,6 @@ boolean R_SkinUsable(INT32 playernum, INT32 skinnum) return true; } - if (Playing() && (R_SkinAvailable(mapheaderinfo[gamemap-1]->forcecharacter) == skinnum)) - { - // Being forced to play as this character by the level - return true; - } - if (netgame && (cv_forceskin.value == skinnum)) { // Being forced to play as this character by the server From cb8becb2d37c5ada6f35c953152ef725f8098e75 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 22 Sep 2022 17:34:02 +0100 Subject: [PATCH 44/60] Enforce maximum length of 63 for map lumpname Also, in g_demo.c, use SKIPSTRING (instead of READSTRINGN into a discard buffer) --- src/dehacked.c | 11 ++++++++++- src/doomstat.h | 2 ++ src/g_demo.c | 16 +++++++--------- src/g_game.c | 6 +++--- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index e9ab537e9..eeb4acc69 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -382,7 +382,16 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile) } else if (fastcmp(word, "LEVEL")) { - readlevelheader(f, word2); + size_t len = strlen(word2); + if (len <= MAXMAPLUMPNAME-1) + { + readlevelheader(f, word2); + } + else + { + deh_warning("Map header's lumpname %s is too long (%d characters VS %d max)", word2, len, (MAXMAPLUMPNAME-1)); + ignorelines(f); + } } else if (fastcmp(word, "GAMETYPE")) { diff --git a/src/doomstat.h b/src/doomstat.h index 0ed88b1aa..b64385d33 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -364,6 +364,8 @@ typedef struct cupheader_s extern cupheader_t *kartcupheaders; // Start of cup linked list extern UINT16 numkartcupheaders; +#define MAXMAPLUMPNAME 64 // includes \0, for cleaner savedata + /** Map header information. */ typedef struct diff --git a/src/g_demo.c b/src/g_demo.c index c060762b5..27e42e541 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -1994,7 +1994,7 @@ void G_BeginRecording(void) // game data M_Memcpy(demo_p, "PLAY", 4); demo_p += 4; - WRITESTRINGN(demo_p, mapheaderinfo[gamemap-1]->lumpname, 255); + WRITESTRINGN(demo_p, mapheaderinfo[gamemap-1]->lumpname, MAXMAPLUMPNAME); M_Memcpy(demo_p, mapmd5, 16); demo_p += 16; WRITEUINT8(demo_p, demoflags); @@ -2406,7 +2406,6 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname) UINT16 s ATTRUNUSED; UINT8 aflags = 0; boolean uselaps = false; - char discard[255]; // load the new file FIL_DefaultExtension(newname, ".lmp"); @@ -2427,7 +2426,7 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname) p += 16; // demo checksum I_Assert(!memcmp(p, "PLAY", 4)); p += 4; // PLAY - READSTRINGN(p, discard, sizeof(discard)); // gamemap + SKIPSTRING(p); // gamemap p += 16; // map md5 flags = READUINT8(p); // demoflags p++; // gametype @@ -2485,7 +2484,7 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname) Z_Free(buffer); return UINT8_MAX; } p += 4; // "PLAY" - READSTRINGN(p, discard, sizeof(discard)); // gamemap + SKIPSTRING(p); // gamemap p += 16; // mapmd5 flags = READUINT8(p); p++; // gametype @@ -2704,7 +2703,7 @@ void G_DoPlayDemo(char *defdemoname) { UINT8 i, p; lumpnum_t l; - char skin[17],color[MAXCOLORNAME+1],follower[17],mapname[255],*n,*pdemoname; + char skin[17],color[MAXCOLORNAME+1],follower[17],mapname[MAXMAPLUMPNAME],*n,*pdemoname; UINT8 version,subversion; UINT32 randseed; char msg[1024]; @@ -3146,7 +3145,7 @@ void G_AddGhost(char *defdemoname) { INT32 i; lumpnum_t l; - char name[17],skin[17],color[MAXCOLORNAME+1],discard[255],*n,*pdemoname,md5[16]; + char name[17],skin[17],color[MAXCOLORNAME+1],*n,*pdemoname,md5[16]; demoghost *gh; UINT8 flags; UINT8 *buffer,*p; @@ -3235,7 +3234,7 @@ void G_AddGhost(char *defdemoname) } p += 4; // "PLAY" - READSTRINGN(p, discard, sizeof(discard)); // gamemap + SKIPSTRING(p); // gamemap p += 16; // mapmd5 (possibly check for consistency?) flags = READUINT8(p); @@ -3431,7 +3430,6 @@ void G_UpdateStaffGhostName(lumpnum_t l) UINT8 *buffer,*p; UINT16 ghostversion; UINT8 flags; - char discard[255]; buffer = p = W_CacheLumpNum(l, PU_CACHE); @@ -3465,7 +3463,7 @@ void G_UpdateStaffGhostName(lumpnum_t l) } p += 4; // "PLAY" - READSTRINGN(p, discard, sizeof(discard)); // gamemap + SKIPSTRING(p); // gamemap p += 16; // mapmd5 (possibly check for consistency?) flags = READUINT8(p); diff --git a/src/g_game.c b/src/g_game.c index 7d75245e1..cbd3f7db8 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4227,7 +4227,7 @@ void G_LoadGameData(void) for (i = 0; i < numgamedatamapheaders; i++) { - char mapname[255]; + char mapname[MAXMAPLUMPNAME]; INT16 mapnum; tic_t rectime; tic_t reclap; @@ -4297,7 +4297,7 @@ void G_SaveGameData(void) return; // If never loaded (-nodata), don't save length = (4+4+4+1+(MAXEMBLEMS)+MAXEXTRAEMBLEMS+MAXUNLOCKABLES+MAXCONDITIONSETS+4+4); - length += nummapheaders * (255+1+4+4); + length += nummapheaders * (MAXMAPLUMPNAME+1+4+4); save_p = savebuffer = (UINT8 *)malloc(length); if (!save_p) @@ -4366,7 +4366,7 @@ void G_SaveGameData(void) for (i = 0; i < nummapheaders; i++) // nummapheaders * (255+1+4+4) { // For figuring out which header to assing it to on load - WRITESTRINGN(save_p, mapheaderinfo[i]->lumpname, 255); + WRITESTRINGN(save_p, mapheaderinfo[i]->lumpname, MAXMAPLUMPNAME); WRITEUINT8(save_p, (mapheaderinfo[i]->mapvisited & MV_MAX)); From 937e1d10d4a667928611cc999e53490729ef9bd6 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 22 Sep 2022 09:56:50 -0700 Subject: [PATCH 45/60] Fix -Wformat --- src/dehacked.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dehacked.c b/src/dehacked.c index eeb4acc69..0a532bb6f 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -389,7 +389,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile) } else { - deh_warning("Map header's lumpname %s is too long (%d characters VS %d max)", word2, len, (MAXMAPLUMPNAME-1)); + deh_warning("Map header's lumpname %s is too long (%s characters VS %d max)", word2, sizeu1(len), (MAXMAPLUMPNAME-1)); ignorelines(f); } } From bd965ccd50b6a9c4bca407dcc82bf3358f9035a9 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 22 Sep 2022 18:02:14 +0100 Subject: [PATCH 46/60] Off by one for music name default generation --- src/p_setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_setup.c b/src/p_setup.c index fa4adff30..a141f2a31 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -368,7 +368,7 @@ static void P_ClearSingleMapHeaderInfo(INT16 num) mapheaderinfo[num]->typeoflevel = 0; mapheaderinfo[num]->gravity = DEFAULT_GRAVITY; mapheaderinfo[num]->keywords[0] = '\0'; - sprintf(mapheaderinfo[num]->musname, "%.5sM", G_BuildMapName(num)); + sprintf(mapheaderinfo[num]->musname, "%.5sM", G_BuildMapName(num+1)); mapheaderinfo[num]->musname[6] = 0; mapheaderinfo[num]->mustrack = 0; mapheaderinfo[num]->muspos = 0; From 89a22783b6ae069583e15e11891c987a38ae89b3 Mon Sep 17 00:00:00 2001 From: SteelT Date: Thu, 22 Sep 2022 16:05:44 -0400 Subject: [PATCH 47/60] vres_GetMap: Count resources in folders up until next 0-length lump, instead of "MAPXX" As having named map lumps means the lump being named "MAPXX" isn't guaranteed anymore. --- src/w_wad.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/w_wad.c b/src/w_wad.c index 3c739493c..ee4c8e68a 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -2278,11 +2278,15 @@ virtres_t* vres_GetMap(lumpnum_t lumpnum) } else { - // Count number of lumps until the end of resource OR up until next "MAPXX" lump. + // Count number of lumps until the end of resource OR up until next 0-length lump. lumpnum_t lumppos = lumpnum + 1; for (i = LUMPNUM(lumppos); i < wadfiles[WADFILENUM(lumpnum)]->numlumps; i++, lumppos++, numlumps++) - if (memcmp(W_CheckNameForNum(lumppos), "MAP", 3) == 0) + { + if (W_LumpLength(lumppos) == 0) + { break; + } + } numlumps++; vlumps = Z_Malloc(sizeof(virtlump_t)*numlumps, PU_LEVEL, NULL); From 959bb14f59e58f9a0a52bb3e06fdfad57c656973 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 23 Sep 2022 11:55:11 +0100 Subject: [PATCH 48/60] Fix an error that used map ID when lumpname is better for debugging --- src/p_setup.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index a141f2a31..5a7b86c90 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -314,11 +314,19 @@ boolean P_IsDegeneratedTubeWaypointSequence(UINT8 sequence) FUNCNORETURN static ATTRNORETURN void CorruptMapError(const char *msg) { // don't use va() because the calling function probably uses it - char mapnum[10]; + char mapname[MAXMAPLUMPNAME]; - sprintf(mapnum, "%hd", gamemap); + if (gamemap > 0 && gamemap <= nummapheaders && mapheaderinfo[gamemap-1]) + { + sprintf(mapname, "%s", mapheaderinfo[gamemap-1]->lumpname); + } + else + { + sprintf(mapname, "ID %d", gamemap-1); + } + CON_LogMessage("Map "); - CON_LogMessage(mapnum); + CON_LogMessage(mapname); CON_LogMessage(" is corrupt: "); CON_LogMessage(msg); CON_LogMessage("\n"); From 8afd9b03b243dd19d413a488f3e1bb9ec45bab67 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 23 Sep 2022 12:26:32 +0100 Subject: [PATCH 49/60] Only allow W_CheckNumForMap to return lumpnums fitting certain criteria - For PK3, if it's a .wad - For .wad, if it's a header (0-length) --- src/w_wad.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/w_wad.c b/src/w_wad.c index ee4c8e68a..6660028ff 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -966,8 +966,15 @@ UINT16 W_CheckNumForMapPwad(const char *name, UINT16 wad, UINT16 startlump) { for (i = startlump; i < wadfiles[wad]->numlumps; i++) { - if (!strcasecmp(name, (wadfiles[wad]->lumpinfo + i)->name)) - return i; + // Not the name? + if (strcasecmp(name, (wadfiles[wad]->lumpinfo + i)->name)) + continue; + + // Not a header? + if (W_LumpLength(i | (wad << 16)) > 0) + continue; + + return i; } } else if (wadfiles[wad]->type == RET_PK3) @@ -981,8 +988,15 @@ UINT16 W_CheckNumForMapPwad(const char *name, UINT16 wad, UINT16 startlump) // Now look for the specified map. for (; i < end; i++) { - if (!strcasecmp(name, (wadfiles[wad]->lumpinfo + i)->longname)) - return i; + // Not the name? + if (strcasecmp(name, (wadfiles[wad]->lumpinfo + i)->longname)) + continue; + + // Not a .wad? + if (!W_IsLumpWad(i | (wad << 16))) + continue; + + return i; } } } From 1538055091d5d2847996610e100231842d55661a Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 23 Sep 2022 13:03:37 +0100 Subject: [PATCH 50/60] Skip over empty entries when populating vres, saving memory --- src/w_wad.c | 48 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/src/w_wad.c b/src/w_wad.c index 6660028ff..83dad0db7 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -2271,23 +2271,43 @@ virtres_t* vres_GetMap(lumpnum_t lumpnum) if (W_IsLumpWad(lumpnum)) { + UINT32 realentry; + size_t *vsizecache; + // Remember that we're assuming that the WAD will have a specific set of lumps in a specific order. UINT8 *wadData = W_CacheLumpNum(lumpnum, PU_LEVEL); filelump_t *fileinfo = (filelump_t *)(wadData + ((wadinfo_t *)wadData)->infotableofs); - numlumps = ((wadinfo_t *)wadData)->numlumps; - vlumps = Z_Malloc(sizeof(virtlump_t)*numlumps, PU_LEVEL, NULL); - // Build the lumps. - for (i = 0; i < numlumps; i++) + i = ((wadinfo_t *)wadData)->numlumps; + vsizecache = Z_Malloc(sizeof(size_t)*i, PU_LEVEL, NULL); + + for (realentry = 0; realentry < i; realentry++) { - vlumps[i].size = (size_t)(((filelump_t *)(fileinfo + i))->size); - // Play it safe with the name in this case. - memcpy(vlumps[i].name, (fileinfo + i)->name, 8); - vlumps[i].name[8] = '\0'; - vlumps[i].data = Z_Malloc(vlumps[i].size, PU_LEVEL, NULL); // This is memory inefficient, sorry about that. - memcpy(vlumps[i].data, wadData + (fileinfo + i)->filepos, vlumps[i].size); + vsizecache[realentry] = (size_t)(((filelump_t *)(fileinfo + realentry))->size); + + if (!vsizecache[realentry]) + continue; + + numlumps++; } + vlumps = Z_Malloc(sizeof(virtlump_t)*numlumps, PU_LEVEL, NULL); + + // Build the lumps, skipping over empty entries. + for (i = 0, realentry = 0; i < numlumps; realentry++) + { + if (vsizecache[realentry] == 0) + continue; + vlumps[i].size = vsizecache[realentry]; + // Play it safe with the name in this case. + memcpy(vlumps[i].name, (fileinfo + realentry)->name, 8); + vlumps[i].name[8] = '\0'; + vlumps[i].data = Z_Malloc(vlumps[i].size, PU_LEVEL, NULL); // This is memory inefficient, sorry about that. + memcpy(vlumps[i].data, wadData + (fileinfo + realentry)->filepos, vlumps[i].size); + i++; + } + + Z_Free(vsizecache); Z_Free(wadData); } else @@ -2296,10 +2316,10 @@ virtres_t* vres_GetMap(lumpnum_t lumpnum) lumpnum_t lumppos = lumpnum + 1; for (i = LUMPNUM(lumppos); i < wadfiles[WADFILENUM(lumpnum)]->numlumps; i++, lumppos++, numlumps++) { - if (W_LumpLength(lumppos) == 0) - { - break; - } + if (W_LumpLength(lumppos) > 0) + continue; + + break; } numlumps++; From a4c73b204ae6ca5ced740bab93306b7488e4dd9e Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 23 Sep 2022 13:07:59 +0100 Subject: [PATCH 51/60] Kill spstage_start and spmarathon_start --- src/deh_soc.c | 16 ---------------- src/doomstat.h | 3 --- src/g_game.c | 7 +------ src/lua_script.c | 6 ------ 4 files changed, 1 insertion(+), 31 deletions(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index ac22781ed..8edb2ef19 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -2857,22 +2857,6 @@ void readmaincfg(MYFILE *f) COM_BufInsertText(W_CacheLumpNum(lumpnum, PU_CACHE)); } } - - else if (fastcmp(word, "SPSTAGE_START")) - { - // TODO: Use map name string - // Haven't done it because of how special stage ends are handled - // Though, we likely won't be using these for Kart anyhow - INT16 maptmp = G_MapNumber(word2)+1; - if (maptmp <= nummapheaders) - spstage_start = spmarathon_start = maptmp; - } - else if (fastcmp(word, "SPMARATHON_START")) - { - INT16 maptmp = G_MapNumber(word2)+1; - if (maptmp <= nummapheaders) - spmarathon_start = maptmp; - } else if (fastcmp(word, "REDTEAM")) { skincolor_redteam = (UINT16)get_number(word2); diff --git a/src/doomstat.h b/src/doomstat.h index b64385d33..0c3eafa5e 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -205,9 +205,6 @@ extern INT32 splitscreen_party[MAXPLAYERS][MAXSPLITSCREENPLAYERS]; /* the only local one */ extern boolean splitscreen_partied[MAXPLAYERS]; -// Maps of special importance -extern INT16 spstage_start, spmarathon_start; - extern char * titlemap; extern boolean hidetitlepics; extern char * bootmap; //bootmap for loading a map on startup diff --git a/src/g_game.c b/src/g_game.c index cbd3f7db8..19834d0ed 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -154,8 +154,6 @@ tic_t levelstarttic; // gametic at level start INT16 lastmap; // last level you were at (returning from special stages) tic_t timeinmap; // Ticker for time spent in level (used for levelcard display) -INT16 spstage_start, spmarathon_start; - char * titlemap = NULL; boolean hidetitlepics = false; char * bootmap = NULL; //bootmap for loading a map on startup @@ -3655,7 +3653,7 @@ static void G_HandleSaveLevel(void) cursaveslot = 0; } else if ((!modifiedgame || savemoddata) && !(netgame || multiplayer || ultimatemode || demo.recording || metalrecording || modeattacking)) - G_SaveGame((UINT32)cursaveslot, spstage_start); + G_SaveGame((UINT32)cursaveslot, 0); // TODO when we readd a campaign one day } } // and doing THIS here means you don't lose your progress if you close the game mid-intermission @@ -4116,9 +4114,6 @@ void G_EndGame(void) // Sets a tad of default info we need. void G_LoadGameSettings(void) { - // defaults - spstage_start = spmarathon_start = 1; - // initialize free sfx slots for skin sounds S_InitRuntimeSounds(); } diff --git a/src/lua_script.c b/src/lua_script.c index 33dbe9fc3..a9eb964cd 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -211,12 +211,6 @@ int LUA_PushGlobals(lua_State *L, const char *word) lua_pushinteger(L, cv_pointlimit.value); return 1; // begin map vars - } else if (fastcmp(word,"spstage_start")) { - lua_pushinteger(L, spstage_start); - return 1; - } else if (fastcmp(word,"spmarathon_start")) { - lua_pushinteger(L, spmarathon_start); - return 1; } else if (fastcmp(word,"titlemap")) { lua_pushstring(L, titlemap); return 1; From 3786d9a33dc3e0c2042be82cfc2a53254fe04b57 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 23 Sep 2022 17:27:57 +0100 Subject: [PATCH 52/60] Update configuration - Support new map lump ordering (THANKS STEEL FOR FINDING THESE OPTIONS!!) - Prevent rotating waypoints causing their IDs to become corrupted - Rename to `D3R-Config.cfg` - Synchronise with changelog-tracked resource - Integrate relevant 2.2 changes - Add new credits according to historical changelogs - A whole bunch of other cleanup --- extras/conf/{SRB2Kart2.cfg => D3R-Config.cfg} | 2258 +++++------------ 1 file changed, 578 insertions(+), 1680 deletions(-) rename extras/conf/{SRB2Kart2.cfg => D3R-Config.cfg} (75%) diff --git a/extras/conf/SRB2Kart2.cfg b/extras/conf/D3R-Config.cfg similarity index 75% rename from extras/conf/SRB2Kart2.cfg rename to extras/conf/D3R-Config.cfg index 97db26fc2..354d7a176 100644 --- a/extras/conf/SRB2Kart2.cfg +++ b/extras/conf/D3R-Config.cfg @@ -1,22 +1,26 @@ /*********************************************************\ vim: ai Zone Builder Game Configuration - For SRB2Kart Version 2.0 - Based on the Configuration for Sonic Robo Blast 2 Version 2.1 + For Dr. Robotnik's Ring Racers + Based on the Configuration for Sonic Robo Blast 2 Version 2.2 Contributors (alphabetical): * Foxboy + * James(/Jart) * JJames19119 * Kalaron * Kristos * MascaraSnake + * MK * Morpheus * Neo Chaotikal * Oogaland * Rob + * SeventhSentinel * Shadow Hog * SRB2-Playah * SSNTails * ST218 + * TehRealSalt * toaster * Viola \*********************************************************/ @@ -25,7 +29,7 @@ type = "Doom Builder 2 Game Configuration"; // This is the title to show for this game -game = "SRB2Jart v2.0"; +game = "Dr. Robotnik's Ring Racers"; //GZDB specific. Don't try to load lumps that don't exist. basegame = 0; @@ -126,7 +130,7 @@ skins Knuckles; Amy; Mighty; - Ray; + Motobug; Eggman; MetalSonic; Fang; @@ -158,7 +162,7 @@ generalizedsectors = true; defaultwalltexture = "GFZROCK"; defaultfloortexture = "GFZFLR01"; defaultceilingtexture = "F_SKY1"; -mixtexturesflats = false; +mixtexturesflats = true; defaulttexturescale = 1.0f; defaultflatscale = 1.0f; @@ -223,34 +227,6 @@ sprites } } -// Flat sources -flats -{ - standard1 - { - start = "F_START"; - end = "F_END"; - } - - standard2 - { - start = "FF_START"; - end = "FF_END"; - } - - standard3 - { - start = "FF_START"; - end = "F_END"; - } - - standard4 - { - start = "F_START"; - end = "FF_END"; - } -} - /* GAME DETECT PATTERN @@ -367,6 +343,34 @@ maplumpnames nodebuild = true; allowempty = true; } + + PICTURE + { + required = false; + blindcopy = true; + nodebuild = false; + } + + MINIMAP + { + required = false; + blindcopy = true; + nodebuild = false; + } + + TWEAKMAP + { + required = false; + blindcopy = true; + nodebuild = false; + } + + ENCORE + { + required = false; + blindcopy = true; + nodebuild = false; + } } scriptlumpnames @@ -656,11 +660,9 @@ linedeftypes { title = "Sector Flat Alignment"; prefix = "(7)"; - flags64text = "[6] Align only floor"; - flags2text = "[1] Align only ceiling"; - flags512text = "[9] Rotate flats"; - flags16384text = "[14] Rotate only floor"; - flags1024text = "[10] Rotate only ceiling"; + flags2048text = "[11] Don't align floor"; + flags4096text = "[12] Don't align ceiling"; + flags8192text = "[13] Use texture offsets"; } 10 @@ -681,6 +683,12 @@ linedeftypes title = "Visual Portal Between Tagged Linedefs"; prefix = "(40)"; } + + 41 + { + title = "Horizon Effect"; + prefix = "(41)"; + } 50 { @@ -706,6 +714,12 @@ linedeftypes prefix = "(80)"; } + 81 + { + title = "Block enemies"; + prefix = "(81)"; + } + 96 { title = "Apply Tag to Tagged Sectors"; @@ -769,7 +783,9 @@ linedeftypes { title = "Special Sector Properties"; prefix = "(8)"; + flags32text = "[5] Invert precipitation"; flags64text = "[6] Touch only ceiling"; + flags128text = "[7] Allow opposite gravity"; flags256text = "[8] Touch sector edge"; flags512text = "[9] Touch floor or ceiling"; } @@ -778,7 +794,12 @@ linedeftypes { title = "Chain Parameters"; prefix = "(9)"; - flags64text = "[6] Fixed spinning direction"; + flags32text = "[5] Swing instead of spin"; + flags128text = "[7] Make chain from end item"; + flags64text = "[6] Player-turnable chain"; + flags256text = "[8] Spawn link at origin"; + flags512text = "[9] Don't clip inside ground"; + flags1024text = "[10] No distance check"; } 11 @@ -796,6 +817,19 @@ linedeftypes flags64text = "[6] Randomize speed"; } + 14 + { + title = "Bustable Block Parameters"; + prefix = "(14)"; + flags32text = "[5] Particles launch from center"; + } + + 15 + { + title = "Fan Particle Spawner Parameters"; + prefix = "(15)"; + } + 64 { title = "Continuously Appearing/Disappearing FOF"; @@ -817,37 +851,42 @@ linedeftypes 20 { - title = "First Line"; + title = "PolyObject First Line"; prefix = "(20)"; - flags64text = "[6] Trigger linedef executor"; - flags128text = "[7] Intangible"; - flags256text = "[8] Stopped by pushables"; - flags512text = "[9] Render flats"; - } - - 21 - { - title = "Explicitly Include Line"; - prefix = "(21)"; } 22 { - title = "Parameters"; + title = "PolyObject Parameters"; prefix = "(22)"; + flags8text = "[3] Set translucency by X offset"; + flags32text = "[5] Render outer sides only"; + flags64text = "[6] Trigger linedef executor"; + flags128text = "[7] Intangible"; + flags256text = "[8] Stopped by pushables"; + flags512text = "[9] Render flats"; + flags8192text = "[13] Cut cyan flat pixels"; } 30 { - title = "Waving Flag"; + title = "PolyObject Waving Flag"; prefix = "(30)"; } 31 { - title = "Displacement by Front Sector"; + title = "Move PolyObject by Front Sector Displacement"; prefix = "(31)"; } + + 32 + { + title = "Rotate PolyObject by Front Sector Displacement"; + prefix = "(32)"; + flags64text = "[6] Don't turn players"; + flags512text = "[9] Turn all objects"; + } } planemove @@ -1760,7 +1799,7 @@ linedeftypes title = "Set Tagged Sector's Floor Height/Texture"; prefix = "(400)"; flags8text = "[3] Set delay by backside sector"; - flags64text = "[6] Don't change floor texture"; + flags64text = "[6] Keep floor flat"; } 401 @@ -1856,7 +1895,7 @@ linedeftypes prefix = "(403)"; flags2text = "[1] Trigger linedef executor"; flags8text = "[3] Set delay by backside sector"; - flags64text = "[6] Change floor texture"; + flags64text = "[6] Change floor flat"; } 404 @@ -1865,7 +1904,7 @@ linedeftypes prefix = "(404)"; flags2text = "[1] Trigger linedef executor"; flags8text = "[3] Set delay by backside sector"; - flags64text = "[6] Change ceiling texture"; + flags64text = "[6] Change ceiling flat"; } 405 @@ -2107,7 +2146,6 @@ linedeftypes flags8text = "[3] Set delay by backside sector"; } - 445 { title = "Make FOF Disappear/Reappear"; @@ -2116,6 +2154,45 @@ linedeftypes flags64text = "[6] Reappear"; } + 446 + { + title = "Make FOF Crumble"; + prefix = "(446)"; + flags2text = "[1] Flags determine respawn"; + flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] Don't respawn"; + } + + 447 + { + title = "Change Tagged Sector's Colormap"; + prefix = "(447)"; + flags8text = "[3] Set delay by backside sector"; + flags16text = "[4] Front X/Y = Alpha"; + flags32text = "[5] Subtract Red value"; + flags64text = "[6] Subtract Green value"; + flags128text = "[7] Subtract Blue value"; + flags256text = "[8] Set relative to current"; + flags32768text = "[15] Use backside colormap"; + } + + 448 + { + title = "Change Skybox"; + prefix = "(448)"; + flags2text = "[1] Change centerpoint"; + flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] For everyone"; + flags512text = "[9] Don't change viewpoint"; + } + + 449 + { + title = "Enable/Disable Waypoints"; + prefix = "(449)"; + flags64text = "[6] Enable waypoints"; + } + 450 { title = "Execute Linedef Executor (specific tag)"; @@ -2129,6 +2206,12 @@ linedeftypes prefix = "(451)"; flags8text = "[3] Set delay by backside sector"; } + + 460 + { + title = "Award Rings"; + prefix = "(460)"; + } } linedefexecpoly @@ -2201,7 +2284,7 @@ linedeftypes 488 { - title = "Move by Waypoints"; + title = "Move by Zoom Tube Waypoints"; prefix = "(488)"; flags8text = "[3] Set delay by backside sector"; flags32text = "[5] Reverse order"; @@ -2520,8 +2603,10 @@ linedeftypes prefix = "(700)"; flags2048text = "[11] No physics"; flags4096text = "[12] Not dynamic"; + flags32768text = "[15] Copy to other side"; slope = "regular"; slopeargs = 1; + copyslopeargs = 1; } 701 @@ -2530,8 +2615,10 @@ linedeftypes prefix = "(701)"; flags2048text = "[11] No physics"; flags4096text = "[12] Not dynamic"; + flags32768text = "[15] Copy to other side"; slope = "regular"; slopeargs = 2; + copyslopeargs = 4; } 702 @@ -2540,8 +2627,10 @@ linedeftypes prefix = "(702)"; flags2048text = "[11] No physics"; flags4096text = "[12] Not dynamic"; + flags32768text = "[15] Copy to other side"; slope = "regular"; slopeargs = 3; + copyslopeargs = 5; } 703 @@ -2550,8 +2639,10 @@ linedeftypes prefix = "(703)"; flags2048text = "[11] No physics"; flags4096text = "[12] Not dynamic"; + flags32768text = "[15] Copy to other side"; slope = "regular"; slopeargs = 9; + copyslopeargs = 8; } 704 @@ -2582,8 +2673,10 @@ linedeftypes prefix = "(710)"; flags2048text = "[11] No physics"; flags4096text = "[12] Not dynamic"; + flags32768text = "[15] Copy to other side"; slope = "regular"; slopeargs = 4; + copyslopeargs = 2; } 711 @@ -2592,8 +2685,10 @@ linedeftypes prefix = "(711)"; flags2048text = "[11] No physics"; flags4096text = "[12] Not dynamic"; + flags32768text = "[15] Copy to other side"; slope = "regular"; slopeargs = 8; + copyslopeargs = 8; } 712 @@ -2602,8 +2697,10 @@ linedeftypes prefix = "(712)"; flags2048text = "[11] No physics"; flags4096text = "[12] Not dynamic"; + flags32768text = "[15] Copy to other side"; slope = "regular"; slopeargs = 12; + copyslopeargs = 10; } 713 @@ -2612,8 +2709,10 @@ linedeftypes prefix = "(713)"; flags2048text = "[11] No physics"; flags4096text = "[12] Not dynamic"; + flags32768text = "[15] Copy to other side"; slope = "regular"; slopeargs = 6; + copyslopeargs = 6; } 714 @@ -2662,6 +2761,30 @@ linedeftypes slopeargs = 3; } + 720 + { + title = "Copy Frontside Floor Slope from Line Tag"; + prefix = "(720)"; + slope = "copy"; + slopeargs = 1; + } + + 721 + { + title = "Copy Frontside Ceiling Slope from Line Tag"; + prefix = "(721)"; + slope = "copy"; + slopeargs = 2; + } + + 722 + { + title = "Copy Frontside Floor and Ceiling Slope from Line Tag"; + prefix = "(722)"; + slope = "copy"; + slopeargs = 3; + } + 723 { title = "Copy Backside Floor Slope from Line Tag"; @@ -2691,7 +2814,6 @@ linedeftypes title = "Copy Frontside Floor Slope to Backside"; prefix = "(730)"; slope = "copy"; - slopeargs = 1; copyslopeargs = 1; } @@ -2700,7 +2822,6 @@ linedeftypes title = "Copy Frontside Ceiling Slope to Backside"; prefix = "(731)"; slope = "copy"; - slopeargs = 2; copyslopeargs = 4; } @@ -2709,7 +2830,6 @@ linedeftypes title = "Copy Frontside Floor and Ceiling Slope to Backside"; prefix = "(732)"; slope = "copy"; - slopeargs = 3; copyslopeargs = 5; } @@ -2718,7 +2838,6 @@ linedeftypes title = "Copy Backside Floor Slope to Frontside"; prefix = "(733)"; slope = "copy"; - slopeargs = 1; copyslopeargs = 2; } @@ -2727,7 +2846,6 @@ linedeftypes title = "Copy Backside Ceiling Slope to Frontside"; prefix = "(734)"; slope = "copy"; - slopeargs = 2; copyslopeargs = 8; } @@ -2736,7 +2854,6 @@ linedeftypes title = "Copy Backside Floor and Ceiling Slope to Frontside"; prefix = "(735)"; slope = "copy"; - slopeargs = 3; copyslopeargs = 10; } @@ -2768,7 +2885,7 @@ linedeftypes flags2048text = "[11] No physics"; flags4096text = "[12] Dynamic"; } - + 799 { title = "Set Tagged Dynamic Slope Vertex to Front Sector Height"; @@ -2839,11 +2956,35 @@ linedeftypes title = "Fog Wall"; prefix = "(909)"; } + + 910 + { + title = "Additive Blend"; + prefix = "(910)"; + } + + 911 + { + title = "Subtractive Blend"; + prefix = "(911)"; + } + + 912 + { + title = "Reverse-Subtractive Blend"; + prefix = "(912)"; + } + + 913 + { + title = "Modulate Blend"; + prefix = "(913)"; + } } derrlines { - title = "SRB2Kart"; + title = "Ring Racers"; 2000 { @@ -2857,6 +2998,28 @@ linedeftypes prefix = "(2001)"; flags64text = "[6] Use backside"; } + + 2002 + { + title = "Per Lap Executor"; + prefix = "(2002)"; + flags2text = "[2] Every lap lower"; + flags64text = "[6] Every lap higher"; + flags512text = "[9] Activate for 1st place"; + } + + 2003 + { + title = "Death Line"; + prefix = "(2003)"; + flags64text = "[6] Use frontside"; + } + + 2004 + { + title = "Bot Trick Controller"; + prefix = "(2004)"; + } } } @@ -3014,193 +3177,6 @@ thingtypes }*/ } - enemies - { - color = 9; // Light_Blue - arrow = 1; - title = "Enemies"; - width = 24; - height = 32; - sprite = "POSSA1"; - - 100 - { - title = "Crawla (Blue)"; - sprite = "POSSA1"; - } - 101 - { - title = "Crawla (Red)"; - sprite = "SPOSA1"; - } - 102 - { - title = "Stupid Dumb Unnamed RoboFish"; - sprite = "FISHA0"; - width = 8; - height = 28; - angletext = "Jump strength"; - } - 103 - { - title = "Buzz (Gold)"; - sprite = "BUZZA1"; - width = 20; - height = 24; - flags8text = "[8] Cannot move"; - } - 104 - { - title = "Buzz (Red)"; - sprite = "RBUZA1"; - width = 20; - height = 24; - flags8text = "[8] Cannot move"; - } - 124 - { - title = "Buzz (Aqua)"; - sprite = "BBUZA1"; - width = 20; - height = 24; - } - 105 - { - title = "Jetty-Syn Bomber"; - sprite = "JETBB1"; - width = 20; - height = 48; - flags8text = "[8] Cannot move"; - } - 106 - { - title = "Jetty-Syn Gunner"; - sprite = "JETGB1"; - width = 20; - height = 48; - flags8text = "[8] Cannot move"; - } - 107 - { - title = "Crawla Commander"; - sprite = "CCOMA1"; - width = 16; - } - 108 - { - title = "Deton"; - sprite = "DETNA1"; - width = 20; - } - 109 - { - title = "Skim"; - sprite = "SKIMA1"; - width = 16; - height = 24; - } - 110 - { - title = "Turret"; - sprite = "TRETA1"; - width = 16; - height = 32; - } - 111 - { - title = "Pop-up Turret"; - sprite = "TURRI1"; - width = 12; - height = 64; - angletext = "Firing delay"; - } - 112 - { - title = "Sharp"; - sprite = "SHRPA1"; - width = 16; - height = 24; - } - 113 - { - title = "Jet Jaw"; - sprite = "JJAWA3A7"; - width = 12; - height = 20; - } - 114 - { - title = "Snailer"; - sprite = "SNLRA3A7"; - height = 48; - } - 115 - { - title = "Bird Aircraft Strike Hazard"; - sprite = "VLTRF1"; - width = 12; - height = 24; - } - 116 - { - title = "Pointy"; - sprite = "PNTYA1"; - width = 8; - height = 16; - } - 117 - { - title = "Robo-Hood"; - sprite = "ARCHA1"; - flags8text = "[8] Cannot jump"; - } - 118 - { - title = "CastleBot FaceStabber"; - sprite = "CBFSA1"; - width = 32; - height = 64; - } - 119 - { - title = "Egg Guard"; - sprite = "ESHIA1"; - width = 16; - height = 48; - flags8text = "[8] Double speed"; - } - 120 - { - title = "Green Snapper"; - sprite = "GSNPA1"; - height = 24; - } - 121 - { - title = "Minus"; - sprite = "MNUSA1"; - } - 122 - { - title = "Spring Shell (Green)"; - sprite = "SSHLA1"; - height = 40; - } - 125 - { - title = "Spring Shell (Yellow)"; - sprite = "SSHLI1"; - height = 40; - } - 123 - { - title = "Unidus"; - sprite = "UNIDA1"; - width = 18; - height = 36; - } - } - bosses { color = 8; // Dark_Gray @@ -3208,76 +3184,15 @@ thingtypes title = "Bosses"; width = 24; height = 52; - sprite = "EGGMA1"; + sprite = "internal:eggmanway"; - 200 - { - title = "Boss 1 - Egg Mobile"; - sprite = "EGGMA1"; - flags4text = "[4] End level on death"; - flags8text = "[8] Alternate laser attack"; - } - 201 - { - title = "Boss 2 - Egg Slimer"; - sprite = "EGGNA1"; - height = 48; - flags4text = "[4] End level on death"; - flags8text = "[8] Speed up when hit"; - } - 202 - { - title = "Boss 3 - Sea Egg"; - sprite = "EGGOA1"; - width = 32; - height = 80; - flags4text = "[4] End level on death"; - } - 203 - { - title = "Boss 4 - Eggscalibur"; - sprite = "EGGPA1"; - flags4text = "[4] End level on death"; - } - 207 - { - title = "Boss 5A - Metal Sonic (Race)"; - sprite = "METLI1"; - width = 16; - height = 48; - } - 208 - { - title = "Boss 5B - Metal Sonic (Battle)"; - sprite = "METLC1"; - width = 16; - height = 48; - flags4text = "[4] End level on death"; - } - 209 - { - title = "Boss 6 - Brak Eggman"; - sprite = "BRAK[1"; - width = 48; - height = 160; - flags4text = "[4] End level on death"; - flags8text = "[8] Electric barrier"; - } - 206 - { - title = "Boss ? - Brak Eggman (Old)"; - sprite = "BRAKB1"; - width = 48; - height = 160; - flags4text = "[4] End level on death"; - } 290 { arrow = 0; title = "Boss Escape Point"; width = 8; height = 16; - sprite = "internal:eggmanend"; + sprite = "internal:eggmanendy"; } 291 { @@ -3298,12 +3213,22 @@ thingtypes angletext = "No. (Sea Egg)"; flagsvaluetext = "No. (Brak)"; parametertext = "Next"; + fixedrotation = 1; } 293 { title = "Metal Sonic Gather Point"; sprite = "internal:metal"; } + 294 + { + arrow = 0; + title = "Fang Waypoint"; + flags8text = "[8] Center waypoint"; + sprite = "internal:eggmanway"; + width = 8; + height = 16; + } } rings @@ -3322,83 +3247,6 @@ thingtypes sprite = "RINGA0"; width = 16; } - 301 - { - title = "Bounce Ring"; - sprite = "internal:RNGBA0"; - } - 302 - { - title = "Rail Ring"; - sprite = "internal:RNGRA0"; - } - 303 - { - title = "Infinity Ring"; - sprite = "internal:RNGIA0"; - } - 304 - { - title = "Automatic Ring"; - sprite = "internal:RNGAA0"; - } - 305 - { - title = "Explosion Ring"; - sprite = "internal:RNGEA0"; - } - 306 - { - title = "Scatter Ring"; - sprite = "internal:RNGSA0"; - } - 307 - { - title = "Grenade Ring"; - sprite = "internal:RNGGA0"; - } - 308 - { - title = "CTF Team Ring (Red)"; - sprite = "internal:RRNGA0"; - width = 16; - } - 309 - { - title = "CTF Team Ring (Blue)"; - sprite = "internal:BRNGA0"; - width = 16; - } - 330 - { - title = "Bounce Ring Panel"; - sprite = "internal:PIKBA0"; - } - 331 - { - title = "Rail Ring Panel"; - sprite = "internal:PIKRA0"; - } - 332 - { - title = "Automatic Ring Panel"; - sprite = "internal:PIKAA0"; - } - 333 - { - title = "Explosion Ring Panel"; - sprite = "internal:PIKEA0"; - } - 334 - { - title = "Scatter Ring Panel"; - sprite = "internal:PIKSA0"; - } - 335 - { - title = "Grenade Ring Panel"; - sprite = "internal:PIKGA0"; - } } collectibles @@ -3408,204 +3256,27 @@ thingtypes width = 16; height = 32; sort = 1; - sprite = "CEMGA0"; + sprite = "ITEMALAR"; - 310 + 2000 { - title = "CTF Red Flag"; - sprite = "RFLGA0"; - width = 24; - height = 64; + title = "Random Item"; + sprite = "RNDMA0"; + width = 36; + height = 36; } - 311 + 2010 { - title = "CTF Blue Flag"; - sprite = "BFLGA0"; - width = 24; - height = 64; - } - 312 - { - title = "Special Stage Token"; - sprite = "internal:token"; - width = 8; - height = 16; - flags8height = 24; - flags4text = "[4] Mario Block version"; - flags8text = "[8] Float"; - } - 313 - { - title = "Chaos Emerald 1 (Green)"; - sprite = "EMMYA0"; - } - 314 - { - title = "Chaos Emerald 2 (Purple)"; - sprite = "EMMYB0"; - } - 315 - { - title = "Chaos Emerald 3 (Blue)"; - sprite = "EMMYC0"; - } - 316 - { - title = "Chaos Emerald 4 (Cyan)"; - sprite = "EMMYD0"; - } - 317 - { - title = "Chaos Emerald 5 (Orange)"; - sprite = "EMMYE0"; - } - 318 - { - title = "Chaos Emerald 6 (Red)"; - sprite = "EMMYF0"; - } - 319 - { - title = "Chaos Emerald 7 (Gray)"; - sprite = "EMMYG0"; - } - 320 - { - title = "Emerald Hunt Location"; - sprite = "internal:hunt"; - } - 323 - { - title = "Match Chaos Emerald Spawn"; - sprite = "CEMGA0"; - width = 8; - height = 16; - flags8height = 24; - flags8text = "[8] Float"; - } - } - - boxes - { - color = 7; // Gray - blocking = 2; - title = "Monitors"; - width = 16; - height = 32; - flags4text = "[4] Random (Strong)"; - flags8text = "[8] Random (Weak)"; - sprite = "SRBXA0"; - - 400 - { - title = "Super Ring (10 Rings)"; - sprite = "SRBXA0"; - } - 401 - { - title = "Pity Shield"; - sprite = "GRTVA0"; - } - 402 - { - title = "Attraction Shield"; - sprite = "YLTVA0"; - } - 403 - { - title = "Force Shield"; - sprite = "BLTVA0"; - } - 404 - { - title = "Armageddon Shield"; - sprite = "BKTVA0"; - } - 405 - { - title = "Whirlwind Shield"; - sprite = "WHTVA0"; - } - 406 - { - title = "Elemental Shield"; - sprite = "ELTVA0"; - } - 407 - { - title = "Super Sneakers"; - sprite = "SHTVA0"; - } - 408 - { - title = "Invincibility"; - sprite = "PINVA0"; - } - 409 - { - title = "Extra Life"; - sprite = "PRUPA0"; - flags4text = "[4] Random (Strong) / 10k points"; - flags8text = "[8] Random (Weak) / 10k points"; - } - 410 - { - title = "Eggman"; - sprite = "EGGBA0"; - flags4text = "[4] Special"; - flags8text = "[8] Ambush"; - } - 411 - { - title = "Teleporter"; - sprite = "MIXUA0"; - } - 412 - { - title = "Random"; - sprite = "QUESA0"; - flags4text = "[4] Special"; - flags8text = "[8] Ambush"; - } - 413 - { - title = "Gravity Boots"; - sprite = "GBTVA0"; - flags4text = "[4] Special"; - flags8text = "[8] Ambush"; - } - 414 - { - title = "CTF Team Ring Monitor (Red)"; - sprite = "RRBXA0"; - flags4text = "[4] Special"; - flags8text = "[8] Ambush"; - } - 415 - { - title = "CTF Team Ring Monitor (Blue)"; - sprite = "BRBXA0"; - flags4text = "[4] Special"; - flags8text = "[8] Ambush"; - } - 416 - { - title = "Recycler"; - sprite = "RECYA0"; - } - 418 - { - title = "Score (1,000 Points)"; - sprite = "PTTVA0"; - flags4text = "[4] Special"; - flags8text = "[8] Ambush"; - } - 419 - { - title = "Score (10,000 Points)"; - sprite = "PTTVF0"; - flags4text = "[4] Special"; - flags8text = "[8] Ambush"; + title = "Item Capsule"; + sprite = "ICAPA0"; + width = 56; + height = 96; + angletext = "Object Type"; + parametertext = "Amount"; + flags1text = "[1] Toggle RA persistence"; + flags4text = "[4] Add 16"; + flags8text = "[8] Double Size"; + fixedrotation = 1; } } @@ -3615,175 +3286,143 @@ thingtypes title = "Miscellaneous"; width = 16; height = 40; - sprite = "STPTA0"; + sprite = "SIGND0"; - 500 + 2424 { - title = "Air Bubble Patch"; - sprite = "BUBLA0"; - width = 8; - height = 16; - flags8text = "[8] No distance check"; + title = "Finish-Line Beam Points"; + sprite = "FLBMA0"; } 501 { + arrow = 1; title = "Level End Sign"; sprite = "SIGND0"; width = 8; height = 32; } - 502 + 3775 + { + title = "Kiosk"; + sprite = "OTCPA0"; + width = 12; + height = 48; + } + 2333 { arrow = 1; - title = "Star Post"; - sprite = "STPTA0"; - width = 64; - height = 80; - angletext = "Angle/Order"; - } - 526 - { + title = "Target Capsule"; + //sprite = "internal:kartcapsule"; + width = 28; + height = 112; blocking = 2; - title = "Cannonball"; - sprite = "CBLLA0"; - width = 20; - flags4text = "[4] Slides when pushed"; - flags8text = "[8] Not pushable"; + angletext = "Speed"; + parametertext = "Movement sequence"; + flags4text = "[4] Reverse movement"; + flags8text = "[8] Back and forth"; + fixedrotation = 1; } - 1000 + 1104 { - arrow = 1; - blocking = 2; - title = "Gargoyle"; - sprite = "GARGA1"; - flags4text = "[4] Slides when pushed"; - flags8text = "[8] Not pushable"; - } - 1102 - { - arrow = 1; - blocking = 2; - title = "Eggman Statue"; - sprite = "ESTAA1"; - width = 32; - height = 240; - flags4text = "[4] Slides when pushed"; - flags8text = "[8] Not pushable"; - } - 1106 - { - arrow = 1; - title = "Chain (Swinging)"; - sprite = "internal:chain1"; - height = 32; + title = "Mace Spawnpoint"; + sprite = "SMCEA0"; + width = 17; + height = 34; + flags4text = "[4] No sounds"; flags8text = "[8] Double size"; angletext = "Tag"; + parametertext = "Spokes"; + fixedrotation = 1; + fixedrotation = 1; + } + 1105 + { + title = "Chain with Maces Spawnpoint"; + sprite = "SMCEA0"; + width = 17; + height = 34; + flags4text = "[4] No sounds"; + flags8text = "[8] Double size"; + angletext = "Tag"; + parametertext = "Spokes"; + fixedrotation = 1; } 1107 { - arrow = 1; - title = "Chain (Spinning)"; - sprite = "internal:chain2"; - height = 32; + title = "Chain Spawnpoint"; + sprite = "BMCHA0"; + width = 17; + height = 34; flags8text = "[8] Double size"; angletext = "Tag"; + parametertext = "Spokes"; + fixedrotation = 1; } 1108 { arrow = 1; - title = "Chain (Hidden)"; + title = "Hidden Chain Spawnpoint"; sprite = "internal:chain3"; - height = 32; + width = 17; + height = 34; flags8text = "[8] Double size"; } - 1200 + 1109 { - title = "Tumbleweed (Big)"; - sprite = "BTBLA0"; - width = 24; - height = 48; - flags8text = "[8] Moves perpetually"; + title = "Firebar Spawnpoint"; + sprite = "BFBRA0"; + width = 17; + height = 34; + flags4text = "[4] No sounds"; + flags8text = "[8] Double size"; + angletext = "Tag"; + parametertext = "Spokes"; + fixedrotation = 1; } - 1201 + 1110 { - title = "Tumbleweed (Small)"; - sprite = "STBLA0"; - width = 12; - height = 24; - flags8text = "[8] Moves perpetually"; - } - 1504 - { - title = "ATZ Target"; - sprite = "RCRYB0"; - width = 24; - height = 32; - } - 1852 - { - blocking = 2; - title = "Snowman"; - sprite = "XMS3A0"; - flags4text = "[4] Slides when pushed"; - flags8text = "[8] Not pushable"; - } - 1876 - { - arrow = 1; - blocking = 2; - title = "Eggman Disco Statue"; - sprite = "ESTAB1"; - width = 20; - height = 96; - flags4text = "[4] Slides when pushed"; - flags8text = "[8] Not pushable"; + title = "Custom Mace Spawnpoint"; + sprite = "SMCEA0"; + width = 17; + height = 34; + flags4text = "[4] No sounds"; + angletext = "Tag"; + parametertext = "Spokes"; + fixedrotation = 1; } } springs { color = 12; // Light_Red - title = "Springs and Fans"; + title = "Springs and Dash Rings"; width = 48; height = 32; sprite = "RSPRD2"; - 540 - { - title = "Fan"; - sprite = "FANSA0D0"; - width = 16; - height = 16; - flags4text = "[4] Invisible"; - flags8text = "[8] No distance check"; - angletext = "Lift height"; - } - 541 - { - title = "Gas Jet"; - sprite = "STEMD0"; - width = 32; - height = 16; - } 550 { title = "Yellow Spring"; sprite = "SPVYA0"; + flags8text = "[8] Add Gravity"; } 551 { title = "Red Spring"; sprite = "SPVRA0"; + flags8text = "[8] Add Gravity"; } 552 { title = "Blue Spring"; sprite = "SPVBA0"; + flags8text = "[8] Add Gravity"; } 553 { title = "Grey Spring"; sprite = "SPVGA0"; + flags8text = "[8] Add Gravity"; } 554 { @@ -3841,92 +3480,34 @@ thingtypes sprite = "SPHGA2A8"; flags8text = "[8] Rotate 22.5° CCW"; } - } - - patterns - { - color = 5; // Magenta - arrow = 1; - title = "Special Placement Patterns"; - width = 16; - height = 384; - sprite = "RINGA0"; - - 600 + 3441 { - arrow = 0; - title = "5 Vertical Rings (Yellow Spring)"; - sprite = "RINGA0"; + title = "Dash Ring"; + sprite = "DASRA1"; + width = 32; + height = 45; + parametertext = "Strength"; + flags1text = "[1] 30 Degrees Up"; + flags4text = "[4] 60 Degrees Up"; + flags8text = "[8] Angle Upwards"; } - 601 + 3442 { - arrow = 0; - title = "5 Vertical Rings (Red Spring)"; - sprite = "RINGA0"; - height = 1024; + title = "Rainbow Ring"; + sprite = "RAIRA1"; + width = 32; + height = 45; + parametertext = "Strength"; + flags1text = "[1] 30 Degrees Up"; + flags4text = "[4] 60 Degrees Up"; + flags8text = "[8] Angle Upwards"; } - 602 + 541 { - title = "5 Diagonal Rings (Yellow Spring)"; - sprite = "RINGA0"; - height = 32; - } - 603 - { - title = "10 Diagonal Rings (Red Spring)"; - sprite = "RINGA0"; - height = 32; - } - 604 - { - title = "Circle of Rings"; - sprite = "RINGA0"; - width = 96; - height = 192; - unflippable = true; - centerHitbox = true; - } - 605 - { - title = "Circle of Rings (Big)"; - sprite = "RINGA0"; - width = 192; - unflippable = true; - centerHitbox = true; - } - 606 - { - title = "Circle of Wing Logos"; - sprite = "NWNGA0"; - width = 96; - height = 192; - unflippable = true; - centerHitbox = true; - } - 607 - { - title = "Circle of Wing Logos (Big)"; - sprite = "NWNGA0"; - width = 192; - unflippable = true; - centerHitbox = true; - } - 608 - { - title = "Circle of Rings and Wings"; - sprite = "NWNGA0"; - width = 96; - height = 192; - unflippable = true; - centerHitbox = true; - } - 609 - { - title = "Circle of Rings and Wings (Big)"; - sprite = "NWNGA0"; - width = 192; - unflippable = true; - centerHitbox = true; + title = "Gas Jet"; + sprite = "STEMD0"; + width = 32; + height = 16; } } @@ -3938,12 +3519,140 @@ thingtypes height = 16; sprite = "UNKNA0"; + 750 + { + title = "Slope Vertex"; + sprite = "internal:vertexslope"; + angletext = "Tag"; + fixedrotation = 1; + } + + 751 + { + arrow = 1; + title = "Teleport Destination"; + sprite = "internal:tele"; + } + + 752 + { + arrow = 1; + title = "Alternate View Point"; + sprite = "internal:view"; + } + + 753 + { + title = "Zoom Tube Waypoint"; + sprite = "internal:zoom"; + angletext = "Order"; + fixedrotation = 1; + } + + 754 + { + title = "Push Point"; + flags4text = "[4] Fades using XY"; + flags8text = "[8] Push using XYZ"; + sprite = "internal:tele"; + angletext = "Radius"; + fixedrotation = 1; + } + 755 + { + title = "Pull Point"; + flags4text = "[4] Fades using XY"; + flags8text = "[8] Pull using XYZ"; + sprite = "internal:tele"; + angletext = "Radius"; + fixedrotation = 1; + } + 756 + { + title = "Blast Linedef Executor"; + sprite = "internal:tele"; + width = 32; + height = 16; + angletext = "Tag"; + fixedrotation = 1; + } + 757 + { + title = "Fan Particle Generator"; + sprite = "PRTLA0"; + width = 8; + height = 16; + angletext = "Tag"; + fixedrotation = 1; + } + 758 + { + title = "Object Angle Anchor"; + sprite = "internal:view"; + } + 760 + { + title = "PolyObject Anchor"; + sprite = "internal:polyanchor"; + angletext = "ID"; + fixedrotation = 1; + } + + 761 + { + title = "PolyObject Spawn Point"; + sprite = "internal:polycenter"; + angletext = "ID"; + fixedrotation = 1; + } + + 762 + { + title = "PolyObject Spawn Point (Crush)"; + sprite = "internal:polycentercrush"; + flags4text = "[4] In-map centerpoint"; + angletext = "ID"; + fixedrotation = 1; + } + + 777 + { + title = "Floor Slope Anchor"; + sprite = "SAFA0"; + parametertext = "Level"; + } + + 778 + { + title = "Ceiling Slope Anchor"; + sprite = "SACA0"; + parametertext = "Level"; + } + + 780 + { + title = "Skybox View Point"; + sprite = "internal:skyb"; + flags4text = "[4] In-map reference point"; + angletext = "View height"; + fixedrotation = 1; + } + } + + ambience + { + color = 15; // White + title = "Ambience"; + width = 8; + height = 16; + sprite = "UNKNA0"; + 700 { title = "Water Ambience A (Large)"; sprite = "internal:ambiance"; } - + 701 { title = "Water Ambience B (Large)"; @@ -3998,94 +3707,21 @@ thingtypes sprite = "internal:ambiance"; } - 750 + 710 { - title = "Slope Vertex"; - sprite = "internal:vertexslope"; - angletext = "Tag"; + title = "Machine Ambience"; + sprite = "internal:ambiance"; } - - 751 + 735 { - arrow = 1; - title = "Teleport Destination"; - sprite = "internal:tele"; + title = "PC Merry-Go-Round Ambience"; + sprite = "internal:ambiance"; } - - 752 + 734 { - arrow = 1; - title = "Alternate View Point"; - sprite = "internal:view"; + title = "Twinkle Cart Ambience"; + sprite = "internal:ambiance"; } - - 753 - { - title = "Zoom Tube Waypoint"; - sprite = "internal:zoom"; - angletext = "Order"; - } - - 754 - { - title = "Push Point"; - flags4text = "[4] Fades using XY"; - flags8text = "[8] Push using XYZ"; - sprite = "GWLGA0"; - angletext = "Radius"; - } - 755 - { - title = "Pull Point"; - flags4text = "[4] Fades using XY"; - flags8text = "[8] Pull using XYZ"; - sprite = "GWLRA0"; - angletext = "Radius"; - } - - 760 - { - title = "PolyObject Anchor"; - sprite = "internal:polyanchor"; - angletext = "ID"; - } - - 761 - { - title = "PolyObject Spawn Point"; - sprite = "internal:polycenter"; - angletext = "ID"; - } - - 762 - { - title = "PolyObject Spawn Point (Crush)"; - sprite = "internal:polycentercrush"; - angletext = "ID"; - } - - 777 - { - title = "Floor Slope Anchor"; - sprite = "internal:Vertex_Anchor_Floor.png"; - parametertext = "Level"; - } - - 778 - { - title = "Ceiling Slope Anchor"; - sprite = "internal:Ceiling_Anchor_Floor.png"; - parametertext = "Level"; - } - - 780 - { - title = "Skybox View Point"; - sprite = "internal:skyb"; - flags4text = "[4] In-map reference point"; - angletext = "View height"; - } - } hazards @@ -4104,59 +3740,58 @@ thingtypes flags8height = 24; flags8text = "[8] Float"; } + 522 + { + title = "Wall Spike"; + sprite = "WSPKALAR"; + width = 16; + height = 14; + arrow = 1; + flags1text = "[1] Start retracted"; + flags4text = "[4] Retractable"; + flags8text = "[8] Intangible"; + parametertext = "Start delay"; + } 523 { title = "Spike"; sprite = "USPKA0"; width = 8; - height = 42; + height = 32; + flags1text = "[1] Start retracted"; flags4text = "[4] Retractable"; - flags8text = "[8] Solid"; + flags8text = "[8] Intangible"; angletext = "Retraction interval"; + fixedrotation = 1; + parametertext = "Start delay"; } - 524 + 1130 { - arrow = 1; - title = "Big Floating Mine"; - width = 16; - height = 32; - sprite = "BMNEA1"; + title = "Small Mace"; + sprite = "SMCEA0"; + width = 17; + height = 34; } - 527 + 1131 { - arrow = 1; - title = "Big Floating Mine (Air)"; - width = 16; - height = 32; - sprite = "BMNEA1"; + title = "Big Mace"; + sprite = "BMCEA0"; + width = 34; + height = 68; } - 525 + 1136 { - title = "Cannonball Launcher"; - sprite = "internal:cannonball"; + title = "Small Fireball"; + sprite = "SFBRA0"; + width = 17; + height = 34; } - 1101 + 1137 { - title = "Torch"; - sprite = "FLAMA0"; - width = 8; - height = 32; - } - 1105 - { - title = "Mace (Swinging)"; - sprite = "internal:mace1"; - flags4text = "[4] No sounds"; - flags8text = "[8] Double size"; - angletext = "Tag"; - } - 1104 - { - title = "Mace (Spinning)"; - sprite = "internal:mace2"; - flags4text = "[4] No sounds"; - flags8text = "[8] Double size"; - angletext = "Tag"; + title = "Large Fireball"; + sprite = "BFBRA0"; + width = 34; + height = 68; } 1202 { @@ -4164,6 +3799,7 @@ thingtypes title = "Rock Spawner"; sprite = "ROIAA0"; angletext = "Tag"; + fixedrotation = 1; } 1300 { @@ -4174,6 +3810,7 @@ thingtypes flags8text = "[8] Waves vertically"; angletext = "On/Off time"; parametertext = "Strength"; + fixedrotation = 1; } 1301 { @@ -4183,50 +3820,7 @@ thingtypes flags8text = "[8] Shoot downwards"; angletext = "On/Off time"; parametertext = "Strength"; - } - 1500 - { - arrow = 1; - blocking = 2; - title = "Trapgoyle"; - sprite = "GARGA1"; - width = 16; - height = 40; - flags4text = "[4] Slides when pushed"; - flags8text = "[8] Not pushable"; - } - 1501 - { - arrow = 1; - blocking = 2; - title = "Trapgoyle (Up)"; - sprite = "GARGA1"; - width = 16; - height = 40; - flags4text = "[4] Slides when pushed"; - flags8text = "[8] Not pushable"; - } - 1502 - { - arrow = 1; - blocking = 2; - title = "Trapgoyle (Down)"; - sprite = "GARGA1"; - width = 16; - height = 40; - flags4text = "[4] Slides when pushed"; - flags8text = "[8] Not pushable"; - } - 1503 - { - arrow = 1; - blocking = 2; - title = "Trapgoyle (Long)"; - sprite = "GARGA1"; - width = 16; - height = 40; - flags4text = "[4] Slides when pushed"; - flags8text = "[8] Not pushable"; + fixedrotation = 1; } 3576 { @@ -4250,15 +3844,6 @@ thingtypes height = 40; sprite = "FWR1A0"; - 757 - { - title = "Fan Particle Generator"; - sprite = "PRTLA0"; - width = 8; - height = 16; - angletext = "Particle speed"; - parametertext = "Interval"; - } 800 { title = "GFZ Flower"; @@ -4319,27 +3904,7 @@ thingtypes height = 16; hangs = 1; angletext = "Dripping interval"; - } - 1003 - { - title = "Coral (Green)"; - sprite = "CRL1A0"; - width = 8; - height = 16; - } - 1004 - { - title = "Coral (Red)"; - sprite = "CRL2A0"; - width = 8; - height = 16; - } - 1005 - { - title = "Coral (Orange)"; - sprite = "CRL3A0"; - width = 8; - height = 16; + fixedrotation = 1; } 1006 { @@ -4456,104 +4021,6 @@ thingtypes } } - nights - { - color = 13; // Pink - title = "NiGHTS Items"; - width = 12; - height = 32; - sprite = "NWNGA0"; - - 1703 - { - title = "Ideya Drone"; - sprite = "NDRNA1"; - width = 16; - height = 56; - flags8text = "[8] Die upon time up"; - angletext = "Time limit"; - } - 1704 - { - arrow = 1; - title = "Bumper"; - sprite = "NBMPG3G7"; - width = 32; - height = 64; - unflippable = true; - flagsvaluetext = "Pitch"; - angletext = "Yaw"; - } - 1705 - { - arrow = 1; - title = "Hoop (Generic)"; - sprite = "HOOPA0"; - width = 80; - height = 160; - unflippable = true; - centerHitbox = true; - flagsvaluetext = "Height"; - angletext = "Pitch/Yaw"; - } - 1706 - { - title = "Wing Logo"; - sprite = "NWNGA0"; - height = 24; - unflippable = true; - } - 1707 - { - title = "Super Paraloop"; - sprite = "NPRUA0"; - flags4text = "[4] Bonus time only"; - flags8text = "[8] Spawn immediately"; - } - 1708 - { - title = "Drill Refill"; - sprite = "NPRUB0"; - flags4text = "[4] Bonus time only"; - flags8text = "[8] Spawn immediately"; - } - 1709 - { - title = "Nightopian Helper"; - sprite = "NPRUC0"; - flags4text = "[4] Bonus time only"; - flags8text = "[8] Spawn immediately"; - } - 1711 - { - title = "Extra Time"; - sprite = "NPRUD0"; - flags4text = "[4] Bonus time only"; - flags8text = "[8] Spawn immediately"; - } - 1712 - { - title = "Link Freeze"; - sprite = "NPRUE0"; - flags4text = "[4] Bonus time only"; - flags8text = "[8] Spawn immediately"; - } - 1713 - { - arrow = 1; - title = "Hoop (Customizable)"; - flags1text = "[1] Radius +16"; - flags2text = "[2] Radius +32"; - flags4text = "[4] Radius +64"; - flags8text = "[8] Radius +128"; - sprite = "HOOPA0"; - width = 80; - height = 160; - unflippable = true; - centerHitbox = true; - } - } - nightstrk { color = 13; // Pink @@ -4572,6 +4039,7 @@ thingtypes flagsvaluetext = "Order"; angletext = "Radius/Direction"; parametertext = "Mare"; + fixedrotation = 1; } 1701 { @@ -4591,216 +4059,6 @@ thingtypes flagsvaluetext = "Order"; parametertext = "Mare"; } - 1710 - { - title = "Ideya Capture"; - sprite = "CAPSA0"; - width = 72; - height = 144; - angletext = "Rings"; - parametertext = "Mare"; - } - } - - mario - { - color = 6; // Brown - title = "Mario Items"; - width = 16; - height = 32; - sprite = "GOOMA0"; - - 1800 - { - title = "Coin"; - sprite = "COINA0"; - height = 24; - flags8height = 24; - flags8text = "[8] Float"; - } - 1801 - { - arrow = 1; - title = "Goomba"; - sprite = "GOOMA0"; - width = 24; - } - 1802 - { - arrow = 1; - title = "Goomba (Blue)"; - sprite = "BGOMA0"; - width = 24; - } - 1803 - { - title = "Fire Flower"; - sprite = "FFWRB0"; - } - 1804 - { - title = "Koopa Shell"; - sprite = "SHLLA0"; - width = 8; - height = 16; - } - 1805 - { - title = "Puma (Jumping Fireball)"; - sprite = "PUMAA0"; - width = 8; - height = 16; - angletext = "Jump strength"; - } - 1806 - { - title = "King Bowser"; - sprite = "KOOPA0"; - height = 28; - } - 1807 - { - title = "Axe"; - sprite = "MAXEA0"; - width = 8; - height = 16; - } - 1808 - { - title = "Bush (Short)"; - sprite = "MUS1A0"; - } - 1809 - { - title = "Bush (Tall)"; - sprite = "MUS2A0"; - } - 1810 - { - title = "Toad"; - sprite = "TOADA0"; - width = 8; - } - } - - srb1 - { - color = 3; // Cyan - arrow = 1; - title = "SRB1 Remake"; - width = 20; - height = 32; - sprite = "SRBAA1"; - - 4000 - { - title = "SRB1 Crawla"; - sprite = "SRBAA1"; - height = 40; - } - 4001 - { - title = "GuardRobo"; - sprite = "SRBBA1"; - width = 17; - height = 40; - } - 4002 - { - title = "Pyrin"; - sprite = "SRBCB1"; - width = 22; - } - 4003 - { - title = "HotRobo"; - sprite = "SRBDA0"; - height = 40; - } - 4004 - { - title = "Pogminz"; - sprite = "SRBEA1"; - } - 4005 - { - title = "Pogminz (Water)"; - sprite = "SRBEA1"; - } - 4006 - { - title = "Pog-GX2"; - sprite = "SRBFA0"; - width = 10; - height = 34; - } - 4007 - { - title = "Pyrex"; - sprite = "SRBGA1"; - width = 24; - } - 4008 - { - title = "SRB1 Turret"; - sprite = "SRBHA0"; - width = 24; - hangs = 1; - } - 4009 - { - title = "SWAT Bot"; - sprite = "SRBIA1"; - width = 21; - height = 69; - } - 4010 - { - title = "SpyBot 2000"; - sprite = "SRBJA0"; - width = 36; - height = 62; - } - 4011 - { - title = "Buzz Bomber"; - sprite = "SRBKA0"; - width = 44; - height = 45; - } - 4012 - { - arrow = 0; - title = "RBZ Spike"; - sprite = "SRBLA0"; - width = 10; - height = 53; - } - 4013 - { - arrow = 0; - blocking = 2; - title = "Dumb Metal Sonic"; - sprite = "SRBMC0"; - width = 16; - height = 40; - flags4text = "[4] Slides when pushed"; - flags8text = "[8] Not pushable"; - } - 4014 - { - title = "Super SWAT Bot"; - sprite = "SRBNA1"; - width = 21; - height = 69; - } - 4015 - { - title = "Genrex"; - sprite = "SRBOA1"; - width = 17; - height = 40; - } } bsz @@ -4900,36 +4158,6 @@ thingtypes title = "Short Flower (Orange)"; sprite = "BSZ3F0"; } - 1430 - { - title = "Tulip (Red)"; - sprite = "BSZ4A0"; - } - 1431 - { - title = "Tulip (Purple)"; - sprite = "BSZ4B0"; - } - 1432 - { - title = "Tulip (Blue)"; - sprite = "BSZ4C0"; - } - 1433 - { - title = "Tulip (Cyan)"; - sprite = "BSZ4D0"; - } - 1434 - { - title = "Tulip (Yellow)"; - sprite = "BSZ4E0"; - } - 1435 - { - title = "Tulip (Orange)"; - sprite = "BSZ4F0"; - } 1440 { title = "Cluster (Red)"; @@ -5046,29 +4274,17 @@ thingtypes { color = 4; // Red arrow = 1; - title = "SRB2Kart Stuff"; - sprite = "ITEMALAR"; + title = "Ring Racers Stuff"; + sprite = "AUDIA2A8"; width = 8; height = 16; - 2000 + 4095 { - title = "Random Item"; - sprite = "RNDMA0"; - width = 36; - height = 36; - } - 2333 - { - title = "Capsule"; - //sprite = "internal:kartcapsule"; - width = 28; - height = 112; - blocking = 2; - angletext = "Speed"; - parametertext = "Movement sequence"; - flags4text = "[4] Reverse movement"; - flags8text = "[8] Back and forth"; + title = "Empty Kart"; + sprite = "KARTA2A8"; + width = 30; + height = 30; } 1488 { @@ -5078,13 +4294,6 @@ thingtypes width = 8; height = 20; } - 1479 - { - title = "Torch (no fullbright)"; - sprite = "FLAMA0"; - width = 8; - height = 32; - } 1480 { blocking = 2; @@ -5406,6 +4615,30 @@ thingtypes width = 5; height = 204; } + 691 + { + title = "FPZ FrostThrower"; + sprite = "SFTRB0"; + width = 32; + height = 45; + flags1text = "[1] Max Range"; + flags8text = "[8] Alternate timming"; + angletext = "Delay"; + } + 693 + { + title = "FPZ Side-FrostThrower"; + sprite = "SFTRB0"; + width = 32; + height = 45; + } + 3456 + { + title = "SSZ Cloud Cluster"; + sprite = "SSCLA0"; + width = 48; + height = 45; + } 717 { title = "HTZ Bush"; @@ -5767,16 +5000,6 @@ thingtypes width = 16; height = 64; } - 735 - { - title = "PC Merry-Go-Round Ambience"; - sprite = "internal:ambiance"; - } - 734 - { - title = "Twinkle Cart Ambience"; - sprite = "internal:ambiance"; - } 733 { title = "PC Exploding Barrel"; @@ -5902,35 +5125,40 @@ thingtypes 2001 { title = "Waypoint (height = next waypoint ID)"; - sprite = "EMBMP0"; + sprite = "WAY1A0"; angletext = "ID"; flags1text = "[1] Disable"; - flags4text = "[4] Shortcut"; + flags4text = "[4] Start of shortcut"; flags8text = "[8] No respawn"; heighttext = "Next"; + parametertext = "Finish?"; + fixedrotation = 1; } 2002 { title = "Waypoint Riser"; - sprite = "EMBMY0"; + sprite = "WAY3A0"; angletext = "ID (if flag [4] set)"; flags2text = "[2] Look for FOF above"; flags4text = "[4] Require matching waypoint ID"; flags8text = "[8] Copy exact height"; + fixedrotation = 1; } 2003 { title = "Waypoint Anchor"; - sprite = "EMBMR0"; + sprite = "WAY2A0"; angletext = "ID"; + fixedrotation = 1; } 2004 { title = "Bot Hint"; - sprite = "EMBMA0"; + sprite = "WAY4A0"; angletext = "Radius"; flags8text = "[8] Avoid this area"; parametertext = "Strength (default = 2)"; + fixedrotation = 1; } } } @@ -6006,333 +5234,3 @@ thingsfilters type = 292; } } - -texturesets -{ - - set0 - { - name = "Greenflower Zone"; - filter0 = "GFZ*"; - filter1 = "FWATER*"; - filter2 = "CFALL*"; - filter3 = "GFALL*"; - filter4 = "FLOOR0_4"; - filter5 = "FLOOR1_2"; - filter6 = "FLOOR1_3"; - filter7 = "BWATER*"; - filter8 = "FLOOR0_2"; - filter9 = "DEM1_5"; - filter10 = "OLDROCKW"; - filter11 = "ROCKY*"; - filter12 = "OWOODW"; - filter13 = "WOODFLR"; - } - - set1 - { - name = "Techno Hill Zone"; - filter0 = "TH*"; - filter1 = "CHEMG*"; - filter2 = "TFALL?"; - filter3 = "ALTBOX*"; - filter4 = "BOXWARN?"; - filter5 = "PIPE*"; - filter6 = "PISTON"; - filter7 = "WHZ*"; - filter8 = "BAR*"; - filter9 = "COMP?"; - filter10 = "INFOWAL?"; - filter11 = "SPECWLL?"; - filter12 = "SUPPORT?"; - filter13 = "LITE*"; - filter14 = "BLUEW?"; - filter15 = "GREYW?"; - filter16 = "RED?"; - filter17 = "YEL?"; - filter18 = "SLITE?"; - filter19 = "DOORTRK1"; - filter20 = "GOOP*"; - filter21 = "AFALL?"; - filter22 = "STEEL*"; - filter23 = "CONVEY?"; - } - - set2 - { - name = "Deep Sea Zone"; - filter0 = "DSZ*"; - filter1 = "LWATER*"; - filter2 = "LFALL?"; - filter3 = "BFALL?"; - filter4 = "DEEPSE*"; - filter5 = "WEB?"; - filter6 = "RUINS1_1"; - filter7 = "CLRWAL*"; - } - - set3 - { - name = "Castle Eggman Zone"; - filter0 = "CASTLE*"; - filter1 = "STONE*"; - filter2 = "DMA*"; - filter3 = "LIB*"; - filter4 = "CEZ*"; - filter5 = "CEFLAG*"; - filter6 = "TOMBST?"; - filter7 = "NCEZW?"; - filter8 = "DEM1_1"; - filter9 = "WEBB?"; - filter10 = "LFZ*"; - filter11 = "WEEDWALL"; - filter12 = "STORM1"; - filter13 = "STR_M1"; - } - - set4 - { - name = "Arid Canyon Zone"; - filter0 = "AC*"; - filter1 = "OIL*"; - filter2 = "SOLFALL?"; - } - - set5 - { - name = "Red Volcano Zone"; - filter0 = "RVZ*"; - filter1 = "D2LAVA"; - filter2 = "MM*"; - filter3 = "ROCKFLR*"; - filter4 = "ROCKWLL*"; - filter5 = "DLAVA?"; - filter6 = "LAVA?"; - filter7 = "RLAVA?"; - filter8 = "SFALL?"; - filter9 = "MINE*"; - filter10 = "LVASAND?"; - filter11 = "FLOOR6_2"; - filter12 = "TLITE6_1"; - filter13 = "ROCKBOIL"; - filter14 = "TLITE6_5"; - filter15 = "TLITE6_6"; - filter16 = "FLOOR6_1"; - } - - set6 - { - name = "Dark City Zone"; - filter0 = "DC*"; - filter1 = "SIDEWALK"; - filter2 = "BRICK*"; - filter3 = "CEMENT?"; - filter4 = "BRIDGE*"; - filter5 = "CATFLR02"; - filter6 = "LIFT*"; - } - - set7 - { - name = "Doomship Zone"; - filter0 = "DSHIP*"; - } - - set8 - { - name = "Egg Rock Zone"; - filter0 = "ER*"; - filter1 = "MEK*"; - filter2 = "VENT*"; - filter3 = "DOWN*"; - filter4 = "UP*"; - filter5 = "LITE*"; - filter6 = "BLUEW?"; - filter7 = "GREYW?"; - filter8 = "RED?"; - filter9 = "YEL?"; - filter10 = "EGRID*"; - filter11 = "CONVEY?"; - } - - set9 - { - name = "Mario"; - filter0 = "MARFLAG?"; - filter1 = "THWOMP*"; - filter2 = "PTZ*"; - filter3 = "MARIO*"; - filter4 = "MARROCK?"; - } - - set10 - { - name = "Special Stage"; - filter0 = "ASPEC*"; - filter1 = "CSPEC*"; - filter2 = "EMTEX?"; - filter3 = "GSPEC*"; - filter4 = "PSPEC*"; - filter5 = "RSPEC*"; - filter6 = "SFLR*"; - filter7 = "SPACE*"; - filter8 = "SPC*"; - filter9 = "SPEC*"; - filter10 = "VOID*"; - filter11 = "WSPEC*"; - filter12 = "YSPEC*"; - filter13 = "BSPEC*"; - } - - set11 - { - name = "Multiplayer levels"; - filter0 = "ALLYRING"; - filter1 = "BRAKCAT?"; - filter2 = "SANDWLL"; - filter3 = "LAKE*"; - filter4 = "AP*"; - filter5 = "ZIM*"; - filter6 = "RCZ*"; - } - - set12 - { - name = "Caves and Cliffs"; - filter0 = "CAVE*"; - filter1 = "ROCK?"; - filter2 = "ROCKF?"; - filter3 = "CLIFF*"; - filter4 = "SHAL*"; - filter5 = "MRNR*"; - } - - set13 - { - name = "Christmas"; - filter0 = "XM*"; - filter1 = "FROST*"; - filter2 = "GRSWALL3"; - filter3 = "GRSWALL4"; - } - - set14 - { - name = "Forts"; - filter0 = "2FORT*"; - } - - set15 - { - name = "Ice and Snow"; - filter0 = "ICE*"; - filter1 = "SNOW*"; - } - - set16 - { - name = "Jungle"; - filter0 = "GRSEDG?"; - filter1 = "JNG*"; - filter2 = "SHROOM*"; - } - - set17 - { - name = "Sand"; - filter0 = "SAND"; - filter1 = "SANDW"; - filter2 = "SANDFLR*"; - filter3 = "SND*"; - filter4 = "AGZ*"; - filter5 = "QUIK*"; - filter6 = "Q?FALL?"; - } - - set18 - { - name = "Forest"; - filter0 = "WOOD*"; - filter1 = "EC*"; - filter2 = "GRASS1*"; - filter3 = "VFZ*"; - filter4 = "OWOODW"; - filter5 = "DEM1_2"; - } - - set19 - { - name = "Generic"; - filter0 = "BUST*"; - filter1 = "CEIL3_1"; - filter2 = "CTFFLG*"; - filter3 = "DEM1_3"; - filter4 = "BIGX"; - filter5 = "ARROW?"; - filter6 = "HAZARD?"; - filter7 = "*PIT"; - filter8 = "SPIKE*"; - filter9 = "*CAUTN"; - filter10 = "TRAPFLR"; - filter11 = "EGGTRAP?"; - filter12 = "GLASS*"; - filter13 = "DIRT*"; - filter14 = "EGGOLD*"; - filter15 = "MARE*"; - filter16 = "BLUEFLR"; - filter17 = "BLUWALL"; - filter18 = "CYAN*"; - filter19 = "GOLD*"; - filter20 = "GREENFLR"; - filter21 = "GRNWALL"; - filter22 = "GREYFLR"; - filter23 = "GRYWALL"; - filter24 = "LIME*"; - filter25 = "NEOG*"; - filter26 = "ORGFLR"; - filter27 = "ORANGE"; - filter28 = "PUR*"; - filter29 = "REDFLR"; - filter30 = "REDWALL"; - filter31 = "VIO*"; - filter32 = "YELFLR"; - filter33 = "YELWALL"; - } - - set20 - { - name = "Unsorted"; - filter0 = "FLAT1_2"; - filter1 = "FOSSIL*"; - filter2 = "F_METAL?"; - filter3 = "GRASSY*"; - filter4 = "WATER?"; - filter5 = "SURF*"; - filter6 = "OFALL?"; - filter7 = "MFALL1"; - filter8 = "SCREEN01"; - filter9 = "TRCKWLL1"; - filter10 = "WINDOW"; - filter11 = "XTRMCHK*"; - filter12 = "CHAINFEN"; - filter13 = "SRB1*"; - filter14 = "DISCO*"; - filter15 = "DANCE?"; - filter16 = "RECORD"; - filter17 = "DFZ*"; - } - - set21 - { - name = "Classic levels"; - filter0 = "GHZ*"; - filter1 = "HPZ*"; - filter2 = "LBZ*"; - filter3 = "GRASS2"; - filter4 = "GRASS3"; - filter5 = "GRSWALL"; - filter6 = "GRNLITE1"; - filter7 = "GATE2"; - filter8 = "DEM1_6"; - } -} From 3dd4394d7003ce8fb58618f10e72a1be484de34d Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 23 Sep 2022 17:47:14 +0100 Subject: [PATCH 53/60] Correct misconception in config --- extras/conf/D3R-Config.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extras/conf/D3R-Config.cfg b/extras/conf/D3R-Config.cfg index 354d7a176..0482dc439 100644 --- a/extras/conf/D3R-Config.cfg +++ b/extras/conf/D3R-Config.cfg @@ -5128,7 +5128,7 @@ thingtypes sprite = "WAY1A0"; angletext = "ID"; flags1text = "[1] Disable"; - flags4text = "[4] Start of shortcut"; + flags4text = "[4] On shortcut"; flags8text = "[8] No respawn"; heighttext = "Next"; parametertext = "Finish?"; From f5998c7624d831c29060e1c79591cbdaeb45a232 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 23 Sep 2022 20:52:51 +0100 Subject: [PATCH 54/60] Skip over locked maps/cups when getting nextmap (carve out an exception for marathon mode, although we will probably want to lock that behind all cups available) --- src/g_game.c | 36 +++++++++++++++++++++++------------- src/m_cond.c | 3 ++- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 19834d0ed..e038ea9ff 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3709,15 +3709,23 @@ static void G_GetNextMap(void) else { UINT32 tolflag = G_TOLFlag(gametype); + register INT16 cm; if (gametyperules & GTR_CAMPAIGN) { - register INT16 cm; cupheader_t *cup = mapheaderinfo[gamemap-1]->cup; UINT8 gettingresult = 0; while (cup) { + // Not unlocked? Grab the next result afterwards + if (!marathonmode && cup->unlockrequired != -1 && !unlockables[cup->unlockrequired].unlocked) + { + cup = cup->next; + gettingresult = 1; + continue; + } + for (i = 0; i < cup->numlevels; i++) { cm = cup->cachedlevels[i]; @@ -3726,7 +3734,8 @@ static void G_GetNextMap(void) if (cm >= nummapheaders || !mapheaderinfo[cm] || mapheaderinfo[cm]->lumpnum == LUMPERROR - || !(mapheaderinfo[cm]->typeoflevel & tolflag)) + || !(mapheaderinfo[cm]->typeoflevel & tolflag) + || (!marathonmode && M_MapLocked(cm+1))) continue; // Grab the first valid after the map you're on @@ -3772,26 +3781,27 @@ static void G_GetNextMap(void) } else { - i = prevmap; - if (++i >= nummapheaders) - i = 0; + cm = prevmap; + if (++cm >= nummapheaders) + cm = 0; - while (i != prevmap) + while (cm != prevmap) { - if (!mapheaderinfo[i] - || mapheaderinfo[i]->lumpnum == LUMPERROR - || !(mapheaderinfo[i]->typeoflevel & tolflag) - || (mapheaderinfo[i]->menuflags & LF2_HIDEINMENU)) + if (!mapheaderinfo[cm] + || mapheaderinfo[cm]->lumpnum == LUMPERROR + || !(mapheaderinfo[cm]->typeoflevel & tolflag) + || (mapheaderinfo[cm]->menuflags & LF2_HIDEINMENU) + || M_MapLocked(cm+1)) { - if (++i >= nummapheaders) - i = 0; + if (++cm >= nummapheaders) + cm = 0; continue; } break; } - nextmap = i; + nextmap = cm; } if (!marathonmode) diff --git a/src/m_cond.c b/src/m_cond.c index 94169936c..4dd42edca 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -432,7 +432,8 @@ UINT8 M_MapLocked(INT32 mapnum) if (1) return false; #endif - + if (!mapnum || mapnum > nummapheaders) + return false; if (!mapheaderinfo[mapnum-1] || mapheaderinfo[mapnum-1]->unlockrequired < 0) return false; if (!unlockables[mapheaderinfo[mapnum-1]->unlockrequired].unlocked) From fe2757cb440c4e1cd4207d030d00ee6e7da6355f Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 23 Sep 2022 20:59:02 +0100 Subject: [PATCH 55/60] Fix special map usage - Free header on `CLEAR LEVELS` even if it's `tutorialmap` - `titlemap` infinite recursion prevention Z_Free's instead of leaking --- src/deh_soc.c | 3 --- src/f_finale.c | 2 +- src/g_game.c | 3 ++- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index 2f2b4c1fc..427493f28 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -149,9 +149,6 @@ void clear_levels(void) if (!mapheaderinfo[nummapheaders]) continue; - if (strcmp(mapheaderinfo[nummapheaders]->lumpname, tutorialmap) == 0) // Sal: Is this needed...? - continue; - // Custom map header info // (no need to set num to 0, we're freeing the entire header shortly) Z_Free(mapheaderinfo[nummapheaders]->customopts); diff --git a/src/f_finale.c b/src/f_finale.c index 05457f5dd..08ab3acfc 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1865,7 +1865,7 @@ void F_StartTitleScreen(void) globalweather = mapheaderinfo[titleMapNum]->weather; G_DoLoadLevel(true); - if (!titleMapNum) + if (!titlemap) return; players[displayplayers[0]].playerstate = PST_DEAD; // Don't spawn the player in dummy (I'm still a filthy cheater) diff --git a/src/g_game.c b/src/g_game.c index e038ea9ff..6547b84f5 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1336,7 +1336,8 @@ void G_DoLoadLevel(boolean resetplayer) //if (W_CheckNumForName(G_BuildMapName(gamemap)) == LUMPERROR) if (gamemap < 1 || gamemap > nummapheaders) { - titlemap = 0; // let's not infinite recursion ok + Z_Free(titlemap); + titlemap = NULL; // let's not infinite recursion ok Command_ExitGame_f(); return; } From 859375ce3d1179dd939436c2e1e9edf6454173b9 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 23 Sep 2022 21:08:26 +0100 Subject: [PATCH 56/60] Disable all staffghosts code since the lumpname stuff needs addressing (but that'll come later) --- src/f_finale.c | 27 ++------------------------- src/g_game.c | 2 ++ src/k_menufunc.c | 4 ++-- src/p_setup.c | 2 ++ 4 files changed, 8 insertions(+), 27 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index 08ab3acfc..88260f068 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2197,6 +2197,7 @@ void F_TitleScreenTicker(boolean run) return; } +#ifdef STAFFGHOSTS // is it time? if (!(--demoIdleLeft)) { @@ -2233,38 +2234,13 @@ void F_TitleScreenTicker(boolean run) return; } - // Replay intro when done cycling through demos - /* - if (curDemo == numDemos) -- uuuh... we have a LOT of maps AND a big devteam... probably not gonna see a repeat unless you're super unlucky :V - { - curDemo = 0; - F_StartIntro(); - return; - } - */ - mapname = G_BuildMapName(G_RandMap(TOL_RACE, -2, 0, 0, false, NULL)+1); numstaff = 1; while (numstaff < 99 && (l = W_CheckNumForLongName(va("%sS%02u",mapname,numstaff+1))) != LUMPERROR) numstaff++; -#if 0 // turns out this isn't how we're gonna organise 'em - if (numstaff > 1) - { - if (laststaff && laststaff <= numstaff) // don't do the same staff member twice in a row, even if they're on different maps - { - numstaff = M_RandomKey(numstaff-1)+1; - if (numstaff >= laststaff) - numstaff++; - } - else - numstaff = M_RandomKey(numstaff)+1; - } - laststaff = numstaff; -#else numstaff = M_RandomKey(numstaff)+1; -#endif // Setup demo name dname2 = Z_StrDup(va("%sS%02u", mapname, numstaff)); @@ -2287,6 +2263,7 @@ loadreplay: Z_Free(dname2); } } +#endif //#ifdef STAFFGHOSTS } void F_TitleDemoTicker(void) diff --git a/src/g_game.c b/src/g_game.c index 6547b84f5..1defa4369 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3512,6 +3512,7 @@ tryagain: continue; } +#ifdef STAFFGHOSTS if (pprevmap == -2) // title demo hack { lumpnum_t l; @@ -3519,6 +3520,7 @@ tryagain: if ((l = W_CheckNumForLongName(va("%sS01",G_BuildMapName(ix+1)))) == LUMPERROR) continue; } +#endif //#ifdef STAFFGHOSTS okmaps[numokmaps++] = ix; } diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 0fad3451a..a1b8505cc 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -245,7 +245,7 @@ static void Dummymenuplayer_OnChange(void) static void Dummystaff_OnChange(void) { -#if 0 +#ifdef STAFFGHOSTS lumpnum_t l; dummystaffname[0] = '\0'; @@ -277,7 +277,7 @@ static void Dummystaff_OnChange(void) sprintf(temp, " - %d", cv_dummystaff.value); } -#endif +#endif //#ifdef STAFFGHOSTS } void Screenshot_option_Onchange(void) diff --git a/src/p_setup.c b/src/p_setup.c index 5a7b86c90..9d60e49d8 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -3760,6 +3760,7 @@ static void P_LoadRecordGhosts(void) if (cv_ghost_guest.value && FIL_FileExists(va("%s-guest.lmp", gpath))) G_AddGhost(va("%s-guest.lmp", gpath)); +#ifdef STAFFGHOSTS // Staff Attack ghosts if (cv_ghost_staff.value) { @@ -3772,6 +3773,7 @@ static void P_LoadRecordGhosts(void) j++; } } +#endif //#ifdef STAFFGHOSTS free(gpath); } From a5d0fc41233575a904184329efb7d8b662374dab Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 23 Sep 2022 21:08:36 +0100 Subject: [PATCH 57/60] Add newline to end of w_wad.c --- src/w_wad.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/w_wad.c b/src/w_wad.c index 83dad0db7..099ce0ded 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -2408,4 +2408,4 @@ void *vres_GetPatch(virtlump_t *vlump, INT32 tag) Patch_CreateGL(patch); return (void *)patch; #endif -} \ No newline at end of file +} From 2b9701d01eebc44b163066382ef1d1eeb9fc1816 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 24 Sep 2022 21:15:44 -0700 Subject: [PATCH 58/60] Load palette before map data Fixes PNG patch conversion crashing when called from vres at game startup. Also does not reload palette every time the resolution is changed. (This had no effect on the SDL backend, don't worry.) --- src/d_main.c | 4 ++++ src/v_video.c | 8 +++----- src/v_video.h | 3 +++ 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 412149469..7e3843b8e 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1438,6 +1438,10 @@ void D_SRB2Main(void) #endif //ifndef DEVELOP + // Do it before P_InitMapData because PNG patch + // conversion sometimes needs the palette + V_ReloadPalette(); + // // search for mainwad maps // diff --git a/src/v_video.c b/src/v_video.c index c2d3e3c4c..8ed5ed53f 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -404,7 +404,7 @@ const char *GetPalette(void) return "PLAYPAL"; } -static void LoadMapPalette(void) +void V_ReloadPalette(void) { LoadPalette(GetPalette()); } @@ -416,7 +416,7 @@ static void LoadMapPalette(void) void V_SetPalette(INT32 palettenum) { if (!pLocalPalette) - LoadMapPalette(); + V_ReloadPalette(); #ifdef HWRENDER if (rendermode == render_opengl) @@ -449,7 +449,7 @@ void V_SetPaletteLump(const char *pal) static void CV_palette_OnChange(void) { // reload palette - LoadMapPalette(); + V_ReloadPalette(); V_SetPalette(0); } @@ -2980,8 +2980,6 @@ void V_Init(void) UINT8 *base = vid.buffer; const INT32 screensize = vid.rowbytes * vid.height; - LoadMapPalette(); - for (i = 0; i < NUMSCREENS; i++) screens[i] = NULL; diff --git a/src/v_video.h b/src/v_video.h index 099d22d86..9564bca15 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -56,6 +56,9 @@ void InitColorLUT(colorlookup_t *lut, RGBA_t *palette, boolean makecolors); UINT8 GetColorLUT(colorlookup_t *lut, UINT8 r, UINT8 g, UINT8 b); UINT8 GetColorLUTDirect(colorlookup_t *lut, UINT8 r, UINT8 g, UINT8 b); +// Loads the correct palette into memory +void V_ReloadPalette(void); + // Set the current RGB palette lookup to use for palettized graphics void V_SetPalette(INT32 palettenum); From bf9bbaaec94323e61314708d4aa3b0f95ad99243 Mon Sep 17 00:00:00 2001 From: SteelT Date: Sun, 25 Sep 2022 00:17:46 -0400 Subject: [PATCH 59/60] Add missing line feed --- src/g_game.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index 4c6d85efa..01d32146d 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4261,7 +4261,7 @@ void G_LoadGameData(void) { // Since it's not worth declaring the entire gamedata // corrupt over extra maps, we report and move on. - CONS_Alert(CONS_WARNING, "Map with lumpname %s does not exist, time record data will be discarded", mapname); + CONS_Alert(CONS_WARNING, "Map with lumpname %s does not exist, time record data will be discarded\n", mapname); } } From d970c9198b1fdd3f42bab0f2e9c1c638e9bc7177 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 25 Sep 2022 04:39:42 -0700 Subject: [PATCH 60/60] Let S_StopSound, S_StopSoundByID, S_StopSoundByNum stop multiple sounds Previously stopped only one, probably the first that started playing. --- src/s_sound.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/s_sound.c b/src/s_sound.c index 12e35e5c5..bd2831307 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -386,7 +386,6 @@ void S_StopSoundByID(void *origin, sfxenum_t sfx_id) if (channels[cnum].sfxinfo == &S_sfx[sfx_id] && channels[cnum].origin == origin) { S_StopChannel(cnum); - break; } } } @@ -407,7 +406,6 @@ void S_StopSoundByNum(sfxenum_t sfxnum) if (channels[cnum].sfxinfo == &S_sfx[sfxnum]) { S_StopChannel(cnum); - break; } } } @@ -763,7 +761,6 @@ void S_StopSound(void *origin) if (channels[cnum].sfxinfo && channels[cnum].origin == origin) { S_StopChannel(cnum); - break; } } }