From 3350b02cc846b5d9274a1b6f33a262c1d005e953 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Wed, 5 Feb 2025 17:46:21 -0500 Subject: [PATCH 001/117] Long Map Names Port pt 1. --- src/acs/call-funcs.cpp | 9 +-- src/d_main.cpp | 37 ++--------- src/d_netcmd.c | 13 ++-- src/deh_soc.c | 144 +++++++++-------------------------------- src/deh_soc.h | 2 +- src/dehacked.c | 24 +++---- src/doomstat.h | 6 +- src/g_demo.c | 2 +- src/g_game.c | 129 ++++++++++++++++++------------------ src/g_game.h | 6 +- src/lua_baselib.c | 25 ++++--- src/m_menu.c | 7 +- src/m_misc.cpp | 26 -------- src/m_misc.h | 2 - src/p_saveg.c | 2 +- src/p_setup.c | 94 ++++++++++++++++----------- src/p_setup.h | 4 ++ src/w_wad.c | 10 +-- 18 files changed, 207 insertions(+), 335 deletions(-) diff --git a/src/acs/call-funcs.cpp b/src/acs/call-funcs.cpp index b84b3126b..b2e9c9e72 100644 --- a/src/acs/call-funcs.cpp +++ b/src/acs/call-funcs.cpp @@ -3075,13 +3075,10 @@ bool CallFunc_MapWarp(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Wor { CONS_Alert(CONS_WARNING, "MapWarp level name was not provided.\n"); } - - if (levelName[0] == 'M' && levelName[1] == 'A' && levelName[2] == 'P' && levelName[5]=='\0') - { - levelName = va("MAP%d",M_MapNumber(levelName[3], levelName[4])); - } - if (nextmap >= NUMMAPS) + nextmap = G_MapNumber(levelName); + + if (nextmap == NUMMAPS) { CONS_Alert(CONS_WARNING, "MapWarp level %s is not valid or loaded.\n", levelName); return false; diff --git a/src/d_main.cpp b/src/d_main.cpp index ed76adc8c..cc481504a 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -988,13 +988,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))); } } @@ -1515,31 +1509,8 @@ void D_SRB2Main(void) // conversion sometimes needs the palette V_ReloadPalette(); - // - // search for maps - // - for (wadnum = 0; wadnum <= mainwads; wadnum++) - { - 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; - } - } - } - } + P_InitMapData(); + basenummapheaders = nummapheaders; CON_SetLoadingProgress(LOADED_IWAD); @@ -1614,7 +1585,7 @@ void D_SRB2Main(void) 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/d_netcmd.c b/src/d_netcmd.c index 70337b60f..ef7861c2a 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2571,8 +2571,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(mapname) != LUMPERROR); buf_p = buf; if (pencoremode) flags |= 1; @@ -2587,7 +2586,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) @@ -3044,11 +3043,11 @@ 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; boolean pencoremode; + INT16 mapnumber; forceresetplayers = deferencoremode = false; @@ -3085,7 +3084,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)); @@ -3093,7 +3092,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")); } @@ -3109,7 +3108,7 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) 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/deh_soc.c b/src/deh_soc.c index 6509e2f62..5b4466e0e 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -1058,7 +1058,7 @@ static mapheader_lighting_t *usemaplighting(INT32 mapnum, const char *word) } } -void readlevelheader(MYFILE *f, INT32 num) +void readlevelheader(MYFILE *f, char * name) { char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); char *word; @@ -1066,10 +1066,24 @@ 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)) @@ -1267,12 +1281,8 @@ void readlevelheader(MYFILE *f, INT32 num) else if (fastcmp(word2, "CREDITS")) i = 1102; else if (fastcmp(word2, "ENDING")) i = 1103; else - // Support using the actual map name, - // i.e., Nextlevel = AB, Nextlevel = FZ, etc. - // Convert to map number - if (word2[0] >= 'A' && word2[0] <= 'Z' && word2[2] == '\0') - i = M_MapNumber(word2[0], word2[1]); + i = G_MapNumber(word2); mapheaderinfo[num-1]->nextlevel = (INT16)i; } @@ -1283,12 +1293,8 @@ void readlevelheader(MYFILE *f, INT32 num) else if (fastcmp(word2, "CREDITS")) i = 1102; else if (fastcmp(word2, "ENDING")) i = 1103; else - // Support using the actual map name, - // i.e., MarathonNext = AB, MarathonNext = FZ, etc. - // Convert to map number - if (word2[0] >= 'A' && word2[0] <= 'Z' && word2[2] == '\0') - i = M_MapNumber(word2[0], word2[1]); + i = G_MapNumber(word2); mapheaderinfo[num-1]->marathonnext = (INT16)i; } @@ -2557,14 +2563,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 = (INT16)G_MapNumber(word2); } else if (fastcmp(word, "SPRITE")) { @@ -2785,14 +2784,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]); - - unlockables[num].variable = (INT16)i; + unlockables[num].variable = (INT16)G_MapNumber(word2); } else deh_warning("Unlockable %d: unknown word '%s'", num+1, word); @@ -2872,10 +2864,7 @@ static void readcondition(UINT8 set, UINT32 id, char *word2) 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) { @@ -2890,10 +2879,7 @@ static void readcondition(UINT8 set, UINT32 id, char *word2) 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) { @@ -3096,56 +3082,20 @@ 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; + spstage_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")) @@ -3230,16 +3180,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 = (INT16)G_MapNumber(word2); titlechanged = true; } else if (fastcmp(word, "HIDETITLEPICS") || fastcmp(word, "TITLEPICSHIDE")) @@ -3365,30 +3306,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 = (INT16)G_MapNumber(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 = (INT16)G_MapNumber(word2); } else deh_warning("Maincfg: unknown word '%s'", word); @@ -3613,9 +3536,6 @@ void readcupheader(MYFILE *f, cupheader_t *cup) 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; @@ -3631,16 +3551,12 @@ 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]); + i = (INT16)G_MapNumber(word2); cup->bonusgame = (INT16)i - 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]); + i = (INT16)G_MapNumber(word2); cup->specialstage = (INT16)i - 1; } else if (fastcmp(word, "EMERALDNUM")) diff --git a/src/deh_soc.h b/src/deh_soc.h index d8a652579..cb24db595 100644 --- a/src/deh_soc.h +++ b/src/deh_soc.h @@ -73,7 +73,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); #ifdef HWRENDER diff --git a/src/dehacked.c b/src/dehacked.c index 211223ec0..6943c5c47 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -368,25 +368,19 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile) #endif 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) + size_t len = strlen(word2); + if (len <= MAXMAPLUMPNAME-1) { - if (mapheaderinfo[i]) - { - G_SetGameModified(multiplayer, true); // Only a major mod if editing stuff that isn't your own! - } - - readlevelheader(f, i); + if (len == 1) + readlevelheader(f, va("MAP0%s",word2)); + else if (len == 2) + readlevelheader(f, va("MAP%s",word2)); + else + readlevelheader(f, word2); } else { - deh_warning("Level number %d out of range (1 - %d)", i, NUMMAPS); + deh_warning("Map header's lumpname %s is too long (%s characters VS %d max)", word2, sizeu1(len), (MAXMAPLUMPNAME-1)); ignorelines(f); } } diff --git a/src/doomstat.h b/src/doomstat.h index 6031355ae..338958693 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -348,7 +348,8 @@ struct mapheader_lighting_t */ struct mapheader_t { - // The original eight, plus one. + char * lumpname; ///< Lump name can be really long + lumpnum_t lumpnum; ///< Lump number for the map 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 @@ -449,6 +450,9 @@ struct mapheader_t #define LF2_VISITNEEDED (1<<3) ///< Not available in Time Attack modes until you visit the level extern mapheader_t* mapheaderinfo[NUMMAPS]; +extern INT32 nummapheaders,basenummapheaders; + +#define MAXMAPLUMPNAME 64 // includes \0, for cleaner savedata // 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_demo.c b/src/g_demo.c index 2e2a05149..52a29d27c 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -3225,7 +3225,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 2b8bbd3f7..9baec3b6b 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -183,6 +183,8 @@ struct quake quake; // Map Header Information mapheader_t* mapheaderinfo[NUMMAPS] = {NULL}; +INT32 nummapheaders = 0; +INT32 basenummapheaders = 0; // Kart cup definitions cupheader_t *kartcupheaders = NULL; @@ -685,18 +687,13 @@ void G_SetGameModified(boolean silent, boolean major) } /** Builds an original game map name from a map number. - * The complexity is due to MAPA0-MAPZZ. * * \param map Map number. * \return Pointer to a static buffer containing the desired map name. - * \sa M_MapNumber + * \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??? { @@ -709,19 +706,35 @@ const char *G_BuildMapName(INT32 map) map = G_RandMap(G_TOLFlag(cv_newgametype.value), map, 0, 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. @@ -4629,7 +4642,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; @@ -4661,18 +4674,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; @@ -4723,14 +4735,14 @@ void G_InitNew(UINT8 pencoremode, const char *mapname, boolean resetplayer, bool // 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 (W_CheckNumForName(mapheaderinfo[gamemap-1]->lumpname) == LUMPERROR) { I_Error("Internal game map '%s' not found\n", mapname); Command_ExitGame_f(); return; } - gamemap = (INT16)M_MapNumber(mapname[3], mapname[4]); // get xx out of MAPxx + gamemap = map; // gamemap changed; we assume that its map header is always valid, // so make it so @@ -4758,7 +4770,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)); @@ -4873,21 +4885,17 @@ 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) - if (mapheaderinfo[i]) + + for (i = 0, mapnum = 1; i < nummapheaders; ++i, ++mapnum) { + if (!mapheaderinfo[i] || mapheaderinfo[i]->lumpnum == LUMPERROR) + continue; + if (!( realmapname = G_BuildMapTitle(mapnum) )) continue; @@ -4996,8 +5004,6 @@ void G_FreeMapSearch(mapsearchfreq_t *freq, INT32 freqc) INT32 G_FindMapByNameOrCode(const char *mapname, char **realmapnamep) { - boolean usemapcode = false; - INT32 newmapnum; size_t mapnamelen; @@ -5006,45 +5012,44 @@ INT32 G_FindMapByNameOrCode(const char *mapname, char **realmapnamep) mapnamelen = strlen(mapname); - if (mapnamelen == 2)/* maybe two digit code */ + if (mapnamelen == 1) { - if (( newmapnum = M_MapNumber(mapname[0], mapname[1]) )) - usemapcode = true; - } - else if (mapnamelen == 5 && strnicmp(mapname, "MAP", 3) == 0) - { - if (( newmapnum = M_MapNumber(mapname[3], mapname[4]) )) - 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 (mapname[0] == '*') // current map + return gamemap; + else if (mapname[0] == '+' && mapheaderinfo[gamemap-1]) // next map { + newmapnum = mapheaderinfo[gamemap-1]->nextlevel; if (newmapnum < 1 || newmapnum > NUMMAPS) { - CONS_Alert(CONS_ERROR, M_GetText("Invalid map number %d.\n"), newmapnum); + CONS_Alert(CONS_ERROR, M_GetText("NextLevel (%d) is not a valid map.\n"), newmapnum); return 0; } - usemapcode = true; - } - else - { - newmapnum = G_FindMap(mapname, realmapnamep, NULL, NULL); + else + return newmapnum; } } - 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 */ { - /* 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); + if (!mapheaderinfo[newmapnum-1] || mapheaderinfo[newmapnum-1]->lumpnum == LUMPERROR) + return 0; } + else + { + newmapnum = G_MapNumber(mapname); + + if (newmapnum > nummapheaders) + return G_FindMap(mapname, realmapnamep, NULL, NULL); + } + + if (realmapnamep) + (*realmapnamep) = G_BuildMapTitle(newmapnum); return newmapnum; } diff --git a/src/g_game.h b/src/g_game.h index 091e162ff..3352ce069 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -93,8 +93,8 @@ void weaponPrefChange4(void); #define MAXPLMOVE (50) #define SLOWTURNTICS (cv_turnsmooth.value * 3) -// build an internal map name MAPxx from map number const char *G_BuildMapName(INT32 map); +INT32 G_MapNumber(const char *mapname); void G_ResetAnglePrediction(player_t *player); void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer); @@ -136,7 +136,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); @@ -173,7 +173,7 @@ void G_SpawnPlayer(INT32 playernum, boolean starpost); // 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 020a6dcf8..0ff37d383 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -34,7 +34,6 @@ #include "k_hud.h" #include "d_netcmd.h" // IsPlayerAdmin #include "m_menu.h" // Player Setup menu color stuff -#include "m_misc.h" // M_MapNumber #include "p_spec.h" // P_StartQuake #include "i_system.h" // I_GetPreciseTime, I_GetPrecisePrecision @@ -390,18 +389,18 @@ static int lib_pGetColorAfter(lua_State *L) // M_MISC ////////////// -static int lib_mMapNumber(lua_State *L) +static int lib_gMapNumber(lua_State *L) { const char *arg = luaL_checkstring(L, 1); - size_t len = strlen(arg); - if (len == 2 || len == 5) { - char first = arg[len-2]; - char second = arg[len-1]; - lua_pushinteger(L, M_MapNumber(first, second)); - } else { - lua_pushinteger(L, 0); - } - return 1; + INT32 map; + + map = G_MapNumber(arg); + + if (map == INT32_MAX) + return 0; + + + return map; } // M_RANDOM @@ -3968,9 +3967,6 @@ static luaL_Reg lib[] = { {"M_GetColorAfter",lib_pGetColorAfter}, {"M_GetColorBefore",lib_pGetColorBefore}, - // m_misc - {"M_MapNumber",lib_mMapNumber}, - // m_random {"P_RandomFixed",lib_pRandomFixed}, {"P_RandomByte",lib_pRandomByte}, @@ -4173,6 +4169,7 @@ static luaL_Reg lib[] = { // g_game {"G_AddGametype", lib_gAddGametype}, {"G_BuildMapName",lib_gBuildMapName}, + {"G_MapNumber",lib_gMapNumber}, {"G_BuildMapTitle",lib_gBuildMapTitle}, {"G_FindMap",lib_gFindMap}, {"G_FindMapByNameOrCode",lib_gFindMapByNameOrCode}, diff --git a/src/m_menu.c b/src/m_menu.c index 720a0fdb9..c5837fe5c 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -6252,12 +6252,11 @@ static boolean M_ExitPandorasBox(void) static void M_ChangeLevel(INT32 choice) { - char mapname[6]; + char mapname[MAXMAPLUMPNAME-1]; (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)); @@ -7837,7 +7836,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 @@ -8134,7 +8133,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.cpp b/src/m_misc.cpp index 63859293f..b4da15099 100644 --- a/src/m_misc.cpp +++ b/src/m_misc.cpp @@ -182,32 +182,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 f3a464fc7..a11a384c6 100644 --- a/src/m_misc.h +++ b/src/m_misc.h @@ -46,8 +46,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 e9470b148..9dba5ea7d 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -5350,7 +5350,7 @@ boolean P_LoadGame(savebuffer_t *save, 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 0d5f95c2b..0791b6ffd 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -469,8 +469,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); } @@ -8713,6 +8715,51 @@ static lumpinfo_t* FindFolder(const char *folName, UINT16 *start, UINT16 *end, l return lumpinfo; } +// Initialising map data... +UINT8 P_InitMapData(void) +{ + UINT8 ret = 0; + INT32 i; + lumpnum_t maplump; + char *name; + + for (i = 0; i < nummapheaders; ++i) + { + name = mapheaderinfo[i]->lumpname; + maplump = W_CheckNumForMap(name); + + // Doesn't exist? + if (maplump == INT16_MAX) + continue; + + // No change? + if (mapheaderinfo[i]->lumpnum == maplump) + continue; + + // Okay, it does... + { + ret |= MAPRET_ADDED; + + if (basenummapheaders) + { + CONS_Printf("%s\n", name); + + if (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; + } + } + + return ret; +} + // // Add a wadfile to the active wad files, // replace sounds, musics, patches, textures, sprites and maps @@ -8738,7 +8785,6 @@ UINT16 P_PartialAddWadFile(const char *wadfilename, wadcompat_t compat) UINT16 numlumps, wadnum; char *name; lumpinfo_t *lumpinfo; - boolean mapsadded = false; // Vars to help us with the position start and amount of each resource type. // Useful for PK3s since they use folders. @@ -8894,41 +8940,6 @@ UINT16 P_PartialAddWadFile(const char *wadfilename, wadcompat_t compat) // R_LoadSpriteInfoLumps(wadnum, numlumps); - // - // search for maps - // - lumpinfo = wadfiles[wadnum]->lumpinfo; - for (i = 0; i < numlumps; i++, lumpinfo++) - { - name = lumpinfo->name; - if (name[0] == 'M' && name[1] == 'A' && name[2] == 'P') // Ignore the headers - { - INT16 num; - if (name[5]!='\0') - continue; - num = (INT16)M_MapNumber(name[3], name[4]); - - // 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; - } - - if (num == gamemap) - partadd_replacescurrentmap = true; - - CONS_Printf("%s\n", name); - mapsadded = true; - } - } - - if (!mapsadded) - CONS_Printf(M_GetText("No maps added\n")); - refreshdirmenu &= ~REFRESHDIR_GAMEDATA; // Under usual circumstances we'd wait for REFRESHDIR_ flags to disappear the next frame, but this one's a bit too dangerous for that... partadd_stage = 0; return wadnum; @@ -8992,9 +9003,16 @@ boolean P_MultiSetupWadFiles(boolean fullsetup) if (partadd_stage == 2) { - if (partadd_replacescurrentmap && gamestate == GS_LEVEL && (netgame || multiplayer)) + UINT8 mapsadded = P_InitMapData(); + + if (!mapsadded) + CONS_Printf(M_GetText("No maps added\n")); + + if ((mapsadded & MAPRET_CURRENTREPLACED) + && (gamestate == GS_LEVEL) + && (netgame || multiplayer)) { - CONS_Printf(M_GetText("Current map %d replaced, ending the level to ensure consistency.\n"), gamemap); + CONS_Printf(M_GetText("Current map %s replaced by added file, ending the level to ensure consistency.\n"), mapheaderinfo[gamemap-1]->lumpname); if (server) SendNetXCmd(XD_EXITLEVEL, NULL, 0); } diff --git a/src/p_setup.h b/src/p_setup.h index 2e72c626a..c7ddb7aa3 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -114,6 +114,10 @@ void HWR_LoadLevel(void); #endif boolean P_AddWadFile(const char *wadfilename, wadcompat_t compat); +#define MAPRET_ADDED (1) +#define MAPRET_CURRENTREPLACED (1<<1) +UINT8 P_InitMapData(void); + // WARNING: The following functions should be grouped as follows: // any amount of PartialAdds followed by MultiSetups until returned true, // as soon as possible. diff --git a/src/w_wad.c b/src/w_wad.c index 6271664a4..8567e0c6b 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -67,8 +67,7 @@ #ifdef SCANTHINGS #include "p_setup.h" // P_ScanThings #endif -#include "m_misc.h" // M_MapNumber -#include "g_game.h" // G_SetGameModified +#include "g_game.h" // G_MapNumber #include "k_terrain.h" @@ -281,11 +280,8 @@ static inline void W_LoadDehackedLumps(UINT16 wadnum, boolean mainfile) 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)M_MapNumber(name[3], name[4]); - P_ScanThings(mapnum, wadnum, lump + ML_THINGS); - } + INT16 mapnum = (INT16)G_MapNumber(name); + P_ScanThings(mapnum, wadnum, lump + ML_THINGS); } } #endif From 954156cd1ba98d9d2f7fd6f778872c9cfbee599f Mon Sep 17 00:00:00 2001 From: NepDisk Date: Wed, 5 Feb 2025 17:53:53 -0500 Subject: [PATCH 002/117] Long Map Names Port pt 2. --- src/deh_soc.c | 14 +++++++++----- src/p_setup.c | 1 + 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index 5b4466e0e..a6a44456b 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -1073,11 +1073,15 @@ void readlevelheader(MYFILE *f, char * name) 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 (num >= nummapheaders) + { + P_AllocMapHeader((INT16)(num -1)); + } + else if (f->wad > mainwads) + { + // only mark as a major mod if it replaces an already-existing mapheaderinfo + G_SetGameModified(multiplayer, true); + } if (mapheaderinfo[num-1]->lumpname == NULL) { diff --git a/src/p_setup.c b/src/p_setup.c index 0791b6ffd..4d9b91e67 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -469,6 +469,7 @@ 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]->flickies = NULL; mapheaderinfo[i]->grades = NULL; From 6c8440bfff4f99e3d80505757787d99585866bb5 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Wed, 5 Feb 2025 21:57:03 -0500 Subject: [PATCH 003/117] Long Map Names Port pt 3. shits broke --- src/d_main.cpp | 95 ++++++++--------------- src/filesrch.c | 16 ++-- src/g_demo.c | 2 +- src/g_game.c | 8 +- src/m_menu.c | 24 ++++-- src/p_setup.c | 27 +++++-- src/p_setup.h | 3 + src/w_wad.c | 205 +++++++++++++++++++++++++++++++++++++++---------- src/w_wad.h | 1 + 9 files changed, 253 insertions(+), 128 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index cc481504a..49f05cd9f 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1244,11 +1244,6 @@ D_ConvertVersionNumbers (void) // void D_SRB2Main(void) { - INT32 i; - UINT16 wadnum; - lumpinfo_t *lumpinfo; - char *name; - INT32 p; INT32 pstartmap = 0; @@ -1569,39 +1564,7 @@ void D_SRB2Main(void) // // search for pwad maps // - - // - // search for maps... again. - // - for (wadnum = mainwads+1; wadnum < numwadfiles; wadnum++) - { - 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)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; - } - - CONS_Printf("%s\n", name); - } - } - } + P_InitMapData(); HU_LoadGraphics(); } @@ -1704,33 +1667,41 @@ void D_SRB2Main(void) { const char *word = M_GetNextParm(); - pstartmap = G_FindMapByNameOrCode(word, 0); - - if (! pstartmap) - I_Error("Cannot find a map remotely named '%s'\n", word); + if (WADNAMECHECK(word)) + { + if (!(pstartmap = wadnamemap)) + I_Error("Bad '%s' level warp.\n" +#if defined (_WIN32) + "Are you using MSDOS 8.3 filenames in Zone Builder?\n" +#endif + , word); + } else { - if (!M_CheckParm("-server") && !M_CheckParm("-dedicated") && !M_CheckParm("-nograndprix")) - { - 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; + if (!(pstartmap = G_FindMapByNameOrCode(word, 0))) + I_Error("Cannot find a map remotely named '%s'\n", word); } + + if (!M_CheckParm("-server") && !M_CheckParm("-dedicated") && !M_CheckParm("-nograndprix")) + { + 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; } // Set up splitscreen players before joining! diff --git a/src/filesrch.c b/src/filesrch.c index 053855b9b..a662cc160 100644 --- a/src/filesrch.c +++ b/src/filesrch.c @@ -41,7 +41,6 @@ #include #define SUFFIX "*" -#define SLASH "\\" #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #ifndef INVALID_FILE_ATTRIBUTES @@ -139,7 +138,7 @@ opendir (const CHAR *szPath) /* Allocate enough space to store DIR structure and the complete * directory path given. */ nd = (DIR *) malloc (sizeof (DIR) + (strlen(szFullPath) + strlen (SLASH) + - strlen(SUFFIX) + 1) * sizeof (CHAR)); + strlen(PATHSEP) + 1) * sizeof (CHAR)); if (!nd) { @@ -153,10 +152,9 @@ opendir (const CHAR *szPath) /* Add on a slash if the path does not end with one. */ if (nd->dd_name[0] != '\0' && - nd->dd_name[strlen (nd->dd_name) - 1] != '/' && - nd->dd_name[strlen (nd->dd_name) - 1] != '\\') + nd->dd_name[strlen (nd->dd_name) - 1] != PATHSEP[0]) { - strcat (nd->dd_name, SLASH); + strcat (nd->dd_name, PATHSEP); } /* Add on the search pattern */ @@ -473,9 +471,9 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want return FS_NOTFOUND; } - if (searchpath[searchpathindex[depthleft]-2] != '/') + if (searchpath[searchpathindex[depthleft]-2] != PATHSEP[0]) { - searchpath[searchpathindex[depthleft]-1] = '/'; + searchpath[searchpathindex[depthleft]-1] = PATHSEP[0]; searchpath[searchpathindex[depthleft]] = 0; } else @@ -517,8 +515,8 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want depthleft++; } - searchpath[searchpathindex[depthleft]-1]='/'; - searchpath[searchpathindex[depthleft]]=0; + searchpath[searchpathindex[depthleft]-1] = PATHSEP[0]; + searchpath[searchpathindex[depthleft]] = 0; } else if (!strcasecmp(searchname, dent->d_name)) { diff --git a/src/g_demo.c b/src/g_demo.c index 52a29d27c..0d2c9708b 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -3024,7 +3024,7 @@ void G_DoPlayDemo(char *defdemoname) demobuf.p += 4; // Extrainfo location // ...*map* not loaded? - if (!gamemap || (gamemap > NUMMAPS) || !mapheaderinfo[gamemap-1] || !(mapheaderinfo[gamemap-1]->alreadyExists == true)) + 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 9baec3b6b..412f4daa2 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4735,7 +4735,13 @@ 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(mapheaderinfo[gamemap-1]->lumpname) == LUMPERROR) + 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); Command_ExitGame_f(); diff --git a/src/m_menu.c b/src/m_menu.c index c5837fe5c..3bcbd05c1 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -5590,8 +5590,10 @@ 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))); - if (lumpnum != LUMPERROR) + char *mapname = va("%sP", G_BuildMapName(cv_nextmap.value+1)); + SINT8 length = strlen(mapname); + lumpnum = W_CheckNumForName(mapname); + if (lumpnum != LUMPERROR && (length < 7)) patch = W_CachePatchNum(lumpnum, PU_CACHE); else patch = W_CachePatchName("M_NOLVL", PU_CACHE); @@ -8948,8 +8950,10 @@ 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))); - if (lumpnum != LUMPERROR) + char *mapname = va("%sP", G_BuildMapName(cv_nextmap.value+1)); + SINT8 length = strlen(mapname); + lumpnum = W_CheckNumForName(mapname); + if (lumpnum != LUMPERROR && (length < 7)) PictureOfLevel = W_CachePatchNum(lumpnum, PU_CACHE); else PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE); @@ -9014,8 +9018,10 @@ 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))); - if (lumpnum != LUMPERROR) + char *mapname = va("%sP", G_BuildMapName(i+1)); + SINT8 length = strlen(mapname); + lumpnum = W_CheckNumForName(mapname); + if (lumpnum != LUMPERROR && (length < 7)) PictureOfLevel = W_CachePatchNum(lumpnum, PU_CACHE); else PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE); @@ -9052,8 +9058,10 @@ 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))); - if (lumpnum != LUMPERROR) + char *mapname = va("%sP", G_BuildMapName(i+1)); + SINT8 length = strlen(mapname); + lumpnum = W_CheckNumForName(mapname); + if (lumpnum != LUMPERROR && (length < 7)) PictureOfLevel = W_CachePatchNum(lumpnum, PU_CACHE); else PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE); diff --git a/src/p_setup.c b/src/p_setup.c index 4d9b91e67..4a289922c 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -332,11 +332,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]; + + if (gamemap > 0 && gamemap <= nummapheaders && mapheaderinfo[gamemap-1]) + { + sprintf(mapname, "%s", mapheaderinfo[gamemap-1]->lumpname); + } + else + { + sprintf(mapname, "ID %d", gamemap-1); + } - sprintf(mapnum, "%hd", gamemap); CON_LogMessage("Map "); - CON_LogMessage(mapnum); + CON_LogMessage(mapname); CON_LogMessage(" is corrupt: "); CON_LogMessage(msg); CON_LogMessage("\n"); @@ -2303,7 +2311,7 @@ typedef struct static FILE *P_OpenTextmap(const char *mode, const char *error) { FILE *f; - char *filepath = va(pandf, srb2home, "TEXTMAP"); + char *filepath = va("%s" PATHSEP "TEXTMAP.%s.txt", srb2home, mapheaderinfo[gamemap-1]->lumpname); f = fopen(filepath, mode); if (!f) @@ -8355,15 +8363,15 @@ 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); curmapvirt = vres_GetMap(lastloadedmaplumpnum); R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette, - W_CheckNumForName(va("%s%c", maplumpname, (encoremode ? 'E' : 'T')))); + W_CheckNumForName(va("%s%c", maplumpname, (encoremode ? 'E' : 'T')))); CON_SetupBackColormap(); // SRB2 determines the sky texture to be used depending on the map header. @@ -8716,6 +8724,9 @@ static lumpinfo_t* FindFolder(const char *folName, UINT16 *start, UINT16 *end, l return lumpinfo; } +lumpnum_t wadnamelump = LUMPERROR; +INT16 wadnamemap = 0; // gamemap based + // Initialising map data... UINT8 P_InitMapData(void) { @@ -8755,6 +8766,8 @@ UINT8 P_InitMapData(void) } } mapheaderinfo[i]->lumpnum = maplump; + if (maplump == wadnamelump) + wadnamemap = i+1; } } diff --git a/src/p_setup.h b/src/p_setup.h index c7ddb7aa3..590d1db87 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -117,6 +117,9 @@ boolean P_AddWadFile(const char *wadfilename, wadcompat_t compat); #define MAPRET_ADDED (1) #define MAPRET_CURRENTREPLACED (1<<1) UINT8 P_InitMapData(void); +extern lumpnum_t wadnamelump; +extern INT16 wadnamemap; +#define WADNAMECHECK(name) (!strncmp(name, "WADNAME", 7)) // WARNING: The following functions should be grouped as follows: // any amount of PartialAdds followed by MultiSetups until returned true, diff --git a/src/w_wad.c b/src/w_wad.c index 8567e0c6b..c7bafcd4b 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -93,10 +93,12 @@ typedef struct // Must be a power of two #define LUMPNUMCACHESIZE 64 +#define LUMPNUMCACHENAME 32 typedef struct lumpnum_cache_s { char lumpname[32]; + UINT32 lumphash; lumpnum_t lumpnum; } lumpnum_cache_t; @@ -506,14 +508,63 @@ static lumpinfo_t* ResGetLumpsWad (FILE* handle, UINT16* nlmp, const char* filen } else lump_p->compression = CM_NOCOMPRESSION; + memset(lump_p->name, 0x00, 9); strncpy(lump_p->name, fileinfo->name, 8); - lump_p->hash = quickncasehash(lump_p->name, 8); - // Allocate the lump's long name. - lump_p->longname = Z_Malloc(9 * sizeof(char), PU_STATIC, NULL); - strncpy(lump_p->longname, fileinfo->name, 8); - lump_p->longname[8] = '\0'; + if (WADNAMECHECK(fileinfo->name)) + { + size_t namelen; + const char *trimname, *dotpos; + + trimname = strrchr(filename, PATHSEP[0]); +#if defined (_WIN32) + // For Zone Builder support, work around temporary filenames. + if (trimname != 0) + { + const char *temp = trimname-1; + while (temp >= filename+5 && *temp != PATHSEP[0]) + temp--; + + if (temp-filename >= 5 && !strncmp(temp-5, PATHSEP"Temp", 5)) + { + filename = wadfiles[numwadfiles-1]->filename; + trimname = strrchr(filename, PATHSEP[0]); + } + } +#endif + + // Strip away file address + if (trimname != 0) + trimname++; + else + trimname = filename; // Care taken for root files. + + // First stop, not last, to permit RR_GREENHILLS.beta3.wad + if ((dotpos = strchr(trimname, '.')) != 0) + namelen = (dotpos + 1 - trimname); + else + namelen = strlen(trimname); + + // Allocate the lump's long and full name (save on memory). + lump_p->longname = lump_p->fullname = Z_Calloc(namelen * sizeof(char), PU_STATIC, NULL); + strncpy(lump_p->longname, trimname, namelen); + lump_p->longname[namelen-1] = '\0'; + + // Grab the hash from the first part + lump_p->hash = quickncasehash(lump_p->longname, 8); + + wadnamelump = i | (numwadfiles << 16); + } + else + { + // Set up true hash + lump_p->hash = quickncasehash(lump_p->name, 8); + // Allocate the lump's long and full name (save on memory). + lump_p->longname = lump_p->fullname = Z_Malloc(9 * sizeof(char), PU_STATIC, NULL); + strncpy(lump_p->longname, fileinfo->name, 8); + lump_p->longname[8] = '\0'; + } // Allocate the lump's full name. lump_p->fullname = Z_Malloc(9 * sizeof(char), PU_STATIC, NULL); @@ -1055,6 +1106,61 @@ 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, UINT32 hash, UINT16 wad, UINT16 startlump) +{ + UINT16 i, end; + + if (wadfiles[wad]->type == RET_WAD) + { + for (i = startlump; i < wadfiles[wad]->numlumps; i++) + { + // Not the hash? + if ((wadfiles[wad]->lumpinfo + i)->hash != hash) + continue; + + // Not the name? (always use longname, even in wads, to accomodate WADNAME) + if (strcasecmp(name, (wadfiles[wad]->lumpinfo + i)->longname)) + continue; + + // Not a header? + if (W_LumpLength(i | (wad << 16)) > 0) + continue; + + 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++) + { + // Not the hash? + if ((wadfiles[wad]->lumpinfo + i)->hash != hash) + continue; + + // Not the name? + if (strcasecmp(name, (wadfiles[wad]->lumpinfo + i)->longname)) + continue; + + // Not a .wad? + if (!W_IsLumpWad(i | (wad << 16))) + continue; + + return i; + } + } + } + + return INT16_MAX; +} + // // Same as the original, but checks in one pwad only. // wadid is a wad number @@ -1102,12 +1208,14 @@ UINT16 W_CheckNumForLongNamePwad(const char *name, UINT16 wad, UINT16 startlump) { UINT16 i; static char uname[256 + 1]; + UINT32 hash; if (!TestValidLump(wad,0)) return INT16_MAX; strlcpy(uname, name, sizeof uname); strupr(uname); + hash = quickncasehash(uname, 8); // Not a mistake, legacy system for short lumpnames // // scan forward @@ -1118,8 +1226,14 @@ UINT16 W_CheckNumForLongNamePwad(const char *name, UINT16 wad, UINT16 startlump) { lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo + startlump; for (i = startlump; i < wadfiles[wad]->numlumps; i++, lump_p++) - if (!strcmp(lump_p->longname, uname)) - return i; + { + if (lump_p->hash != hash) + continue; + if (strcmp(lump_p->longname, uname)) + continue; + return i; + } + } // not found. @@ -1195,6 +1309,7 @@ UINT16 W_CheckNumForFullNamePK3(const char *name, UINT16 wad, UINT16 startlump) lumpnum_t W_CheckNumForName(const char *name) { INT32 i; + UINT32 hash = name ? quickncasehash(name, 8) : 0; lumpnum_t check = INT16_MAX; if (name == NULL) @@ -1208,6 +1323,7 @@ lumpnum_t W_CheckNumForName(const char *name) for (i = lumpnumcacheindex + LUMPNUMCACHESIZE; i > lumpnumcacheindex; i--) { if (!lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumpname[8] + && lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumphash == hash && strncmp(lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumpname, name, 8) == 0) { lumpnumcacheindex = i & (LUMPNUMCACHESIZE - 1); @@ -1245,6 +1361,7 @@ lumpnum_t W_CheckNumForName(const char *name) lumpnum_t W_CheckNumForLongName(const char *name) { INT32 i; + UINT32 hash = name ? quickncasehash(name, 8) : 0; lumpnum_t check = INT16_MAX; if (name == NULL) @@ -1282,6 +1399,7 @@ lumpnum_t W_CheckNumForLongName(const char *name) memset(lumpnumcache[lumpnumcacheindex].lumpname, '\0', 32); strlcpy(lumpnumcache[lumpnumcacheindex].lumpname, name, 32); lumpnumcache[lumpnumcacheindex].lumpnum = (i << 16) + check; + lumpnumcache[lumpnumcacheindex].lumphash = hash; } return (i << 16) + check; @@ -1290,45 +1408,52 @@ lumpnum_t W_CheckNumForLongName(const char *name) // Look for valid map data through all added files in descendant order. // Get a map marker for WADs, and a standalone WAD file lump inside PK3s. -// TODO: Make it search through cache first, maybe...? lumpnum_t W_CheckNumForMap(const char *name) { - UINT32 hash = quickncasehash(name, 8); - UINT16 lumpNum, end; - UINT32 i; - lumpinfo_t *p; - for (i = numwadfiles - 1; i < numwadfiles; i--) + lumpnum_t check = INT16_MAX; + UINT32 uhash, hash = quickncasehash(name, LUMPNUMCACHENAME); + INT32 i; + + // 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 (lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumphash == hash + && strcasecmp(lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumpname, name) == 0) { - for (lumpNum = 0; lumpNum < wadfiles[i]->numlumps; lumpNum++) - { - p = wadfiles[i]->lumpinfo + lumpNum; - if (p->hash == hash && !strncmp(name, p->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++) - { - p = wadfiles[i]->lumpinfo + lumpNum; - if (p->hash == hash && !strnicmp(name, p->name, 8)) - { - const char *extension = strrchr(p->fullname, '.'); - if (!(extension && stricmp(extension, ".wad"))) - return (i<<16) + lumpNum; - } - } + lumpnumcacheindex = i & (LUMPNUMCACHESIZE - 1); + return lumpnumcache[lumpnumcacheindex].lumpnum; } } - return LUMPERROR; + + uhash = quickncasehash(name, 8); // Not a mistake, legacy system for short lumpnames + + for (i = numwadfiles - 1; i >= 0; i--) + { + check = W_CheckNumForMapPwad(name, uhash, (UINT16)i, 0); + + if (check != INT16_MAX) + break; // found it + } + + if (check == INT16_MAX) + { + return LUMPERROR; + } + else + { + if (strlen(name) < LUMPNUMCACHENAME) + { + // Update the cache. + lumpnumcacheindex = (lumpnumcacheindex + 1) & (LUMPNUMCACHESIZE - 1); + memset(lumpnumcache[lumpnumcacheindex].lumpname, '\0', LUMPNUMCACHENAME); + strlcpy(lumpnumcache[lumpnumcacheindex].lumpname, name, LUMPNUMCACHENAME); + lumpnumcache[lumpnumcacheindex].lumpnum = (i << 16) + check; + lumpnumcache[lumpnumcacheindex].lumphash = hash; + } + + return (i << 16) + check; + } } // diff --git a/src/w_wad.h b/src/w_wad.h index 3b5375ca4..3eddb8b99 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -163,6 +163,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, UINT32 hash, 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 1147d3eaa8270b11c97662041f91b10588f39eb5 Mon Sep 17 00:00:00 2001 From: SteelT Date: Mon, 12 Sep 2022 12:51:31 -0400 Subject: [PATCH 004/117] Add patch support from a virtual lump --- src/w_wad.c | 74 ++++++++++++++++++++++++++++++++++++++++++----------- src/w_wad.h | 2 ++ 2 files changed, 61 insertions(+), 15 deletions(-) diff --git a/src/w_wad.c b/src/w_wad.c index c7bafcd4b..bcbcc9e41 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -1979,6 +1979,27 @@ 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, boolean remap) +{ + 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 + + if (remap) + R_DoPaletteRemapPatch(ptr, len); + + 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; @@ -1991,25 +2012,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 - - // we already know this is a patch, do palette remapping here - if (wadfiles[wad]->compatmode) - R_DoPaletteRemapPatch(ptr, len); - - dest = Z_Calloc(sizeof(patch_t), tag, &lumpcache[lump]); - Patch_Create(ptr, len, dest); - - Z_Free(ptr); + MakePatch(lumpdata, len, tag, &lumpcache[lump], wadfiles[wad]->compatmode); } else Z_ChangeTag(lumpcache[lump], tag); @@ -2496,6 +2504,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); @@ -2527,6 +2536,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); @@ -2580,3 +2590,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, false); + } + 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 3eddb8b99..d753f5d6f 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -82,6 +82,7 @@ struct virtlump_t { char name[9]; UINT8* data; size_t size; + void *cache; }; struct virtres_t { @@ -92,6 +93,7 @@ struct virtres_t { 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 14e5796cf28a0bb681d47aefd696b33c53797c98 Mon Sep 17 00:00:00 2001 From: SteelT Date: Mon, 12 Sep 2022 17:29:15 -0400 Subject: [PATCH 005/117] Support reading PICTURE/MINIMAP/ENCORE/TWEAKMAP lumps from a map resource This supersedes the header-based method of fetching those lumps. (G: a LOT of creative liberties... but i'd rather this thing compiles) --- src/d_main.cpp | 2 +- src/doomstat.h | 2 ++ src/k_hud.c | 9 ++++---- src/lua_hudlib.c | 9 ++++---- src/m_menu.c | 26 ++++++--------------- src/p_setup.c | 60 +++++++++++++++++++++++++++++++++++++++++++++--- src/r_data.c | 9 ++++---- src/r_data.h | 2 +- src/w_wad.c | 24 +++++++++---------- src/w_wad.h | 3 +-- src/y_inter.c | 13 +++++++---- 11 files changed, 100 insertions(+), 59 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 49f05cd9f..84b43701a 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -347,7 +347,7 @@ static bool 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, false); } F_WipeStartScreen(); diff --git a/src/doomstat.h b/src/doomstat.h index 338958693..881bc9ca4 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -350,6 +350,8 @@ struct mapheader_t { char * lumpname; ///< Lump name can be really long lumpnum_t lumpnum; ///< Lump number for the map + void * thumbnailPic; ///< Lump data for the level select thumbnail. + void * minimapPic; ///< Lump data for the minimap graphic. 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 diff --git a/src/k_hud.c b/src/k_hud.c index cdc714e43..fd96ca62c 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -3300,7 +3300,6 @@ static void K_drawKartMinimapWaypoint(waypoint_t *wp, INT32 hudx, INT32 hudy, IN static void K_drawKartMinimap(void) { - INT32 lumpnum; patch_t *AutomapPic, *workingPic; INT32 i = 0; INT32 x, y; @@ -3323,12 +3322,12 @@ static void K_drawKartMinimap(void) if (stplyr != &players[displayplayers[0]]) return; - lumpnum = W_CheckNumForName(va("%sR", G_BuildMapName(gamemap))); + AutomapPic = mapheaderinfo[gamemap-1]->minimapPic; - if (lumpnum != -1) - AutomapPic = W_CachePatchName(va("%sR", G_BuildMapName(gamemap)), PU_HUDGFX); - else + if (!AutomapPic) + { return; // no pic, just get outta here + } if (r_splitscreen < 2) // 1/2P right aligned { diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 6a61b2782..9130a61bd 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -597,7 +597,6 @@ static int libd_drawOnMinimap(lua_State *L) huddrawlist_h list; // variables used to replicate k_kart's mmap drawer: - INT32 lumpnum; patch_t *AutomapPic; INT32 mx, my; INT32 splitflags, minimaptrans; @@ -683,12 +682,12 @@ static int libd_drawOnMinimap(lua_State *L) if (stplyr != &players[displayplayers[0]]) return 0; - lumpnum = W_CheckNumForName(va("%sR", G_BuildMapName(gamemap))); + AutomapPic = mapheaderinfo[gamemap-1]->minimapPic; - if (lumpnum != -1) - AutomapPic = W_CachePatchName(va("%sR", G_BuildMapName(gamemap)), PU_HUDGFX); - else + if (!AutomapPic) + { return 0; // no pic, just get outta here + } 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 3bcbd05c1..80d9fc240 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -8947,15 +8947,11 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) 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 + // A 160x100 image of the level if (cv_nextmap.value) { - char *mapname = va("%sP", G_BuildMapName(cv_nextmap.value+1)); - SINT8 length = strlen(mapname); - lumpnum = W_CheckNumForName(mapname); - if (lumpnum != LUMPERROR && (length < 7)) - PictureOfLevel = W_CachePatchNum(lumpnum, PU_CACHE); - else + PictureOfLevel = mapheaderinfo[cv_nextmap.value+1]->thumbnailPic; + if (!PictureOfLevel) PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE); } else @@ -9018,12 +9014,8 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) // A 160x100 image of the level as entry MAPxxP if (i+1) { - char *mapname = va("%sP", G_BuildMapName(i+1)); - SINT8 length = strlen(mapname); - lumpnum = W_CheckNumForName(mapname); - if (lumpnum != LUMPERROR && (length < 7)) - PictureOfLevel = W_CachePatchNum(lumpnum, PU_CACHE); - else + PictureOfLevel = mapheaderinfo[i+1]->thumbnailPic; + if (!PictureOfLevel) PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE); } else @@ -9058,12 +9050,8 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) // A 160x100 image of the level as entry MAPxxP if (i+1) { - char *mapname = va("%sP", G_BuildMapName(i+1)); - SINT8 length = strlen(mapname); - lumpnum = W_CheckNumForName(mapname); - if (lumpnum != LUMPERROR && (length < 7)) - PictureOfLevel = W_CachePatchNum(lumpnum, PU_CACHE); - else + PictureOfLevel = mapheaderinfo[i+1]->thumbnailPic; + if (!PictureOfLevel) PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE); } else diff --git a/src/p_setup.c b/src/p_setup.c index 4a289922c..33614f175 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -397,7 +397,19 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) { const INT16 num = (INT16)(i-1); boolean exists = (mapheaderinfo[gamemap-1]->alreadyExists == true); - + + if (mapheaderinfo[num]->thumbnailPic) + { + Z_Free(mapheaderinfo[num]->thumbnailPic); + mapheaderinfo[num]->thumbnailPic = NULL; + } + + if (mapheaderinfo[num]->minimapPic) + { + Z_Free(mapheaderinfo[num]->minimapPic); + mapheaderinfo[num]->minimapPic = NULL; + } + mapheaderinfo[num]->lvlttl[0] = '\0'; mapheaderinfo[num]->selectheading[0] = '\0'; mapheaderinfo[num]->subttl[0] = '\0'; @@ -479,6 +491,8 @@ void P_AllocMapHeader(INT16 i) mapheaderinfo[i] = Z_Malloc(sizeof(mapheader_t), PU_STATIC, NULL); mapheaderinfo[i]->lumpnum = LUMPERROR; mapheaderinfo[i]->lumpname = NULL; + mapheaderinfo[i]->thumbnailPic = NULL; + mapheaderinfo[i]->minimapPic = NULL; mapheaderinfo[i]->flickies = NULL; mapheaderinfo[i]->grades = NULL; nummapheaders++; @@ -8152,6 +8166,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; @@ -8370,8 +8385,26 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) curmapvirt = vres_GetMap(lastloadedmaplumpnum); - R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette, - W_CheckNumForName(va("%s%c", maplumpname, (encoremode ? 'E' : 'T')))); + if (mapheaderinfo[gamemap-1]) + { + if (encoremode) + { + encoreLump = vres_Find(curmapvirt, "ENCORE"); + } + else + { + encoreLump = vres_Find(curmapvirt, "TWEAKMAP"); + } + } + + if (encoreLump) + { + R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette, encoreLump->data, encoreLump->size, false); + } + else + { + R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette, NULL, 0, false); + } CON_SetupBackColormap(); // SRB2 determines the sky texture to be used depending on the map header. @@ -8733,6 +8766,8 @@ UINT8 P_InitMapData(void) UINT8 ret = 0; INT32 i; lumpnum_t maplump; + virtres_t *virtmap; + virtlump_t *minimap, *thumbnailPic; char *name; for (i = 0; i < nummapheaders; ++i) @@ -8768,6 +8803,23 @@ UINT8 P_InitMapData(void) mapheaderinfo[i]->lumpnum = maplump; if (maplump == wadnamelump) wadnamemap = i+1; + + // 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); } } @@ -8799,6 +8851,8 @@ UINT16 P_PartialAddWadFile(const char *wadfilename, wadcompat_t compat) UINT16 numlumps, wadnum; char *name; lumpinfo_t *lumpinfo; + virtres_t *virtmap; + virtlump_t *minimap, *thumbnailPic; // Vars to help us with the position start and amount of each resource type. // Useful for PK3s since they use folders. diff --git a/src/r_data.c b/src/r_data.c index ecac6920a..69f583914 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -287,7 +287,7 @@ void R_InitColormaps(void) #endif } -void R_ReInitColormaps(UINT16 num, lumpnum_t newencoremap) +void R_ReInitColormaps(UINT16 num, void *newencoremap, size_t encoremapsize, boolean compat) { char colormap[9] = "COLORMAP"; lumpnum_t lump; @@ -325,18 +325,17 @@ void R_ReInitColormaps(UINT16 num, lumpnum_t newencoremap) } // 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; - remap = wadfiles[WADFILENUM(newencoremap)]->compatmode; - if (remap) + if (compat) { UINT8 *copy = malloc(256); memcpy(copy, encoremap, 256); diff --git a/src/r_data.h b/src/r_data.h index b006ac862..a76978693 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, boolean compat); 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 bcbcc9e41..84487db5b 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -1979,7 +1979,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, boolean remap) +static void *MakePatch(void *lumpdata, size_t size, INT32 tag, void *cache, boolean remap) { void *ptr, *dest; size_t len = size; @@ -1995,9 +1995,10 @@ static void MakePatch(void *lumpdata, size_t size, INT32 tag, void *cache, boole R_DoPaletteRemapPatch(ptr, len); 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) @@ -2018,6 +2019,7 @@ void *W_CacheSoftwarePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag) W_ReadLumpHeaderPwad(wad, lump, lumpdata, 0, 0); MakePatch(lumpdata, len, tag, &lumpcache[lump], wadfiles[wad]->compatmode); + Z_Free(lumpdata); } else Z_ChangeTag(lumpcache[lump], tag); @@ -2504,7 +2506,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); @@ -2536,7 +2537,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); @@ -2559,7 +2559,12 @@ 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); } @@ -2604,14 +2609,7 @@ void *vres_GetPatch(virtlump_t *vlump, INT32 tag) if (!vlump) return NULL; - if (!vlump->cache) - { - MakePatch(vlump->data, vlump->size, tag, &vlump->cache, false); - } - else - Z_ChangeTag(vlump->cache, tag); - - patch = vlump->cache; + patch = MakePatch(vlump->data, vlump->size, tag, NULL, false); #ifdef HWRENDER // Software-only compile cache the data without conversion diff --git a/src/w_wad.h b/src/w_wad.h index d753f5d6f..8a088ad3c 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -82,7 +82,6 @@ struct virtlump_t { char name[9]; UINT8* data; size_t size; - void *cache; }; struct virtres_t { @@ -93,7 +92,7 @@ struct virtres_t { 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 f0478449e..4707b4f76 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -1640,8 +1640,6 @@ void Y_StartVote(void) for (i = 0; i < 4; i++) { - lumpnum_t lumpnum; - // set up the encore levelinfo[i].encore = (votelevels[i][1] & 0x80); votelevels[i][1] &= ~0x80; @@ -1684,9 +1682,14 @@ void Y_StartVote(void) levelinfo[i].gts = NULL; // set up the pic - lumpnum = W_CheckNumForName(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); + 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); } From a97dcae2c2bc3f0f38e3a56562a52c8d729874ae Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Fri, 7 Feb 2025 03:02:34 +0100 Subject: [PATCH 006/117] The rest of toaster's changes --- src/hu_stuff.c | 3 +++ src/m_menu.c | 6 ++--- src/p_setup.c | 20 ++++++++++++---- src/r_defs.h | 1 + src/y_inter.c | 65 ++++++++++++++++++++------------------------------ 5 files changed, 49 insertions(+), 46 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 972faab56..624085591 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -98,6 +98,7 @@ static char hu_tick; //------------------------------------------- patch_t *missingpat; +patch_t *blanklvl; // song credits static patch_t *songcreditbg; @@ -186,6 +187,8 @@ void HU_LoadGraphics(void) Font_Load(); + HU_UpdatePatch(&blanklvl, "BLANKLVL"); + HU_UpdatePatch(&songcreditbg, "K_SONGCR"); // cache ping gfx: diff --git a/src/m_menu.c b/src/m_menu.c index 80d9fc240..50f6a2c65 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -8952,7 +8952,7 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) { PictureOfLevel = mapheaderinfo[cv_nextmap.value+1]->thumbnailPic; if (!PictureOfLevel) - PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE); + PictureOfLevel = blanklvl; } else PictureOfLevel = W_CachePatchName("RANDOMLV", PU_CACHE); @@ -9016,7 +9016,7 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) { PictureOfLevel = mapheaderinfo[i+1]->thumbnailPic; if (!PictureOfLevel) - PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE); + PictureOfLevel = blanklvl; } else PictureOfLevel = W_CachePatchName("RANDOMLV", PU_CACHE); @@ -9052,7 +9052,7 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) { PictureOfLevel = mapheaderinfo[i+1]->thumbnailPic; if (!PictureOfLevel) - PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE); + PictureOfLevel = blanklvl; } else PictureOfLevel = W_CachePatchName("RANDOMLV", PU_CACHE); diff --git a/src/p_setup.c b/src/p_setup.c index 33614f175..8d8f0d2f3 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -400,13 +400,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; } @@ -8809,14 +8809,26 @@ UINT8 P_InitMapData(void) 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_CACHE); + mapheaderinfo[i]->thumbnailPic = vres_GetPatch(thumbnailPic, PU_STATIC); } if (minimap) { - mapheaderinfo[i]->minimapPic = vres_GetPatch(minimap, PU_HUDGFX); + mapheaderinfo[i]->minimapPic = vres_GetPatch(minimap, PU_STATIC); } vres_Free(virtmap); diff --git a/src/r_defs.h b/src/r_defs.h index 7dd2c1d88..54da08673 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -892,6 +892,7 @@ struct patch_t }; extern patch_t *missingpat; +extern patch_t *blanklvl; #if defined(_MSC_VER) #pragma pack(1) diff --git a/src/y_inter.c b/src/y_inter.c index 4707b4f76..e13f9986b 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -128,7 +128,6 @@ typedef struct char str[62]; UINT8 gtc; const char *gts; - patch_t *pic; boolean encore; } y_votelvlinfo; @@ -1158,7 +1157,17 @@ 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]) @@ -1278,9 +1287,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) { @@ -1680,18 +1703,6 @@ void Y_StartVote(void) levelinfo[i].gts = gametype_cons_t[votelevels[i][1]].strvalue; 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; @@ -1712,8 +1723,6 @@ void Y_EndVote(void) // static void Y_UnloadVoteData(void) { - UINT8 i; - voteclient.loaded = false; if (rendermode != render_soft) @@ -1728,28 +1737,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 372532ad0fed68a4e23c5adf41640a649b638794 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Fri, 7 Feb 2025 03:34:16 +0100 Subject: [PATCH 007/117] Old thumbnail/encore compat, fix level select --- src/m_menu.c | 11 +++++------ src/p_setup.c | 30 ++++++++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 50f6a2c65..5d6bf1d40 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -8943,14 +8943,13 @@ static void M_StartServer(INT32 choice) static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) { - 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 if (cv_nextmap.value) { - PictureOfLevel = mapheaderinfo[cv_nextmap.value+1]->thumbnailPic; + PictureOfLevel = mapheaderinfo[cv_nextmap.value-1]->thumbnailPic; if (!PictureOfLevel) PictureOfLevel = blanklvl; } @@ -9012,9 +9011,9 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) } while (!M_CanShowLevelInList(i, cv_newgametype.value)); // A 160x100 image of the level as entry MAPxxP - if (i+1) + if (i >= 0) { - PictureOfLevel = mapheaderinfo[i+1]->thumbnailPic; + PictureOfLevel = mapheaderinfo[i]->thumbnailPic; if (!PictureOfLevel) PictureOfLevel = blanklvl; } @@ -9048,9 +9047,9 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) } while (!M_CanShowLevelInList(i, cv_newgametype.value)); // A 160x100 image of the level as entry MAPxxP - if (i+1) + if (i >= 0) { - PictureOfLevel = mapheaderinfo[i+1]->thumbnailPic; + PictureOfLevel = mapheaderinfo[i]->thumbnailPic; if (!PictureOfLevel) PictureOfLevel = blanklvl; } diff --git a/src/p_setup.c b/src/p_setup.c index 8d8f0d2f3..eb7917a29 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -8167,6 +8167,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) INT32 i, ranspecialwipe = 0; sector_t *ss; virtlump_t *encoreLump = NULL; + lumpnum_t oldEncore = LUMPERROR; levelloading = true; @@ -8390,10 +8391,14 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) if (encoremode) { encoreLump = vres_Find(curmapvirt, "ENCORE"); + if (!encoreLump) + oldEncore = W_CheckNumForName(va("%sE", maplumpname)); } else { encoreLump = vres_Find(curmapvirt, "TWEAKMAP"); + if (!encoreLump) + oldEncore = W_CheckNumForName(va("%sT", maplumpname)); } } @@ -8401,6 +8406,15 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) { R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette, encoreLump->data, encoreLump->size, false); } + else if (oldEncore != LUMPERROR) + { + // mildly annoying, but whatever + size_t size = W_LumpLength(oldEncore); + void *data = malloc(size); + W_ReadLump(oldEncore, data); + R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette, data, size, wadfiles[WADFILENUM(oldEncore)]->compatmode); + free(data); + } else { R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette, NULL, 0, false); @@ -8768,6 +8782,7 @@ UINT8 P_InitMapData(void) lumpnum_t maplump; virtres_t *virtmap; virtlump_t *minimap, *thumbnailPic; + patch_t *oldPic; char *name; for (i = 0; i < nummapheaders; ++i) @@ -8825,11 +8840,24 @@ UINT8 P_InitMapData(void) { mapheaderinfo[i]->thumbnailPic = vres_GetPatch(thumbnailPic, PU_STATIC); } + // okay... try finding them the old-fashioned way + else + { + oldPic = W_CachePatchName(va("%sP", name), PU_STATIC); + if (oldPic != missingpat) + mapheaderinfo[i]->thumbnailPic = oldPic; + } if (minimap) { mapheaderinfo[i]->minimapPic = vres_GetPatch(minimap, PU_STATIC); } + else + { + oldPic = W_CachePatchName(va("%sR", name), PU_STATIC); + if (oldPic != missingpat) + mapheaderinfo[i]->minimapPic = oldPic; + } vres_Free(virtmap); } @@ -8863,8 +8891,6 @@ UINT16 P_PartialAddWadFile(const char *wadfilename, wadcompat_t compat) UINT16 numlumps, wadnum; char *name; lumpinfo_t *lumpinfo; - virtres_t *virtmap; - virtlump_t *minimap, *thumbnailPic; // Vars to help us with the position start and amount of each resource type. // Useful for PK3s since they use folders. From de6919c64f43818d642669cbb57b26a1ba959c78 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Fri, 7 Feb 2025 10:38:54 -0500 Subject: [PATCH 008/117] vres_GetMap: Count resources in folders up until next 0-length lump, instead of 'MAP' https://git.do.srb2.org/KartKrew/RingRacers/-/commit/89a22783b6ae069583e15e11891c987a38ae89b3 --- src/w_wad.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/w_wad.c b/src/w_wad.c index 84487db5b..841fbc498 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -2512,7 +2512,7 @@ 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; lumpnum_t lastlump = wadfiles[WADFILENUM(lumpnum)]->numlumps; // or the end of directory, for PK3 files @@ -2526,8 +2526,12 @@ virtres_t* vres_GetMap(lumpnum_t lumpnum) free(dirname); } for (i = LUMPNUM(lumppos); i < lastlump; 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); @@ -2621,4 +2625,4 @@ void *vres_GetPatch(virtlump_t *vlump, INT32 tag) Patch_CreateGL(patch); return (void *)patch; #endif -} \ No newline at end of file +} From 6d5e3eb262063ced17d1bef2c7e8fc3410146e4f Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 23 Sep 2022 13:03:37 +0100 Subject: [PATCH 009/117] 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 841fbc498..ce0f5ff51 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -2491,23 +2491,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 @@ -2527,10 +2547,10 @@ virtres_t* vres_GetMap(lumpnum_t lumpnum) } for (i = LUMPNUM(lumppos); i < lastlump; i++, lumppos++, numlumps++) { - if (W_LumpLength(lumppos) == 0) - { - break; - } + if (W_LumpLength(lumppos) > 0) + continue; + + break; } numlumps++; From 21a431d341a1f8aabd2aabfc9a2791228554891a Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 3 Feb 2023 13:53:26 +0000 Subject: [PATCH 010/117] ACS Environment::loadModule: Free vres after generation Discovered (temporary) memory leak while writing the following commit --- src/acs/environment.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/acs/environment.cpp b/src/acs/environment.cpp index b49323938..51db58f10 100644 --- a/src/acs/environment.cpp +++ b/src/acs/environment.cpp @@ -300,6 +300,8 @@ void Environment::loadModule(ACSVM::Module *module) { CONS_Debug(DBG_SETUP, "No BEHAVIOR lump found.\n"); } + + vres_Free(vRes); } else { From 462a4f875688a446d5c5aa65fd9b70db48c434ae Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Fri, 7 Feb 2025 16:26:17 +0100 Subject: [PATCH 011/117] Legalize loose lumps --- src/w_wad.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/w_wad.c b/src/w_wad.c index ce0f5ff51..75861c6f6 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -1149,9 +1149,11 @@ UINT16 W_CheckNumForMapPwad(const char *name, UINT32 hash, UINT16 wad, UINT16 st if (strcasecmp(name, (wadfiles[wad]->lumpinfo + i)->longname)) continue; +#if 0 // Not a .wad? if (!W_IsLumpWad(i | (wad << 16))) continue; +#endif return i; } From ca4602848c6b9b456dd61eb6772818ffb69da375 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 3 Jan 2023 16:03:47 +0000 Subject: [PATCH 012/117] Use Zone memory functions for sending compressed saves Fixes an issue where `SF_RAM` meant `free()` was being called on Zone memory produced by `P_SaveBufferAlloc` --- src/d_clisrv.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 30dfc6487..0c115f774 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1186,7 +1186,7 @@ static void SV_SendSaveGame(INT32 node, boolean resending) // Allocate space for compressed save: one byte fewer than for the // uncompressed data to ensure that the compression is worthwhile. - compressedsave = malloc(length - 1); + compressedsave = Z_Malloc(length - 1, PU_STATIC, NULL); if (!compressedsave) { CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n")); @@ -1207,14 +1207,14 @@ static void SV_SendSaveGame(INT32 node, boolean resending) else { // Compression failed to make it smaller; send original - free(compressedsave); + Z_Free(compressedsave); // State that we're not compressed buffertosend = save.buffer; WRITEUINT32(save.buffer, 0); } - AddRamToSendQueue(node, buffertosend, length, SF_RAM, 0); + AddRamToSendQueue(node, buffertosend, length, SF_Z_RAM, 0); // Remember when we started sending the savegame so we can handle timeouts sendingsavegame[node] = true; From 5fee047fe62ae89e7b22cedbc2f27809f553a1e7 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 2 Jan 2023 19:47:59 -0500 Subject: [PATCH 013/117] Add functions to initialize savebuffer_t g_demo.c is mostly unaltered because it is made of twigs. --- src/d_clisrv.c | 66 ++++++++++++++----------------------- src/d_netcmd.c | 14 +++++--- src/g_demo.c | 38 ++++++++++----------- src/g_game.c | 67 +++++++++++++------------------------ src/p_saveg.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/p_saveg.h | 7 ++++ src/p_setup.c | 9 ++--- 7 files changed, 171 insertions(+), 119 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 0c115f774..e654512c0 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1158,29 +1158,26 @@ static boolean SV_ResendingSavegameToAnyone(void) static void SV_SendSaveGame(INT32 node, boolean resending) { size_t length, compressedlen; - savebuffer_t save; + savebuffer_t save = {0}; UINT8 *compressedsave; UINT8 *buffertosend; // first save it in a malloced buffer - save.size = NETSAVEGAMESIZE; - save.buffer = (UINT8 *)malloc(save.size); - if (!save.buffer) + if (P_SaveBufferAlloc(&save, NETSAVEGAMESIZE) == false) { CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n")); return; } // Leave room for the uncompressed length. - save.p = save.buffer + sizeof(UINT32); - save.end = save.buffer + save.size; + save.p += sizeof(UINT32); P_SaveNetGame(&save, resending); length = save.p - save.buffer; if (length > NETSAVEGAMESIZE) { - free(save.buffer); + P_SaveBufferFree(&save); I_Error("Savegame buffer overrun"); } @@ -1197,7 +1194,7 @@ static void SV_SendSaveGame(INT32 node, boolean resending) if ((compressedlen = lzf_compress(save.buffer + sizeof(UINT32), length - sizeof(UINT32), compressedsave + sizeof(UINT32), length - sizeof(UINT32) - 1))) { // Compressing succeeded; send compressed data - free(save.buffer); + P_SaveBufferFree(&save); // State that we're compressed. buffertosend = compressedsave; @@ -1228,7 +1225,7 @@ static consvar_t cv_dumpconsistency = CVAR_INIT ("dumpconsistency", "Off", CV_SA static void SV_SavedGame(void) { size_t length; - savebuffer_t save; + savebuffer_t save = {0}; char tmpsave[256]; if (!cv_dumpconsistency.value) @@ -1237,22 +1234,18 @@ static void SV_SavedGame(void) sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home); // first save it in a malloced buffer - save.size = NETSAVEGAMESIZE; - save.p = save.buffer = (UINT8 *)malloc(save.size); - if (!save.p) + if (P_SaveBufferAlloc(&save, NETSAVEGAMESIZE) == false) { CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n")); return; } - save.end = save.buffer + save.size; - P_SaveNetGame(&save, false); length = save.p - save.buffer; if (length > NETSAVEGAMESIZE) { - free(save.buffer); + P_SaveBufferFree(&save); I_Error("Savegame buffer overrun"); } @@ -1260,7 +1253,7 @@ static void SV_SavedGame(void) if (!FIL_WriteFile(tmpsave, save.buffer, length)) CONS_Printf(M_GetText("Didn't save %s for netgame"), tmpsave); - free(save.buffer); + P_SaveBufferFree(&save); } #undef TMPSAVENAME @@ -1270,37 +1263,31 @@ static void SV_SavedGame(void) static void CL_LoadReceivedSavegame(boolean reloading) { - savebuffer_t save; + savebuffer_t save = {0}; size_t length, decompressedlen; char tmpsave[256]; sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home); - length = FIL_ReadFile(tmpsave, &save.buffer); - - CONS_Printf(M_GetText("Loading savegame length %s\n"), sizeu1(length)); - if (!length) + if (P_SaveBufferFromFile(&save, tmpsave) == false) { I_Error("Can't read savegame sent"); return; } - save.p = save.buffer; - save.size = length; - save.end = save.buffer + save.size; + length = save.size; + CONS_Printf(M_GetText("Loading savegame length %s\n"), sizeu1(length)); // Decompress saved game if necessary. decompressedlen = READUINT32(save.p); - if(decompressedlen > 0) + if (decompressedlen > 0) { UINT8 *decompressedbuffer = Z_Malloc(decompressedlen, PU_STATIC, NULL); lzf_decompress(save.p, length - sizeof(UINT32), decompressedbuffer, decompressedlen); - Z_Free(save.buffer); - save.p = save.buffer = decompressedbuffer; - save.size = decompressedlen; - save.end = save.buffer + decompressedlen; + P_SaveBufferFree(&save); + P_SaveBufferFromExisting(&save, decompressedbuffer, decompressedlen); } paused = false; @@ -1332,10 +1319,13 @@ static void CL_LoadReceivedSavegame(boolean reloading) } // done - Z_Free(save.buffer); - save.p = NULL; + P_SaveBufferFree(&save); + if (unlink(tmpsave) == -1) + { CONS_Alert(CONS_ERROR, M_GetText("Can't delete %s\n"), tmpsave); + } + consistancy[gametic%BACKUPTICS] = Consistancy(); CON_ToggleOff(); @@ -6134,7 +6124,7 @@ void CL_ClearRewinds(void) rewind_t *CL_SaveRewindPoint(size_t demopos) { - savebuffer_t save; + savebuffer_t save = {0}; rewind_t *rewind; if (rewindhead && rewindhead->leveltime + REWIND_POINT_INTERVAL > leveltime) @@ -6144,10 +6134,7 @@ rewind_t *CL_SaveRewindPoint(size_t demopos) if (!rewind) return NULL; - save.buffer = save.p = rewind->savebuffer; - save.size = NETSAVEGAMESIZE; - save.end = save.buffer + save.size; - + P_SaveBufferFromExisting(&save, rewind->savebuffer, NETSAVEGAMESIZE); P_SaveNetGame(&save, false); rewind->leveltime = leveltime; @@ -6160,7 +6147,7 @@ rewind_t *CL_SaveRewindPoint(size_t demopos) rewind_t *CL_RewindToTime(tic_t time) { - savebuffer_t save; + savebuffer_t save = {0}; rewind_t *rewind; while (rewindhead && rewindhead->leveltime > time) @@ -6173,10 +6160,7 @@ rewind_t *CL_RewindToTime(tic_t time) if (!rewindhead) return NULL; - save.buffer = save.p = rewindhead->savebuffer; - save.size = NETSAVEGAMESIZE; - save.end = save.buffer + save.size; - + P_SaveBufferFromExisting(&save, rewindhead->savebuffer, NETSAVEGAMESIZE); P_LoadNetGame(&save, false); wipegamestate = gamestate; // No fading back in! diff --git a/src/d_netcmd.c b/src/d_netcmd.c index ef7861c2a..9414a1a25 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -5785,7 +5785,7 @@ static void Command_Togglemodified_f(void) static void Command_Archivetest_f(void) { - savebuffer_t save; + savebuffer_t save = {0}; UINT32 i, wrote; thinker_t *th; if (gamestate != GS_LEVEL) @@ -5801,9 +5801,11 @@ static void Command_Archivetest_f(void) ((mobj_t *)th)->mobjnum = i++; // allocate buffer - save.size = 1024; - save.buffer = save.p = ZZ_Alloc(save.size); - save.end = save.buffer + save.size; + if (P_SaveBufferAlloc(&save, 1024) == false) + { + CONS_Printf("Unable to allocate buffer.\n"); + return; + } // test archive CONS_Printf("LUA_Archive...\n"); @@ -5821,10 +5823,12 @@ static void Command_Archivetest_f(void) LUA_UnArchive(&save, true); i = READUINT8(save.p); if (i != 0x7F || wrote != (UINT32)(save.p - save.buffer)) + { CONS_Printf("Savegame corrupted. (write %u, read %u)\n", wrote, (UINT32)(save.p - save.buffer)); + } // free buffer - Z_Free(save.buffer); + P_SaveBufferFree(&save); CONS_Printf("Done. No crash.\n"); } #endif diff --git a/src/g_demo.c b/src/g_demo.c index 0d2c9708b..688885547 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -64,7 +64,7 @@ boolean noblit; // for comparative timing purposes tic_t demostarttime; // for comparative timing purposes static char demoname[MAX_WADPATH]; -static savebuffer_t demobuf; +static savebuffer_t demobuf = {0}; static UINT8 *demotime_p, *demoinfo_p; static UINT8 demoflags; boolean demosynced = true; // console warning message @@ -2009,10 +2009,8 @@ void G_RecordDemo(const char *name) // if (demobuf.buffer) // P_SaveBufferFree(&demobuf); - demobuf.size = maxsize; - demobuf.buffer = (UINT8 *)malloc(maxsize); + P_SaveBufferAlloc(&demobuf, maxsize); demobuf.p = NULL; - demobuf.end = demobuf.buffer + demobuf.size; demo.recording = true; //demo.buffer = &demobuf; @@ -2039,10 +2037,8 @@ void G_RecordMetal(void) if (M_CheckParm("-maxdemo") && M_IsNextParm()) maxsize = atoi(M_GetNextParm()) * 1024; - demobuf.size = maxsize; - demobuf.buffer = (UINT8 *)malloc(maxsize); + P_SaveBufferAlloc(&demobuf, maxsize); demobuf.p = NULL; - demobuf.end = demobuf.buffer + demobuf.size; metalrecording = true; } @@ -2848,7 +2844,7 @@ void G_DoPlayDemo(char *defdemoname) if (FIL_CheckExtension(defdemoname)) { //FIL_DefaultExtension(defdemoname, ".lmp"); - if (!FIL_ReadFile(defdemoname, &demobuf.buffer)) + if (P_SaveBufferFromFile(&demobuf, defdemoname) == false) { snprintf(msg, 1024, M_GetText("Failed to read file '%s'.\n"), defdemoname); CONS_Alert(CONS_ERROR, "%s", msg); @@ -2856,20 +2852,20 @@ void G_DoPlayDemo(char *defdemoname) M_StartMessage(msg, NULL, MM_NOTHING); return; } - demobuf.p = demobuf.buffer; } // load demo resource from WAD - else if ((l = W_CheckNumForName(defdemoname)) == LUMPERROR) + else { - snprintf(msg, 1024, M_GetText("Failed to read lump '%s'.\n"), defdemoname); - CONS_Alert(CONS_ERROR, "%s", msg); - gameaction = ga_nothing; - M_StartMessage(msg, NULL, MM_NOTHING); - return; - } - else // it's an internal demo - { - demobuf.buffer = demobuf.p = W_CacheLumpNum(l, PU_STATIC); + if ((l = W_CheckNumForName(defdemoname)) == LUMPERROR) + { + snprintf(msg, 1024, M_GetText("Failed to read lump '%s'.\n"), defdemoname); + CONS_Alert(CONS_ERROR, "%s", msg); + gameaction = ga_nothing; + M_StartMessage(msg, NULL, MM_NOTHING); + return; + } + + P_SaveBufferFromLump(&demobuf, l); #if defined(SKIPERRORS) && !defined(DEVELOP) skiperrors = true; // SRB2Kart: Don't print warnings for staff ghosts, since they'll inevitably happen when we make bugfixes/changes... #endif @@ -3758,7 +3754,7 @@ ATTRNORETURN void FUNCNORETURN G_StopMetalRecording(boolean kill) WriteDemoChecksum(); saved = FIL_WriteFile(va("%sMS.LMP", G_BuildMapName(gamemap)), demobuf.buffer, demobuf.p - demobuf.buffer); // finally output the file. } - free(demobuf.buffer); + Z_Free(demobuf.buffer); metalrecording = false; if (saved) I_Error("Saved to %sMS.LMP", G_BuildMapName(gamemap)); @@ -3966,7 +3962,7 @@ void G_SaveDemo(void) if (FIL_WriteFile(demoname, demobuf.buffer, demobuf.p - demobuf.buffer)) // finally output the file. demo.savemode = DSM_SAVED; - free(demobuf.buffer); + Z_Free(demobuf.buffer); demo.recording = false; if (!modeattacking) diff --git a/src/g_game.c b/src/g_game.c index 412f4daa2..db85d734f 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4119,11 +4119,10 @@ void G_LoadGameSettings(void) // Loads the main data file, which stores information such as emblems found, etc. void G_LoadGameData(void) { - size_t length; INT32 i, j; UINT8 modded = false; UINT8 rtemp; - savebuffer_t save; + savebuffer_t save = {0}; //For records tic_t rectime; @@ -4153,12 +4152,9 @@ void G_LoadGameData(void) if (M_CheckParm("-resetdata")) return; // Don't load (essentially, reset). - - length = FIL_ReadFile(va(pandf, srb2home, gamedatafilename), &save.buffer); - if (!length) // Aw, no game data. Their loss! - return; - save.p = save.buffer; + if (P_SaveBufferFromFile(&save, va(pandf, srb2home, gamedatafilename)) == false) + return; // Version check if (READUINT32(save.p) != 0xFCAFE211) @@ -4167,9 +4163,8 @@ void G_LoadGameData(void) if (strcmp(srb2home,".")) gdfolder = srb2home; - Z_Free(save.buffer); - save.p = NULL; - I_Error("Game data is from another version of SRB2.\nDelete %s(maybe in %s) and try again.", gamedatafilename, gdfolder); + P_SaveBufferFree(&save); + I_Error("Game data is not for SRB2Kart v2.\nDelete %s(maybe in %s) and try again.", gamedatafilename, gdfolder); } totalplaytime = READUINT32(save.p); @@ -4242,8 +4237,7 @@ void G_LoadGameData(void) } // done - Z_Free(save.buffer); - save.p = NULL; + P_SaveBufferFree(&save); // Silent update unlockables in case they're out of sync with conditions M_SilentUpdateUnlockablesAndEmblems(); @@ -4257,8 +4251,7 @@ void G_LoadGameData(void) if (strcmp(srb2home,".")) gdfolder = srb2home; - Z_Free(save.buffer); - save.p = NULL; + P_SaveBufferFree(&save); I_Error("Corrupt game data file.\nDelete %s(maybe in %s) and try again.", gamedatafilename, gdfolder); } @@ -4271,18 +4264,16 @@ void G_SaveGameData(void) size_t length; INT32 i, j; UINT8 btemp; - savebuffer_t save; + savebuffer_t save = {0}; if (!gamedataloaded) return; // If never loaded (-nodata), don't save - save.p = save.buffer = (UINT8 *)malloc(GAMEDATASIZE); - if (!save.p) + if (P_SaveBufferAlloc(&save, length) == false) { CONS_Alert(CONS_ERROR, M_GetText("No more free memory for saving game data\n")); return; } - save.end = save.buffer + save.size; #if 0 // SRB2Kart: Let players unlock stuff with addons. @@ -4364,8 +4355,7 @@ void G_SaveGameData(void) length = save.p - save.buffer; FIL_WriteFile(va(pandf, srb2home, gamedatafilename), save.buffer, length); - free(save.buffer); - save.p = save.buffer = NULL; + P_SaveBufferFree(&save); } #define VERSIONSIZE 16 @@ -4376,10 +4366,9 @@ void G_SaveGameData(void) // void G_LoadGame(UINT32 slot, INT16 mapoverride) { - size_t length; char vcheck[VERSIONSIZE]; char savename[255]; - savebuffer_t save; + savebuffer_t save = {0}; // memset savedata to all 0, fixes calling perfectly valid saves corrupt because of bots memset(&savedata, 0, sizeof(savedata)); @@ -4394,17 +4383,12 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride) else sprintf(savename, savegamename, slot); - length = FIL_ReadFile(savename, &save.buffer); - if (!length) + if (P_SaveBufferFromFile(&save, savename) == false) { CONS_Printf(M_GetText("Couldn't read file %s\n"), savename); return; } - save.p = save.buffer; - save.size = length; - save.end = save.buffer + save.size; - memset(vcheck, 0, sizeof (vcheck)); sprintf(vcheck, (marathonmode ? "back-up %d" : "version %d"), VERSION); if (strcmp((const char *)save.p, (const char *)vcheck)) @@ -4417,7 +4401,7 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride) M_ClearMenus(true); // so ESC backs out to title M_StartMessage(M_GetText("Save game from different version\n\nPress ESC\n"), NULL, MM_NOTHING); Command_ExitGame_f(); - Z_Free(save.buffer); + P_SaveBufferFree(&save); // no cheating! memset(&savedata, 0, sizeof(savedata)); @@ -4452,7 +4436,7 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride) } // done - Z_Free(save.buffer); + P_SaveBufferFree(&save); // gameaction = ga_nothing; // G_SetGamestate(GS_LEVEL); @@ -4478,7 +4462,7 @@ void G_SaveGame(UINT32 slot, INT16 mapnum) boolean saved; char savename[256] = ""; const char *backup; - savebuffer_t save; + savebuffer_t save = {0}; if (marathonmode) strcpy(savename, liveeventbackup); @@ -4491,14 +4475,11 @@ void G_SaveGame(UINT32 slot, INT16 mapnum) char name[VERSIONSIZE]; size_t length; - save.size = SAVEGAMESIZE; - save.p = save.buffer = (UINT8 *)malloc(save.size); - if (!save.p) + if (P_SaveBufferAlloc(&save, SAVEGAMESIZE) == false) { CONS_Alert(CONS_ERROR, M_GetText("No more free memory for saving game data\n")); return; } - save.end = save.buffer + save.size; memset(name, 0, sizeof (name)); sprintf(name, (marathonmode ? "back-up %d" : "version %d"), VERSION); @@ -4516,7 +4497,7 @@ void G_SaveGame(UINT32 slot, INT16 mapnum) length = save.p - save.buffer; saved = FIL_WriteFile(backup, save.buffer, length); - free(save.buffer); + P_SaveBufferFree(&save); } gameaction = ga_nothing; @@ -4536,7 +4517,7 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives) char vcheck[VERSIONSIZE]; char savename[255]; const char *backup; - savebuffer_t save; + savebuffer_t save = {0}; if (marathonmode) strcpy(savename, liveeventbackup); @@ -4544,22 +4525,19 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives) sprintf(savename, savegamename, slot); backup = va("%s",savename); - length = FIL_ReadFile(savename, &save.buffer); - if (!length) + if (P_SaveBufferFromFile(&save, savename) == false) { CONS_Printf(M_GetText("Couldn't read file %s\n"), savename); return; } + length = save.size; + { char temp[sizeof(timeattackfolder)]; UINT8 *lives_p; SINT8 pllives; - save.p = save.buffer; - save.size = length; - save.end = save.buffer + save.size; - // Version check memset(vcheck, 0, sizeof (vcheck)); sprintf(vcheck, (marathonmode ? "back-up %d" : "version %d"), VERSION); @@ -4630,9 +4608,8 @@ cleanup: CONS_Printf(M_GetText("Game saved.\n")); else if (!saved) CONS_Alert(CONS_ERROR, M_GetText("Error while writing to %s for save slot %u, base: %s\n"), backup, slot, (marathonmode ? liveeventbackup : savegamename)); - Z_Free(save.buffer); - save.p = save.buffer = NULL; + P_SaveBufferFree(&save); } #undef CHECKPOS #undef BADSAVE diff --git a/src/p_saveg.c b/src/p_saveg.c index 9dba5ea7d..528a274a3 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -5389,3 +5389,92 @@ boolean P_LoadNetGame(savebuffer_t *save, boolean reloading) return P_UnArchiveLuabanksAndConsistency(save); } + +boolean P_SaveBufferZAlloc(savebuffer_t *save, size_t alloc_size, INT32 tag, void *user) +{ + I_Assert(save->buffer == NULL); + save->buffer = (UINT8 *)Z_Malloc(alloc_size, tag, user); + + if (save->buffer == NULL) + { + return false; + } + + save->size = alloc_size; + save->p = save->buffer; + save->end = save->buffer + save->size; + + return true; +} + +boolean P_SaveBufferFromExisting(savebuffer_t *save, UINT8 *existing_buffer, size_t existing_size) +{ + I_Assert(save->buffer == NULL); + + if (existing_buffer == NULL || existing_size == 0) + { + return false; + } + + save->buffer = existing_buffer; + save->size = existing_size; + + save->p = save->buffer; + save->end = save->buffer + save->size; + + return true; +} + +boolean P_SaveBufferFromLump(savebuffer_t *save, lumpnum_t lump) +{ + I_Assert(save->buffer == NULL); + + if (lump == LUMPERROR) + { + return false; + } + + save->buffer = (UINT8 *)W_CacheLumpNum(lump, PU_STATIC); + + if (save->buffer == NULL) + { + return false; + } + + save->size = W_LumpLength(lump); + + save->p = save->buffer; + save->end = save->buffer + save->size; + + return true; +} + +boolean P_SaveBufferFromFile(savebuffer_t *save, char const *name) +{ + size_t len = 0; + + I_Assert(save->buffer == NULL); + len = FIL_ReadFile(name, &save->buffer); + + if (len != 0) + { + save->size = len; + + save->p = save->buffer; + save->end = save->buffer + save->size; + } + + return len; +} + +static void P_SaveBufferInvalidate(savebuffer_t *save) +{ + save->buffer = save->p = save->end = NULL; + save->size = 0; +} + +void P_SaveBufferFree(savebuffer_t *save) +{ + Z_Free(save->buffer); + P_SaveBufferInvalidate(save); +} diff --git a/src/p_saveg.h b/src/p_saveg.h index 0da3b065d..d528aa308 100644 --- a/src/p_saveg.h +++ b/src/p_saveg.h @@ -53,6 +53,13 @@ struct savebuffer_t size_t size; }; +boolean P_SaveBufferZAlloc(savebuffer_t *save, size_t alloc_size, INT32 tag, void *user); +#define P_SaveBufferAlloc(a,b) P_SaveBufferZAlloc(a, b, PU_STATIC, NULL) +boolean P_SaveBufferFromExisting(savebuffer_t *save, UINT8 *existing_buffer, size_t existing_size); +boolean P_SaveBufferFromLump(savebuffer_t *save, lumpnum_t lump); +boolean P_SaveBufferFromFile(savebuffer_t *save, char const *name); +void P_SaveBufferFree(savebuffer_t *save); + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/p_setup.c b/src/p_setup.c index eb7917a29..a4b7ead15 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -991,20 +991,15 @@ void P_WriteThings(void) { size_t i, length; mapthing_t *mt; - savebuffer_t save; + savebuffer_t save = {0}; INT16 temp; - save.size = nummapthings * sizeof (mapthing_t); - save.p = save.buffer = (UINT8 *)malloc(nummapthings * sizeof (mapthing_t)); - - if (!save.p) + if (P_SaveBufferAlloc(&save, nummapthings * sizeof (mapthing_t)) == false) { CONS_Alert(CONS_ERROR, M_GetText("No more free memory for thing writing!\n")); return; } - save.end = save.buffer + save.size; - mt = mapthings; for (i = 0; i < nummapthings; i++, mt++) { From 76dcbec741ec682b48a238cfd1483f5686cd4803 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 3 Feb 2023 18:18:43 +0000 Subject: [PATCH 014/117] G_DoPlayDemo: Add support for replays stored inside map vres --- src/g_demo.c | 70 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 60 insertions(+), 10 deletions(-) diff --git a/src/g_demo.c b/src/g_demo.c index 688885547..27ede650e 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -2804,7 +2804,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[MAXMAPLUMPNAME],*n,*pdemoname; UINT8 version,subversion; UINT32 randseed; char msg[1024]; @@ -2856,18 +2856,68 @@ void G_DoPlayDemo(char *defdemoname) // load demo resource from WAD else { - if ((l = W_CheckNumForName(defdemoname)) == LUMPERROR) + if (n == defdemoname) { - snprintf(msg, 1024, M_GetText("Failed to read lump '%s'.\n"), defdemoname); - CONS_Alert(CONS_ERROR, "%s", msg); - gameaction = ga_nothing; - M_StartMessage(msg, NULL, MM_NOTHING); - return; - } + // Raw lump. + if ((l = W_CheckNumForName(defdemoname)) == LUMPERROR) + { + snprintf(msg, 1024, M_GetText("Failed to read lump '%s'.\n"), defdemoname); + CONS_Alert(CONS_ERROR, "%s", msg); + Z_Free(pdemoname); + gameaction = ga_nothing; + M_StartMessage(msg, NULL, MM_NOTHING); + return; + } - P_SaveBufferFromLump(&demobuf, l); + P_SaveBufferFromLump(&demobuf, l); + } + else + { + // vres GHOST_%u + virtres_t *vRes; + virtlump_t *vLump; + UINT16 mapnum; + size_t step = 0; + + step = 0; + while (defdemoname+step < n-1) + { + mapname[step] = defdemoname[step]; + step++; + } + mapname[step] = '\0'; + + mapnum = G_MapNumber(mapname); + if (mapnum >= nummapheaders || mapheaderinfo[mapnum]->lumpnum == LUMPERROR) + { + snprintf(msg, 1024, M_GetText("Failed to read lump '%s (couldn't find map %s)'.\n"), defdemoname, mapname); + CONS_Alert(CONS_ERROR, "%s", msg); + Z_Free(pdemoname); + gameaction = ga_nothing; + M_StartMessage(msg, NULL, MM_NOTHING); + return; + } + + vRes = vres_GetMap(mapheaderinfo[mapnum]->lumpnum); + vLump = vres_Find(vRes, pdemoname); + + if (vLump == NULL) + { + snprintf(msg, 1024, M_GetText("Failed to read lump '%s (couldn't find lump %s in %s)'.\n"), defdemoname, pdemoname, mapname); + CONS_Alert(CONS_ERROR, "%s", msg); + Z_Free(pdemoname); + gameaction = ga_nothing; + M_StartMessage(msg, NULL, MM_NOTHING); + return; + } + + P_SaveBufferAlloc(&demobuf, vLump->size); + memcpy(demobuf.buffer, vLump->data, vLump->size); + + vres_Free(vRes); + } #if defined(SKIPERRORS) && !defined(DEVELOP) - skiperrors = true; // SRB2Kart: Don't print warnings for staff ghosts, since they'll inevitably happen when we make bugfixes/changes... + skiperrors = true; // RR: Don't print warnings for staff ghosts, since they'll inevitably happen when we make bugfixes/changes... #endif } } From 70e39d3d58b063f080f02d917c04ca6387dcec90 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 3 Feb 2023 18:23:59 +0000 Subject: [PATCH 015/117] Title demos: Add support for game loading vRes staff ghosts as title demos Nep: I tried adding support for the old ghosts format idk if it works lmao --- src/f_finale.c | 61 +++++++++----------------------------------------- src/g_game.c | 32 ++++++++++++++++++++------ 2 files changed, 35 insertions(+), 58 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index 4deaaa375..bee9bb663 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1417,20 +1417,17 @@ void F_TitleScreenTicker(boolean run) // is it time? if (!(--demoIdleLeft)) { - //static boolean use_netreplay = false; - - char dname[9]; - lumpnum_t l; - const char *mapname; + char dname[MAXMAPLUMPNAME+1+8+1]; + UINT16 mapnum; UINT8 numstaff; + static boolean use_netreplay = false; - //@TODO uncomment this when this goes into vanilla - /*if ((use_netreplay = !use_netreplay))*/ + if ((use_netreplay = !use_netreplay)) { - numstaff = 1; - while ((l = W_CheckNumForName(va("TDEMO%03u", numstaff))) != LUMPERROR) + lumpnum_t l = LUMPERROR; + numstaff = 0; + while (numstaff < 99 && (l = W_CheckNumForName(va("TDEMO%03u", numstaff))) != LUMPERROR) numstaff++; - numstaff--; if (numstaff) { @@ -1443,54 +1440,16 @@ void F_TitleScreenTicker(boolean run) // prevent console spam if failed demoIdleLeft = demoIdleTime; - if ((l = W_CheckNumForName("MAP01S01")) == LUMPERROR) // gotta have ONE + mapnum = G_RandMap(TOL_RACE|TOL_BATTLE, -2, 2, 0, false, NULL); + if (mapnum == 0) // gotta have ONE { - F_StartIntro(); 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_CheckNumForName(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 - snprintf(dname, 9, "%sS%02u", mapname, numstaff); - - /*if ((l = W_CheckNumForName(dname)) == LUMPERROR) -- we KNOW it exists now - { - CONS_Alert(CONS_ERROR, M_GetText("Demo lump \"%s\" doesn't exist\n"), dname); - F_StartIntro(); - return; - }*/ + sprintf(dname, "%s/GHOST_%u", mapheaderinfo[mapnum]->lumpname, numstaff); loadreplay: demo.title = demo.fromtitle = true; diff --git a/src/g_game.c b/src/g_game.c index db85d734f..2d5a59ae7 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3523,6 +3523,31 @@ tryagain: || (usehellmaps != (mapheaderinfo[ix]->menuflags & LF2_HIDEINMENU))) // this is bad continue; //isokmap = false; + if (pprevmap == -2) // title demo hack + { + // vres GHOST_%u + virtres_t *vRes; + virtlump_t *vLump; + size_t step = 0; + lumpnum_t l; + + vRes = vres_GetMap(mapheaderinfo[ix+1]->lumpnum); + + for (int i = 0; i < 10; i++) + { + vLump = vres_Find(vRes, va("GHOST_%u",i)); + + if (vLump != NULL) + break; + } + + if (vLump == NULL) + { + if (((l = W_CheckNumForName(va("%sS01",G_BuildMapName(ix+1)))) == LUMPERROR)) + continue; + } + } + if (!ignorebuffer) { if (extbufsize > 0) @@ -3557,13 +3582,6 @@ tryagain: continue; } - if (pprevmap == -2) // title demo hack - { - lumpnum_t l; - if ((l = W_CheckNumForName(va("%sS01",G_BuildMapName(ix+1)))) == LUMPERROR) - continue; - } - okmaps[numokmaps++] = ix; } From f8b2bd809d3850c08aa2b8bf528336432c45af6c Mon Sep 17 00:00:00 2001 From: NepDisk Date: Fri, 7 Feb 2025 12:45:24 -0500 Subject: [PATCH 016/117] Fix legacy titledemos not loading --- src/d_main.cpp | 2 +- src/f_finale.c | 24 +++++++++++++++++++++++- src/g_game.c | 13 +++++++------ 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 84b43701a..f10221730 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1794,7 +1794,7 @@ void D_SRB2Main(void) { pstartmap = bootmap; - if (pstartmap < 1 || pstartmap > NUMMAPS) + if (pstartmap < 1 || pstartmap > nummapheaders) I_Error("Cannot warp to map %d (out of range)\n", pstartmap); else { diff --git a/src/f_finale.c b/src/f_finale.c index bee9bb663..5c8eb5514 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1440,7 +1440,7 @@ void F_TitleScreenTicker(boolean run) // prevent console spam if failed demoIdleLeft = demoIdleTime; - mapnum = G_RandMap(TOL_RACE|TOL_BATTLE, -2, 2, 0, false, NULL); + mapnum = G_RandMap(TOL_RACE, -2, 2, 0, false, NULL); if (mapnum == 0) // gotta have ONE { return; @@ -1451,6 +1451,28 @@ void F_TitleScreenTicker(boolean run) // Setup demo name sprintf(dname, "%s/GHOST_%u", mapheaderinfo[mapnum]->lumpname, numstaff); + { + // vres GHOST_%u + virtres_t *vRes; + virtlump_t *vLump; + + vRes = vres_GetMap(mapheaderinfo[mapnum]->lumpnum); + vLump = vres_Find(vRes, dname); + + if (vLump == NULL) + { + vres_Free(vRes); + + if (((W_CheckNumForName(va("%sS%02u", mapheaderinfo[mapnum]->lumpname, numstaff)))) != LUMPERROR) + sprintf(dname, "%sS%02u", mapheaderinfo[mapnum]->lumpname, numstaff); + else + { + return; + } + } + vres_Free(vRes); + } + loadreplay: demo.title = demo.fromtitle = true; demo.ignorefiles = true; diff --git a/src/g_game.c b/src/g_game.c index 2d5a59ae7..2aad1d373 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3510,7 +3510,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; @@ -3528,24 +3528,25 @@ tryagain: // vres GHOST_%u virtres_t *vRes; virtlump_t *vLump; - size_t step = 0; lumpnum_t l; vRes = vres_GetMap(mapheaderinfo[ix+1]->lumpnum); for (int i = 0; i < 10; i++) { - vLump = vres_Find(vRes, va("GHOST_%u",i)); + vLump = vres_Find(vRes, va("%s/GHOST_%u",mapheaderinfo[ix+1]->lumpname,i)); if (vLump != NULL) break; } - if (vLump == NULL) + if (vLump == NULL && ((l = W_CheckNumForName(va("%sS01",mapheaderinfo[ix+1]->lumpname))) == LUMPERROR)) { - if (((l = W_CheckNumForName(va("%sS01",G_BuildMapName(ix+1)))) == LUMPERROR)) - continue; + vres_Free(vRes); + continue; } + + vres_Free(vRes); } if (!ignorebuffer) From 747c94e774c90667599678507d319449480dcafb Mon Sep 17 00:00:00 2001 From: NepDisk Date: Fri, 7 Feb 2025 12:55:00 -0500 Subject: [PATCH 017/117] Fix double vres free in demo code --- src/f_finale.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/f_finale.c b/src/f_finale.c index 5c8eb5514..82f85aedd 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1461,12 +1461,12 @@ void F_TitleScreenTicker(boolean run) if (vLump == NULL) { - vres_Free(vRes); if (((W_CheckNumForName(va("%sS%02u", mapheaderinfo[mapnum]->lumpname, numstaff)))) != LUMPERROR) sprintf(dname, "%sS%02u", mapheaderinfo[mapnum]->lumpname, numstaff); else { + vres_Free(vRes); return; } } From 7449c15eba027ea8e846fcb8a6a99a821f4d38f8 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 29 Jan 2024 02:20:23 -0800 Subject: [PATCH 018/117] devmode DEMO: replay buffer usage displayed in real-time on the HUD - Buffer usage in megabytes, bytes and percentage - Approximate usage per second - Estimated time until buffer runs out and replay is stopped --- src/doomdef.h | 1 + src/g_demo.c | 3 ++- src/g_demo.h | 1 + src/m_cheat.c | 2 ++ src/st_stuff.c | 30 ++++++++++++++++++++++++++++++ 5 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/doomdef.h b/src/doomdef.h index a2c0bec26..5c6702db1 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -386,6 +386,7 @@ typedef enum DBG_SETUP = 0x00000400, DBG_LUA = 0x00000800, DBG_RNG = 0x00001000, + DBG_DEMO = 0x00002000, } debugFlags_t; struct debugFlagNames_s diff --git a/src/g_demo.c b/src/g_demo.c index 27ede650e..fb1d277de 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -2013,7 +2013,7 @@ void G_RecordDemo(const char *name) demobuf.p = NULL; demo.recording = true; - //demo.buffer = &demobuf; + demo.buffer = &demobuf; /* FIXME: This whole file is in a wretched state. Take a look at G_WriteAllGhostTics and G_WriteDemoTiccmd, they @@ -2925,6 +2925,7 @@ void G_DoPlayDemo(char *defdemoname) // read demo header gameaction = ga_nothing; demo.playback = true; + demo.buffer = &demobuf; if (memcmp(demobuf.p, DEMOHEADER, 12)) { snprintf(msg, 1024, M_GetText("%s is not a SRB2Kart replay file.\n"), pdemoname); diff --git a/src/g_demo.h b/src/g_demo.h index a8e2c15d2..fe85550d1 100644 --- a/src/g_demo.h +++ b/src/g_demo.h @@ -58,6 +58,7 @@ struct demovars_s { boolean freecam; + const savebuffer_t *buffer; // debug, valid only if recording or playback }; extern struct demovars_s demo; diff --git a/src/m_cheat.c b/src/m_cheat.c index 8cf65b60e..1fcadfe32 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -759,6 +759,8 @@ struct debugFlagNames_s const debug_flag_names[] = {"Lua", DBG_LUA}, {"RNG", DBG_RNG}, {"Randomizer", DBG_RNG}, // alt name + {"Demo", DBG_DEMO}, + {"Replay", DBG_DEMO}, // alt name {NULL, 0} }; diff --git a/src/st_stuff.c b/src/st_stuff.c index 8b0e5a491..28e0379cb 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -438,6 +438,31 @@ static void ST_drawRenderDebug(INT32 *height) ST_pushDebugString(height, va("Skybox Portals: %4s", sizeu1(i->skybox_portals))); } +static void ST_drawDemoDebug(INT32 *height) +{ + if (!demo.recording && !demo.playback) + return; + + size_t needle = demo.buffer->p - demo.buffer->buffer; + size_t size = demo.buffer->size; + double percent = (double)needle / size * 100.0; + double avg = (double)needle / leveltime; + + ST_pushDebugString(height, va("%s/%s bytes", sizeu1(needle), sizeu2(size))); + ST_pushDebugString(height, va( + "%.2f/%.2f MB %5.2f%%", + needle / (1024.0 * 1024.0), + size / (1024.0 * 1024.0), + percent + )); + ST_pushDebugString(height, va( + "%.2f KB/s (ETA %.2f minutes)", + avg * TICRATE / 1024.0, + (size - needle) / (avg * TICRATE * 60.0) + )); + ST_pushDebugString(height, va("Demo (%s)", demo.recording ? "recording" : "playback")); +} + static void ST_drawDebugInfo(void) { INT32 height = 192; @@ -508,6 +533,11 @@ static void ST_drawDebugInfo(void) ST_drawRenderDebug(&height); } + if (cht_debug & DBG_DEMO) + { + ST_drawDemoDebug(&height); + } + if (cht_debug & DBG_MEMORY) V_DrawRightAlignedString(320, height, V_MONOSPACE, va("Heap used: %7sKB", sizeu1(Z_TagsUsage(0, INT32_MAX)>>10))); } From 96989428b2ff75040a0087d738726bf232a47dd5 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Fri, 7 Feb 2025 14:59:39 -0500 Subject: [PATCH 019/117] Fix map switch crashes Great now its crashing over deadspace --- src/g_demo.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/g_demo.c b/src/g_demo.c index fb1d277de..4474d2ea0 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -59,6 +59,8 @@ consvar_t cv_recordmultiplayerdemos = CVAR_INIT ("netdemo_record", "Manual Save" static CV_PossibleValue_t netdemosyncquality_cons_t[] = {{1, "MIN"}, {35, "MAX"}, {0, NULL}}; consvar_t cv_netdemosyncquality = CVAR_INIT ("netdemo_syncquality", "1", CV_SAVE, netdemosyncquality_cons_t, NULL); +consvar_t cv_netdemosize = CVAR_INIT ("netdemo_size", "6", CV_SAVE, CV_Natural, NULL); + boolean nodrawers; // for comparative timing purposes boolean noblit; // for comparative timing purposes tic_t demostarttime; // for comparative timing purposes @@ -1996,20 +1998,22 @@ void G_WriteMetalTic(mobj_t *metal) // void G_RecordDemo(const char *name) { + if (demo.recording) + G_CheckDemoStatus(); + INT32 maxsize; strcpy(demoname, name); strcat(demoname, ".lmp"); - //@TODO make a maxdemosize cvar - maxsize = 1024*1024*2; - - if (M_CheckParm("-maxdemo") && M_IsNextParm()) - maxsize = atoi(M_GetNextParm()) * 1024; + maxsize = 1024 * 1024 * cv_netdemosize.value; // if (demobuf.buffer) -// P_SaveBufferFree(&demobuf); +// Z_Free(demobuf.buffer); + // FIXME: this file doesn't manage its memory and actually free this when it's done using it + Z_Free(demobuf.buffer); P_SaveBufferAlloc(&demobuf, maxsize); + Z_SetUser(demobuf.buffer, (void**)&demobuf.buffer); demobuf.p = NULL; demo.recording = true; From 2b9dd6a9e071955b474aceb8dc49d89bc9107750 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Sun, 9 Feb 2025 23:05:11 +0100 Subject: [PATCH 020/117] Make Valgrind builds usable when not running with Valgrind + cleanup --- src/z_zone.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/src/z_zone.c b/src/z_zone.c index 19bef7f17..711d87443 100644 --- a/src/z_zone.c +++ b/src/z_zone.c @@ -47,7 +47,6 @@ #ifdef HAVE_VALGRIND #include "valgrind.h" static boolean Z_calloc = false; -#include "memcheck.h" #endif #define ZONEID 0xa441d13d @@ -151,7 +150,7 @@ void Z_Free2(void *ptr, const char *file, INT32 line) if (block->user != NULL) *block->user = NULL; -#ifdef VALGRIND_DESTROY_MEMPOOL +#ifdef HAVE_VALGRIND VALGRIND_DESTROY_MEMPOOL(block); #endif block->prev->next = block->next; @@ -217,10 +216,6 @@ void *Z_Malloc2(size_t size, INT32 tag, void *user, INT32 alignbits, ptr = MEMORY(block); I_Assert((intptr_t)ptr % alignof (max_align_t) == 0); -#ifdef HAVE_VALGRIND - Z_calloc = false; -#endif - block->next = head.next; block->prev = &head; head.next = block; @@ -233,8 +228,9 @@ void *Z_Malloc2(size_t size, INT32 tag, void *user, INT32 alignbits, block->size = sizeof (memblock_t) + size; block->realsize = size; -#ifdef VALGRIND_CREATE_MEMPOOL +#ifdef HAVE_VALGRIND VALGRIND_CREATE_MEMPOOL(block, size, Z_calloc); + Z_calloc = false; #endif block->id = ZONEID; @@ -266,7 +262,7 @@ void *Z_Malloc2(size_t size, INT32 tag, void *user, INT32 alignbits, */ void *Z_Calloc2(size_t size, INT32 tag, void *user, INT32 alignbits, const char *file, INT32 line) { -#ifdef VALGRIND_MEMPOOL_ALLOC +#ifdef HAVE_VALGRIND Z_calloc = true; #endif return memset(Z_Malloc2 (size, tag, user, alignbits, file, line), 0, size); @@ -435,13 +431,12 @@ void Z_CheckHeap(INT32 i) CONS_Debug(DBG_MEMORY, "block %u owned by %s:%d\n", blocknumon, block->ownerfile, block->ownerline); #endif -#ifdef VALGRIND_MEMPOOL_EXISTS - if (!VALGRIND_MEMPOOL_EXISTS(block)) +#ifdef HAVE_VALGRIND + if (RUNNING_ON_VALGRIND && !VALGRIND_MEMPOOL_EXISTS(block)) { I_Error("Z_CheckHeap %d: block %u" "(owned by %s:%d)" " should not exist", i, blocknumon, - " should not exist", i, blocknumon, block->ownerfile, block->ownerline ); } @@ -470,9 +465,6 @@ void Z_CheckHeap(INT32 i) block->ownerfile, block->ownerline ); } -#ifdef VALGRIND_MAKE_MEM_DEFINED - VALGRIND_MAKE_MEM_DEFINED(hdr, sizeof *hdr); -#endif if (block->id != ZONEID) { I_Error("Z_CheckHeap %d: block %u" From a3e531d0d4b6d2deb9900ee649e5cae9960baf48 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Sun, 9 Feb 2025 23:12:47 +0100 Subject: [PATCH 021/117] All the save buffer fixes all at once! * Register cv_netdemosize so it actually works * Replace all the raw Z_Frees on demobuf with the appropriate function * Free demobuf in G_CheckDemoStatus (yay, no more buffer == NULL asserts) * ...allocating a buffer of uninitialized length? what --- src/d_netcmd.c | 5 +++++ src/g_demo.c | 34 +++++++++++++--------------------- src/g_demo.h | 2 +- src/g_game.c | 7 +++++++ src/p_saveg.c | 3 ++- src/p_saveg.h | 2 +- 6 files changed, 29 insertions(+), 24 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 9414a1a25..3d3b23801 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -834,6 +834,7 @@ void D_RegisterServerCommands(void) CV_RegisterVar(&cv_recordmultiplayerdemos); CV_RegisterVar(&cv_netdemosyncquality); + CV_RegisterVar(&cv_netdemosize); CV_RegisterVar(&cv_shoutname); CV_RegisterVar(&cv_shoutcolor); @@ -3108,6 +3109,10 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) demo.savemode = (cv_recordmultiplayerdemos.value == 2) ? DSM_WILLAUTOSAVE : DSM_NOTSAVING; demo.savebutton = 0; + // clear this demo before recording a new one + if (demo.recording && !modeattacking) + G_CheckDemoStatus(); + G_InitNew(pencoremode, mapnumber, resetplayer, skipprecutscene, FLS); if (demo.playback && !demo.timing) precache = true; diff --git a/src/g_demo.c b/src/g_demo.c index 4474d2ea0..287629c07 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -1998,22 +1998,13 @@ void G_WriteMetalTic(mobj_t *metal) // void G_RecordDemo(const char *name) { - if (demo.recording) - G_CheckDemoStatus(); - INT32 maxsize; strcpy(demoname, name); strcat(demoname, ".lmp"); maxsize = 1024 * 1024 * cv_netdemosize.value; -// if (demobuf.buffer) -// Z_Free(demobuf.buffer); - - // FIXME: this file doesn't manage its memory and actually free this when it's done using it - Z_Free(demobuf.buffer); P_SaveBufferAlloc(&demobuf, maxsize); - Z_SetUser(demobuf.buffer, (void**)&demobuf.buffer); demobuf.p = NULL; demo.recording = true; @@ -2936,7 +2927,7 @@ void G_DoPlayDemo(char *defdemoname) CONS_Alert(CONS_ERROR, "%s", msg); M_StartMessage(msg, NULL, MM_NOTHING); Z_Free(pdemoname); - Z_Free(demobuf.buffer); + P_SaveBufferFree(&demobuf); demo.playback = false; demo.title = false; return; @@ -2956,7 +2947,7 @@ void G_DoPlayDemo(char *defdemoname) CONS_Alert(CONS_ERROR, "%s", msg); M_StartMessage(msg, NULL, MM_NOTHING); Z_Free(pdemoname); - Z_Free(demobuf.buffer); + P_SaveBufferFree(&demobuf); demo.playback = false; demo.title = false; return; @@ -2974,7 +2965,7 @@ void G_DoPlayDemo(char *defdemoname) CONS_Alert(CONS_ERROR, "%s", msg); M_StartMessage(msg, NULL, MM_NOTHING); Z_Free(pdemoname); - Z_Free(demobuf.buffer); + P_SaveBufferFree(&demobuf); demo.playback = false; demo.title = false; return; @@ -3038,7 +3029,7 @@ void G_DoPlayDemo(char *defdemoname) if (!CON_Ready()) // In the console they'll just see the notice there! No point pulling them out. M_StartMessage(msg, NULL, MM_NOTHING); Z_Free(pdemoname); - Z_Free(demobuf.buffer); + P_SaveBufferFree(&demobuf); demo.playback = false; demo.title = false; return; @@ -3081,7 +3072,7 @@ void G_DoPlayDemo(char *defdemoname) CONS_Alert(CONS_ERROR, "%s", msg); M_StartMessage(msg, NULL, MM_NOTHING); Z_Free(pdemoname); - Z_Free(demobuf.buffer); + P_SaveBufferFree(&demobuf); demo.playback = false; demo.title = false; return; @@ -3100,7 +3091,7 @@ void G_DoPlayDemo(char *defdemoname) CONS_Alert(CONS_ERROR, "%s", msg); M_StartMessage(msg, NULL, MM_NOTHING); Z_Free(pdemoname); - Z_Free(demobuf.buffer); + P_SaveBufferFree(&demobuf); demo.playback = false; demo.title = false; return; @@ -3150,7 +3141,7 @@ void G_DoPlayDemo(char *defdemoname) CONS_Alert(CONS_ERROR, "%s", msg); M_StartMessage(msg, NULL, MM_NOTHING); Z_Free(pdemoname); - Z_Free(demobuf.buffer); + P_SaveBufferFree(&demobuf); demo.playback = false; demo.title = false; return; @@ -3166,7 +3157,7 @@ void G_DoPlayDemo(char *defdemoname) CONS_Alert(CONS_ERROR, "%s", msg); M_StartMessage(msg, NULL, MM_NOTHING); Z_Free(pdemoname); - Z_Free(demobuf.buffer); + P_SaveBufferFree(&demobuf); demo.playback = false; demo.title = false; return; @@ -3809,7 +3800,7 @@ ATTRNORETURN void FUNCNORETURN G_StopMetalRecording(boolean kill) WriteDemoChecksum(); saved = FIL_WriteFile(va("%sMS.LMP", G_BuildMapName(gamemap)), demobuf.buffer, demobuf.p - demobuf.buffer); // finally output the file. } - Z_Free(demobuf.buffer); + P_SaveBufferFree(&demobuf); metalrecording = false; if (saved) I_Error("Saved to %sMS.LMP", G_BuildMapName(gamemap)); @@ -3877,8 +3868,7 @@ static void G_StopTimingDemo(void) // called from stopdemo command, map command, and g_checkdemoStatus. void G_StopDemo(void) { - Z_Free(demobuf.buffer); - demobuf.buffer = NULL; + P_SaveBufferFree(&demobuf); demo.playback = false; if (demo.title) modeattacking = false; @@ -3944,6 +3934,8 @@ boolean G_CheckDemoStatus(void) return true; } + if (demo.recording) + P_SaveBufferFree(&demobuf); demo.recording = false; return false; } @@ -4017,7 +4009,7 @@ void G_SaveDemo(void) if (FIL_WriteFile(demoname, demobuf.buffer, demobuf.p - demobuf.buffer)) // finally output the file. demo.savemode = DSM_SAVED; - Z_Free(demobuf.buffer); + P_SaveBufferFree(&demobuf); demo.recording = false; if (!modeattacking) diff --git a/src/g_demo.h b/src/g_demo.h index fe85550d1..420809845 100644 --- a/src/g_demo.h +++ b/src/g_demo.h @@ -28,7 +28,7 @@ extern UINT8 *demo_p; // DEMO playback/recording related stuff. // ====================================== -extern consvar_t cv_recordmultiplayerdemos, cv_netdemosyncquality; +extern consvar_t cv_recordmultiplayerdemos, cv_netdemosyncquality, cv_netdemosize; extern tic_t demostarttime; diff --git a/src/g_game.c b/src/g_game.c index 2aad1d373..ed268838c 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4288,6 +4288,13 @@ void G_SaveGameData(void) if (!gamedataloaded) return; // If never loaded (-nodata), don't save + length = 4+4+4+(PWRLV_NUMTYPES*2)+1+(NUMMAPS) + + BIT_ARRAY_SIZE(MAXEMBLEMS) + + BIT_ARRAY_SIZE(MAXEXTRAEMBLEMS) + + BIT_ARRAY_SIZE(MAXUNLOCKABLES) + + BIT_ARRAY_SIZE(MAXCONDITIONSETS) + + 4+(NUMMAPS*9); + if (P_SaveBufferAlloc(&save, length) == false) { CONS_Alert(CONS_ERROR, M_GetText("No more free memory for saving game data\n")); diff --git a/src/p_saveg.c b/src/p_saveg.c index 528a274a3..859418d99 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -5449,7 +5449,7 @@ boolean P_SaveBufferFromLump(savebuffer_t *save, lumpnum_t lump) return true; } -boolean P_SaveBufferFromFile(savebuffer_t *save, char const *name) +size_t P_SaveBufferFromFile(savebuffer_t *save, char const *name) { size_t len = 0; @@ -5475,6 +5475,7 @@ static void P_SaveBufferInvalidate(savebuffer_t *save) void P_SaveBufferFree(savebuffer_t *save) { + I_Assert(save->buffer != NULL); Z_Free(save->buffer); P_SaveBufferInvalidate(save); } diff --git a/src/p_saveg.h b/src/p_saveg.h index d528aa308..a85916f69 100644 --- a/src/p_saveg.h +++ b/src/p_saveg.h @@ -57,7 +57,7 @@ boolean P_SaveBufferZAlloc(savebuffer_t *save, size_t alloc_size, INT32 tag, voi #define P_SaveBufferAlloc(a,b) P_SaveBufferZAlloc(a, b, PU_STATIC, NULL) boolean P_SaveBufferFromExisting(savebuffer_t *save, UINT8 *existing_buffer, size_t existing_size); boolean P_SaveBufferFromLump(savebuffer_t *save, lumpnum_t lump); -boolean P_SaveBufferFromFile(savebuffer_t *save, char const *name); +size_t P_SaveBufferFromFile(savebuffer_t *save, char const *name); void P_SaveBufferFree(savebuffer_t *save); #ifdef __cplusplus From 2334bde81e9a878d1418796ec83bcced6ecdbac2 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Mon, 10 Feb 2025 00:05:38 +0100 Subject: [PATCH 022/117] Revert "ACS Environment::loadModule: Free vres after generation" This reverts commit 21a431d341a1f8aabd2aabfc9a2791228554891a. --- src/acs/environment.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/acs/environment.cpp b/src/acs/environment.cpp index 51db58f10..b49323938 100644 --- a/src/acs/environment.cpp +++ b/src/acs/environment.cpp @@ -300,8 +300,6 @@ void Environment::loadModule(ACSVM::Module *module) { CONS_Debug(DBG_SETUP, "No BEHAVIOR lump found.\n"); } - - vres_Free(vRes); } else { From 51afed8b76b5a2799637a6283bf4f3585c2eefa9 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Mon, 10 Feb 2025 00:42:54 +0100 Subject: [PATCH 023/117] Fix map thumbnails in replay hut --- src/m_menu.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 5d6bf1d40..c68ae8ebb 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -5563,7 +5563,6 @@ static void M_HandleReplayHutList(INT32 choice) #define SCALEDVIEWHEIGHT (vid.height/vid.dupy) static void DrawReplayHutReplayInfo(void) { - lumpnum_t lumpnum; patch_t *patch; UINT8 *colormap; INT32 x, y, w, h; @@ -5588,15 +5587,11 @@ static void DrawReplayHutReplayInfo(void) // Draw level stuff x = 15; y = 15; - // A 160x100 image of the level as entry MAPxxP + // A 160x100 image of the level //CONS_Printf("%d %s\n", demolist[dir_on[menudepthleft]].map, G_BuildMapName(demolist[dir_on[menudepthleft]].map)); - char *mapname = va("%sP", G_BuildMapName(cv_nextmap.value+1)); - SINT8 length = strlen(mapname); - lumpnum = W_CheckNumForName(mapname); - if (lumpnum != LUMPERROR && (length < 7)) - patch = W_CachePatchNum(lumpnum, PU_CACHE); - else - patch = W_CachePatchName("M_NOLVL", PU_CACHE); + patch = mapheaderinfo[demolist[dir_on[menudepthleft]].map-1] + ? mapheaderinfo[demolist[dir_on[menudepthleft]].map-1]->thumbnailPic + : W_CachePatchName("M_NOLVL", PU_CACHE); if (!(demolist[dir_on[menudepthleft]].kartspeed & DF_ENCORE)) V_DrawSmallScaledPatch(x, y, V_SNAPTOTOP, patch); From 1ea4f89817523e07811d1674e277d892e8af8732 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Thu, 6 Feb 2025 00:32:25 +0100 Subject: [PATCH 024/117] SHUUUUUUUUUUUUT UUUUUUUUUUUUUUPPPPP --- src/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 347f78ffe..83b175305 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -248,7 +248,6 @@ target_compile_options(SRB2SDL2 PRIVATE -Wmissing-declarations -Wmissing-noreturn -Wnested-externs - -Winline -Wformat-y2k -Wformat-security From 3444d3a6a286d7ad634ec7673fec84cd9acd09ab Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Thu, 6 Feb 2025 00:35:39 +0100 Subject: [PATCH 025/117] Thank you --- src/w_wad.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/w_wad.c b/src/w_wad.c index 75861c6f6..dc8927d96 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -289,7 +289,7 @@ static inline void W_LoadDehackedLumps(UINT16 wadnum, boolean mainfile) #endif } -static inline boolean CheckCompatFilename(char *filename) +static inline boolean CheckCompatFilename(const char *filename) { // check for a K prefix char *basename = strrchr(filename, *PATHSEP); @@ -322,6 +322,7 @@ static inline boolean CheckCompatSkins(UINT16 wadnum) // so we need compatmode to load skins from this file! return (maxframe - 'A') >= 18; #else + (void)wadnum; return false; #endif } @@ -1063,7 +1064,7 @@ const char *W_CheckNameForNum(lumpnum_t lumpnum) return W_CheckNameForNumPwad(WADFILENUM(lumpnum),LUMPNUM(lumpnum)); } -const char *W_CheckFullNameForNumPwad(UINT16 wad, UINT16 lump) +static const char *W_CheckFullNameForNumPwad(UINT16 wad, UINT16 lump) { if (lump >= wadfiles[wad]->numlumps || !TestValidLump(wad, 0)) return NULL; @@ -1071,7 +1072,7 @@ const char *W_CheckFullNameForNumPwad(UINT16 wad, UINT16 lump) return wadfiles[wad]->lumpinfo[lump].fullname; } -const char *W_CheckFullNameForNum(lumpnum_t lumpnum) +static const char *W_CheckFullNameForNum(lumpnum_t lumpnum) { return W_CheckFullNameForNumPwad(WADFILENUM(lumpnum),LUMPNUM(lumpnum)); } From 82b17eb7b990a0a151391c6f91f89dcffe3e0ed7 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Thu, 6 Feb 2025 02:52:43 +0100 Subject: [PATCH 026/117] Fix crumbling FOF in Ancient Tomb (and missing flags for pushables) What a fucking ride... I spent an hour stepping through T_StartCrumble and P_CheckSector and whatnot only to realize the gargoyle isn't supposed to have MF_PUSHABLE because it has the ambush flag set --- src/p_mobj.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/p_mobj.c b/src/p_mobj.c index bf49f56a3..736b29238 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -12049,6 +12049,25 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean if (mthing->args[1]) // No egg trap for this boss mobj->flags2 |= MF2_BOSSNOTRAP; } + if (mobj->flags & MF_PUSHABLE) + { + switch (mthing->args[0]) + { + case TMP_NORMAL: + default: + break; + case TMP_SLIDE: + mobj->flags2 |= MF2_SLIDEPUSH; + mobj->flags |= MF_BOUNCE; + break; + case TMP_IMMOVABLE: + mobj->flags &= ~MF_PUSHABLE; + break; + case TMP_CLASSIC: + mobj->flags2 |= MF2_CLASSICPUSH; + break; + } + } return true; } From 0cf80a7277de471b86d490ca0b01a36ff97ca800 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Thu, 6 Feb 2025 20:15:04 +0100 Subject: [PATCH 027/117] Set jump strength for big pumas --- src/p_setup.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/p_setup.c b/src/p_setup.c index a4b7ead15..4ba419535 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -6858,6 +6858,7 @@ static void P_ConvertBinaryThingTypes(void) { case 102: //SDURF case 1805: //Puma + case 2400: // Big Puma mapthings[i].args[0] = mapthings[i].angle; break; case 110: //THZ Turret From bf0b3dfddf98df369f532acd3895248d750ae833 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sat, 8 Feb 2025 12:38:58 -0500 Subject: [PATCH 028/117] Add SSF flags for kart specials, use SSF for compat, implement way to set offroad and tripwire without terrain --- extras/ACS/BlanKart_ACS.cfg | 6 + extras/ACS/lib/inc/ACS/bkdefs.acs | 11 +- extras/blanudmf/Includes/BlanKart_misc.cfg | 42 ++- src/deh_tables.c | 10 +- src/p_mobj.c | 14 +- src/p_setup.c | 71 ++++- src/p_spec.c | 314 ++++++++++----------- src/r_defs.h | 27 +- 8 files changed, 288 insertions(+), 207 deletions(-) diff --git a/extras/ACS/BlanKart_ACS.cfg b/extras/ACS/BlanKart_ACS.cfg index 743c12dbe..f72216b83 100644 --- a/extras/ACS/BlanKart_ACS.cfg +++ b/extras/ACS/BlanKart_ACS.cfg @@ -1362,10 +1362,16 @@ constants SSF_NOSTEPDOWN; SSF_WINDCURRENT; SSF_CONVEYOR; + SSF_SPEEDPAD; SSF_STARPOSTACTIVATOR; SSF_EXIT; SSF_DELETEITEMS; + SSF_SNEAKERPANEL; + SSF_WATERPANEL; + SSF_REDPOGOSPRING; + SSF_YELLOWPOGOSPRING; SSF_FAN; + SSF_FINISHLINE; SSF_ZOOMTUBESTART; SSF_ZOOMTUBEEND; diff --git a/extras/ACS/lib/inc/ACS/bkdefs.acs b/extras/ACS/lib/inc/ACS/bkdefs.acs index 5edaef7b6..e61e25bbf 100644 --- a/extras/ACS/lib/inc/ACS/bkdefs.acs +++ b/extras/ACS/lib/inc/ACS/bkdefs.acs @@ -364,13 +364,16 @@ enum SSF_NOSTEPDOWN = 1<<2, SSF_WINDCURRENT = 1<<3, SSF_CONVEYOR = 1<<4, - + SSF_SPEEDPAD = 1<<5, SSF_STARPOSTACTIVATOR = 1<<6, SSF_EXIT = 1<<7, SSF_DELETEITEMS = 1<<8, - - SSF_FAN = 1<<12, - + SSF_SNEAKERPANEL = 1<<9, + SSF_WATERPANEL = 1<<10, + SSF_REDPOGOSPRING = 1<<11, + SSF_YELLOWPOGOSPRING = 1<<12, + SSF_FAN = 1<<13, + SSF_FINISHLINE = 1<14, SSF_ZOOMTUBESTART = 1<<15, SSF_ZOOMTUBEEND = 1<<16, }; diff --git a/extras/blanudmf/Includes/BlanKart_misc.cfg b/extras/blanudmf/Includes/BlanKart_misc.cfg index 76e2fc6e5..6d8c76add 100644 --- a/extras/blanudmf/Includes/BlanKart_misc.cfg +++ b/extras/blanudmf/Includes/BlanKart_misc.cfg @@ -63,31 +63,29 @@ sectorflags invertprecip = "Invert Precipitation"; gravityflip = "Flip Objects in Reverse Gravity"; heatwave = "Heat Wave"; - noclipcamera = "Intangible to the Camera"; colormapfog = "Fog Planes"; colormapfadesprites = "Fade Fullbright"; colormapprotected = "Protected from Tagging"; - outerspace = "Space Countdown"; - doublestepup = "Ramp Sector (double step-up/down)"; + nostepup = "Wall Sector (No step-up)"; + doublestepup = "Ramp Sector (Double step-up/down)"; nostepdown = "Non-Ramp Sector (No step-down)"; - speedpad = "Speed Pad"; starpostactivator = "Star Post Activator"; exit = "Exit"; - specialstagepit = "Special Stage Pit"; - returnflag = "Return Flag"; - redteambase = "Red Team Base"; - blueteambase = "Blue Team Base"; fan = "Fan Sector"; - supertransform = "Super Sonic Transform"; - forcespin = "Force Spin"; zoomtubestart = "Zoom Tube Start"; zoomtubeend = "Zoom Tube End"; - finishline = "Circuit Finish Line"; - ropehang = "Rope Hang"; jumpflip = "Flip Gravity on Jump"; gravityoverride = "Make Reverse Gravity Temporary"; ripple_floor = "Ripple Floor"; ripple_ceiling = "Ripple Ceiling"; + + // BlanKart SSF flags + speedpad = "Speed Pad"; + finishline = "Legacy Finish Line (Use line instead)"; + sneakerpanel = "Sneaker Panel"; + waterpanel = "Water Run Panel"; + redpogospring = "Spring Panel"; + yellowpogospring = "Capped Spring Panel"; // RR ACS executor flags repeatspecial = "Each Time (?) (ACS)"; @@ -108,31 +106,29 @@ sectorflagscategories invertprecip = "regular"; gravityflip = "regular"; heatwave = "regular"; - noclipcamera = "regular"; colormapfog = "colormap"; colormapfadesprites = "colormap"; colormapprotected = "colormap"; - outerspace = "special"; + nostepup = "special"; doublestepup = "special"; nostepdown = "special"; - speedpad = "special"; starpostactivator = "special"; exit = "special"; - specialstagepit = "special"; - returnflag = "special"; - redteambase = "special"; - blueteambase = "special"; fan = "special"; - supertransform = "special"; - forcespin = "special"; zoomtubestart = "special"; zoomtubeend = "special"; - finishline = "special"; - ropehang = "special"; jumpflip = "special"; gravityoverride = "special"; ripple_floor = "regular"; ripple_ceiling = "regular"; + + // BlanKart SSF flags + speedpad = "special"; + finishline = "special"; + sneakerpanel = "special"; + waterpanel = "special"; + redpogospring = "special"; + yellowpogospring = "special"; // RR ACS executor flags repeatspecial = "trigger"; diff --git a/src/deh_tables.c b/src/deh_tables.c index 0a9fcb919..4a5ff0a66 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -389,15 +389,15 @@ const char *const SSF_LIST[] = { "NOSTEPDOWN", "WINDCURRENT", "CONVEYOR", - "\x01", // free (name un-matchable) + "SPEEDPAD", "STARPOSTACTIVATOR", "EXIT", "DELETEITEMS", - "\x01", // free (name un-matchable) - "\x01", // free (name un-matchable) - "\x01", // free (name un-matchable) + "SNEAKERPANEL" , + "REDPOGOSPRING", + "YELLOWPOGOSPRING" , "FAN", - "\x01", // free (name un-matchable) + "FINISHLINE", "\x01", // free (name un-matchable) "ZOOMTUBESTART", "ZOOMTUBEEND", diff --git a/src/p_mobj.c b/src/p_mobj.c index 736b29238..566600230 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6819,6 +6819,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) case MT_ORBINAUT: { boolean grounded = P_IsObjectOnGround(mobj); + sector_t *sec2; if (mobj->flags2 & MF2_AMBUSH) { @@ -6875,7 +6876,10 @@ static boolean P_MobjRegularThink(mobj_t *mobj) P_Thrust(mobj, mobj->angle, thrustamount); - if (P_MobjTouchingSectorSpecial(mobj, 3, 1)) + sec2 = P_ThingOnSpecial3DFloor(mobj); + if ((mobj->terrain && mobj->terrain->pogoSpring > 0) || (sec2 && (sec2->specialflags & (SSF_YELLOWPOGOSPRING|SSF_REDPOGOSPRING))) + || (P_IsObjectOnRealGround(mobj, mobj->subsector->sector) + && (mobj->subsector->sector->specialflags & (SSF_YELLOWPOGOSPRING|SSF_REDPOGOSPRING)))) K_DoPogoSpring(mobj, 0, 1); if (mobj->threshold > 0) @@ -6939,9 +6943,9 @@ static boolean P_MobjRegularThink(mobj_t *mobj) K_DriftDustHandling(mobj); sec2 = P_ThingOnSpecial3DFloor(mobj); - if ((sec2 && GETSECSPECIAL(sec2->special, 3) == 1) + if ((mobj->terrain && mobj->terrain->pogoSpring > 0) || (sec2 && (sec2->specialflags & (SSF_YELLOWPOGOSPRING|SSF_REDPOGOSPRING))) || (P_IsObjectOnRealGround(mobj, mobj->subsector->sector) - && GETSECSPECIAL(mobj->subsector->sector->special, 3) == 1)) + && (mobj->subsector->sector->specialflags & (SSF_YELLOWPOGOSPRING|SSF_REDPOGOSPRING)))) K_DoPogoSpring(mobj, 0, 1); break; @@ -6968,9 +6972,9 @@ static boolean P_MobjRegularThink(mobj_t *mobj) if (grounded) { sector_t *sec2 = P_ThingOnSpecial3DFloor(mobj); - if ((sec2 && GETSECSPECIAL(sec2->special, 3) == 1) + if ((mobj->terrain && mobj->terrain->pogoSpring > 0) || (sec2 && (sec2->specialflags & (SSF_YELLOWPOGOSPRING|SSF_REDPOGOSPRING))) || (P_IsObjectOnRealGround(mobj, mobj->subsector->sector) - && GETSECSPECIAL(mobj->subsector->sector->special, 3) == 1)) + && (mobj->subsector->sector->specialflags & (SSF_YELLOWPOGOSPRING|SSF_REDPOGOSPRING)))) K_DoPogoSpring(mobj, 0, 1); } diff --git a/src/p_setup.c b/src/p_setup.c index 4ba419535..8e406d5be 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -1411,6 +1411,7 @@ static void P_LoadSidedefs(UINT8 *data) break; } + case 4: // Speed pad parameters case 414: // Play SFX { sd->toptexture = sd->midtexture = sd->bottomtexture = 0; @@ -1902,18 +1903,30 @@ static void ParseTextmapSectorParameter(UINT32 i, const char *param, const char sectors[i].specialflags |= SSF_DOUBLESTEPUP; else if (fastcmp(param, "nostepdown") && fastcmp("true", val)) sectors[i].specialflags |= SSF_NOSTEPDOWN; + else if (fastcmp(param, "speedpad") && fastcmp("true", val)) + sectors[i].specialflags |= SSF_SPEEDPAD; else if ((fastcmp(param, "cheatcheckactivator") || fastcmp(param, "starpostactivator")) && fastcmp("true", val)) sectors[i].specialflags |= SSF_STARPOSTACTIVATOR; else if (fastcmp(param, "exit") && fastcmp("true", val)) sectors[i].specialflags |= SSF_EXIT; else if (fastcmp(param, "deleteitems") && fastcmp("true", val)) sectors[i].specialflags |= SSF_DELETEITEMS; + else if (fastcmp(param, "sneakerpanel") && fastcmp("true", val)) + sectors[i].specialflags |= SSF_SNEAKERPANEL; + else if (fastcmp(param, "waterpanel") && fastcmp("true", val)) + sectors[i].specialflags |= SSF_WATERPANEL; + else if (fastcmp(param, "redpogospring") && fastcmp("true", val)) + sectors[i].specialflags |= SSF_REDPOGOSPRING; + else if (fastcmp(param, "yellowpogospring") && fastcmp("true", val)) + sectors[i].specialflags |= SSF_YELLOWPOGOSPRING; else if (fastcmp(param, "fan") && fastcmp("true", val)) sectors[i].specialflags |= SSF_FAN; else if (fastcmp(param, "zoomtubestart") && fastcmp("true", val)) sectors[i].specialflags |= SSF_ZOOMTUBESTART; else if (fastcmp(param, "zoomtubeend") && fastcmp("true", val)) sectors[i].specialflags |= SSF_ZOOMTUBEEND; + else if (fastcmp(param, "finishline") && fastcmp("true", val)) + sectors[i].specialflags |= SSF_FINISHLINE; else if (fastcmp(param, "friction")) sectors[i].friction = FLOAT_TO_FIXED(atof(val)); else if (fastcmp(param, "gravity")) @@ -1929,6 +1942,17 @@ static void ParseTextmapSectorParameter(UINT32 i, const char *param, const char if (fastcmp(val, "Instakill")) sectors[i].damagetype = SD_INSTAKILL; } + else if (fastcmp(param, "offroad")) + { + if (fastcmp(val, "Weak")) + sectors[i].offroad = FRACUNIT; + else if (fastcmp(val, "Normal")) + sectors[i].offroad = 2*FRACUNIT; + else if (fastcmp(val, "Strong")) + sectors[i].offroad = 3*FRACUNIT; + else + sectors[i].offroad = FLOAT_TO_FIXED(atof(val)); + } else if (fastcmp(param, "triggertag")) sectors[i].triggertag = atol(val); else if (fastcmp(param, "triggerer")) @@ -2054,6 +2078,8 @@ static void ParseTextmapLinedefParameter(UINT32 i, const char *param, const char } else if (fastcmp(param, "executordelay")) lines[i].executordelay = atol(val); + else if (fastcmp(param, "tripwire") && fastcmp("true", val)) // who needs terraindefs amiright :^) + lines[i].tripwire = true; // Flags else if (fastcmp(param, "blocking") && fastcmp("true", val)) @@ -3025,22 +3051,45 @@ static void P_WriteTextmap(void) fprintf(f, "doublestepup = true;\n"); if (wsectors[i].specialflags & SSF_NOSTEPDOWN) fprintf(f, "nostepdown = true;\n"); + if (wsectors[i].specialflags & SSF_SPEEDPAD) + fprintf(f, "speedpad = true;\n"); if (wsectors[i].specialflags & SSF_STARPOSTACTIVATOR) fprintf(f, "starpostactivator = true;\n"); if (wsectors[i].specialflags & SSF_EXIT) fprintf(f, "exit = true;\n"); if (wsectors[i].specialflags & SSF_DELETEITEMS) fprintf(f, "deleteitems = true;\n"); + if (wsectors[i].specialflags & SSF_SNEAKERPANEL) + fprintf(f, "sneakerpanel = true;\n"); + if (wsectors[i].specialflags & SSF_WATERPANEL) + fprintf(f, "waterpanel = true;\n"); + if (wsectors[i].specialflags & SSF_REDPOGOSPRING) + fprintf(f, "redpogospring = true;\n"); + if (wsectors[i].specialflags & SSF_YELLOWPOGOSPRING) + fprintf(f, "yellowpogospring = true;\n"); if (wsectors[i].specialflags & SSF_FAN) fprintf(f, "fan = true;\n"); if (wsectors[i].specialflags & SSF_ZOOMTUBESTART) fprintf(f, "zoomtubestart = true;\n"); if (wsectors[i].specialflags & SSF_ZOOMTUBEEND) fprintf(f, "zoomtubeend = true;\n"); + if (wsectors[i].specialflags & SSF_FINISHLINE) + fprintf(f, "finishline = true;\n"); if (wsectors[i].friction != ORIG_FRICTION) fprintf(f, "friction = %f;\n", FIXED_TO_FLOAT(wsectors[i].friction)); if (wsectors[i].gravity != FRACUNIT) fprintf(f, "gravity = %f;\n", FIXED_TO_FLOAT(wsectors[i].gravity)); + if (wsectors[i].offroad != 0) + { + if (wsectors[i].offroad == FRACUNIT) + fprintf(f, "offroad = Weak;\n"); + else if (wsectors[i].offroad == 2*FRACUNIT) + fprintf(f, "offroad = Normal;\n"); + else if (wsectors[i].offroad == 3*FRACUNIT) + fprintf(f, "offroad = Strong;\n"); + else + fprintf(f, "gravity = %f;\n", FIXED_TO_FLOAT(wsectors[i].offroad)); + } if (wsectors[i].damagetype != SD_NONE) { switch (wsectors[i].damagetype) @@ -3423,7 +3472,7 @@ static boolean P_CheckLineSideTripWire(line_t *ld, int p) sda = &sides[n]; terrain = K_GetTerrainForTextureNum(sda->midtexture); - tripwire = terrain && (terrain->flags & TRF_TRIPWIRE); + tripwire = (terrain && (terrain->flags & TRF_TRIPWIRE)) || (ld->tripwire == true); if (tripwire) { @@ -4859,7 +4908,11 @@ static void P_ConvertBinaryLinedefTypes(void) lines[i].args[2] = !!(lines[i].flags & ML_MIDSOLID); break; case 4: //Speed pad parameters - //CONS_Alert(CONS_WARNING, "Speed Pad linedef is deprecated. Use the TERRAIN effect!\n"); + lines[i].args[0] = P_AproxDistance(lines[i].v2->x-lines[i].v1->x, lines[i].v2->y-lines[i].v1->y) >> FRACBITS; + if (lines[i].flags & ML_MIDSOLID) + lines[i].args[1] |= TMSP_NOTELEPORT; + if (lines[i].flags & ML_WRAPMIDTEX) + lines[i].args[1] |= TMSP_FORCESPIN; break; case 7: //Sector flat alignment lines[i].args[0] = tag; @@ -6757,10 +6810,14 @@ static void P_ConvertBinarySectorTypes(void) switch(GETSECSPECIAL(sectors[i].special, 3)) { - case 1: //Trick panel + case 1: //Spring Panel + sectors[i].specialflags |= SSF_REDPOGOSPRING; + break; case 3: + sectors[i].specialflags |= SSF_YELLOWPOGOSPRING; break; case 5: //Speed pad + sectors[i].specialflags |= SSF_SPEEDPAD; break; default: break; @@ -6778,9 +6835,10 @@ static void P_ConvertBinarySectorTypes(void) sectors[i].specialflags |= SSF_FAN; break; case 6: //Sneaker panel + sectors[i].specialflags |= SSF_SNEAKERPANEL; break; - case 7: //Destroy items - sectors[i].specialflags |= SSF_DELETEITEMS; + case 7: // Oil Slik + sectors[i].damagetype = SD_GENERIC; break; case 8: //Zoom tube start sectors[i].specialflags |= SSF_ZOOMTUBESTART; @@ -6788,6 +6846,9 @@ static void P_ConvertBinarySectorTypes(void) case 9: //Zoom tube end sectors[i].specialflags |= SSF_ZOOMTUBEEND; break; + case 10: // Circuit Finish Line + sectors[i].specialflags |= SSF_FINISHLINE; + break; default: break; } diff --git a/src/p_spec.c b/src/p_spec.c index 823da9689..6e76b6add 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -4916,6 +4916,140 @@ static void P_ProcessEggCapsule(player_t *player, sector_t *sector) } } +static void P_ProcessSpeedPad(player_t *player, sector_t *sector, sector_t *roversector, mtag_t sectag) +{ + INT32 lineindex = -1; + angle_t lineangle; + fixed_t linespeed; + fixed_t sfxnum; + size_t i; + + if (player->dashpadcooldown != 0) + return; + + // Try for lines facing the sector itself, with tag 0. + for (i = 0; i < sector->linecount; i++) + { + line_t *li = sector->lines[i]; + + if (li->frontsector != sector) + continue; + + if (li->special != 4) + continue; + + if (!Tag_Find(&li->tags, 0)) + continue; + + lineindex = li - lines; + break; + } + + // Nothing found? Look via tag. + if (lineindex == -1) + lineindex = Tag_FindLineSpecial(4, sectag); + + if (lineindex == -1) + { + CONS_Debug(DBG_GAMELOGIC, "ERROR: Speed pad missing line special #4.\n"); + return; + } + + lineangle = R_PointToAngle2(lines[lineindex].v1->x, lines[lineindex].v1->y, lines[lineindex].v2->x, lines[lineindex].v2->y); + linespeed = lines[lineindex].args[0] << FRACBITS; + + if (linespeed == 0) + { + CONS_Debug(DBG_GAMELOGIC, "ERROR: Speed pad (tag %d) at zero speed.\n", sectag); + return; + } + + player->mo->angle = player->drawangle = lineangle; + + // SRB2Kart: Scale the speed you get from them! + // This is scaled differently from other horizontal speed boosts from stuff like springs, because of how this is used for some ramp jumps. + if (player->mo->scale > mapobjectscale) + linespeed = FixedMul(linespeed, mapobjectscale + (player->mo->scale - mapobjectscale)); + + if (!demo.playback) + P_SetPlayerAngle(player, player->mo->angle); + + if (!(lines[lineindex].args[1] & TMSP_NOTELEPORT)) + { + P_UnsetThingPosition(player->mo); + if (roversector) // make FOF speed pads work + { + player->mo->x = roversector->soundorg.x; + player->mo->y = roversector->soundorg.y; + } + else + { + player->mo->x = sector->soundorg.x; + player->mo->y = sector->soundorg.y; + } + P_SetThingPosition(player->mo); + } + + P_InstaThrust(player->mo, player->mo->angle, linespeed); + + player->dashpadcooldown = TICRATE/3; + player->drift = 0; + player->driftcharge = 0; + player->pogospring = 0; + + sfxnum = lines[lineindex].stringargs[0] ? get_number(lines[lineindex].stringargs[0]) : sfx_spdpad; + + if (!sfxnum) + sfxnum = sfx_spdpad; + + S_StartSound(player->mo, sfxnum); + { + sfxenum_t pick = P_RandomKey(2); // Gotta roll the RNG every time this is called for sync reasons + if (cv_kartvoices.value) + S_StartSound(player->mo, sfx_kbost1+pick); + //K_TauntVoiceTimers(player); + } +} + +static void P_ProcessPogoSpring(player_t *player, boolean isTouching, boolean type) +{ + const fixed_t hscale = mapobjectscale + (mapobjectscale - player->mo->scale); + const fixed_t minspeed = 24*hscale; + const fixed_t maxspeed = 28*hscale; + angle_t pushangle = FixedHypot(player->mo->momx, player->mo->momy) ? R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy) : player->mo->angle; + + if (!isTouching) + return; + + if ((player->speed > maxspeed) && type == 2) // Prevent overshooting jumps + P_InstaThrust(player->mo, pushangle, maxspeed); + else if (player->speed < minspeed) // Push forward to prevent getting stuck + P_InstaThrust(player->mo, pushangle, minspeed); + + if (type == 2) + player->pogospring = 2; + else + player->pogospring = 1; + + K_DoPogoSpring(player->mo, 0, 1); +} + +static void P_ProcessBoostPanel(player_t *player, boolean isTouching, boolean type) +{ + if (isTouching) + { + if (!player->floorboost) + player->floorboost = 3; + else + player->floorboost = 2; + + if (type == SBPT_WATER) + K_DoWaterRunPanel(player); + else + K_DoSneaker(player, 0); + } +} + static void P_ProcessExitSector(player_t *player, mtag_t sectag) { INT32 lineindex; @@ -5032,6 +5166,8 @@ static boolean P_SectorHasSpecial(sector_t *sec) return false; } + + static void P_EvaluateSpecialFlags(player_t *player, sector_t *sector, sector_t *roversector, boolean isTouching) { mtag_t sectag = Tag_FGet(§or->tags); @@ -5043,6 +5179,8 @@ static void P_EvaluateSpecialFlags(player_t *player, sector_t *sector, sector_t player->onconveyor = 2; if (sector->specialflags & SSF_CONVEYOR) player->onconveyor = 4; + if ((sector->specialflags & SSF_SPEEDPAD) && isTouching) + P_ProcessSpeedPad(player, sector, roversector, sectag); if (sector->specialflags & SSF_STARPOSTACTIVATOR) { mobj_t *post = P_GetObjectTypeInSectorNum(MT_STARPOST, sector - sectors); @@ -5064,10 +5202,26 @@ static void P_EvaluateSpecialFlags(player_t *player, sector_t *sector, sector_t P_SetPlayerMobjState(player->mo, S_PLAY_FALL); */ } + if (sector->specialflags & SSF_SNEAKERPANEL) + P_ProcessBoostPanel(player, isTouching, SBPT_SNEAKER); + if (sector->specialflags & SSF_WATERPANEL) + P_ProcessBoostPanel(player, isTouching, SBPT_WATER); + if (sector->specialflags & SSF_REDPOGOSPRING) + P_ProcessPogoSpring(player, isTouching, SSPT_RED); + if (sector->specialflags & SSF_YELLOWPOGOSPRING) + P_ProcessPogoSpring(player, isTouching, SSPT_YELLOW); if (sector->specialflags & SSF_ZOOMTUBESTART) P_ProcessZoomTube(player, sectag, false); if (sector->specialflags & SSF_ZOOMTUBEEND) P_ProcessZoomTube(player, sectag, true); + if (sector->specialflags & SSF_FINISHLINE) + { + if ((gametyperules & GTR_CIRCUIT) && (player->exiting == 0) && !(player->pflags & PF_HITFINISHLINE)) + { + K_HandleLapIncrement(player); + player->pflags |= PF_HITFINISHLINE; + } + } } static void P_EvaluateDamageType(player_t *player, sector_t *sector, boolean isTouching) @@ -5131,134 +5285,9 @@ static void P_EvaluateOldSectorSpecial(player_t *player, sector_t *sector, secto break; } - switch (GETSECSPECIAL(sector->special, 3)) - { - case 1: // SRB2kart: Spring Panel - { - if (roversector || isTouching) - { - const fixed_t hscale = mapobjectscale + (mapobjectscale - player->mo->scale); - const fixed_t minspeed = 24*hscale; - angle_t pushangle = FixedHypot(player->mo->momx, player->mo->momy) ? R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy) : player->mo->angle; - // if we have no speed for SOME REASON, use the player's angle, otherwise we'd be forcefully thrusted to what I can only assume is angle 0 - - if (player->mo->eflags & MFE_SPRUNG) - break; - - if (player->speed < minspeed) // Push forward to prevent getting stuck - P_InstaThrust(player->mo, pushangle, minspeed); - - player->pogospring = 1; - K_DoPogoSpring(player->mo, 0, 1); - } - break; - } - case 3: // SRB2kart: Spring Panel (capped speed) - { - if (roversector || isTouching) - { - const fixed_t hscale = mapobjectscale + (mapobjectscale - player->mo->scale); - const fixed_t minspeed = 24*hscale; - const fixed_t maxspeed = 28*hscale; - angle_t pushangle = FixedHypot(player->mo->momx, player->mo->momy) ? R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy) : player->mo->angle; - // if we have no speed for SOME REASON, use the player's angle, otherwise we'd be forcefully thrusted to what I can only assume is angle 0 - - if (player->mo->eflags & MFE_SPRUNG) - break; - - if (player->speed > maxspeed) // Prevent overshooting jumps - P_InstaThrust(player->mo, pushangle, maxspeed); - else if (player->speed < minspeed) // Push forward to prevent getting stuck - P_InstaThrust(player->mo, pushangle, minspeed); - - player->pogospring = 2; - K_DoPogoSpring(player->mo, 0, 1); - } - break; - } - case 5: // Speed pad w/o spin - case 6: // Speed pad w/ spin - { - int i; - if (player->dashpadcooldown != 0) - break; - - - i = P_FindSpecialLineFromTag(4, Tag_FGet(§or->tags), -1); - - if ((i != -1) && (roversector || isTouching)) - { - angle_t lineangle; - fixed_t linespeed; - - lineangle = R_PointToAngle2(lines[i].v1->x, lines[i].v1->y, lines[i].v2->x, lines[i].v2->y); - linespeed = P_AproxDistance(lines[i].v2->x-lines[i].v1->x, lines[i].v2->y-lines[i].v1->y); - - player->mo->angle = lineangle; - player->angleturn = player->mo->angle; - - // SRB2Kart: Scale the speed you get from them! - // This is scaled differently from other horizontal speed boosts from stuff like springs, because of how this is used for some ramp jumps. - if (player->mo->scale > mapobjectscale) - linespeed = FixedMul(linespeed, mapobjectscale + (player->mo->scale - mapobjectscale)); - - if (!demo.playback) - { - for (SINT8 j = 0; j <= r_splitscreen; j++) - { - if (player == &players[displayplayers[j]]) - { - localangle[j] = player->mo->angle; - break; - } - } - } - - if (!(lines[i].flags & 512)) - { - P_UnsetThingPosition(player->mo); - if (roversector) // make FOF speed pads work - { - player->mo->x = roversector->soundorg.x; - player->mo->y = roversector->soundorg.y; - } - else - { - player->mo->x = sector->soundorg.x; - player->mo->y = sector->soundorg.y; - } - P_SetThingPosition(player->mo); - } - - P_InstaThrust(player->mo, player->mo->angle, linespeed); - - player->dashpadcooldown = TICRATE/3; - player->drift = 0; - player->driftcharge = 0; - player->pogospring = 0; - S_StartSound(player->mo, sfx_spdpad); - { - sfxenum_t pick = P_RandomKey(2); // Gotta roll the RNG every time this is called for sync reasons - if (cv_kartvoices.value) - S_StartSound(player->mo, sfx_kbost1+pick); - //K_TauntVoiceTimers(player); - } - } - break; - } - } - switch (GETSECSPECIAL(sector->special, 4)) { - case 1: // StarPost Activator - { - mobj_t *post = P_GetObjectTypeInSectorNum(MT_STARPOST, sector - sectors); - if (!post) - break; - P_TouchStarPost(post, player, false); - break; - } - case 5: // Fan sector + case 5: // Fan sector { player->mo->momz += 5*FRACUNIT/4; @@ -5268,37 +5297,6 @@ static void P_EvaluateOldSectorSpecial(player_t *player, sector_t *sector, secto P_ResetPlayer(player); break; } - case 6: // SRB2kart 190117 - Sneaker Panel - { - if (roversector || isTouching) - { - if (!player->floorboost) - player->floorboost = 3; - else - player->floorboost = 2; - K_DoSneaker(player, 0); - } - break; - } - case 7: // SRB2kart 190117 - Oil Slick (deprecated) - if (roversector || isTouching) - { - if (player) - P_DamageMobj(player->mo, NULL, NULL, 1, DMG_NORMAL); - } - break; - case 10: // Finish Line - { - if ((gametyperules & GTR_CIRCUIT) && (player->exiting == 0) && !(player->pflags & PF_HITFINISHLINE)) - { - K_HandleLapIncrement(player); - - //ACS_RunLapScript(mo, line); - //K_HandleLapIncrement(player); - player->pflags |= PF_HITFINISHLINE; - } - break; - } } } @@ -5333,7 +5331,7 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers P_EvaluateDamageType(player, sector, isTouching); P_EvaluateLinedefExecutorTrigger(player, sector, isTouching); - //if (!udmf) + if (!udmf) P_EvaluateOldSectorSpecial(player, sector, roversector, isTouching); } diff --git a/src/r_defs.h b/src/r_defs.h index 54da08673..c52b99bfc 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -367,16 +367,16 @@ typedef enum SSF_NOSTEPDOWN = 1<<2, SSF_WINDCURRENT = 1<<3, SSF_CONVEYOR = 1<<4, - // free: 1<<5, + SSF_SPEEDPAD = 1<<5, SSF_STARPOSTACTIVATOR = 1<<6, SSF_EXIT = 1<<7, SSF_DELETEITEMS = 1<<8, - // free: 1<<9, - // free: 1<<10, - // free: 1<<11, - SSF_FAN = 1<<12, - // free: 1<<13, - // free: 1<<14, + SSF_SNEAKERPANEL = 1<<9, + SSF_WATERPANEL = 1<<10, + SSF_REDPOGOSPRING = 1<<11, + SSF_YELLOWPOGOSPRING = 1<<12, + SSF_FAN = 1<<13, + SSF_FINISHLINE = 1<14, SSF_ZOOMTUBESTART = 1<<15, SSF_ZOOMTUBEEND = 1<<16, } sectorspecialflags_t; @@ -448,6 +448,19 @@ typedef enum CRUMBLE_RESTORE, // Crumble thinker is about to restore to original position } crumblestate_t; +// enums for new SSF flags to prevent magic numbers! +typedef enum +{ + SBPT_SNEAKER, + SBPT_WATER, +} specialboostpaneltype_t; + +typedef enum +{ + SSPT_RED, + SSPT_YELLOW, +} specialspringpaneltype_t; + // // The SECTORS record, at runtime. // Stores things/mobjs. From 1db499edf33fd3c984349880a853e95badfc86d3 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sat, 8 Feb 2025 12:42:35 -0500 Subject: [PATCH 029/117] Add tripwire to textmap write --- src/p_setup.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/p_setup.c b/src/p_setup.c index 8e406d5be..920f7d3af 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2831,6 +2831,8 @@ static void P_WriteTextmap(void) CONS_Alert(CONS_WARNING, M_GetText("Linedef %s has an executor delay. Changes to the delay at runtime will not be reflected in the converted map. Use linedef type 465 for this.\n"), sizeu1(i)); fprintf(f, "executordelay = %d;\n", (wlines[i].backsector->ceilingheight >> FRACBITS) + (wlines[i].backsector->floorheight >> FRACBITS)); } + if (wlines[i].tripwire) + fprintf(f, "tripwire = true;\n"); if (wlines[i].flags & ML_IMPASSABLE) fprintf(f, "blocking = true;\n"); if (wlines[i].flags & ML_BLOCKPLAYERS) From ac2e10ecfb73d4af48b9abd5465b31dfa3748df3 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sat, 8 Feb 2025 12:47:31 -0500 Subject: [PATCH 030/117] Add waterpanels to dehacked --- src/deh_tables.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/deh_tables.c b/src/deh_tables.c index 4a5ff0a66..cef433039 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -394,11 +394,11 @@ const char *const SSF_LIST[] = { "EXIT", "DELETEITEMS", "SNEAKERPANEL" , + "WATERPANEL" , "REDPOGOSPRING", "YELLOWPOGOSPRING" , "FAN", "FINISHLINE", - "\x01", // free (name un-matchable) "ZOOMTUBESTART", "ZOOMTUBEEND", NULL From 4586925da86bfb3f109e2feb9883b2046bcf580c Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 14 Nov 2023 20:32:22 -0800 Subject: [PATCH 031/117] P_PlayerRingBurst: check player->curshield directly --- src/p_inter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_inter.c b/src/p_inter.c index 7759d375a..8be8ada20 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2415,7 +2415,7 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings) return; // Have a shield? You get hit, but don't lose your rings! - if (K_GetShieldFromItem(player->itemtype) != KSHIELD_NONE) + if (player->curshield != KSHIELD_NONE) return; // 20 is the maximum number of rings that can be taken from you at once - half the span of your counter From 62477b51e3ac00393e2830e01f78ee5e304ae4c1 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sat, 8 Feb 2025 15:17:41 -0500 Subject: [PATCH 032/117] Fix tripwire line flag turns out the false set here effects it. hopefully this is safe. If you are using the linedef flag to set a tripwire up be sure the midtexture has both sides as it wont automatically copy like a terraindef tripwire would. --- extras/blanudmf/Includes/BlanKart_misc.cfg | 1 + src/p_setup.c | 15 +++++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/extras/blanudmf/Includes/BlanKart_misc.cfg b/extras/blanudmf/Includes/BlanKart_misc.cfg index 6d8c76add..167abf03f 100644 --- a/extras/blanudmf/Includes/BlanKart_misc.cfg +++ b/extras/blanudmf/Includes/BlanKart_misc.cfg @@ -46,6 +46,7 @@ linedefflags_udmf playerpush = "Player Push"; monsterpush = "Monster (?) Push"; impact = "Impact"; + tripwire = "Tripwire"; } linedefrenderstyles diff --git a/src/p_setup.c b/src/p_setup.c index 920f7d3af..d745778a5 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -1173,7 +1173,7 @@ static void P_InitializeLinedef(line_t *ld) ld->validcount = 0; ld->polyobj = NULL; - ld->tripwire = false; + //ld->tripwire = false; ld->text = NULL; ld->callcount = 0; @@ -2078,10 +2078,10 @@ static void ParseTextmapLinedefParameter(UINT32 i, const char *param, const char } else if (fastcmp(param, "executordelay")) lines[i].executordelay = atol(val); - else if (fastcmp(param, "tripwire") && fastcmp("true", val)) // who needs terraindefs amiright :^) - lines[i].tripwire = true; // Flags + else if (fastcmp(param, "tripwire") && fastcmp("true", val)) // who needs terraindefs amiright :^) + lines[i].tripwire = true; else if (fastcmp(param, "blocking") && fastcmp("true", val)) lines[i].flags |= ML_IMPASSABLE; else if (fastcmp(param, "blockmonsters") && fastcmp("true", val)) @@ -3465,6 +3465,7 @@ static boolean P_CheckLineSideTripWire(line_t *ld, int p) terrain_t *terrain; boolean tripwire; + boolean terraintripwire; n = ld->sidenum[p]; @@ -3474,9 +3475,10 @@ static boolean P_CheckLineSideTripWire(line_t *ld, int p) sda = &sides[n]; terrain = K_GetTerrainForTextureNum(sda->midtexture); - tripwire = (terrain && (terrain->flags & TRF_TRIPWIRE)) || (ld->tripwire == true); + terraintripwire = (terrain && (terrain->flags & TRF_TRIPWIRE)); + tripwire = terraintripwire ? terraintripwire : ld->tripwire; - if (tripwire) + if (terraintripwire) { // copy midtexture to other side n = ld->sidenum[!p]; @@ -3512,8 +3514,9 @@ static void P_ProcessLinedefsAfterSidedefs(void) ld->frontsector = sides[ld->sidenum[0]].sector; //e6y: Can't be -1 here ld->backsector = ld->sidenum[1] != 0xffff ? sides[ld->sidenum[1]].sector : 0; - // Check for tripwire, if either side matches then + // Check for tripwire, if either side matches a terraindef then // copy that (mid)texture to the other side. + // NOTE: If you are using the flag instead of terrain you must do the other side yourself. ld->tripwire = P_CheckLineSideTripWire(ld, 0) || P_CheckLineSideTripWire(ld, 1); From f30b2e46141a624122c507cfdae92e266f2f7a21 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sat, 8 Feb 2025 18:08:29 -0500 Subject: [PATCH 033/117] Nerf tripwire knockback to account for the lack of hitlag --- src/k_kart.c | 2 +- src/p_map.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index f49ee5c55..2fac039eb 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3767,7 +3767,7 @@ void K_ApplyTripWire(player_t *player, tripwirestate_t state) { // We are either softlocked or wildly misbehaving. Stop that! if (state == TRIPSTATE_BLOCKED && player->tripwireReboundDelay && (player->speed > 5 * K_GetKartSpeed(player, false, false))) - P_DamageMobj(player->mo, NULL, NULL, 1, DMG_STING); + P_DamageMobj(player->mo, NULL, NULL, 1, DMG_NORMAL); if (state == TRIPSTATE_PASSED) { diff --git a/src/p_map.c b/src/p_map.c index 5db02d99f..b83e7c378 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -3145,8 +3145,8 @@ static void P_PlayerHitBounceLine(line_t *ld, vector2_t* normal) if (ld && P_IsLineTripWire(ld)) { - tmxmove = x * 4; - tmymove = y * 4; + tmxmove = FixedMul(x, FRACUNIT+(FRACUNIT/2)); + tmymove = FixedMul(y, FRACUNIT+(FRACUNIT/2)); } else { From d85625f1eeb83e15241f3ea9faf6c4b293431179 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sat, 8 Feb 2025 18:44:56 -0500 Subject: [PATCH 034/117] Fix Yellow Spring Panel issue Use the constant dummy thats why it exists --- src/p_spec.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/p_spec.c b/src/p_spec.c index 6e76b6add..82316b422 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -5011,7 +5011,7 @@ static void P_ProcessSpeedPad(player_t *player, sector_t *sector, sector_t *rove } } -static void P_ProcessPogoSpring(player_t *player, boolean isTouching, boolean type) +static void P_ProcessPogoSpring(player_t *player, boolean isTouching, int type) { const fixed_t hscale = mapobjectscale + (mapobjectscale - player->mo->scale); const fixed_t minspeed = 24*hscale; @@ -5021,12 +5021,12 @@ static void P_ProcessPogoSpring(player_t *player, boolean isTouching, boolean ty if (!isTouching) return; - if ((player->speed > maxspeed) && type == 2) // Prevent overshooting jumps + if ((player->speed > maxspeed) && type == SSPT_YELLOW) // Prevent overshooting jumps P_InstaThrust(player->mo, pushangle, maxspeed); else if (player->speed < minspeed) // Push forward to prevent getting stuck P_InstaThrust(player->mo, pushangle, minspeed); - if (type == 2) + if (type == SSPT_YELLOW) player->pogospring = 2; else player->pogospring = 1; @@ -5034,7 +5034,7 @@ static void P_ProcessPogoSpring(player_t *player, boolean isTouching, boolean ty K_DoPogoSpring(player->mo, 0, 1); } -static void P_ProcessBoostPanel(player_t *player, boolean isTouching, boolean type) +static void P_ProcessBoostPanel(player_t *player, boolean isTouching, int type) { if (isTouching) { From 5a356f14e36e3d4a72bf4032087ca4a72a9515dd Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sat, 8 Feb 2025 19:21:30 -0500 Subject: [PATCH 035/117] Add Document Spec This is based on the RR one with extensions/differences to account for BlanKart. --- extras/blanudmf/Includes/BlanKart_common.cfg | 2 +- extras/udmf-spec.txt | 293 +++++++++++++++++++ 2 files changed, 294 insertions(+), 1 deletion(-) create mode 100644 extras/udmf-spec.txt diff --git a/extras/blanudmf/Includes/BlanKart_common.cfg b/extras/blanudmf/Includes/BlanKart_common.cfg index 26677b515..646fa2f4c 100644 --- a/extras/blanudmf/Includes/BlanKart_common.cfg +++ b/extras/blanudmf/Includes/BlanKart_common.cfg @@ -85,7 +85,7 @@ mapformat_udmf // Determines the textmap namespace engine = "blankart"; - version = 2; + version = 3; maplumpnames { diff --git a/extras/udmf-spec.txt b/extras/udmf-spec.txt new file mode 100644 index 000000000..52e6ff41e --- /dev/null +++ b/extras/udmf-spec.txt @@ -0,0 +1,293 @@ +=============================================================================== +Universal Doom Map Format - BlanKart extensions v1.0 - 20.09.2024 + + Copyright (c) 2024 Sally Cochenour. + Copyright (c) 2024 Kart Krew Dev. + Copyright (c) 2025 NepDisk. + + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.2 + or any later version published by the Free Software Foundation; + with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. + +=============================================================================== + +This document serves to only specify changes that "BlanKart" +makes to the base UDMF specification. + +This document is based on the original from Ring Racers with extensions to account for BlanKart's differences. + +======================================= +I. Grammar / Syntax +======================================= + +No changes were made. + +======================================= +II. Implementation Semantics +======================================= + +------------------------------------ +II.A : Storage and Retrieval of Data +------------------------------------ + +No changes were made. + +----------------------------------- +II.B : Storage Within Archive Files +----------------------------------- + +Between the TEXTMAP and ENDMAP lumps, BlanKart supports the following +additional lumps: + + BEHAVIOR = Compiled ACS code. + ZNODES = Compiled extended / GL friendly nodes. These are required. + PICTURE = A Doom graphic lump, expected to be 320x200. Intended to be a + screenshot of the map itself. This is used by the game for level + select menus. + MINIMAP = A Doom graphic lump, expected to be 100x100. Intended to be a + an overview of the map. This is used by the game for the minimap + on-screen HUD. + ENCORE = A Doom flat lump, expected to be 16x16. Describes a color remap + palette to use in Encore Mode. + TWEAKMAP = A Doom flat lump, expected to be 16x16. Describes a color remap + palette to use outside of Encore Mode. + +Any lumps not listed or specified in the original document will be ignored by +the game. In particular, the "SCRIPTS" lump is considered to be ACS source +code, and is guaranteed to be ignored by the engine. + +-------------------------------- +II.C : Implementation Dependence +-------------------------------- + +BlanKart does not aspire for Doom backwards compatibility, thus it does not +support any of the namespaces in the original document, and only implements +its own: "blankart". It also supports "srb2", "srb2kart", "blankart" or "ringracers" namespaces as well. +Any maps not using the mentioned namespaces are considered unsupported. + +======================================= +III. Standardized Fields +======================================= + +BlanKart's namespace implements the following additional fields: + + version = ; // Specifies the map format version. + // This is used for resolving backwards compatibility issues. + + // Note that this doesn't map directly to specification version; + // it means behavior of an already existing field or action special + // was changed. + + // 0 / default - RR indev + // 1 - RR v2.0, RR spec v1.0 + // 2 - RR v2.4, RR spec v1.0 + // 3 - BlanKart indev, BK spec v1.0 + + linedef + { + moreids = ; // Additional IDs, specified as a space separated list of numbers (e.g. "2 666 1003 4505") + + arg5 = ; // Argument 5. Default = 0. + arg6 = ; // Argument 6. Default = 0. + arg7 = ; // Argument 7. Default = 0. + arg8 = ; // Argument 8. Default = 0. + arg9 = ; // Argument 9. Default = 0. + + stringarg0 = ; // String argument 0. This replaces usage of 'arg0' when specified. + stringarg1 = ; // String argument 1. This replaces usage of 'arg1' when specified. + + alpha = ; // Transparency value of the mid-textures. Default = 1.0. + renderstyle = ; // The rendering mode to use for the mid-textures. + // Can be "translucent", "add", "subtract", "reversesubtract", "modulate", or "fog". + // Default = "translucent". + + // The following flags default to false. + blockplayers = ; // true = line blocks players. + skewtd = ; // true = upper and lower textures are skewed to match slopes. + noskew = ; // true = mid-textures are not skewed to match slopes. + midpeg = ; // true = invert mid-texture unpegged behavior. + midsolid = ; // true = mid-texture has collision. + wrapmidtex = ; // true = mid-textures are wrapped. + nonet = ; // true = special is disabled in networked multiplayer games. + netonly = ; // true = special is only enabled in networked multiplayer games. + notbouncy = ; // true = disable bouncing collision. + transfer = ; // true = use FOF transfer properties effect. + tripwire = ; // true = mark linedef as tripwire line. + } + + sidedef + { + repeatcnt = ; // Number of times to mid-texture wrap. Default = 0. + } + + vertex + { + zfloor = ; // The floor height at this vertex, for vertex slopes. + zceiling = ; // The ceiling height at this vertex, for vertex slopes + } + + sector + { + lightfloor = ; // The floor's light level. Default is 0. + lightceiling = ; // The ceiling's light level. Default is 0. + + lightfloorabsolute = ; // true = 'lightfloor' is an absolute value. Default is + // relative to the owning sector's light level. + lightceilingabsolute = ; // true = 'lightceiling' is an absolute value. Default is + // relative to the owning sector's light level. + + moreids = ; // Additional IDs, specified as a space separated list of numbers (e.g. "2 666 1003 4505") + + xpanningfloor = ; // X texture offset of floor texture, Default = 0.0. + ypanningfloor = ; // Y texture offset of floor texture, Default = 0.0. + + xpanningceiling = ; // X texture offset of ceiling texture, Default = 0.0. + ypanningceiling = ; // Y texture offset of ceiling texture, Default = 0.0. + + rotationfloor = ; // Rotation of floor texture in degrees, Default = 0.0. + rotationceiling = ; // Rotation of ceiling texture in degrees, Default = 0.0. + + floorplane_a = ; // Define the plane equation for the sector's floor. Default is a horizontal plane at 'heightfloor'. + floorplane_b = ; // 'heightfloor' will still be used to calculate texture alignment. + floorplane_c = ; // The plane equation will only be used if all 4 values are given. + floorplane_d = ; + + ceilingplane_a = ; // Define the plane equation for the sector's ceiling. Default is a horizontal plane at 'heightceiling'. + ceilingplane_b = ; // 'heightceiling' will still be used to calculate texture alignment. + ceilingplane_c = ; // The plane equation will only be used if all 4 values are given. + ceilingplane_d = ; + + friction = ; // Sector's friction. Default = 0.90625. + gravity = ; // Sector's gravity multiplier. Default = 1.0. + offroad = ; // Sector's offroad multiplier. Default = 0.0. + damagetype = ; // Damage inflicted by the sector. + // Can be "None", "Generic", "Lava", "DeathPit", "Instakill", or "Stumble". + // Default = "None". + + action = ; // Sector action, same as line special. Default = 0. + arg0 = ; // Argument 0. Default = 0. + arg1 = ; // Argument 1. Default = 0. + arg2 = ; // Argument 2. Default = 0. + arg3 = ; // Argument 3. Default = 0. + arg4 = ; // Argument 4. Default = 0. + arg5 = ; // Argument 5. Default = 0. + arg6 = ; // Argument 6. Default = 0. + arg7 = ; // Argument 7. Default = 0. + arg8 = ; // Argument 8. Default = 0. + arg9 = ; // Argument 9. Default = 0. + stringarg0 = ; // String argument 0. This replaces usage of 'arg0' when specified. + stringarg1 = ; // String argument 1. This replaces usage of 'arg1' when specified. + + lightcolor = ; // Sector's light color as RRGGBB value. Default = 0x000000. + lightalpha = ; // Sector's light color alpha value. Default = 25. + fadecolor = ; // Sector's fog color as RRGGBB value. Default = 0x000000. + fadealpha = ; // Sector's fog color alpha value. Default = 25. + fadestart = ; // Sector's fog start distance. Default = 0. + fadeend = ; // Sector's fog end distance. Default = 31. + + // The following flags default to false. + colormapfog = ; // true = render transparent planes at light level instead of fullbright. + colormapfadesprites = ; // true = fog color affects fullbright sprites. + colormapprotected = ; // true = colormap cannot be changed at run-time. + + flipspecial_nofloor = ; // true = plane touch specials aren't ran when on the floor. + flipspecial_ceiling = ; // true = plane touch specials are ran when on the ceiling. + triggerspecial_touch = ; // true = specials are ran when touching edges of sector. + triggerspecial_headbump = ; // true = plane touch specials are ran when touching the opposite plane than gravity. + invertprecip = ; // true = precipitation spawning rules are inverted.. + gravityflip = ; // true = flip gravity of objects in this sector. + heatwave = ; // true = add heat wave screen effect. + ripple_floor = ; // true = add ripple effect to floor. + ripple_ceiling = ; // true = add ripple effect to ceiling. + invertencore = ; // true = encore remap rules are inverted. + flatlighting = ; // true = directional lighting is forced off. + forcedirectionallighting = ; // true = directional lighting is forced on. + nostepup = ; // true = objects can't step up. + doublestepup = ; // true = objects have increased step up. + nostepdown = ; // true = objects can't step down. + cheatcheckactivator = ; // true = players activate cheat checks when in this sector. + exit = ; // true = players finish match when entering sector. + deleteitems = ; // true = items instantly explode when entering sector. + fan = ; // true = players are propelled upwards in this sector. + zoomtubestart = ; // true = sector is start of a zoom tube. + zoomtubeend = ; // true = sector is end of a zoom tube. + + speedpad = ; // true = players are launched forward by this sector. + finishline = l // true = players gain a lap or finish the race in this sector. Used for legacy support. + sneakerpanel = ; // true = players are speed boosted forward by this sector. + waterpanel = ; // true = players are speed boosted forward by this sector and are able to drive on water. + redpogospring = ; // true = players are bounced into the air by this sector. + yellowpogospring = ; // true = players are bounced into the air and then speedcapped by this sector. + + repeatspecial = ; // true = repeatable action. + continuousspecial = ; // true = action is executed every game tick. + playerenter = ; // true = player activates when entering. + playerfloor = ; // true = player activates when touching floor. + playerceiling = ; // true = player activates when touching ceiling. + monsterenter = ; // true = enemy activates when entering. + monsterfloor = ; // true = enemy activates when touching floor. + monsterceiling = ; // true = enemy activates when touching ceiling. + missileenter = ; // true = items / projectiles activate when entering. + missilefloor = ; // true = items / projectiles activate when touching floor. + missileceiling = ; // true = items / projectiles activate when touching ceiling. + } + + thing + { + pitch = ; // Pitch of thing in degrees. Default = 0 (horizontal). + roll = ; // Pitch of thing in degrees. Default = 0 (horizontal). + + scalex = ; // Vertical visual scale on thing. Default = 1.0. + scaley = ; // Horizontal visual scale on thing. Default = 1.0. + scale = ; // Vertical and horizontal visual scale on thing. Default = 1.0. + + mobjscale = ; // Physical scale on thing. Default = 1.0. + + foflayer = ; // Which FOF is treated as the base floor/ceiling. + // This changes what 'height' is relative to. + // Default = 0, for no FOF. + + // These arguments modify object behavior on a per-type basis. + arg0 = ; // Argument 0. Default = 0. + arg1 = ; // Argument 1. Default = 0. + arg2 = ; // Argument 2. Default = 0. + arg3 = ; // Argument 3. Default = 0. + arg4 = ; // Argument 4. Default = 0. + arg5 = ; // Argument 5. Default = 0. + arg6 = ; // Argument 6. Default = 0. + arg7 = ; // Argument 7. Default = 0. + arg8 = ; // Argument 8. Default = 0. + arg9 = ; // Argument 9. Default = 0. + + stringarg0 = ; // String argument 0. This replaces usage of 'arg0' when specified. + stringarg1 = ; // String argument 1. This replaces usage of 'arg1' when specified. + + + // Action special arguments. + scriptarg0 = ; // Argument 0. Default = 0. + scriptarg1 = ; // Argument 1. Default = 0. + scriptarg2 = ; // Argument 2. Default = 0. + scriptarg3 = ; // Argument 3. Default = 0. + scriptarg4 = ; // Argument 4. Default = 0. + scriptarg5 = ; // Argument 5. Default = 0. + scriptarg6 = ; // Argument 6. Default = 0. + scriptarg7 = ; // Argument 7. Default = 0. + scriptarg8 = ; // Argument 8. Default = 0. + scriptarg9 = ; // Argument 9. Default = 0. + scriptstringarg0 = ; // String argument 0. This replaces usage of 'scriptarg0' when specified. + scriptstringarg1 = ; // String argument 1. This replaces usage of 'scriptarg1' when specified. + + // Following flags default to false. + flip = ; // true = object has reversed gravity + } + +======================================= +Changelog +======================================= + +RR 1.0: 20.09.2024 +- Initial document created. + +BK 1.0: 08.09.2025 +- Document spec updated to account for BlanKart differnces. From 563cfd75a9ffb4be449942df3803366ce95035b4 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sun, 9 Feb 2025 00:24:49 +0000 Subject: [PATCH 036/117] Fix dates on UDMF Spec --- extras/udmf-spec.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extras/udmf-spec.txt b/extras/udmf-spec.txt index 52e6ff41e..df852ee1e 100644 --- a/extras/udmf-spec.txt +++ b/extras/udmf-spec.txt @@ -1,5 +1,5 @@ =============================================================================== -Universal Doom Map Format - BlanKart extensions v1.0 - 20.09.2024 +Universal Doom Map Format - BlanKart extensions v1.0 - 08.02.2025 Copyright (c) 2024 Sally Cochenour. Copyright (c) 2024 Kart Krew Dev. @@ -289,5 +289,5 @@ Changelog RR 1.0: 20.09.2024 - Initial document created. -BK 1.0: 08.09.2025 +BK 1.0: 08.02.2025 - Document spec updated to account for BlanKart differnces. From 575a26b651930cb9a057454190d00eec814e21aa Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sat, 8 Feb 2025 21:21:21 -0500 Subject: [PATCH 037/117] Fix Textmap Output --- src/p_setup.c | 10 +++++----- src/r_state.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index d745778a5..4f7737b44 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2730,7 +2730,7 @@ static void P_WriteTextmap(void) } } - fprintf(f, "namespace = \"srb2\";\n"); + fprintf(f, "namespace = \"blankart\";\n"); fprintf(f, "version = %d;\n", UDMF_CURRENT_VERSION); for (i = k = 0; i < nummapthings; i++) { @@ -3084,13 +3084,13 @@ static void P_WriteTextmap(void) if (wsectors[i].offroad != 0) { if (wsectors[i].offroad == FRACUNIT) - fprintf(f, "offroad = Weak;\n"); + fprintf(f, "offroad = \"Weak\";\n"); else if (wsectors[i].offroad == 2*FRACUNIT) - fprintf(f, "offroad = Normal;\n"); + fprintf(f, "offroad = \"Normal\";\n"); else if (wsectors[i].offroad == 3*FRACUNIT) - fprintf(f, "offroad = Strong;\n"); + fprintf(f, "offroad = \"Strong\";\n"); else - fprintf(f, "gravity = %f;\n", FIXED_TO_FLOAT(wsectors[i].offroad)); + fprintf(f, "offroad = %f;\n", FIXED_TO_FLOAT(wsectors[i].offroad)); } if (wsectors[i].damagetype != SD_NONE) { diff --git a/src/r_state.h b/src/r_state.h index 2436ddd0f..bb5aea6b3 100644 --- a/src/r_state.h +++ b/src/r_state.h @@ -63,7 +63,7 @@ extern size_t numspritelumps, max_spritelumps; // // Lookup tables for map data. // -#define UDMF_CURRENT_VERSION (2) +#define UDMF_CURRENT_VERSION (3) extern boolean udmf; extern INT32 udmf_version; From 6b865e5e7b7f038ef2c2ff84c191b69fa002e173 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sat, 8 Feb 2025 23:05:02 -0500 Subject: [PATCH 038/117] Add slope anchor stuff here. --- .../blanudmf/Includes/BlanKart_linedefs.cfg | 33 +++++++++++++++++++ extras/blanudmf/Includes/BlanKart_things.cfg | 8 +++++ 2 files changed, 41 insertions(+) diff --git a/extras/blanudmf/Includes/BlanKart_linedefs.cfg b/extras/blanudmf/Includes/BlanKart_linedefs.cfg index 88d09bfa7..43da97f83 100644 --- a/extras/blanudmf/Includes/BlanKart_linedefs.cfg +++ b/extras/blanudmf/Includes/BlanKart_linedefs.cfg @@ -4089,6 +4089,39 @@ udmf } } + 777 + { + title = "Create Anchor-Based Slope"; + prefix = "(777)"; + requiresactivation = false; + arg0 + { + title = "Planes"; + type = 12; + enum + { + 1 = "Floor"; + 2 = "Ceiling"; + } + } + arg1 + { + title = "Flags"; + type = 12; + enum + { + 1 = "No physics"; + 2 = "Dynamic"; + 4 = "Slope backside"; + 8 = "Mirror plane"; + } + } + arg2 + { + title = "Group"; + } + } + 799 { title = "Set Tagged Dynamic Slope Vertex to Front Sector Height"; diff --git a/extras/blanudmf/Includes/BlanKart_things.cfg b/extras/blanudmf/Includes/BlanKart_things.cfg index eb6c14342..a94937571 100644 --- a/extras/blanudmf/Includes/BlanKart_things.cfg +++ b/extras/blanudmf/Includes/BlanKart_things.cfg @@ -2238,12 +2238,20 @@ udmf { title = "Floor Slope Anchor"; sprite = "SAFA0"; + arg0 + { + title = "Group"; + } } 778 { title = "Ceiling Slope Anchor"; sprite = "SACA0"; + arg0 + { + title = "Group"; + } } 780 { From d47880120f0b93e788d63d8fa7e45835ba79a073 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sat, 8 Feb 2025 23:28:58 -0500 Subject: [PATCH 039/117] RingRacers: add loop things 2020 and 2021 4579879f2a915f9d09a075c26a7d6d2dbc3a059a --- extras/blanudmf/Includes/BlanKart_things.cfg | 59 ++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/extras/blanudmf/Includes/BlanKart_things.cfg b/extras/blanudmf/Includes/BlanKart_things.cfg index a94937571..7e82ee7cf 100644 --- a/extras/blanudmf/Includes/BlanKart_things.cfg +++ b/extras/blanudmf/Includes/BlanKart_things.cfg @@ -2268,6 +2268,65 @@ udmf } } } + 2020 + { + title = "Loop Gate Post (place 2 things for a single side)"; + arrow = 1; + arg0 + { + title = "Gate Side"; + type = 11; + enum + { + 0 = "First"; + 1 = "Second"; + } + } + } + 2021 + { + title = "Loop Center (distance from gate = loop radius, tag matches gates)"; + arg0 + { + title = "Reverse gravity"; + type = 3; + } + arg1 + { + title = "Degrees of rotation"; + } + arg2 + { + title = "Zoom-out tics"; + } + arg3 + { + title = "Zoom-in tics"; + } + arg4 + { + title = "Zoom-out distance"; + type = 1; + } + arg5 + { + title = "Pan to side"; + type = 1; + } + arg6 + { + title = "Pan speed (degrees)"; + type = 1; + } + arg7 + { + title = "Pan accel (tics)"; + } + arg8 + { + title = "Pan reset (tics)"; + } + } } greenflower From fae60bade422ac1bb46d6db61e23f1a99f5cafa6 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sat, 8 Feb 2025 23:33:59 -0500 Subject: [PATCH 040/117] add radius action thing --- extras/blanudmf/Includes/BlanKart_things.cfg | 23 ++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/extras/blanudmf/Includes/BlanKart_things.cfg b/extras/blanudmf/Includes/BlanKart_things.cfg index 7e82ee7cf..9b30508a8 100644 --- a/extras/blanudmf/Includes/BlanKart_things.cfg +++ b/extras/blanudmf/Includes/BlanKart_things.cfg @@ -2327,6 +2327,29 @@ udmf title = "Pan reset (tics)"; } } + 4096 + { + title = "Radius Action"; + sprite = "OTCPAL"; + arg0 + { + title = "Radius"; + default = 128; + renderstyle = "Circle"; + } + arg1 + { + title = "Repeatable?"; + type = 11; + enum = "noyes"; + } + arg2 + { + title = "Disabled?"; + type = 11; + enum = "noyes"; + } + } } greenflower From 6844715c5eec65d6ab71e020c881776deea6e9ce Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sat, 8 Feb 2025 23:41:24 -0500 Subject: [PATCH 041/117] Reorder items in UDMF config --- extras/blanudmf/Includes/BlanKart_misc.cfg | 30 +++++++++----------- extras/blanudmf/Includes/BlanKart_things.cfg | 2 +- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/extras/blanudmf/Includes/BlanKart_misc.cfg b/extras/blanudmf/Includes/BlanKart_misc.cfg index 167abf03f..5d41ce3d4 100644 --- a/extras/blanudmf/Includes/BlanKart_misc.cfg +++ b/extras/blanudmf/Includes/BlanKart_misc.cfg @@ -709,8 +709,8 @@ udmfmaplumpnames // Reserved names are: angledeg, anglerad, color, texture, flat enums { - // USED FOR RING RACERS - rritems + // USED FOR CAPSULES + kartitems { 0 = "None"; 1 = "Sneaker"; @@ -721,21 +721,19 @@ enums 6 = "Orbinaut"; 7 = "Jawz"; 8 = "Mine"; - 9 = "Landmine"; - 10 = "Ballhog"; - 11 = "Self-Propelled Bomb"; - 12 = "Grow"; - 13 = "Shrink"; - 14 = "Lightning Shield"; - 15 = "Bubble Shield"; - 16 = "Flame Shield"; - 17 = "Hyudoro"; - 18 = "Pogo Spring"; - 19 = "Super Ring"; - 20 = "Kitchen Sink"; + 9 = "Ballhog"; + 10 = "Self-Propelled Bomb"; + 11 = "Grow"; + 12 = "Shrink"; + 13 = "Lightning Shield"; + 14 = "Hyudoro"; + 15 = "Pogo Spring"; + 16 = "Kitchen Sink"; + 17 = "Super Ring"; + 18 = "Landmine"; + 19 = "Bubble Shield"; + 20 = "Flame Shield"; 21 = "Drop Target"; - 22 = "Garden Top"; - 23 = "Gachabom"; } falsetrue diff --git a/extras/blanudmf/Includes/BlanKart_things.cfg b/extras/blanudmf/Includes/BlanKart_things.cfg index 9b30508a8..cf681f924 100644 --- a/extras/blanudmf/Includes/BlanKart_things.cfg +++ b/extras/blanudmf/Includes/BlanKart_things.cfg @@ -1231,7 +1231,7 @@ udmf { title = "Item Type"; type = 11; - enum = "rritems"; + enum = "kartitems"; } arg1 { From 633ec1a045ba46b06f9f77c3a2b39160f83644d8 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sat, 8 Feb 2025 23:53:58 -0500 Subject: [PATCH 042/117] Add missing sector special flags for lighting --- extras/blanudmf/Includes/BlanKart_misc.cfg | 69 +++++++++++----------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/extras/blanudmf/Includes/BlanKart_misc.cfg b/extras/blanudmf/Includes/BlanKart_misc.cfg index 5d41ce3d4..07174157e 100644 --- a/extras/blanudmf/Includes/BlanKart_misc.cfg +++ b/extras/blanudmf/Includes/BlanKart_misc.cfg @@ -79,6 +79,9 @@ sectorflags gravityoverride = "Make Reverse Gravity Temporary"; ripple_floor = "Ripple Floor"; ripple_ceiling = "Ripple Ceiling"; + invertencore = "Encore Remap Invert"; + flatlighting = "Disable Directional Lighting"; + forcedirectionallighting = "Force Directional Lighting On"; // BlanKart SSF flags speedpad = "Speed Pad"; @@ -87,7 +90,7 @@ sectorflags waterpanel = "Water Run Panel"; redpogospring = "Spring Panel"; yellowpogospring = "Capped Spring Panel"; - + // RR ACS executor flags repeatspecial = "Each Time (?) (ACS)"; continuousspecial = "Continuous (ACS)"; @@ -130,7 +133,7 @@ sectorflagscategories waterpanel = "special"; redpogospring = "special"; yellowpogospring = "special"; - + // RR ACS executor flags repeatspecial = "trigger"; continuousspecial = "trigger"; @@ -258,7 +261,7 @@ universalfields type = 1; default = 1.0; } - + comment { type = 2; @@ -270,19 +273,19 @@ universalfields type = 2; default = ""; } - + stringarg0 { type = 2; default = ""; } - + stringarg1 { type = 2; default = ""; } - + executordelay { type = 0; @@ -297,7 +300,7 @@ universalfields type = 2; default = ""; } - + //light //{ // type = 0; @@ -344,20 +347,20 @@ universalfields //{ // type = 3; // default = false; - //} - + //} + offsetx { type = 1; default = 0.0; } - + offsety { type = 1; default = 0.0; } - + offsetx_bottom { type = 1; @@ -369,7 +372,7 @@ universalfields type = 1; default = 0.0; } - + offsetx_top { type = 1; @@ -387,43 +390,43 @@ universalfields type = 1; default = 0.0; } - + offsety_top { type = 1; default = 0.0; } - + scalex_bottom { type = 1; default = 1.0; } - + scalex_mid { type = 1; default = 1.0; } - + scalex_top { type = 1; default = 1.0; } - + scaley_bottom { type = 1; default = 1.0; } - + scaley_mid { type = 1; default = 1.0; } - + scaley_top { type = 1; @@ -438,41 +441,41 @@ universalfields type = 2; default = ""; } - + pitch { type = 0; } - + roll { type = 0; } - + scalex { type = 1; default = 1.0; } - + scaley { type = 1; default = 1.0; } - + stringarg0 { type = 2; default = ""; } - + stringarg1 { type = 2; default = ""; } - + mobjscale { type = 1; @@ -480,7 +483,7 @@ universalfields managed = false; } } - + sector { comment @@ -560,7 +563,7 @@ universalfields type = 1; default = 1.0; } - + yscalefloor { type = 1; @@ -572,7 +575,7 @@ universalfields type = 0; default = 0; } - + lightfloorabsolute { type = 3; @@ -602,7 +605,7 @@ universalfields type = 1; default = 1.0; } - + yscaleceiling { type = 1; @@ -614,7 +617,7 @@ universalfields type = 0; default = 0; } - + lightceilingabsolute { type = 3; @@ -660,7 +663,7 @@ udmfmaplumpnames nodebuild = true; allowempty = true; } - + BEHAVIOR { required = false; @@ -735,7 +738,7 @@ enums 20 = "Flame Shield"; 21 = "Drop Target"; } - + falsetrue { 0 = "False"; From c3f5f1dffe33e13faa812ff652fed466d2b62452 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sun, 9 Feb 2025 08:48:51 -0500 Subject: [PATCH 043/117] add visibility flag to script object in UDMF config --- extras/blanudmf/Includes/BlanKart_things.cfg | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/extras/blanudmf/Includes/BlanKart_things.cfg b/extras/blanudmf/Includes/BlanKart_things.cfg index cf681f924..5d2c8283a 100644 --- a/extras/blanudmf/Includes/BlanKart_things.cfg +++ b/extras/blanudmf/Includes/BlanKart_things.cfg @@ -2349,6 +2349,12 @@ udmf type = 11; enum = "noyes"; } + arg3 + { + title = "Invisible?"; + type = 11; + enum = "noyes"; + } } } From a1fdf8210b1d44a572ac1eeefb93df6cee402b35 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sun, 9 Feb 2025 09:39:52 -0500 Subject: [PATCH 044/117] Use signs for player starts instead of player sprites --- extras/blanudmf/Includes/BlanKart_things.cfg | 34 ++++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/extras/blanudmf/Includes/BlanKart_things.cfg b/extras/blanudmf/Includes/BlanKart_things.cfg index 5d2c8283a..f7bf97fca 100644 --- a/extras/blanudmf/Includes/BlanKart_things.cfg +++ b/extras/blanudmf/Includes/BlanKart_things.cfg @@ -25,12 +25,12 @@ udmf title = "Player Starts"; width = 16; height = 48; - sprite = "PLAYA0"; + sprite = "SIGNE0"; 1 { title = "Player 01 Start"; - sprite = "PLAYA0"; + sprite = "SIGNE0"; arg0 { title = "Spawn on ceiling?"; @@ -41,7 +41,7 @@ udmf 2 { title = "Player 02 Start"; - sprite = "PLAYA0"; + sprite = "SIGNE0"; arg0 { title = "Spawn on ceiling?"; @@ -52,7 +52,7 @@ udmf 3 { title = "Player 03 Start"; - sprite = "PLAYA0"; + sprite = "SIGNE0"; arg0 { title = "Spawn on ceiling?"; @@ -63,7 +63,7 @@ udmf 4 { title = "Player 04 Start"; - sprite = "PLAYA0"; + sprite = "SIGNE0"; arg0 { title = "Spawn on ceiling?"; @@ -74,7 +74,7 @@ udmf 5 { title = "Player 05 Start"; - sprite = "PLAYA0"; + sprite = "SIGNE0"; arg0 { title = "Spawn on ceiling?"; @@ -85,7 +85,7 @@ udmf 6 { title = "Player 06 Start"; - sprite = "PLAYA0"; + sprite = "SIGNE0"; arg0 { title = "Spawn on ceiling?"; @@ -96,7 +96,7 @@ udmf 7 { title = "Player 07 Start"; - sprite = "PLAYA0"; + sprite = "SIGNE0"; arg0 { title = "Spawn on ceiling?"; @@ -107,7 +107,7 @@ udmf 8 { title = "Player 08 Start"; - sprite = "PLAYA0"; + sprite = "SIGNE0"; arg0 { title = "Spawn on ceiling?"; @@ -118,7 +118,7 @@ udmf 9 { title = "Player 09 Start"; - sprite = "PLAYA0"; + sprite = "SIGNE0"; arg0 { title = "Spawn on ceiling?"; @@ -129,7 +129,7 @@ udmf 10 { title = "Player 10 Start"; - sprite = "PLAYA0"; + sprite = "SIGNE0"; arg0 { title = "Spawn on ceiling?"; @@ -140,7 +140,7 @@ udmf 11 { title = "Player 11 Start"; - sprite = "PLAYA0"; + sprite = "SIGNE0"; arg0 { title = "Spawn on ceiling?"; @@ -151,7 +151,7 @@ udmf 12 { title = "Player 12 Start"; - sprite = "PLAYA0"; + sprite = "SIGNE0"; arg0 { title = "Spawn on ceiling?"; @@ -162,7 +162,7 @@ udmf 13 { title = "Player 13 Start"; - sprite = "PLAYA0"; + sprite = "SIGNE0"; arg0 { title = "Spawn on ceiling?"; @@ -173,7 +173,7 @@ udmf 14 { title = "Player 14 Start"; - sprite = "PLAYA0"; + sprite = "SIGNE0"; arg0 { title = "Spawn on ceiling?"; @@ -184,7 +184,7 @@ udmf 15 { title = "Player 15 Start"; - sprite = "PLAYA0"; + sprite = "SIGNE0"; arg0 { title = "Spawn on ceiling?"; @@ -195,7 +195,7 @@ udmf 16 { title = "Player 16 Start"; - sprite = "PLAYA0"; + sprite = "SIGNE0"; arg0 { title = "Spawn on ceiling?"; From 591c32e97f661905c3ba0e6e963f782ba65df641 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sun, 9 Feb 2025 11:31:45 -0500 Subject: [PATCH 045/117] Port opengl VHS effect from SRB2Kart-Saturn Does not include uncap stuff currently --- src/hardware/hw_drv.h | 2 + src/hardware/hw_main.c | 5 ++ src/hardware/hw_main.h | 1 + src/hardware/r_opengl/r_opengl.c | 80 ++++++++++++++++++++++++++++++++ src/sdl/hwsym_sdl.c | 1 + src/sdl/i_video.cpp | 1 + src/v_video.c | 25 +++++++++- 7 files changed, 113 insertions(+), 2 deletions(-) diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h index 82be505d7..da4fb8542 100644 --- a/src/hardware/hw_drv.h +++ b/src/hardware/hw_drv.h @@ -66,6 +66,7 @@ EXPORT void HWRAPI(EndScreenWipe) (void); EXPORT void HWRAPI(DoScreenWipe) (void); EXPORT void HWRAPI(DrawIntermissionBG) (void); EXPORT void HWRAPI(MakeScreenTexture) (void); +EXPORT void HWRAPI(RenderVhsEffect) (INT16 upbary, INT16 downbary, UINT8 updistort, UINT8 downdistort, UINT8 barsize); EXPORT void HWRAPI(MakeScreenFinalTexture) (void); EXPORT void HWRAPI(DrawScreenFinalTexture) (int width, int height); @@ -121,6 +122,7 @@ struct hwdriver_s DoScreenWipe pfnDoScreenWipe; DrawIntermissionBG pfnDrawIntermissionBG; MakeScreenTexture pfnMakeScreenTexture; + RenderVhsEffect pfnRenderVhsEffect; MakeScreenFinalTexture pfnMakeScreenFinalTexture; DrawScreenFinalTexture pfnDrawScreenFinalTexture; diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index eac16206c..7d8efb29e 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -6672,6 +6672,11 @@ void HWR_DoTintedWipe(UINT8 wipenum, UINT8 scrnnum) HWR_DoWipe(wipenum, scrnnum); } +void HWR_RenderVhsEffect(INT16 upbary, INT16 downbary, UINT8 updistort, UINT8 downdistort, UINT8 barsize) +{ + HWD.pfnRenderVhsEffect(upbary, downbary, updistort, downdistort, barsize); +} + void HWR_MakeScreenFinalTexture(void) { HWD.pfnMakeScreenFinalTexture(); diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index 7460d9d05..41a742134 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -67,6 +67,7 @@ void HWR_EndScreenWipe(void); void HWR_DrawIntermissionBG(void); void HWR_DoWipe(UINT8 wipenum, UINT8 scrnnum); void HWR_DoTintedWipe(UINT8 wipenum, UINT8 scrnnum); +void HWR_RenderVhsEffect(INT16 upbary, INT16 downbary, UINT8 updistort, UINT8 downdistort, UINT8 barsize); void HWR_MakeScreenFinalTexture(void); void HWR_DrawScreenFinalTexture(int width, int height); diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 50db95a52..b41297d24 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -3512,6 +3512,86 @@ EXPORT void HWRAPI(MakeScreenTexture) (void) tex_downloaded = screentexture; } +EXPORT void HWRAPI(RenderVhsEffect) (INT16 upbary, INT16 downbary, UINT8 updistort, UINT8 downdistort, UINT8 barsize) +{ + float xfix, yfix; + float fix[8]; + GLubyte color[4] = {255, 255, 255, 255}; + float i; + float screenVerts[12] = + { + -1.0f, -1.0f, 1.0f, + -1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + 1.0f, -1.0f, 1.0f + }; + // look for power of two that is large enough for the screen + while (texsize < screen_width || texsize < screen_height) + texsize <<= 1; + xfix = 1/((float)(texsize)/((float)((screen_width)))); + yfix = 1/((float)(texsize)/((float)((screen_height)))); + // Slight fuzziness + MakeScreenTexture(); + SetBlend(PF_Modulated|PF_Translucent|PF_NoDepthTest); + pglBindTexture(GL_TEXTURE_2D, screentexture); + for (i = 0; i < 1; i += 2.f/vid.height) + { + fix[2] = (float)(rand() % 128) / -22000 * xfix; + fix[0] = fix[2]; + fix[6] = fix[0] + xfix; + fix[4] = fix[2] + xfix; + fix[1] = fix[7] = i*yfix; + fix[3] = fix[5] = (i+0.015)*yfix; + screenVerts[1] = screenVerts[10] = 2*i - 1.0f; + screenVerts[4] = screenVerts[7] = screenVerts[1] + 0.03; + pglColor4ubv(color); + pglTexCoordPointer(2, GL_FLOAT, 0, fix); + pglVertexPointer(3, GL_FLOAT, 0, screenVerts); + pglDrawArrays(GL_TRIANGLE_FAN, 0, 4); + } + // Upward bar + MakeScreenTexture(); + pglBindTexture(GL_TEXTURE_2D, screentexture); + color[0] = color[1] = color[2] = 190; + color[3] = 250; + pglColor4ubv(color); + fix[0] = 0.0f; + fix[6] = xfix; + fix[2] = (float)updistort / screen_width * xfix; + fix[4] = fix[2] + fix[6]; + screenVerts[1] = screenVerts[10] = 2.0f*upbary/screen_height - 1.0f; + screenVerts[4] = screenVerts[7] = screenVerts[1] + (float)barsize/screen_height; + fix[1] = fix[7] = (float)upbary/screen_height * yfix; + fix[3] = fix[5] = fix[1] + (float)barsize/2/screen_height * yfix; + pglTexCoordPointer(2, GL_FLOAT, 0, fix); + pglVertexPointer(3, GL_FLOAT, 0, screenVerts); + pglDrawArrays(GL_TRIANGLE_FAN, 0, 4); + fix[1] = fix[7] += (fix[3] - fix[7])*2; + screenVerts[1] = screenVerts[10] += (screenVerts[4] - screenVerts[1])*2; + pglTexCoordPointer(2, GL_FLOAT, 0, fix); + pglVertexPointer(3, GL_FLOAT, 0, screenVerts); + pglDrawArrays(GL_TRIANGLE_FAN, 0, 4); + // Downward bar + MakeScreenTexture(); + pglBindTexture(GL_TEXTURE_2D, screentexture); + fix[0] = 0.0f; + fix[6] = xfix; + fix[2] = (float)downdistort / screen_width * -xfix; + fix[4] = fix[2] + fix[6]; + screenVerts[1] = screenVerts[10] = 2.0f*downbary/screen_height - 1.0f; + screenVerts[4] = screenVerts[7] = screenVerts[1] + (float)barsize/screen_height; + fix[1] = fix[7] = (float)downbary/screen_height * yfix; + fix[3] = fix[5] = fix[1] + (float)barsize/2/screen_height * yfix; + pglTexCoordPointer(2, GL_FLOAT, 0, fix); + pglVertexPointer(3, GL_FLOAT, 0, screenVerts); + pglDrawArrays(GL_TRIANGLE_FAN, 0, 4); + fix[1] = fix[7] += (fix[3] - fix[7])*2; + screenVerts[1] = screenVerts[10] += (screenVerts[4] - screenVerts[1])*2; + pglTexCoordPointer(2, GL_FLOAT, 0, fix); + pglVertexPointer(3, GL_FLOAT, 0, screenVerts); + pglDrawArrays(GL_TRIANGLE_FAN, 0, 4); +} + EXPORT void HWRAPI(MakeScreenFinalTexture) (void) { boolean firstTime = (finalScreenTexture == 0); diff --git a/src/sdl/hwsym_sdl.c b/src/sdl/hwsym_sdl.c index ff4f9f664..16a8c9478 100644 --- a/src/sdl/hwsym_sdl.c +++ b/src/sdl/hwsym_sdl.c @@ -102,6 +102,7 @@ void *hwSym(const char *funcName,void *handle) GETFUNC(DoScreenWipe); GETFUNC(DrawIntermissionBG); GETFUNC(MakeScreenTexture); + GETFUNC(RenderVhsEffect); GETFUNC(MakeScreenFinalTexture); GETFUNC(DrawScreenFinalTexture); diff --git a/src/sdl/i_video.cpp b/src/sdl/i_video.cpp index 074e8e52a..a41e6766b 100644 --- a/src/sdl/i_video.cpp +++ b/src/sdl/i_video.cpp @@ -2080,6 +2080,7 @@ void VID_StartupOpenGL(void) *(void**)&HWD.pfnDoScreenWipe = hwSym("DoScreenWipe",NULL); *(void**)&HWD.pfnDrawIntermissionBG=hwSym("DrawIntermissionBG",NULL); *(void**)&HWD.pfnMakeScreenTexture= hwSym("MakeScreenTexture",NULL); + *(void**)&HWD.pfnRenderVhsEffect = hwSym("RenderVhsEffect",NULL); *(void**)&HWD.pfnMakeScreenFinalTexture=hwSym("MakeScreenFinalTexture",NULL); *(void**)&HWD.pfnDrawScreenFinalTexture=hwSym("DrawScreenFinalTexture",NULL); diff --git a/src/v_video.c b/src/v_video.c index 9f53cb1de..b29dae81f 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -30,6 +30,7 @@ #include "m_misc.h" #include "m_random.h" #include "doomstat.h" +#include "r_fps.h" #ifdef HWRENDER #include "hardware/hw_glob.h" @@ -1421,11 +1422,31 @@ void V_DrawVhsEffect(boolean rewind) if (rewind) V_DrawVhsEffect(false); // experimentation - upbary -= FixedMul(vid.dupy * (rewind ? 3 : 1.8f), renderdeltatics); - downbary += FixedMul(vid.dupy * (rewind ? 2 : 1), renderdeltatics); + if (R_UsingFrameInterpolation()) // omg i fucking hate interp so much, its a bit smoother but still not great whatever, atleast like this shit wont completely go nuts when youre on high framerates + { + if (renderisnewtic) + { + upbary -= FixedMul(vid.dupy * (rewind ? 3 : 1.8f), 22937*3); + downbary += FixedMul(vid.dupy * (rewind ? 2 : 1), 22937*3); + } + } + else + { + upbary -= vid.dupy * (rewind ? 3 : 1.8f); + downbary += vid.dupy * (rewind ? 2 : 1); + } + if (upbary < -barsize) upbary = vid.height; if (downbary > vid.height) downbary = -barsize; +#ifdef HWRENDER + if ((rendermode == render_opengl)) + { + HWR_RenderVhsEffect(upbary, downbary, updistort, downdistort, barsize); + return; + } +#endif + for (y = 0; y < vid.height; y+=2) { thismapstart = normalmapstart; From 78751d96599d19b7b41564a08962fdb6bb4db4a5 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sun, 9 Feb 2025 11:44:19 -0500 Subject: [PATCH 046/117] Uncap input display --- src/f_finale.c | 25 +++++++++++++------------ src/k_hud.c | 21 +++++++++++---------- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index 82f85aedd..ea6efc94f 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -235,30 +235,31 @@ static void F_TitleBGScroll(INT32 scrollspeed) pat = W_CachePatchName("TITLEBG1", PU_CACHE); pat2 = W_CachePatchName("TITLEBG2", PU_CACHE); - w = vid.width / vid.dupx; + w = (vid.width / vid.dupx)<width); - anim2 = SHORT(pat2->width) - (((finalecount*scrollspeed)/16) % SHORT(pat2->width)); + // The scroll offset MUST be clamped before shifting by FRACBITS, or else it'll overflow in about 3 minutes + animtimer = ((((finalecount * scrollspeed) % (SHORT(pat->width)*16))<width)<width)*16))<width); + V_DrawFixedPatch(x, y, FRACUNIT, V_SNAPTOTOP|V_SNAPTOLEFT, pat, NULL); + x += SHORT(pat->width)<height); + y = (BASEVIDHEIGHT - SHORT(pat2->height))<width); + V_DrawFixedPatch(x, y, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTOLEFT, pat2, NULL); + x += SHORT(pat2->width)<= 20) V_DrawSmallScaledPatch(84, 87, 0, ttkart); else if (finalecount >= 10) - V_DrawSciencePatch((84<skincolor].ramp[5]; const INT32 accent2 = splitflags | skincolors[stplyr->skincolor].ramp[9]; ticcmd_t *cmd = &stplyr->cmd; @@ -4035,17 +4036,17 @@ static void K_drawInput(void) #define drawbutt(xoffs, butt, symb)\ if (!stplyr->exiting && (cmd->buttons & butt))\ {\ - offs = 2;\ + offs = 2*FRACUNIT;\ col = accent1;\ }\ else\ {\ offs = 0;\ col = accent2;\ - V_DrawFill(x+(xoffs), y+BUTTH, BUTTW-1, 2, splitflags|31);\ + V_DrawFill((x + xoffs*FRACUNIT)>>FRACBITS, (y + BUTTH*FRACUNIT)>>FRACBITS, BUTTW-1, 2, splitflags|31);\ }\ - V_DrawFill(x+(xoffs), y+offs, BUTTW-1, BUTTH, col);\ - V_DrawFixedPatch((x+1+(xoffs))<>FRACBITS, (y+offs)>>FRACBITS, BUTTW-1, BUTTH, col);\ + V_DrawFixedPatch(x + FRACUNIT + xoffs*FRACUNIT, y + offs + FRACUNIT, FRACUNIT, splitflags, fontv[TINY_FONT].font[symb-HU_FONTSTART], NULL) drawbutt(-2*BUTTW, BT_ACCELERATE, 'A'); drawbutt( -BUTTW, BT_BRAKE, 'B'); @@ -4057,7 +4058,7 @@ static void K_drawInput(void) #undef BUTTW #undef BUTTH - y -= 1; + y -= FRACUNIT; if (stplyr->exiting || !stplyr->cmd.turning) // no turn target = 0; @@ -4083,7 +4084,7 @@ static void K_drawInput(void) if (pn < 0) { splitflags |= V_FLIP; // right turn - x--; + x -= FRACUNIT; } target = abs(pn); @@ -4091,12 +4092,12 @@ static void K_drawInput(void) target = 4; if (!stplyr->skincolor) - V_DrawFixedPatch(x<skincolor, GTC_CACHE); - V_DrawFixedPatch(x< Date: Sun, 9 Feb 2025 11:48:52 -0500 Subject: [PATCH 047/117] uncap vhs effect both this and the last commit are from Saturn --- src/v_video.c | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/src/v_video.c b/src/v_video.c index b29dae81f..60d7e53b8 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -1402,7 +1402,7 @@ void V_DrawPatchFill(patch_t *pat) void V_DrawVhsEffect(boolean rewind) { - static fixed_t upbary = 100, downbary = 150; + static fixed_t upbary = 100*FRACUNIT, downbary = 150*FRACUNIT; UINT8 *buf = screens[0], *tmp = screens[4]; UINT16 y; @@ -1422,27 +1422,19 @@ void V_DrawVhsEffect(boolean rewind) if (rewind) V_DrawVhsEffect(false); // experimentation - if (R_UsingFrameInterpolation()) // omg i fucking hate interp so much, its a bit smoother but still not great whatever, atleast like this shit wont completely go nuts when youre on high framerates - { - if (renderisnewtic) - { - upbary -= FixedMul(vid.dupy * (rewind ? 3 : 1.8f), 22937*3); - downbary += FixedMul(vid.dupy * (rewind ? 2 : 1), 22937*3); - } - } - else - { - upbary -= vid.dupy * (rewind ? 3 : 1.8f); - downbary += vid.dupy * (rewind ? 2 : 1); - } + fixed_t frac = R_UsingFrameInterpolation() ? renderdeltatics : FRACUNIT; + upbary -= frac * (vid.dupy * (rewind ? 3 : 1.8f)); + downbary += frac * (vid.dupy * (rewind ? 2 : 1)); - if (upbary < -barsize) upbary = vid.height; - if (downbary > vid.height) downbary = -barsize; + if (upbary < -barsize*FRACUNIT) upbary = vid.height< vid.height<>FRACBITS, dby = downbary>>FRACBITS; #ifdef HWRENDER if ((rendermode == render_opengl)) { - HWR_RenderVhsEffect(upbary, downbary, updistort, downdistort, barsize); + HWR_RenderVhsEffect(uby, dby, updistort, downdistort, barsize); return; } #endif @@ -1452,15 +1444,15 @@ void V_DrawVhsEffect(boolean rewind) thismapstart = normalmapstart; offs = 0; - if (y >= upbary && y < upbary+barsize) + if (y >= uby && y < uby+barsize) { thismapstart -= (2<= downbary && y < downbary+barsize) + if (y >= dby && y < dby+barsize) { thismapstart -= (2< Date: Sun, 9 Feb 2025 11:58:06 -0500 Subject: [PATCH 048/117] Implement stplyrnum and refactor K_drawBattleFullscreen to use it Thanks Saturn and GHG as per usual --- src/k_hud.c | 15 +++++---------- src/p_enemy.c | 1 - src/p_local.h | 3 --- src/st_stuff.c | 5 +++++ src/st_stuff.h | 2 ++ 5 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/k_hud.c b/src/k_hud.c index 6cef04fb2..839222cb0 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -3767,9 +3767,7 @@ static void K_drawBattleFullscreen(void) if (r_splitscreen) { - if ((r_splitscreen == 1 && stplyr == &players[displayplayers[1]]) - || (r_splitscreen > 1 && (stplyr == &players[displayplayers[2]] - || (stplyr == &players[displayplayers[3]] && r_splitscreen > 2)))) + if ((splitscreen == 1 && stplyrnum == 1) || (splitscreen > 1 && stplyrnum & 2)) { y = 232-(stplyr->karthud[khud_cardanimation]/2); splitflags = V_SNAPTOBOTTOM; @@ -3781,8 +3779,7 @@ static void K_drawBattleFullscreen(void) { scale /= 2; - if (stplyr == &players[displayplayers[1]] - || (stplyr == &players[displayplayers[3]] && r_splitscreen > 2)) + if (stplyrnum & 1) x = 3*BASEVIDWIDTH/4; else x = BASEVIDWIDTH/4; @@ -3791,7 +3788,7 @@ static void K_drawBattleFullscreen(void) { if (stplyr->exiting) { - if (stplyr == &players[displayplayers[1]]) + if (stplyrnum & 1) x = BASEVIDWIDTH-96; else x = 96; @@ -3803,7 +3800,7 @@ static void K_drawBattleFullscreen(void) if (stplyr->exiting) { - if (stplyr == &players[displayplayers[0]]) + if (stplyrnum == 0) V_DrawFadeScreen(0xFF00, 16); if (stplyr->exiting < 6*TICRATE && !stplyr->spectator) { @@ -3837,9 +3834,7 @@ static void K_drawBattleFullscreen(void) { if (r_splitscreen > 1) ty = (BASEVIDHEIGHT/4)+33; - if ((r_splitscreen == 1 && stplyr == &players[displayplayers[1]]) - || (stplyr == &players[displayplayers[2]] && r_splitscreen > 1) - || (stplyr == &players[displayplayers[3]] && r_splitscreen > 2)) + if ((splitscreen == 1 && stplyrnum == 1) || (splitscreen > 1 && stplyrnum & 2)) ty += (BASEVIDHEIGHT/2); } else diff --git a/src/p_enemy.c b/src/p_enemy.c index 82cd7a726..1fb73e702 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -39,7 +39,6 @@ boolean LUA_CallAction(enum actionnum actionnum, mobj_t *actor); -player_t *stplyr; INT32 var1; INT32 var2; INT32 modulothing; diff --git a/src/p_local.h b/src/p_local.h index 2b89e602f..f91e1490b 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -370,9 +370,6 @@ void P_FlashPal(player_t *pl, UINT16 type, UINT16 duration); // P_ENEMY // -// main player in game -extern player_t *stplyr; // for splitscreen correct palette changes and overlay - // Is there a better place for these? extern INT32 var1; extern INT32 var2; diff --git a/src/st_stuff.c b/src/st_stuff.c index 28e0379cb..c83f3061c 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -83,6 +83,10 @@ static patch_t *hud_tv2; static patch_t *envelope; #endif +// current player for overlay drawing +player_t *stplyr; +UINT8 stplyrnum; + static huddrawlist_h luahuddrawlist_game[MAXSPLITSCREENPLAYERS]; static huddrawlist_h luahuddrawlist_titlecard; @@ -912,6 +916,7 @@ void ST_Drawer(void) for (i = 0; i <= r_splitscreen; i++) { stplyr = &players[displayplayers[i]]; + stplyrnum = i; R_SetViewContext(VIEWCONTEXT_PLAYER1 + i); R_InterpolateView(rendertimefrac); // to assist with object tracking ST_overlayDrawer(i); diff --git a/src/st_stuff.h b/src/st_stuff.h index 3cdf3a918..9efeaf406 100644 --- a/src/st_stuff.h +++ b/src/st_stuff.h @@ -81,6 +81,8 @@ boolean ST_SameTeam(player_t *a, player_t *b); extern boolean st_overlay; // sb overlay on or off when fullscreen extern INT32 st_palette; // 0 is default, any others are special palettes. +extern player_t *stplyr; // for splitscreen correct palette changes and overlay +extern UINT8 stplyrnum; extern UINT32 st_translucency; extern lumpnum_t st_borderpatchnum; From e694b38878b3c0c513ea8f8fc692052b65d14c11 Mon Sep 17 00:00:00 2001 From: hayaunderscore Date: Tue, 4 Jun 2024 19:37:27 +0800 Subject: [PATCH 049/117] Add lua hud interpolation by GenericHeroGuy. https://github.com/Indev450/SRB2Kart-Saturn/pull/130 --- src/lua_hud.h | 6 + src/lua_hudlib.c | 46 ++++++ src/lua_hudlib_drawlist.c | 333 +++++++++++++++++++++++++++++++------- src/st_stuff.c | 9 +- 4 files changed, 338 insertions(+), 56 deletions(-) diff --git a/src/lua_hud.h b/src/lua_hud.h index 20a6e6549..0c632b1fa 100644 --- a/src/lua_hud.h +++ b/src/lua_hud.h @@ -49,6 +49,12 @@ enum hud { extern boolean hud_running; +extern boolean hud_interpolate; // interpolation enabled +extern UINT8 hud_interptag; // current tag +extern UINT32 hud_interpcounter; // number of HUD hooks ran +extern boolean hud_interpstring; // string mode +extern boolean hud_interplatch; // string mode was toggled + boolean LUA_HudEnabled(enum hud option); void LUA_SetHudHook(int hook, huddrawlist_h list); diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 9130a61bd..99cc6d0ee 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -34,6 +34,13 @@ #define HUDONLY if (!hud_running) return luaL_error(L, "HUD rendering code should not be called outside of rendering hooks!"); boolean hud_running = false; + +boolean hud_interpolate = false; +UINT8 hud_interptag = 0; +UINT32 hud_interpcounter = 0; +boolean hud_interpstring = false; +boolean hud_interplatch = false; + static UINT8 hud_enabled[(hud_MAX/8)+1]; static UINT8 camnum = 1; @@ -1209,6 +1216,38 @@ static int libd_getDeltaTime(lua_State *L) return 1; } +static int libd_interpolate(lua_State *L) +{ + HUDONLY + + // do type checking even if interpolation is disabled + boolean newinterpolate; + UINT8 newtag; + + if (lua_isnumber(L, 1)) + { + newinterpolate = true; + newtag = luaL_checkinteger(L, 1); + } + else + { + newinterpolate = luaL_checkboolean(L, 1); + newtag = 0; + } + + hud_interpolate = newinterpolate; + hud_interptag = newtag; + + return 0; +} + +static int libd_interpLatch(lua_State *L) +{ + HUDONLY + hud_interpstring = hud_interplatch = luaL_checkboolean(L, 1); + return 0; +} + static luaL_Reg lib_draw[] = { // cache {"patchExists", libd_patchExists}, @@ -1249,6 +1288,9 @@ static luaL_Reg lib_draw[] = { {"drawOnMinimap", libd_drawOnMinimap}, {"userTransFlag", libd_getusertransflag}, {"getDeltaTime", libd_getDeltaTime}, + // interpolation + {"interpolate", libd_interpolate}, + {"interpLatch", libd_interpLatch}, {NULL, NULL} }; @@ -1341,6 +1383,10 @@ boolean LUA_HudEnabled(enum hud option) void LUA_SetHudHook(int hook, huddrawlist_h list) { lua_getref(gL, lib_draw_ref); + + // Update interpolation + hud_interpolate = hud_interpstring = hud_interplatch = false; + hud_interpcounter++; lua_pushlightuserdata(gL, list); lua_setfield(gL, LUA_REGISTRYINDEX, "HUD_DRAW_LIST"); diff --git a/src/lua_hudlib_drawlist.c b/src/lua_hudlib_drawlist.c index 7e5dbdc64..f25e477e6 100644 --- a/src/lua_hudlib_drawlist.c +++ b/src/lua_hudlib_drawlist.c @@ -12,11 +12,18 @@ #include "lua_hudlib_drawlist.h" +#include "lua_hud.h" +#include "blua/lstate.h" // shhhhhh +#include "lua_libs.h" + #include #include "v_video.h" #include "z_zone.h" +#include "r_main.h" +#include "r_fps.h" + enum drawitem_e { DI_Draw = 0, DI_DrawScaled, @@ -34,40 +41,50 @@ enum drawitem_e { // A single draw item with all possible arguments needed for a draw call. typedef struct drawitem_s { + UINT64 id; enum drawitem_e type; fixed_t x; fixed_t y; - fixed_t w; - fixed_t h; - INT32 c; - fixed_t scale; - fixed_t hscale; - fixed_t vscale; - patch_t *patch; - INT32 flags; - UINT16 basecolor; - UINT16 outlinecolor; + union { + INT32 flags; + INT32 c; + }; + union { + fixed_t scale; // drawScaled + fixed_t hscale; // drawStretched + fixed_t w; // drawFill + INT32 align; // drawString + INT32 num; // drawNum, drawPaddedNum, drawPingNum + UINT16 color; // fadeScreen + }; + union { + fixed_t vscale; // drawStretched + fixed_t h; // drawFill + INT32 digits; // drawPaddedNum + UINT8 strength; // fadeScreen + }; UINT8 *colormap; - UINT8 *basecolormap; - UINT8 *outlinecolormap; - fixed_t sx; - fixed_t sy; - INT32 num; - INT32 digits; - size_t stroffset; // offset into strbuf to get str - UINT16 color; - UINT8 strength; - INT32 align; - INT32 timer; - INT32 threshold; - boolean bossmode; + + union { // for title cards + boolean bossmode; + boolean p4; + INT32 timer; + INT32 threshold; + }; + // pointers (and size_t's) last, for potentially better packing + union { + patch_t *patch; + size_t stroffset; // offset into strbuf to get str + }; } drawitem_t; // The internal structure of a drawlist. struct huddrawlist_s { drawitem_t *items; - size_t items_capacity; size_t items_len; + drawitem_t *olditems; + size_t olditems_len; + size_t capacity; char *strbuf; size_t strbuf_capacity; size_t strbuf_len; @@ -92,8 +109,10 @@ huddrawlist_h LUA_HUD_CreateDrawList(void) drawlist = (huddrawlist_h) Z_Calloc(sizeof(struct huddrawlist_s), PU_STATIC, NULL); drawlist->items = NULL; - drawlist->items_capacity = 0; drawlist->items_len = 0; + drawlist->olditems = NULL; + drawlist->olditems_len = 0; + drawlist->capacity = 0; drawlist->strbuf = NULL; drawlist->strbuf_capacity = 0; drawlist->strbuf_len = 0; @@ -103,14 +122,14 @@ huddrawlist_h LUA_HUD_CreateDrawList(void) void LUA_HUD_ClearDrawList(huddrawlist_h list) { + // swap the old and new lists + void *tmp = list->olditems; + list->olditems = list->items; + list->items = tmp; + // rather than deallocate, we'll just save the existing allocation and empty // it out for reuse - - // this memset probably isn't necessary - if (list->items) - { - memset(list->items, 0, sizeof(drawitem_t) * list->items_capacity); - } + list->olditems_len = list->items_len; list->items_len = 0; @@ -129,6 +148,10 @@ void LUA_HUD_DestroyDrawList(huddrawlist_h list) { Z_Free(list->items); } + if (list->olditems) + { + Z_Free(list->olditems); + } if (list->strbuf) { Z_Free(list->strbuf); @@ -147,11 +170,11 @@ boolean LUA_HUD_IsDrawListValid(huddrawlist_h list) static size_t AllocateDrawItem(huddrawlist_h list) { if (!list) I_Error("can't allocate draw item: invalid list"); - if (list->items_capacity <= list->items_len + 1) + if (list->capacity <= list->items_len) { - if (list->items_capacity == 0) list->items_capacity = 128; - else list->items_capacity *= 2; - list->items = (drawitem_t *) Z_Realloc(list->items, sizeof(struct drawitem_s) * list->items_capacity, PU_STATIC, NULL); + list->capacity = list->capacity == 0 ? 128 : list->capacity * 2; + list->items = Z_Realloc(list->items, sizeof(struct drawitem_s) * list->capacity, PU_STATIC, NULL); + list->olditems = Z_Realloc(list->olditems, sizeof(struct drawitem_s) * list->capacity, PU_STATIC, NULL); } return list->items_len++; @@ -181,6 +204,136 @@ static size_t CopyString(huddrawlist_h list, const char* str) } } +static void CalcStringCoords(drawitem_t *item, const char *string) +{ + if (!(item->flags & V_NOSCALESTART)) + { + INT32 dupx = vid.dupx; + INT32 dupy = vid.dupy; + + item->flags |= V_NOSCALESTART; + + if (item->flags & V_SCALEPATCHMASK) switch ((item->flags & V_SCALEPATCHMASK) >> V_SCALEPATCHSHIFT) + { + case 1: // V_NOSCALEPATCH + dupx = dupy = 1; + break; + case 2: // V_SMALLSCALEPATCH + dupx = vid.smalldupx; + dupy = vid.smalldupy; + break; + case 3: // V_MEDSCALEPATCH + dupx = vid.meddupx; + dupy = vid.meddupy; + break; + default: + break; + } + + // only use one dup, to avoid stretching (har har) + dupx = dupy = (dupx < dupy ? dupx : dupy); + + INT32 x = item->x * dupx; + INT32 y = item->y * dupy; + + if (item->flags & V_SPLITSCREEN) + y += (BASEVIDHEIGHT * (dupy - 1))/2; + + if ((item->flags & V_SPLITSCREEN) && r_splitscreen > 1) + x += (BASEVIDWIDTH * (dupx - 1))/2; + + if (vid.width != BASEVIDWIDTH * dupx) + { + // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx, + // so center this imaginary screen + if ((item->flags & (V_SPLITSCREEN|V_SNAPTOLEFT)) == (V_SPLITSCREEN|V_SNAPTOLEFT)) + x += (vid.width/2 - (BASEVIDWIDTH/2 * dupx)); + else if (item->flags & V_SNAPTORIGHT) + x += (vid.width - (BASEVIDWIDTH * dupx)); + else if (!(item->flags & V_SNAPTOLEFT)) + x += (vid.width - (BASEVIDWIDTH * dupx)) / 2; + } + if (vid.height != BASEVIDHEIGHT * dupy) + { + // same thing here + if ((item->flags & (V_SPLITSCREEN|V_SNAPTOTOP)) == (V_SPLITSCREEN|V_SNAPTOTOP)) + y += (vid.height/2 - (BASEVIDHEIGHT/2 * dupy)); + else if (item->flags & V_SNAPTOBOTTOM) + y += (vid.height - (BASEVIDHEIGHT * dupy)); + else if (!(item->flags & V_SNAPTOTOP)) + y += (vid.height - (BASEVIDHEIGHT * dupy)) / 2; + } + + item->x = x; + item->y = y; + } +} + +static void CalcFillCoords(drawitem_t *item) +{ + if (!(item->flags & V_NOSCALESTART)) + { + INT32 dupx = vid.dupx; + INT32 dupy = vid.dupy; + INT32 x = item->x * dupx; + INT32 y = item->y * dupy; + INT32 c = item->c; + + item->flags |= V_NOSCALESTART; + item->w *= dupx; + item->h *= dupy; + + // Center it if necessary + if (vid.width != BASEVIDWIDTH * dupx) + { + // dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx, + // so center this imaginary screen + if (c & V_SNAPTORIGHT) + x += (vid.width - (BASEVIDWIDTH * dupx)); + else if (!(c & V_SNAPTOLEFT)) + x += (vid.width - (BASEVIDWIDTH * dupx)) / 2; + } + if (vid.height != BASEVIDHEIGHT * dupy) + { + // same thing here + if (c & V_SNAPTOBOTTOM) + y += (vid.height - (BASEVIDHEIGHT * dupy)); + else if (!(c & V_SNAPTOTOP)) + y += (vid.height - (BASEVIDHEIGHT * dupy)) / 2; + } + if (c & V_SPLITSCREEN) + y += (BASEVIDHEIGHT * dupy)/2; + if ((c & V_SPLITSCREEN) && r_splitscreen > 1) + x += (BASEVIDWIDTH * dupx)/2; + + item->x = x; + item->y = y; + } +} + +#define INTERP_LATCH 1 +#define INTERP_STRING 2 +#define INTERP_FLAGMASK 0x3 + +static UINT64 GetItemId(void) +{ + if (!hud_interpolate) + return 0; + + // leave bits 0 and 1 free for the string mode + UINT64 id = ((uintptr_t)gL->savedpc << 32) | (hud_interpcounter << 10) | (hud_interptag << 2); + + if (hud_interplatch) + { + id |= INTERP_LATCH; + hud_interplatch = false; + } + if (hud_interpstring) + id |= INTERP_STRING; + + return id; +} + void LUA_HUD_AddDraw( huddrawlist_h list, INT32 x, @@ -192,9 +345,10 @@ void LUA_HUD_AddDraw( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; + item->id = GetItemId(); item->type = DI_Draw; - item->x = x; - item->y = y; + item->x = x << FRACBITS; + item->y = y << FRACBITS; item->patch = patch; item->flags = flags; item->colormap = colormap; @@ -212,6 +366,7 @@ void LUA_HUD_AddDrawScaled( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; + item->id = GetItemId(); item->type = DI_DrawScaled; item->x = x; item->y = y; @@ -234,6 +389,7 @@ void LUA_HUD_AddDrawStretched( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; + item->id = GetItemId(); item->type = DI_DrawStretched; item->x = x; item->y = y; @@ -254,11 +410,13 @@ void LUA_HUD_AddDrawNum( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; + item->id = GetItemId(); item->type = DI_DrawNum; item->x = x; item->y = y; item->num = num; item->flags = flags; + // CalcStringCoords(item, NULL); } void LUA_HUD_AddDrawPaddedNum( @@ -272,12 +430,14 @@ void LUA_HUD_AddDrawPaddedNum( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; + item->id = GetItemId(); item->type = DI_DrawPaddedNum; item->x = x; item->y = y; item->num = num; item->digits = digits; item->flags = flags; + // CalcStringCoords(item, NULL); } void LUA_HUD_AddDrawPingNum( @@ -291,12 +451,14 @@ void LUA_HUD_AddDrawPingNum( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; + item->id = GetItemId(); item->type = DI_DrawPingNum; item->x = x; item->y = y; item->flags = flags; item->num = num; item->colormap = colormap; + // CalcStringCoords(item, NULL); } void LUA_HUD_AddDrawFill( @@ -310,12 +472,14 @@ void LUA_HUD_AddDrawFill( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; + item->id = GetItemId(); item->type = DI_DrawFill; item->x = x; item->y = y; item->w = w; item->h = h; item->c = c; + // CalcFillCoords(item); } void LUA_HUD_AddDrawString( @@ -329,12 +493,14 @@ void LUA_HUD_AddDrawString( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; + item->id = GetItemId(); item->type = DI_DrawString; item->x = x; item->y = y; item->stroffset = CopyString(list, str); item->flags = flags; item->align = align; + // CalcStringCoords(item, str); } void LUA_HUD_AddFadeScreen( @@ -363,6 +529,7 @@ void LUA_HUD_AddDrawTitleCardString( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; + item->id = GetItemId(); item->type = DI_DrawTitleCardString; item->x = x; item->y = y; @@ -383,16 +550,23 @@ void LUA_HUD_AddDrawKartString( { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; + item->id = GetItemId(); item->type = DI_DrawKartString; item->x = x; item->y = y; item->stroffset = CopyString(list, str); item->flags = flags; + // CalcStringCoords(item, str); } void LUA_HUD_DrawList(huddrawlist_h list) { size_t i; + size_t j = 0; + fixed_t frac = R_UsingFrameInterpolation() ? rendertimefrac : FRACUNIT; + fixed_t lerpx = 0, lerpy = 0; + drawitem_t *latchitem = NULL; + drawitem_t *oldlatchitem = NULL; if (!list) I_Error("HUD drawlist invalid"); if (list->items_len <= 0) return; @@ -401,63 +575,112 @@ void LUA_HUD_DrawList(huddrawlist_h list) for (i = 0; i < list->items_len; i++) { drawitem_t *item = &list->items[i]; + drawitem_t *olditem = NULL; const char *itemstr = &list->strbuf[item->stroffset]; + + if (item->id != 0) + { + // find the old one too + // this is kinda cursed... we need to check every item + // but stop when the first-checked item is reached again + size_t stop = j; + do + { + if (j == list->olditems_len) + { + j = 0; + continue; + } + drawitem_t *old = &list->olditems[j++]; + if ((old->id & ~INTERP_FLAGMASK) == (item->id & ~INTERP_FLAGMASK)) + { + // gotcha! + olditem = old; + if (item->id & INTERP_LATCH) + { + lerpx = FixedMul(frac, item->x - olditem->x); + lerpy = FixedMul(frac, item->y - olditem->y); + latchitem = item; + oldlatchitem = olditem; + } + else if (!(item->id & INTERP_STRING)) + { + lerpx = FixedMul(frac, item->x - olditem->x); + lerpy = FixedMul(frac, item->y - olditem->y); + latchitem = NULL; + } + break; + } + } + while (j != stop); + } + else + { + lerpx = lerpy = 0; + latchitem = NULL; + } + + #define LERP(it) (olditem ? olditem->it + FixedMul(frac, item->it - olditem->it) : item->it) + + // half of this could be done when the coordinates are latched... zzzzzz + #define LERPS(it) (latchitem ? ((latchitem->it + (item->it - latchitem->it)) - (latchitem->it - oldlatchitem->it)) + lerp##it : (olditem ? olditem->it + lerp##it : item->it)) + //define LERPS(it) (olditem ? (latchitem ? (latchitem->it + (item->it - latchitem->it)) - (latchitem->it - oldlatchitem->it) : olditem->it) + lerp##it : item->it) switch (item->type) { case DI_Draw: - V_DrawFixedPatch(item->x<y<flags, item->patch, item->colormap); + V_DrawFixedPatch(LERPS(x), LERPS(y), FRACUNIT, item->flags, item->patch, item->colormap); break; case DI_DrawScaled: - V_DrawFixedPatch(item->x, item->y, item->scale, item->flags, item->patch, item->colormap); + V_DrawFixedPatch(LERPS(x), LERPS(y), LERP(scale), item->flags, item->patch, item->colormap); break; case DI_DrawStretched: - V_DrawStretchyFixedPatch(item->x, item->y, item->hscale, item->vscale, item->flags, item->patch, item->colormap); + V_DrawStretchyFixedPatch(LERPS(x), LERPS(y), LERP(hscale), LERP(vscale), item->flags, item->patch, item->colormap); break; case DI_DrawNum: - V_DrawTallNum(item->x, item->y, item->flags, item->num); + V_DrawTallNum(LERPS(x), LERPS(y), item->flags, item->num); break; case DI_DrawPaddedNum: - V_DrawPaddedTallNum(item->x, item->y, item->flags, item->num, item->digits); + V_DrawPaddedTallNum(LERPS(x), LERPS(y), item->flags, item->num, item->digits); break; case DI_DrawPingNum: - V_DrawPingNum(item->x, item->y, item->flags, item->num, item->colormap); + V_DrawPingNum(LERPS(x), LERPS(y), item->flags, item->num, item->colormap); break; case DI_DrawFill: - V_DrawFill(item->x, item->y, item->w, item->h, item->c); + V_DrawFill(LERPS(x), LERPS(y), LERP(w), LERP(h), item->c); break; case DI_DrawString: switch(item->align) { // hu_font case align_left: - V_DrawString(item->x, item->y, item->flags, itemstr); + V_DrawString(LERPS(x), LERPS(y), item->flags, itemstr); break; case align_center: - V_DrawCenteredString(item->x, item->y, item->flags, itemstr); + V_DrawCenteredString(LERPS(x), LERPS(y), item->flags, itemstr); break; case align_right: - V_DrawRightAlignedString(item->x, item->y, item->flags, itemstr); + V_DrawRightAlignedString(LERPS(x), LERPS(y), item->flags, itemstr); break; // hu_font, 0.5x scale case align_small: - V_DrawSmallString(item->x, item->y, item->flags, itemstr); + V_DrawSmallString(LERPS(x), LERPS(y), item->flags, itemstr); break; case align_smallcenter: - V_DrawCenteredSmallString(item->x, item->y, item->flags, itemstr); + V_DrawCenteredSmallString(LERPS(x), LERPS(y), item->flags, itemstr); break; case align_smallright: - V_DrawRightAlignedSmallString(item->x, item->y, item->flags, itemstr); + V_DrawRightAlignedSmallString(LERPS(x), LERPS(y), item->flags, itemstr); break; // tny_font case align_thin: - V_DrawThinString(item->x, item->y, item->flags, itemstr); + V_DrawThinString(LERPS(x), LERPS(y), item->flags, itemstr); break; case align_thincenter: - V_DrawCenteredThinString(item->x, item->y, item->flags, itemstr); + V_DrawCenteredThinString(LERPS(x), LERPS(y), item->flags, itemstr); break; case align_thinright: - V_DrawRightAlignedThinString(item->x, item->y, item->flags, itemstr); + V_DrawRightAlignedThinString(LERPS(x), LERPS(y), item->flags, itemstr); break; } break; @@ -465,10 +688,10 @@ void LUA_HUD_DrawList(huddrawlist_h list) V_DrawFadeScreen(item->color, item->strength); break; case DI_DrawTitleCardString: - V_DrawTitleCardString(item->x, item->y, itemstr, item->flags, item->bossmode, item->timer, item->threshold); + V_DrawTitleCardString(LERPS(x), LERPS(y), itemstr, item->flags, item->bossmode, item->timer, item->threshold); break; case DI_DrawKartString: - V_DrawKartString(item->x, item->y, item->flags, itemstr); + V_DrawKartString(LERPS(x), LERPS(y), item->flags, itemstr); break; default: I_Error("can't draw draw list item: invalid draw list item type"); diff --git a/src/st_stuff.c b/src/st_stuff.c index c83f3061c..6e5079962 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -733,7 +733,6 @@ static void ST_overlayDrawer(UINT8 playernum) if (renderisnewtic) { - LUA_HUD_ClearDrawList(luahuddrawlist_game[playernum]); LUA_HookHUD(luahuddrawlist_game[playernum], HUD_HOOK(game)); } LUA_HUD_DrawList(luahuddrawlist_game[playernum]); @@ -912,6 +911,11 @@ void ST_Drawer(void) if (st_overlay) { UINT8 i; + if (renderisnewtic) + { + for (i = 0; i <= r_splitscreen; i++) + LUA_HUD_ClearDrawList(luahuddrawlist_game[i]); + } // No deadview! for (i = 0; i <= r_splitscreen; i++) { @@ -922,6 +926,9 @@ void ST_Drawer(void) ST_overlayDrawer(i); } + for (i = 0; i <= r_splitscreen; i++) + LUA_HUD_DrawList(luahuddrawlist_game[i]); + // draw Midnight Channel's overlay ontop if (mapheaderinfo[gamemap-1]->typeoflevel & TOL_TV) // Very specific Midnight Channel stuff. ST_MayonakaStatic(); From 71a874f58214ada80464dbf5eeeb77f8c8650275 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sun, 9 Feb 2025 12:27:04 -0500 Subject: [PATCH 050/117] Add R_PointOnSideFast and R_PointInSubsectorFast and use it to optimize some stuff --- src/d_clisrv.c | 2 +- src/hardware/hw_main.c | 2 +- src/p_mobj.c | 14 +++++++------- src/p_setup.c | 4 ++-- src/p_user.c | 4 ++-- src/r_bsp.cpp | 2 +- src/r_fps.c | 2 +- src/r_main.cpp | 2 +- src/r_main.h | 21 +++++++++++++++++++++ src/s_sound.c | 4 ++-- 10 files changed, 39 insertions(+), 18 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index e654512c0..c8041d431 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1358,7 +1358,7 @@ static void CL_ReloadReceivedSavegame(void) for (i = 0; i < MAXSPLITSCREENPLAYERS; i++) { - camera[i].subsector = R_PointInSubsector(camera[i].x, camera[i].y); + camera[i].subsector = R_PointInSubsectorFast(camera[i].x, camera[i].y); } cl_redownloadinggamestate = false; diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 7d8efb29e..4e8261e68 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -3076,7 +3076,7 @@ static void HWR_RenderBSPNode(INT32 bspnum) bsp = &nodes[bspnum]; // Decide which side the view point is on. - side = R_PointOnSide(viewx, viewy, bsp); + side = R_PointOnSideFast(viewx, viewy, bsp); // Recursively divide front space. HWR_RenderBSPNode(bsp->children[side]); diff --git a/src/p_mobj.c b/src/p_mobj.c index 566600230..cfc99ad13 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -3660,7 +3660,7 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled } } - thiscam->subsector = R_PointInSubsector(thiscam->x, thiscam->y); + thiscam->subsector = R_PointInSubsectorFast(thiscam->x, thiscam->y); thiscam->floorz = tm.floorz; thiscam->ceilingz = tm.ceilingz; @@ -10372,12 +10372,12 @@ void P_PrecipitationEffects(void) for (y = yl; y <= yh; y += RADIUSSTEP) for (x = xl; x <= xh; x += RADIUSSTEP) { - if (R_PointInSubsector((fixed_t)x, (fixed_t)y)->sector->ceilingpic == skyflatnum) // Found the outdoors! - { - newdist = S_CalculateSoundDistance(players[g_localplayers[0]].mo->x, players[g_localplayers[0]].mo->y, 0, (fixed_t)x, (fixed_t)y, 0); - if (newdist < closedist) - closedist = newdist; - } + if (R_PointInSubsectorFast((fixed_t)x, (fixed_t)y)->sector->ceilingpic != skyflatnum) // Found the outdoors! + continue; + + newdist = S_CalculateSoundDistance(players[g_localplayers[0]].mo->x, players[g_localplayers[0]].mo->y, 0, (fixed_t)x, (fixed_t)y, 0); + if (newdist < closedist) + closedist = newdist; } #undef RADIUSSTEP diff --git a/src/p_setup.c b/src/p_setup.c index 4f7737b44..094e35602 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -8065,7 +8065,7 @@ static void P_SetupCamera(UINT8 pnum, camera_t *cam) cam->y = players[pnum].mo->y; cam->z = players[pnum].mo->z; cam->angle = players[pnum].mo->angle; - cam->subsector = R_PointInSubsector(cam->x, cam->y); // make sure camera has a subsector set -- Monster Iestyn (12/11/18) + cam->subsector = R_PointInSubsectorFast(cam->x, cam->y); // make sure camera has a subsector set -- Monster Iestyn (12/11/18) } else { @@ -8082,7 +8082,7 @@ static void P_SetupCamera(UINT8 pnum, camera_t *cam) cam->y = thing->y; cam->z = thing->z; cam->angle = FixedAngle((fixed_t)thing->angle << FRACBITS); - cam->subsector = R_PointInSubsector(cam->x, cam->y); // make sure camera has a subsector set -- Monster Iestyn (12/11/18) + cam->subsector = R_PointInSubsectorFast(cam->x, cam->y); // make sure camera has a subsector set -- Monster Iestyn (12/11/18) } } } diff --git a/src/p_user.c b/src/p_user.c index 99443976b..beab7153d 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2941,7 +2941,7 @@ void P_DemoCameraMovement(camera_t *cam) democam.soundmobj = awayviewmobj_hack; // update subsector to avoid crashes; - cam->subsector = R_PointInSubsector(cam->x, cam->y); + cam->subsector = R_PointInSubsectorFast(cam->x, cam->y); } void P_ResetCamera(player_t *player, camera_t *thiscam) @@ -2975,7 +2975,7 @@ void P_ResetCamera(player_t *player, camera_t *thiscam) thiscam->aiming = 0; thiscam->relativex = 0; - thiscam->subsector = R_PointInSubsector(thiscam->x,thiscam->y); + thiscam->subsector = R_PointInSubsectorFast(thiscam->x,thiscam->y); thiscam->radius = 20*FRACUNIT; thiscam->height = 16*FRACUNIT; diff --git a/src/r_bsp.cpp b/src/r_bsp.cpp index ccac34d31..2a93c5d92 100644 --- a/src/r_bsp.cpp +++ b/src/r_bsp.cpp @@ -1453,7 +1453,7 @@ void R_RenderBSPNode(INT32 bspnum) bsp = &nodes[bspnum]; // Decide which side the view point is on. - side = R_PointOnSide(viewx, viewy, bsp); + side = R_PointOnSideFast(viewx, viewy, bsp); // Recursively divide front space. R_RenderBSPNode(bsp->children[side]); diff --git a/src/r_fps.c b/src/r_fps.c index dc894dd5f..a60adf520 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -184,7 +184,7 @@ void R_InterpolateView(fixed_t frac) viewcos = FINECOSINE(viewangle>>ANGLETOFINESHIFT); viewplayer = newview->player; - viewsector = R_PointInSubsector(viewx, viewy)->sector; + viewsector = R_PointInSubsectorFast(viewx, viewy)->sector; R_SetupFreelook(newview->player, newview->sky); } diff --git a/src/r_main.cpp b/src/r_main.cpp index bb628c543..a80b17f2e 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -1427,7 +1427,7 @@ static void R_PortalFrame(portal_t *portal) { portalclipline = NULL; portalcullsector = NULL; - viewsector = R_PointInSubsector(viewx, viewy)->sector; + viewsector = R_PointInSubsectorFast(viewx, viewy)->sector; } } diff --git a/src/r_main.h b/src/r_main.h index b23bdff06..fbf3484f2 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -74,6 +74,15 @@ extern lighttable_t *zlight[LIGHTLEVELS][MAXLIGHTZ]; #define R_PointOnSide(x,y,node) udmf ? R_PointOnSideUDMF(x,y,node) : R_PointOnSideKart(x,y,node) INT32 R_PointOnSideUDMF(fixed_t x, fixed_t y, const node_t *node); INT32 R_PointOnSideKart(fixed_t x, fixed_t y, const node_t *node); + +// This is not as accurate +// SHOULD NOT BE USED FOR ANYTHING GAMEPLAY RELATED!! +FUNCINLINE static ATTRINLINE INT32 R_PointOnSideFast(fixed_t x, fixed_t y, const node_t *node) +{ + // use cross product to determine side quickly + return ((INT64)y - node->y) * node->dx - ((INT64)x - node->x) * node->dy > 0; +} + INT32 R_PointOnSegSide(fixed_t x, fixed_t y, const seg_t *line); #define R_PointToAngle(x, y) R_PointToAngle2(viewx, viewy, x, y) angle_t R_PointToAnglePlayer(player_t *player, fixed_t x, fixed_t y); @@ -86,6 +95,18 @@ fixed_t R_ScaleFromGlobalAngle(angle_t visangle); subsector_t *R_PointInSubsector(fixed_t x, fixed_t y); subsector_t *R_PointInSubsectorOrNull(fixed_t x, fixed_t y); +// uses R_PointOnSideFast +// SHOULD NOT BE USED FOR ANYTHING GAMEPLAY RELATED!! +FUNCINLINE static ATTRINLINE subsector_t *R_PointInSubsectorFast(fixed_t x, fixed_t y) +{ + size_t nodenum = numnodes-1; + + while (!(nodenum & NF_SUBSECTOR)) + nodenum = nodes[nodenum].children[R_PointOnSideFast(x, y, nodes+nodenum)]; + + return &subsectors[nodenum & ~NF_SUBSECTOR]; +} + boolean R_DoCulling(line_t *cullheight, line_t *viewcullheight, fixed_t vz, fixed_t bottomh, fixed_t toph); void R_GetRenderBlockMapDimensions(fixed_t drawdist, INT32 *xl, INT32 *xh, INT32 *yl, INT32 *yh); diff --git a/src/s_sound.c b/src/s_sound.c index 215786b0d..8feb3a3eb 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -1100,7 +1100,7 @@ boolean S_AdjustSoundParams(const mobj_t *listener, const mobj_t *source, INT32 { fixed_t x, y, yl, yh, xl, xh, newdist; - if (R_PointInSubsector(listensource.x, listensource.y)->sector->ceilingpic == skyflatnum) + if (R_PointInSubsectorFast(listensource.x, listensource.y)->sector->ceilingpic == skyflatnum) approx_dist = 0; else { @@ -1113,7 +1113,7 @@ boolean S_AdjustSoundParams(const mobj_t *listener, const mobj_t *source, INT32 for (y = yl; y <= yh; y += FRACUNIT*64) for (x = xl; x <= xh; x += FRACUNIT*64) { - if (R_PointInSubsector(x, y)->sector->ceilingpic == skyflatnum) + if (R_PointInSubsectorFast(x, y)->sector->ceilingpic == skyflatnum) { // Found the outdoors! newdist = S_CalculateSoundDistance(listensource.x, listensource.y, 0, x, y, 0); From d060d3f659afaa6e910947ff60131e490223e3cf Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sun, 9 Feb 2025 12:32:30 -0500 Subject: [PATCH 051/117] Use Windows own high resolution timer for timing things instead of the SDL timer --- src/i_time.c | 9 +++++++++ src/sdl/i_system.cpp | 38 +++++++++++++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/i_time.c b/src/i_time.c index c1cc9dfd4..5cafab041 100644 --- a/src/i_time.c +++ b/src/i_time.c @@ -34,7 +34,11 @@ static double tictimer; // May be incorrect for other platforms, but we don't currently have a way to // query the scheduler granularity. SDL will do what's needed to make this as // low as possible though. +#if defined(_WIN32) +#define MIN_SLEEP_DURATION_MS 1.6 +#else #define MIN_SLEEP_DURATION_MS 2.1 +#endif tic_t I_GetTime(void) { @@ -113,7 +117,12 @@ void I_SleepDuration(precise_t duration) // hard sleep function. if (sleepvalue > 0 && (dest - cur) > delaygranularity) { +#if defined(_WIN32) + DWORD sleepDuration = (DWORD)min((INT64)(dest - cur), sleepvalue); + SleepEx(sleepDuration, TRUE); +#else I_Sleep(sleepvalue); +#endif } // Otherwise, this is a spinloop. diff --git a/src/sdl/i_system.cpp b/src/sdl/i_system.cpp index 0228865e2..beac544be 100644 --- a/src/sdl/i_system.cpp +++ b/src/sdl/i_system.cpp @@ -1751,12 +1751,24 @@ static Uint64 timer_frequency; precise_t I_GetPreciseTime(void) { +#if defined(_WIN32) + LARGE_INTEGER counter; + QueryPerformanceCounter(&counter); + return counter.QuadPart; +#else return SDL_GetPerformanceCounter(); +#endif } UINT64 I_GetPrecisePrecision(void) { +#if defined(_WIN32) + LARGE_INTEGER frequency; + QueryPerformanceFrequency(&frequency); + return frequency.QuadPart; +#else return SDL_GetPerformanceFrequency(); +#endif } static UINT32 frame_rate; @@ -1784,13 +1796,23 @@ static void I_InitFrameTime(const UINT64 now, const UINT32 cap) double I_GetFrameTime(void) { +#if defined(_WIN32) + LARGE_INTEGER now; + QueryPerformanceCounter(&now); + const UINT64 nowValue = now.QuadPart; +#else const UINT64 now = SDL_GetPerformanceCounter(); +#endif const UINT32 cap = R_GetFramerateCap(); if (cap != frame_rate) { // Maybe do this in a OnChange function for cv_fpscap? +#if defined(_WIN32) + I_InitFrameTime(nowValue, cap); +#else I_InitFrameTime(now, cap); +#endif } if (frame_rate == 0) @@ -1800,10 +1822,18 @@ double I_GetFrameTime(void) } else { +#if defined(_WIN32) + elapsed_frames += (nowValue - frame_epoch) / frame_frequency; +#else elapsed_frames += (now - frame_epoch) / frame_frequency; +#endif } - frame_epoch = now; // moving epoch +#if defined(_WIN32) + frame_epoch = nowValue; // moving epoch +#else + frame_epoch = now; // moving epoch +#endif return elapsed_frames; } @@ -1812,7 +1842,13 @@ double I_GetFrameTime(void) // void I_StartupTimer(void) { +#if defined(_WIN32) + LARGE_INTEGER frequency; + QueryPerformanceFrequency(&frequency); + timer_frequency = frequency.QuadPart; +#else timer_frequency = SDL_GetPerformanceFrequency(); +#endif I_InitFrameTime(0, R_GetFramerateCap()); elapsed_frames = 0.0; From 327e1e2f13753b513d84122b2f8bf8b8188cae57 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sun, 9 Feb 2025 12:43:00 -0500 Subject: [PATCH 052/117] Addfile per drag and drop --- src/sdl/i_video.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/sdl/i_video.cpp b/src/sdl/i_video.cpp index a41e6766b..0a614d3bc 100644 --- a/src/sdl/i_video.cpp +++ b/src/sdl/i_video.cpp @@ -60,6 +60,7 @@ #endif #include "../doomstat.h" +#include "../p_setup.h" #include "../i_system.h" #include "../v_video.h" #include "../m_argv.h" @@ -999,6 +1000,7 @@ static void Impl_HandleControllerButtonEvent(SDL_ControllerButtonEvent evt, Uint void I_GetEvent(void) { SDL_Event evt; + char* dropped_filedir; // We only want the first motion event, // otherwise we'll end up catching the warp back to center. @@ -1187,6 +1189,11 @@ void I_GetEvent(void) if (currentMenu == &OP_JoystickSetDef) M_SetupJoystickMenu(0); break; + case SDL_DROPFILE: + dropped_filedir = evt.drop.file; + P_AddWadFile(dropped_filedir); + SDL_free(dropped_filedir); // Free dropped_filedir memory + break; case SDL_QUIT: LUA_HookBool(true, HOOK(GameQuit)); I_Quit(); From 90bcbd99440e675edd58655d160d15ce417175fc Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sun, 9 Feb 2025 12:47:02 -0500 Subject: [PATCH 053/117] Sdldraganddrop utf8 on windows https://github.com/Indev450/SRB2Kart-Saturn/pull/60/ --- src/sdl/i_video.cpp | 2 +- src/w_wad.c | 38 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/sdl/i_video.cpp b/src/sdl/i_video.cpp index 0a614d3bc..19ece061e 100644 --- a/src/sdl/i_video.cpp +++ b/src/sdl/i_video.cpp @@ -1191,7 +1191,7 @@ void I_GetEvent(void) break; case SDL_DROPFILE: dropped_filedir = evt.drop.file; - P_AddWadFile(dropped_filedir); + P_AddWadFile(dropped_filedir, WC_AUTO); SDL_free(dropped_filedir); // Free dropped_filedir memory break; case SDL_QUIT: diff --git a/src/w_wad.c b/src/w_wad.c index dc8927d96..044fb1e35 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -149,6 +149,40 @@ void W_Shutdown(void) static char filenamebuf[MAX_WADPATH]; +// This #if is copied from filesrch.c, so not sure if it is 100% suitable for +// this +#if defined (_WIN32) && !defined (_XBOX) +//#define WIN32_LEAN_AND_MEAN +#define RPC_NO_WINDOWS_H +#include + +// Windows can't open utf-8 path so it must be converted to utf-16 +FILE* fopen_utf8(const char* filename, const char* mode) +{ + static const int MY_PATH_MAX = 2048; + WCHAR nameW[MY_PATH_MAX]; + memset(nameW, 0, sizeof(WCHAR)*MY_PATH_MAX); + WCHAR modeW[16]; + memset(modeW, 0, sizeof(WCHAR)*16); + // the following function converts the UTF-8 filename to UTF-16 (WCHAR) nameW + int len = MultiByteToWideChar(CP_UTF8, 0, filename, -1, nameW, MY_PATH_MAX); + if(len > 0 && MultiByteToWideChar(CP_UTF8, 0, mode, -1, modeW, 16) > 0) + { + // using _wfopen_s() shuts up MSVC's complaints + // about _wfopen() being unsafe.. + FILE* ret = NULL; + if(_wfopen_s(&ret, nameW, modeW) == 0) + return ret; + } + return NULL; +} + +#else + +#define fopen_utf8 fopen + +#endif + // W_OpenWadFile // Helper function for opening the WAD file. // Returns the FILE * handle for the file, or NULL if not found or could not be opened @@ -169,7 +203,7 @@ FILE *W_OpenWadFile(const char **filename, boolean useerrors) } // open wad file - if ((handle = fopen(*filename, "rb")) == NULL) + if ((handle = fopen_utf8(*filename, "rb")) == NULL) { // If we failed to load the file with the path as specified by // the user, strip the directories and search for the file. @@ -179,7 +213,7 @@ FILE *W_OpenWadFile(const char **filename, boolean useerrors) // in filenamebuf == *filename. if (findfile(filenamebuf, NULL, true)) { - if ((handle = fopen(*filename, "rb")) == NULL) + if ((handle = fopen_utf8(*filename, "rb")) == NULL) { if (useerrors) CONS_Alert(CONS_ERROR, M_GetText("Can't open %s\n"), *filename); From cf2bde62e3f245a110880470378656494f77d947 Mon Sep 17 00:00:00 2001 From: Indev Date: Mon, 11 Sep 2023 13:01:29 +0300 Subject: [PATCH 054/117] Don't init discord rich presence untill discordrp is set to On Haven't tested this since i'm on linux and the feature looks like it is windows only --- src/discord.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/discord.c b/src/discord.c index c26cc6fca..96d922a0b 100644 --- a/src/discord.c +++ b/src/discord.c @@ -47,6 +47,8 @@ discordRequest_t *discordRequestList = NULL; static char self_ip[IP_SIZE]; +boolean drpc_init = false; + /*-------------------------------------------------- static char *DRPC_XORIPString(const char *input) @@ -315,6 +317,9 @@ void DRPC_RemoveRequest(discordRequest_t *removeRequest) --------------------------------------------------*/ void DRPC_Init(void) { + if (drpc_init || !cv_discordrp.value) return; + + drpc_init = true; DiscordEventHandlers handlers; memset(&handlers, 0, sizeof(handlers)); @@ -403,6 +408,10 @@ static void DRPC_EmptyRequests(void) --------------------------------------------------*/ void DRPC_UpdatePresence(void) { + if (!cv_discordrp.value) return; + + if (!drpc_init) DRPC_Init(); + char detailstr[48+1]; char mapimg[8+1]; From e5505dd171cb5541c08b8e16b316441d99c91032 Mon Sep 17 00:00:00 2001 From: Indev Date: Mon, 11 Sep 2023 13:17:12 +0300 Subject: [PATCH 055/117] Shutdown DiscordRPC when discordrp cvar is set to Off --- src/discord.c | 32 ++++++++++++++++++++++++++++++-- src/discord.h | 7 +++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/discord.c b/src/discord.c index 96d922a0b..4a361a3f0 100644 --- a/src/discord.c +++ b/src/discord.c @@ -37,7 +37,9 @@ // length of IP strings #define IP_SIZE 21 -consvar_t cv_discordrp = CVAR_INIT ("discordrp", "On", CV_SAVE|CV_CALL, CV_OnOff, DRPC_UpdatePresence); +static void Discordrp_OnChange(void); + +consvar_t cv_discordrp = CVAR_INIT ("discordrp", "On", CV_SAVE|CV_CALL, CV_OnOff, Discordrp_OnChange); consvar_t cv_discordstreamer = CVAR_INIT ("discordstreamer", "Off", CV_SAVE, CV_OnOff, NULL); consvar_t cv_discordasks = CVAR_INIT ("discordasks", "Yes", CV_SAVE|CV_CALL, CV_YesNo, DRPC_UpdatePresence); @@ -330,10 +332,36 @@ void DRPC_Init(void) handlers.joinRequest = DRPC_HandleJoinRequest; Discord_Initialize(DISCORD_APPID, &handlers, 1, NULL); - I_AddExitFunc(Discord_Shutdown); + I_AddExitFunc(DRPC_Shutdown); DRPC_UpdatePresence(); } +void DRPC_Shutdown(void) +{ + if (!drpc_init) + { + CONS_Printf("DiscordRPC never started\n"); + return; + } + + CONS_Printf("Shutting down DiscordRPC\n"); + + Discord_Shutdown(); + drpc_init = false; +} + +static void Discordrp_OnChange(void) +{ + if (cv_discordrp.value) + { + DRPC_UpdatePresence(); + } + else + { + DRPC_Shutdown(); + } +} + /*-------------------------------------------------- static void DRPC_GotServerIP(UINT32 address) diff --git a/src/discord.h b/src/discord.h index 587be6a42..310e6d6cb 100644 --- a/src/discord.h +++ b/src/discord.h @@ -68,6 +68,13 @@ void DRPC_RemoveRequest(discordRequest_t *removeRequest); void DRPC_Init(void); +/*-------------------------------------------------- + void DRPC_Shutdown(void); + + Shutdown Discord Rich Presence if it was started at all. +--------------------------------------------------*/ +void DRPC_Shutdown(void); + /*-------------------------------------------------- void DRPC_UpdatePresence(void); From 56745d621babc308d3268acc3c3c11f53b078cd0 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sun, 9 Feb 2025 13:01:30 -0500 Subject: [PATCH 056/117] Toggable Lap Emblem Animation --- src/d_netcmd.c | 3 +++ src/d_netcmd.h | 1 + src/k_hud.c | 3 +++ 3 files changed, 7 insertions(+) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 3d3b23801..1d8723e7a 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -517,6 +517,8 @@ consvar_t cv_showping = CVAR_INIT ("showping", "Always", CV_SAVE, showping_cons_ static CV_PossibleValue_t pingmeasurement_cons_t[] = {{0, "Frames"}, {1, "Milliseconds"}, {0, NULL}}; consvar_t cv_pingmeasurement = CVAR_INIT ("pingmeasurement", "Frames", CV_SAVE, pingmeasurement_cons_t, NULL); +consvar_t cv_showlapemblem = CVAR_INIT ("showlapemblem", "On", CV_SAVE, CV_OnOff, NULL); + consvar_t cv_showviewpointtext = CVAR_INIT ("showviewpointtext", "On", CV_SAVE, CV_OnOff, NULL); // Intermission time Tails 04-19-2002 @@ -815,6 +817,7 @@ void D_RegisterServerCommands(void) CV_RegisterVar(&cv_pingtimeout); CV_RegisterVar(&cv_showping); CV_RegisterVar(&cv_pingmeasurement); + CV_RegisterVar(&cv_showlapemblem); CV_RegisterVar(&cv_showviewpointtext); CV_RegisterVar(&cv_schedule); diff --git a/src/d_netcmd.h b/src/d_netcmd.h index dfc50c3b4..b624b9d6e 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -115,6 +115,7 @@ extern consvar_t cv_lagless; extern consvar_t cv_pingtimeout; extern consvar_t cv_showping; extern consvar_t cv_pingmeasurement; +extern consvar_t cv_showlapemblem; extern consvar_t cv_showviewpointtext; extern consvar_t cv_skipmapcheck; diff --git a/src/k_hud.c b/src/k_hud.c index 839222cb0..15c626d2c 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -4114,6 +4114,9 @@ static void K_drawChallengerScreen(void) static void K_drawLapStartAnim(void) { + if (!cv_showlapemblem.value) + return; + // This is an EVEN MORE insanely complicated animation. const UINT8 t = stplyr->karthud[khud_lapanimation]; const UINT8 progress = 80 - t; From 0e70fd8ac73453acee3ce17b6e41ab8a09f59edc Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sun, 9 Feb 2025 14:04:15 -0500 Subject: [PATCH 057/117] Patch alias and add listskins https://github.com/Indev450/SRB2Kart-Saturn/pull/33 --- src/command.c | 36 +++++++++++++++- src/d_netcmd.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+), 1 deletion(-) diff --git a/src/command.c b/src/command.c index 047436772..29039d574 100644 --- a/src/command.c +++ b/src/command.c @@ -714,10 +714,44 @@ static void COM_ExecuteString(char *ptext) static void COM_Alias_f(void) { cmdalias_t *a; + const char *alias_format = "\x87%-8s:\x80 %s\n"; + int argc = COM_Argc(); - if (COM_Argc() < 3) + if (argc == 2) { + const char *begin = COM_Argv(1); + size_t szBegin = strlen(begin); + + /* Display all aliases that start with `begin`. */ + CONS_Printf(M_GetText("All aliases that start with \x87'%s'\x80 are:\n"), begin); + + int count = 0; + for (cmdalias_t *head = com_alias; head->next != NULL; head = head->next) + { + if (strncmp(begin, head->name, szBegin) == 0) + { + CONS_Printf(alias_format, head->name, head->value); + count++; + } + } + + if (count == 0) + { + CONS_Printf(M_GetText("There are none.\n")); + } + + return; + } + else if (argc < 3) + { + /* Display alias subtext, show all aliases. */ CONS_Printf(M_GetText("alias : create a shortcut command that executes other command(s)\n")); + + for (cmdalias_t *head = com_alias; head->next != NULL; head = head->next) + { + CONS_Printf(alias_format, head->name, head->value); + } + return; } diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 1d8723e7a..a1b62cc56 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -217,6 +217,9 @@ static void Command_ShowTime_f(void); static void Command_Isgamemodified_f(void); static void Command_Cheats_f(void); + +static void Command_ListSkins(void); + #ifdef _DEBUG static void Command_Togglemodified_f(void); static void Command_Archivetest_f(void); @@ -1130,6 +1133,32 @@ void D_RegisterClientCommands(void) CV_RegisterVar(&cv_discordstreamer); CV_RegisterVar(&cv_discordasks); #endif + + COM_AddCommand("listskins", Command_ListSkins); + +} + +/** + * Searches the skins list for a skin of the "realname", if found, changes + * the CVAR value to be the "name" of the skin. + * \sa cv_skin, Skin_OnChange, Skin2_OnChange + * \author karen + */ +static void Skin_FindRealNameSkin(consvar_t *cvar) +{ + // Not the best way to implements this but it will do. + + int i; + const char *value = cvar->string; + for (i = 0; i < numskins; i++) + { + if (strncmp(value, skins[i].realname, sizeof skins[i].realname) == 0) + { + // Change the cvar to be the value of the name. + CV_StealthSet(cvar, skins[i].name); + return; + } + } } /** Checks if a name (as received from another player) is okay. @@ -6320,6 +6349,8 @@ static void Followercolor4_OnChange(void) */ static void Skin_OnChange(void) { + Skin_FindRealNameSkin(&cv_skin[0]); + if (!Playing()) return; // do whatever you want @@ -6346,6 +6377,8 @@ static void Skin_OnChange(void) */ static void Skin2_OnChange(void) { + Skin_FindRealNameSkin(&cv_skin[1]); + if (!Playing() || !splitscreen) return; // do whatever you want @@ -6360,6 +6393,8 @@ static void Skin2_OnChange(void) static void Skin3_OnChange(void) { + Skin_FindRealNameSkin(&cv_skin[2]); + if (!Playing() || splitscreen < 2) return; // do whatever you want @@ -6374,6 +6409,8 @@ static void Skin3_OnChange(void) static void Skin4_OnChange(void) { + Skin_FindRealNameSkin(&cv_skin[3]); + if (!Playing() || splitscreen < 3) return; // do whatever you want @@ -6386,6 +6423,84 @@ static void Skin4_OnChange(void) } } +static void Command_ListSkins(void) +{ + int i; + int page = 0; + int numpages = numskins / 10 + (numskins % 10 ? 1 : 0); + int longest_name = 0; + + if (COM_Argc() > 1) + { + if (sscanf(COM_Argv(1), " %d", &page) == 0) + { + CONS_Printf("Expected a number.\n"); + return; + } + else if (page > numpages) + { + CONS_Printf("There are only %d pages.\n", numpages); + return; + } + else if (page < 0) + { + CONS_Printf("Page number cannot be negative.\n"); + return; + } + else if (page == 0) + { + CONS_Printf("There is no 0th page. (What are you a programmer?)\n"); + return; + } + + --page; + } + + CONS_Printf("Total %d skins. Page (%d/%d)\n", numskins, page + 1, numpages); + + // Find the longest name and realname in the skins list. (used for alignment) + for (i = page * 10; i < numskins && i < (page + 1) * 10; i++) + { + int length; + skin_t *skin = &skins[i]; + + if ((length = strlen(skin->name)) > longest_name) + longest_name = length; + } + + for (i = page * 10; i < numskins && i < (page + 1) * 10; i++) + { + skin_t *skin = &skins[i]; + UINT16 chatcolor = skincolors[skin->prefcolor].chatcolor; + char color_prefix[2]; + + if (chatcolor > V_TANMAP) + { + sprintf(color_prefix, "%c", '\x80'); + } + else + { + sprintf(color_prefix, "%c", '\x80' + (chatcolor >> V_CHARCOLORSHIFT)); + } + + CONS_Printf( + "%s[%-*s]\x80 %s\n", + color_prefix, + longest_name, + skin->name, + skin->realname); + } + + if (page + 1 != numpages) + { + CONS_Printf("Use \"listskins %d\" to see the next page.\n", page + 2); + } + else + { + CONS_Printf("There are no more pages.\n"); + } +} + /** Sends a color change for the console player, unless that player is moving. * \sa cv_playercolor, Color2_OnChange, Skin_OnChange * \author Graue From 74eb7643fddbc6d7f2db05ea16372d54ecdad945 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sun, 9 Feb 2025 14:48:40 -0500 Subject: [PATCH 058/117] Animated vote screens support --- src/lua_hudlib.c | 36 +++++++++++++ src/y_inter.c | 129 ++++++++++++++++++++++++++++++++++++++++++++--- src/y_inter.h | 1 + 3 files changed, 158 insertions(+), 8 deletions(-) diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 99cc6d0ee..cc7004a55 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -16,6 +16,7 @@ #include "r_local.h" #include "r_fps.h" #include "st_stuff.h" +#include "y_inter.h" #include "g_game.h" #include "i_video.h" // rendermode #include "p_local.h" // camera_t @@ -1328,6 +1329,40 @@ static int lib_hudenabled(lua_State *L) return 1; } +static int lib_hudsetvotebackground(lua_State *L) +{ + if (lua_isnoneornil(L, 1)) + { + if (luaVoteScreen) + { + free(luaVoteScreen); + } + + luaVoteScreen = NULL; + + return 0; + } + + const char *prefix = luaL_checkstring(L, 1); + + if (strlen(prefix) != 4) + { + return luaL_argerror(L, 1, "prefix should 4 characters wide"); + } + + if (!luaVoteScreen) + { + luaVoteScreen = (char*)malloc(5); + luaVoteScreen[4] = 0; + } + + strncpy(luaVoteScreen, prefix, 4); + + strupr(luaVoteScreen); + + return 0; +} + // add a HUD element for rendering extern int lib_hudadd(lua_State *L); @@ -1336,6 +1371,7 @@ static luaL_Reg lib_hud[] = { {"disable", lib_huddisable}, {"enabled", lib_hudenabled}, {"add", lib_hudadd}, + {"setVoteBackground", lib_hudsetvotebackground}, {NULL, NULL} }; diff --git a/src/y_inter.c b/src/y_inter.c index e13f9986b..1b33a51c7 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -111,6 +111,19 @@ static INT32 intertic; static INT32 endtic = -1; static INT32 sorttic = -1; +patch_t *animVoteFramesPatches = NULL; +// VEXTRN - Vote (V) Extra (EXT) Race (R) Normal (N - Normal sized patch) +// VEXTBN - Vote (V) Extra (EXT) Battle (B) Normal (N - Normal sized patch) +// VEXTBW - Vote (V) Extra (EXT) Battle (B) Normal (W - Wide patch used in software) +// VEXTRW - Vote (V) Extra (EXT) Race (R) Normal (W - Wide patch used in software) +char animPrefix[] = "INTSC"; +char animWidePrefix[] = "INTSW"; +char *luaVoteScreen = NULL; + +INT32 currentAnimFrame = 0; +static INT32 foundAnimVoteFrames = 0; +static INT32 foundAnimVoteWideFrames = 0; + intertype_t intertype = int_none; intertype_t intermissiontypes[NUMGAMETYPES]; @@ -152,6 +165,7 @@ typedef struct static y_votelvlinfo levelinfo[5]; static y_voteclient voteclient; static INT32 votetic; +static INT32 lastvotetic; static INT32 voteendtic = -1; static boolean votenotyetpicked; static patch_t *cursor = NULL; @@ -343,6 +357,53 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32)) } } +// +// Y_AnimatedVoteScreenCheck +// +// Check if the lumps exist (checking for VEXTR(N|W)xx for race and VEXTRB(N|W)xx for battle) +static void Y_AnimatedVoteScreenCheck(void) +{ + char tmpPrefix[] = "INTS"; + boolean stopSearching = false; + + if (luaVoteScreen) + strncpy(tmpPrefix, luaVoteScreen, 4); + else + { + if(gametype == GT_BATTLE) + strcpy(tmpPrefix, "BTLS"); + } + + strncpy(animPrefix, tmpPrefix, 4); + animPrefix[4] = 'C'; + strncpy(animWidePrefix, tmpPrefix, 4); + animWidePrefix[4] = 'W'; + + foundAnimVoteFrames = 0; + foundAnimVoteWideFrames = 0; + currentAnimFrame = 0; + + INT32 i = 1; + while(!stopSearching) + { + boolean normalLumpExists = W_LumpExists(va("%sC%d", tmpPrefix, i)); + boolean wideLumpExists = W_LumpExists(va("%sW%d", tmpPrefix, i)); + + if (normalLumpExists || wideLumpExists) + { + if (normalLumpExists) + foundAnimVoteFrames++; + + if (wideLumpExists) + foundAnimVoteWideFrames++; + } + else // If we don't find at least frame 1 (e.g VEXTRN1), let's just stop looking + stopSearching = true; + + i++; + } +} + // // Y_ConsiderScreenBuffer // @@ -1085,6 +1146,37 @@ static void Y_UnloadData(void) // SRB2Kart: Voting! +// Y_DrawAnimatedVoteScreenPatch +// +// Draw animated patch based on frame counter on vote screen +// +static inline void Y_DrawAnimatedVoteScreenPatch(boolean widePatch) +{ + char tempAnimPrefix[7]; + (widePatch) ? strcpy(tempAnimPrefix, animWidePrefix) : strcpy(tempAnimPrefix, animPrefix); + INT32 tempFoundAnimVoteFrames = (widePatch) ? foundAnimVoteWideFrames : foundAnimVoteFrames; + + // Just in case someone provides LESS widescreen frames than normal frames or vice versa, reset the frame counter to 0 + if (widePatch) + { + if (currentAnimFrame > foundAnimVoteWideFrames-1) + currentAnimFrame = 0; + } + else + { + if (currentAnimFrame > foundAnimVoteFrames-1) + currentAnimFrame = 0; + } + + patch_t *background = W_CachePatchName(va("%s%d", tempAnimPrefix, currentAnimFrame + 1), PU_CACHE); + V_DrawScaledPatch(((vid.width/2) / vid.dupx) - (SHORT(background->width)/2), // Keep the width/height adjustments, for screens that are less wide than 320(?) + (vid.height / vid.dupy) - SHORT(background->height), + V_SNAPTOTOP|V_SNAPTOLEFT, background); + + if (renderisnewtic && votetic % 2 == 0 && !paused) + currentAnimFrame = (currentAnimFrame + 1 > tempFoundAnimVoteFrames - 1) ? 0 : currentAnimFrame + 1; +} + // // Y_VoteDrawer // @@ -1113,14 +1205,31 @@ void Y_VoteDrawer(void) V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); - if (widebgpatch && rendermode == render_soft && vid.width / vid.dupx > 320) - V_DrawScaledPatch(((vid.width/2) / vid.dupx) - (SHORT(widebgpatch->width)/2), - (vid.height / vid.dupy) - SHORT(widebgpatch->height), - V_SNAPTOTOP|V_SNAPTOLEFT, widebgpatch); - else - V_DrawScaledPatch(((vid.width/2) / vid.dupx) - (SHORT(bgpatch->width)/2), // Keep the width/height adjustments, for screens that are less wide than 320(?) - (vid.height / vid.dupy) - SHORT(bgpatch->height), - V_SNAPTOTOP|V_SNAPTOLEFT, bgpatch); + if (widebgpatch && vid.width / vid.dupx > 320) { + + if(foundAnimVoteWideFrames == 0){ + V_DrawScaledPatch(((vid.width/2) / vid.dupx) - (SHORT(widebgpatch->width)/2), + (vid.height / vid.dupy) - SHORT(widebgpatch->height), + V_SNAPTOTOP|V_SNAPTOLEFT, widebgpatch); + } else { + // patch_t *currPatch = W_CachePatchName(va("%s%d", animPrefix, currentAnimFrame+1), PU_CACHE); + // V_DrawScaledPatch(((vid.width/2) / vid.dupx) - (SHORT(currPatch->width)/2), // Keep the width/height adjustments, for screens that are less wide than 320(?) + // (vid.height / vid.dupy) - SHORT(currPatch->height), + // V_SNAPTOTOP|V_SNAPTOLEFT, currPatch); + // if(votetic % 4 == 0 && !paused){ + // currentAnimFrame = (currentAnimFrame+1 > foundAnimVoteFrames-1) ? 0 : currentAnimFrame + 1; + // } + Y_DrawAnimatedVoteScreenPatch(true); + } + } else { + if(foundAnimVoteFrames == 0) { + V_DrawScaledPatch(((vid.width/2) / vid.dupx) - (SHORT(bgpatch->width)/2), // Keep the width/height adjustments, for screens that are less wide than 320(?) + (vid.height / vid.dupy) - SHORT(bgpatch->height), + V_SNAPTOTOP|V_SNAPTOLEFT, bgpatch); + } else { + Y_DrawAnimatedVoteScreenPatch(false); + } + } for (i = 0; i < 4; i++) // First, we need to figure out the height of this thing... { @@ -1362,6 +1471,8 @@ void Y_VoteDrawer(void) V_DrawCenteredString(BASEVIDWIDTH/2, 188, hilicol, va("Vote ends in %d", tickdown)); } + + lastvotetic = votetic; } // @@ -1631,6 +1742,8 @@ void Y_StartVote(void) I_Error("voteendtic is dirty"); #endif + Y_AnimatedVoteScreenCheck(); + widebgpatch = W_CachePatchName(((gametype == GT_BATTLE) ? "BATTLSCW" : "INTERSCW"), PU_STATIC); bgpatch = W_CachePatchName(((gametype == GT_BATTLE) ? "BATTLSCR" : "INTERSCR"), PU_STATIC); cursor = W_CachePatchName("M_CURSOR", PU_STATIC); diff --git a/src/y_inter.h b/src/y_inter.h index 37c863fbe..3ad092744 100644 --- a/src/y_inter.h +++ b/src/y_inter.h @@ -17,6 +17,7 @@ extern "C" { #endif extern boolean usebuffer; +extern char *luaVoteScreen; void Y_IntermissionDrawer(void); void Y_Ticker(void); From d1565d1e84b126e46f601495320304c1d03f6325 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sun, 9 Feb 2025 15:03:36 -0500 Subject: [PATCH 059/117] Vote HUD Hook --- src/deh_tables.c | 4 ++++ src/lua_hook.h | 1 + src/y_inter.c | 8 ++++++++ 3 files changed, 13 insertions(+) diff --git a/src/deh_tables.c b/src/deh_tables.c index cef433039..e901efd31 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -1382,6 +1382,10 @@ struct int_const_s const INT_CONST[] = { {"BASEVIDWIDTH", BASEVIDWIDTH}, {"BASEVIDHEIGHT", BASEVIDHEIGHT}, + // Custom client features exposed to lua + {"FEATURE_INTERMISSIONHUD",1}, // This is to trick kart luas that look for this since its already here. + {"FEATURE_VOTEHUD",1}, + {NULL,0} }; diff --git a/src/lua_hook.h b/src/lua_hook.h index 4d8d11c3d..5f4984850 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -95,6 +95,7 @@ automatically. X (title),/* titlescreen */\ X (titlecard),\ X (intermission),\ + X (vote),\ /* I chose to access the hook enums through a macro as well. This could provide diff --git a/src/y_inter.c b/src/y_inter.c index 1b33a51c7..aa7dae964 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -128,6 +128,7 @@ intertype_t intertype = int_none; intertype_t intermissiontypes[NUMGAMETYPES]; static huddrawlist_h luahuddrawlist_intermission; +static huddrawlist_h luahuddrawlist_vote; static void Y_FollowIntermission(void); @@ -1473,6 +1474,13 @@ void Y_VoteDrawer(void) } lastvotetic = votetic; + + if (renderisnewtic) + { + LUA_HUD_ClearDrawList(luahuddrawlist_vote); + LUA_HookHUD(luahuddrawlist_vote, HUD_HOOK(vote)); + } + LUA_HUD_DrawList(luahuddrawlist_vote); } // From 86379856d1b6bc0e7ffa9bdbfeb71cddbca68dfd Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sun, 9 Feb 2025 15:14:08 -0500 Subject: [PATCH 060/117] Oops forgot this for vote hook --- src/y_inter.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/y_inter.c b/src/y_inter.c index aa7dae964..a25e3ba7c 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -1828,6 +1828,9 @@ void Y_StartVote(void) voteclient.loaded = true; Automate_Run(AEV_VOTESTART); + + LUA_HUD_DestroyDrawList(luahuddrawlist_vote); + luahuddrawlist_vote = LUA_HUD_CreateDrawList(); } // From af86e1c6b2c324e6784561ad16fce993660a162a Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sun, 9 Feb 2025 15:32:49 -0500 Subject: [PATCH 061/117] Optimize gif recording in opengl a bit --- src/hardware/hw_draw.c | 5 ++++- src/m_anigif.c | 28 +++++++++++++++++----------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index 47a7f0b6a..9f52e8d52 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -1221,10 +1221,13 @@ static inline boolean saveTGA(const char *file_name, void *buffer, UINT8 *HWR_GetScreenshot(void) { - UINT8 *buf = malloc(vid.width * vid.height * 3 * sizeof (*buf)); + static UINT8 *buf = NULL; + + buf = realloc(buf, vid.width * vid.height * 3); if (!buf) return NULL; + // returns 24bit 888 RGB HWD.pfnReadRect(0, 0, vid.width, vid.height, vid.width * 3, (void *)buf); return buf; diff --git a/src/m_anigif.c b/src/m_anigif.c index a6c830fa3..380eb6f00 100644 --- a/src/m_anigif.c +++ b/src/m_anigif.c @@ -511,19 +511,25 @@ static colorlookup_t gif_colorlookup; static void GIF_rgbconvert(UINT8 *linear, UINT8 *scr) { UINT8 r, g, b; - size_t src = 0, dest = 0; - size_t size = (vid.width * vid.height * 3); + size_t src, dest; + int x, y; InitColorLUT(&gif_colorlookup, (gif_localcolortable) ? gif_framepalette : gif_headerpalette, true); - while (src < size) + for (x = 0; x < vid.width; x += scrbuf_downscaleamt) { - r = (UINT8)linear[src]; - g = (UINT8)linear[src + 1]; - b = (UINT8)linear[src + 2]; - scr[dest] = GetColorLUTDirect(&gif_colorlookup, r, g, b); - src += (3 * scrbuf_downscaleamt); - dest += scrbuf_downscaleamt; + for (y = 0; y < vid.height; y += scrbuf_downscaleamt) + { + dest = y*vid.width + x; + src = dest*3; + + r = (UINT8)linear[src]; + g = (UINT8)linear[src + 1]; + b = (UINT8)linear[src + 2]; + scr[dest] = GetColorLUTDirect(&gif_colorlookup, r, g, b); + src += (3 * scrbuf_downscaleamt); + dest += scrbuf_downscaleamt; + } } } #endif @@ -571,7 +577,7 @@ static void GIF_framewrite(void) { UINT8 *linear = HWR_GetScreenshot(); GIF_rgbconvert(linear, movie_screen); - free(linear); + //free(linear); // Allocated 'statically', no need to free now } #endif } @@ -587,7 +593,7 @@ static void GIF_framewrite(void) { UINT8 *linear = HWR_GetScreenshot(); GIF_rgbconvert(linear, screens[0]); - free(linear); + //free(linear); // Allocated 'statically', no need to free now } #endif From 4c22547ebb1a2907b8311d6dca78e16b1a6d5515 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 13 Nov 2022 11:48:20 +0000 Subject: [PATCH 062/117] Merge branch 'vsync-set-fix' into 'master' Set vsync on screen update or resolution change in software mode See merge request KartKrew/Kart!765 --- src/sdl/i_video.cpp | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/src/sdl/i_video.cpp b/src/sdl/i_video.cpp index 19ece061e..780c91817 100644 --- a/src/sdl/i_video.cpp +++ b/src/sdl/i_video.cpp @@ -107,10 +107,9 @@ rendermode_t chosenrendermode = render_none; // set by command line arguments boolean highcolor = false; -static void Impl_SetVsync(void); // synchronize page flipping with screen refresh -consvar_t cv_vidwait = CVAR_INIT ("vid_wait", "On", CV_SAVE|CV_CALL|CV_NOINIT, CV_OnOff, Impl_SetVsync); +consvar_t cv_vidwait = CVAR_INIT ("vid_wait", "On", CV_SAVE, CV_OnOff, NULL); static consvar_t cv_stretch = CVAR_INIT ("stretch", "Off", CV_SAVE|CV_NOSHOWHELP, CV_OnOff, NULL); static consvar_t cv_alwaysgrabmouse = CVAR_INIT ("alwaysgrabmouse", "Off", CV_SAVE, CV_OnOff, NULL); @@ -186,6 +185,18 @@ static SDL_bool Impl_CreateWindow(SDL_bool fullscreen); //static void Impl_SetWindowName(const char *title); static void Impl_SetWindowIcon(void); +static void Impl_SetSoftwareVsync(int vsync) +{ + static int oldvsync = 0; +#if SDL_VERSION_ATLEAST(2,0,18) + if (oldvsync != vsync) + { + SDL_RenderSetVSync(renderer, vsync); + } + oldvsync = vsync; +#endif +} + static void SDLSetMode(INT32 width, INT32 height, SDL_bool fullscreen, SDL_bool reposition) { static SDL_bool wasfullscreen = SDL_FALSE; @@ -278,6 +289,7 @@ static void SDLSetMode(INT32 width, INT32 height, SDL_bool fullscreen, SDL_bool } SDL_PixelFormatEnumToMasks(sw_texture_format, &bpp, &rmask, &gmask, &bmask, &amask); vidSurface = SDL_CreateRGBSurface(0, width, height, bpp, rmask, gmask, bmask, amask); + Impl_SetSoftwareVsync(cv_vidwait.value); } } @@ -1408,6 +1420,7 @@ void I_FinishUpdate(void) SDL_RenderClear(renderer); SDL_RenderCopy(renderer, texture, &src_rect, NULL); SDL_RenderPresent(renderer); + Impl_SetSoftwareVsync(cv_vidwait.value); } #ifdef HWRENDER else if (rendermode == render_opengl) @@ -1632,15 +1645,6 @@ static SDL_bool Impl_CreateContext(void) int flags = 0; // Use this to set SDL_RENDERER_* flags now if (usesdl2soft) flags |= SDL_RENDERER_SOFTWARE; -#if 0 - // This shit is BROKEN. - // - The version of SDL we're using cannot toggle VSync at runtime. We'll need a new SDL version implemented to have this work properly. - // - cv_vidwait is initialized before config is loaded, so it's forced to default value at runtime, and forced off when switching. The config loading code would need restructured. - // - With both this & frame interpolation on, I_FinishUpdate takes x10 longer. At this point, it is simpler to use a standard FPS cap. - // So you can probably guess why I'm kinda over this, I'm just disabling it. - else if (cv_vidwait.value) - flags |= SDL_RENDERER_PRESENTVSYNC; -#endif // 3 August 2022 // Possibly a Windows 11 issue; the default @@ -2159,11 +2163,3 @@ UINT32 I_GetRefreshRate(void) // trouble querying mode over and over again. return refresh_rate; } - -static void Impl_SetVsync(void) -{ -#if SDL_VERSION_ATLEAST(2,0,18) - if (renderer) - SDL_RenderSetVSync(renderer, cv_vidwait.value); -#endif -} From 508c57f24b0538ad3024046910ab22e28c62ae65 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sun, 9 Feb 2025 16:40:37 -0500 Subject: [PATCH 063/117] prevent credits from running in game --- src/g_game.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index ed268838c..52f081bfe 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4105,13 +4105,6 @@ 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) - { - F_StartCredits(); - return; - } - // 1100 or competitive multiplayer, so go back to title screen. D_StartTitle(); } From 520953fd783653270532bf468b61ceeba14242a5 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sun, 9 Feb 2025 17:36:38 -0500 Subject: [PATCH 064/117] acutally fix going to credits/ending game --- src/g_game.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 52f081bfe..8ab91ae73 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3084,7 +3084,7 @@ const char *Gametype_ConstantNames[NUMGAMETYPES] = UINT32 gametypedefaultrules[NUMGAMETYPES] = { // Race - GTR_CAMPAIGN|GTR_CIRCUIT|GTR_BOTS, + GTR_CIRCUIT|GTR_BOTS, // Battle GTR_BUMPERS|GTR_KARMA|GTR_WANTED|GTR_ITEMARROWS|GTR_ITEMBREAKER|GTR_BATTLESTARTS|GTR_TIMELIMIT }; @@ -3960,7 +3960,7 @@ void G_AfterIntermission(void) return; } - if ((gametyperules & GTR_CAMPAIGN) && mapheaderinfo[gamemap-1]->cutscenenum && !modeattacking && skipstats <= 1 && (gamecomplete || !(marathonmode & MA_NOCUTSCENES))) // Start a custom cutscene. + if (mapheaderinfo[gamemap-1]->cutscenenum && !modeattacking && skipstats <= 1 && (gamecomplete || !(marathonmode & MA_NOCUTSCENES))) // Start a custom cutscene. F_StartCustomCutscene(mapheaderinfo[gamemap-1]->cutscenenum-1, false, false); else { @@ -4760,7 +4760,7 @@ void G_InitNew(UINT8 pencoremode, INT32 map, boolean resetplayer, boolean skippr automapactive = false; imcontinuing = false; - if ((gametyperules & GTR_CAMPAIGN) && !skipprecutscene && mapheaderinfo[gamemap-1]->precutscenenum && !modeattacking && !(marathonmode & MA_NOCUTSCENES)) // Start a custom cutscene. + if (!skipprecutscene && mapheaderinfo[gamemap-1]->precutscenenum && !modeattacking && !(marathonmode & MA_NOCUTSCENES)) // Start a custom cutscene. F_StartCustomCutscene(mapheaderinfo[gamemap-1]->precutscenenum-1, true, resetplayer); else { From 63fe2bbfa1a1bd989fa80966b5975ec6d0f5a00b Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sun, 9 Feb 2025 18:14:35 -0500 Subject: [PATCH 065/117] Numlaps updates from RingRacers --- src/d_netcmd.c | 32 +++++++++++++++++++++----------- src/k_kart.c | 18 ++++++++++++++++++ src/k_kart.h | 1 + src/p_setup.c | 19 +------------------ 4 files changed, 41 insertions(+), 29 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index a1b62cc56..97ac2bab5 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -489,8 +489,8 @@ consvar_t cv_pointlimit = CVAR_INIT ("pointlimit", "None", CV_SAVE|CV_NETVAR|CV_ static CV_PossibleValue_t timelimit_cons_t[] = {{1, "MIN"}, {30, "MAX"}, {0, "None"}, {0, NULL}}; consvar_t cv_timelimit = CVAR_INIT ("timelimit", "None", CV_SAVE|CV_NETVAR|CV_CALL|CV_NOINIT, timelimit_cons_t, TimeLimit_OnChange); -static CV_PossibleValue_t numlaps_cons_t[] = {{1, "MIN"}, {MAX_LAPS, "MAX"}, {0, "Map default"}, {0, NULL}}; -consvar_t cv_numlaps = CVAR_INIT ("numlaps", "Map default", CV_SAVE|CV_NETVAR|CV_CALL|CV_CHEAT, numlaps_cons_t, NumLaps_OnChange); +static CV_PossibleValue_t numlaps_cons_t[] = {{0, "MIN"}, {MAX_LAPS, "MAX"}, {-1, "Map default"}, {0, NULL}}; +consvar_t cv_numlaps = CVAR_INIT ("numlaps", "Map default", CV_NETVAR|CV_CALL|CV_CHEAT, numlaps_cons_t, NumLaps_OnChange); // Point and time limits for every gametype INT32 pointlimits[NUMGAMETYPES]; @@ -6687,19 +6687,29 @@ static void Command_ShowTime_f(void) // SRB2Kart: On change messages static void NumLaps_OnChange(void) { - if (K_CanChangeRules() == false) + if (gamestate == GS_LEVEL) { - return; - } + numlaps = K_RaceLapCount(gamemap - 1); - if (leveltime < starttime) - { - CONS_Printf(M_GetText("Number of laps have been set to %d.\n"), cv_numlaps.value); - numlaps = (UINT8)cv_numlaps.value; + if (cv_numlaps.value == -1) + { + CONS_Printf(M_GetText("Number of laps have been set to %d (map default).\n"), numlaps); + } + else + { + CONS_Printf(M_GetText("Number of laps have been set to %d.\n"), numlaps); + } } - else + else if (Playing()) { - CONS_Printf(M_GetText("Number of laps will be set to %d next round.\n"), cv_numlaps.value); + if (cv_numlaps.value == -1) + { + CONS_Printf(M_GetText("Number of laps will be the map default next round.\n")); + } + else + { + CONS_Printf(M_GetText("Number of laps will be set to %d next round.\n"), cv_numlaps.value); + } } } diff --git a/src/k_kart.c b/src/k_kart.c index 2fac039eb..57d9d83de 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -6826,6 +6826,24 @@ static void K_RaceStart(player_t *player) } +UINT8 K_RaceLapCount(INT16 mapNum) +{ + if (!(gametyperules & GTR_CIRCUIT)) + { + // Not in Race mode + return 0; + } + + if (cv_numlaps.value == -1) + { + // Use map default + return mapheaderinfo[mapNum]->numlaps; + } + + return cv_numlaps.value; +} + + static void K_TireGreaseEffect(player_t *player) { const INT16 spawnrange = player->mo->radius>>FRACBITS; diff --git a/src/k_kart.h b/src/k_kart.h index de36bfae7..c33b9e9b7 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -59,6 +59,7 @@ void K_SpawnBumpEffect(mobj_t *mo); void K_KartMoveAnimation(player_t *player); void K_KartPlayerHUDUpdate(player_t *player); void K_KartResetPlayerColor(player_t *player); +UINT8 K_RaceLapCount(INT16 mapNum); void K_KartPlayerThink(player_t *player, ticcmd_t *cmd); void K_KartPlayerAfterThink(player_t *player); angle_t K_MomentumAngle(mobj_t *mo); diff --git a/src/p_setup.c b/src/p_setup.c index 094e35602..5544629f8 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -8141,24 +8141,7 @@ static void P_InitGametype(void) if (modeattacking && !demo.playback) P_LoadRecordGhosts(); - numlaps = 0; - if (gametyperules & GTR_CIRCUIT) - { - if (K_CanChangeRules() && cv_numlaps.value - && (!(mapheaderinfo[gamemap - 1]->levelflags & LF_SECTIONRACE) - || (mapheaderinfo[gamemap - 1]->numlaps > cv_numlaps.value))) - { - numlaps = cv_numlaps.value; - } - else - { - numlaps = mapheaderinfo[gamemap - 1]->numlaps; - } - } - else - { - numlaps = 0; - } + numlaps = K_RaceLapCount(gamemap - 1); wantedcalcdelay = wantedfrequency*2; indirectitemcooldown = 0; From 77152250dda38e3f413c904fa0a9de525137f1ec Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sun, 9 Feb 2025 18:19:55 -0500 Subject: [PATCH 066/117] Remove GTR_CAMPIGN and assign stuff to grandprix instead --- src/d_main.cpp | 6 +++--- src/d_netcmd.c | 5 ++--- src/doomstat.h | 2 +- src/g_game.c | 6 +----- 4 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index f10221730..787485029 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -982,10 +982,10 @@ 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) + { if (server) { COM_BufAddText(va("map %s\n", G_BuildMapName(spstage_start))); diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 97ac2bab5..dbadef71f 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2588,7 +2588,7 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pencoremode, boolean r CONS_Debug(DBG_GAMELOGIC, "Map change: mapnum=%d gametype=%d pencoremode=%d resetplayers=%d delay=%d skipprecutscene=%d\n", mapnum, newgametype, pencoremode, resetplayers, delay, skipprecutscene); - if ((netgame || multiplayer) && !((gametype == newgametype) && (gametypedefaultrules[newgametype] & GTR_CAMPAIGN))) + if ((netgame || multiplayer) && (grandprixinfo.gp != false)) FLS = false; // Too lazy to change the input value for every instance of this function....... @@ -2962,8 +2962,7 @@ static void Command_Map_f(void) { fromlevelselect = ( netgame || multiplayer ) && - newgametype == gametype && - gametypedefaultrules[newgametype] & GTR_CAMPAIGN; + grandprixinfo.gp != false; } } diff --git a/src/doomstat.h b/src/doomstat.h index 881bc9ca4..179aa5e0e 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -518,7 +518,7 @@ enum GameTypeRules GTR_TEAMSTARTS = 1<<16, // Use team-based start positions // Grand Prix rules - GTR_CAMPAIGN = 1<<17, // Handles cup-based progression + //Free = 1<<17, GTR_LIVES = 1<<18, // Lives system, players are forced to spectate during Game Over. GTR_SPECIALBOTS = 1<<19, // Bot difficulty gets stronger between rounds, and the rival system is enabled. diff --git a/src/g_game.c b/src/g_game.c index 8ab91ae73..714c876bb 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3869,10 +3869,6 @@ static void G_DoCompleted(void) nextmap = cm; } - // wrap around in race - 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) I_Error("Followed map %d to invalid map %d\n", prevmap + 1, nextmap + 1); @@ -3882,7 +3878,7 @@ static void G_DoCompleted(void) automapactive = false; - if (!(gametyperules & GTR_CAMPAIGN)) + if (!(grandprixinfo.gp == true)) { if (cv_advancemap.value == 0) // Stay on same map. { From 972559463eff18db7d779851ca64cfad9e0ddcf4 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sun, 9 Feb 2025 19:08:02 -0500 Subject: [PATCH 067/117] Fix Dr Robotnik's 12 Crazy Laps --- src/p_setup.c | 9 ++- src/p_spec.c | 216 ++++++++++++++++++++++++++++++-------------------- 2 files changed, 137 insertions(+), 88 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index 5544629f8..8b2cfa1fe 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -6303,7 +6303,14 @@ static void P_ConvertBinaryLinedefTypes(void) } break; case 480: //Polyobject - door slide - case 481: //Polyobject - door move + lines[i].args[0] = tag; + lines[i].args[1] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].args[2] = AngleFixed(R_PointToAngle2(lines[i].v1->x, lines[i].v1->y, lines[i].v2->x, lines[i].v2->y)) >> FRACBITS; + lines[i].args[3] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; + if (lines[i].sidenum[1] != 0xffff) + lines[i].args[4] = sides[lines[i].sidenum[1]].textureoffset >> FRACBITS; + break; + case 481: //Polyobject - door swing lines[i].args[0] = tag; lines[i].args[1] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; lines[i].args[2] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; diff --git a/src/p_spec.c b/src/p_spec.c index 82316b422..9d10b702c 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -999,52 +999,53 @@ static sector_t *P_FindModelCeilingSector(fixed_t ceildestheight, INT32 secnum) #endif // Parses arguments for parameterized polyobject door types -static boolean PolyDoor(line_t *line) +static boolean PolyDoor(INT32 *args) { polydoordata_t pdd; - pdd.polyObjNum = line->args[0]; // polyobject id + pdd.polyObjNum = args[0]; // polyobject id - switch(line->special) - { - case 480: // Polyobj_DoorSlide - pdd.doorType = POLY_DOOR_SLIDE; - pdd.speed = line->args[1] << (FRACBITS - 3); - pdd.angle = R_PointToAngle2(line->v1->x, line->v1->y, line->v2->x, line->v2->y); // angle of motion - pdd.distance = line->args[2] << FRACBITS; - pdd.delay = line->args[3]; // delay in tics - break; - case 481: // Polyobj_DoorSwing - pdd.doorType = POLY_DOOR_SWING; - pdd.speed = line->args[1]; // angular speed - pdd.distance = line->args[2]; // angular distance - pdd.delay = line->args[3]; // delay in tics - break; - default: - return 0; // ??? - } + pdd.doorType = POLY_DOOR_SLIDE; + pdd.speed = args[1] << (FRACBITS - 3); + pdd.angle = FixedAngle(args[2] << FRACBITS); // angle of motion + pdd.distance = args[3] << FRACBITS; + pdd.delay = args[4]; // delay in tics + + return EV_DoPolyDoor(&pdd); +} + +static boolean PolyDoorSwing(INT32 *args) +{ + polydoordata_t pdd; + + pdd.polyObjNum = args[0]; // polyobject id + + pdd.doorType = POLY_DOOR_SWING; + pdd.speed = args[1]; // angular speed + pdd.distance = args[2]; // angular distance + pdd.delay = args[3]; // delay in tics return EV_DoPolyDoor(&pdd); } // Parses arguments for parameterized polyobject move special -static boolean PolyMove(line_t *line) +static boolean PolyMove(INT32 *args) { polymovedata_t pmd; - pmd.polyObjNum = line->args[0]; - pmd.speed = line->args[1] << (FRACBITS - 3); - pmd.angle = R_PointToAngle2(line->v1->x, line->v1->y, line->v2->x, line->v2->y); - pmd.distance = line->args[2] << FRACBITS; + pmd.polyObjNum = args[0]; + pmd.speed = args[1] << (FRACBITS - 3); + pmd.angle = FixedAngle(args[2] << FRACBITS); + pmd.distance = args[3] << FRACBITS; - pmd.overRide = !!line->args[3]; // Polyobj_OR_Move + pmd.overRide = !!args[4]; // Polyobj_OR_Move return EV_DoPolyObjMove(&pmd); } -static void PolySetVisibilityTangibility(line_t *line) +static void PolySetVisibilityTangibility(INT32 *args) { - INT32 polyObjNum = line->args[0]; + INT32 polyObjNum = args[0]; polyobj_t* po; if (!(po = Polyobj_GetForNum(polyObjNum))) @@ -1057,27 +1058,27 @@ static void PolySetVisibilityTangibility(line_t *line) if (po->isBad) return; - if (line->args[1] == TMF_ADD) + if (args[1] == TMF_ADD) { po->flags &= ~POF_NOSPECIALS; po->flags |= (po->spawnflags & POF_RENDERALL); } - else if (line->args[1] == TMF_REMOVE) + else if (args[1] == TMF_REMOVE) { po->flags |= POF_NOSPECIALS; po->flags &= ~POF_RENDERALL; } - if (line->args[2] == TMF_ADD) + if (args[2] == TMF_ADD) po->flags |= POF_SOLID; - else if (line->args[2] == TMF_REMOVE) + else if (args[2] == TMF_REMOVE) po->flags &= ~POF_SOLID; } // Sets the translucency of a polyobject -static void PolyTranslucency(line_t *line) +static void PolyTranslucency(INT32 *args) { - INT32 polyObjNum = line->args[0]; + INT32 polyObjNum = args[0]; polyobj_t *po; if (!(po = Polyobj_GetForNum(polyObjNum))) @@ -1090,18 +1091,18 @@ static void PolyTranslucency(line_t *line) if (po->isBad) return; - if (lines->args[2]) // relative calc - po->translucency += line->args[1]; + if (args[2]) // relative calc + po->translucency += args[1]; else - po->translucency = line->args[1]; + po->translucency = args[1]; po->translucency = max(min(po->translucency, NUMTRANSMAPS), 0); } // Makes a polyobject translucency fade and applies tangibility -static boolean PolyFade(line_t *line) +static boolean PolyFade(INT32 *args) { - INT32 polyObjNum = line->args[0]; + INT32 polyObjNum = args[0]; polyobj_t *po; polyfadedata_t pfd; @@ -1116,7 +1117,7 @@ static boolean PolyFade(line_t *line) return 0; // Prevent continuous execs from interfering on an existing fade - if (!(line->args[3] & TMPF_OVERRIDE) + if (!(args[3] & TMPF_OVERRIDE) && po->thinker && po->thinker->function.acp1 == (actionf_p1)T_PolyObjFade) { @@ -1126,10 +1127,10 @@ static boolean PolyFade(line_t *line) pfd.polyObjNum = polyObjNum; - if (line->args[3] & TMPF_RELATIVE) // relative calc - pfd.destvalue = po->translucency + line->args[1]; + if (args[3] & TMPF_RELATIVE) // relative calc + pfd.destvalue = po->translucency + args[1]; else - pfd.destvalue = line->args[1]; + pfd.destvalue = args[1]; pfd.destvalue = max(min(pfd.destvalue, NUMTRANSMAPS), 0); @@ -1137,88 +1138,129 @@ static boolean PolyFade(line_t *line) if (po->translucency == pfd.destvalue) return 1; - pfd.docollision = !(line->args[3] & TMPF_IGNORECOLLISION); // do not handle collision flags - pfd.doghostfade = (line->args[3] & TMPF_GHOSTFADE); // do ghost fade (no collision flags during fade) - pfd.ticbased = (line->args[3] & TMPF_TICBASED); // Speed = Tic Duration + pfd.docollision = !(args[3] & TMPF_IGNORECOLLISION); // do not handle collision flags + pfd.doghostfade = (args[3] & TMPF_GHOSTFADE); // do ghost fade (no collision flags during fade) + pfd.ticbased = (args[3] & TMPF_TICBASED); // Speed = Tic Duration - pfd.speed = line->args[2]; + pfd.speed = args[2]; return EV_DoPolyObjFade(&pfd); } // Parses arguments for parameterized polyobject waypoint movement -static boolean PolyWaypoint(line_t *line) +static boolean PolyWaypoint(INT32 *args) { polywaypointdata_t pwd; - pwd.polyObjNum = line->args[0]; - pwd.speed = line->args[1] << (FRACBITS - 3); - pwd.sequence = line->args[2]; - pwd.returnbehavior = line->args[3]; - pwd.flags = line->args[4]; + pwd.polyObjNum = args[0]; + pwd.speed = args[1] << (FRACBITS - 3); + pwd.sequence = args[2]; + pwd.returnbehavior = args[3]; + pwd.flags = args[4]; return EV_DoPolyObjWaypoint(&pwd); } // Parses arguments for parameterized polyobject rotate special -static boolean PolyRotate(line_t *line) +static boolean PolyRotate(INT32 *args) { polyrotdata_t prd; - prd.polyObjNum = line->args[0]; - prd.speed = line->args[1]; // angular speed - prd.distance = abs(line->args[2]); // angular distance - prd.direction = (line->args[2] < 0) ? -1 : 1; - prd.flags = line->args[3]; + prd.polyObjNum = args[0]; + prd.speed = args[1]; // angular speed + prd.distance = abs(args[2]); // angular distance + prd.direction = (args[2] < 0) ? -1 : 1; + prd.flags = args[3]; return EV_DoPolyObjRotate(&prd); } // Parses arguments for polyobject flag waving special -static boolean PolyFlag(line_t *line) +static boolean PolyFlag(INT32 *args) { polyflagdata_t pfd; - pfd.polyObjNum = line->args[0]; - pfd.speed = line->args[1]; - pfd.angle = line->angle >> ANGLETOFINESHIFT; - pfd.momx = line->args[2]; + pfd.polyObjNum = args[0]; + pfd.speed = args[1]; + pfd.angle = FixedAngle(args[2] << FRACBITS) >> ANGLETOFINESHIFT; + pfd.momx = args[3]; return EV_DoPolyObjFlag(&pfd); } // Parses arguments for parameterized polyobject move-by-sector-heights specials -static boolean PolyDisplace(line_t *line) +static boolean PolyDisplace(INT32 *args, line_t *fallback) { polydisplacedata_t pdd; - fixed_t length = R_PointToDist2(line->v2->x, line->v2->y, line->v1->x, line->v1->y); - fixed_t speed = line->args[1] << FRACBITS; + fixed_t speed; + angle_t angle; - pdd.polyObjNum = line->args[0]; + pdd.polyObjNum = args[0]; - pdd.controlSector = line->frontsector; - pdd.dx = FixedMul(FixedDiv(line->dx, length), speed) >> 8; - pdd.dy = FixedMul(FixedDiv(line->dy, length), speed) >> 8; + if (args[1] == 0) + { + if (fallback == NULL) + { + CONS_Debug(DBG_GAMELOGIC, "PolyDisplace: No frontsector to displace from!\n"); + return false; + } + pdd.controlSector = fallback->frontsector; + } + else + { + INT32 destsec = Tag_Iterate_Sectors(args[1], 0); + if (destsec == -1) + { + CONS_Debug(DBG_GAMELOGIC, "PolyDisplace: No tagged sector to displace from (tag %d)!\n", args[1]); + return false; + } + pdd.controlSector = §ors[destsec]; + } + + speed = args[2] << FRACBITS; + angle = FixedAngle(args[3] << FRACBITS) >> ANGLETOFINESHIFT; + + pdd.dx = FixedMul(FINECOSINE(angle), speed) >> 8; + pdd.dy = FixedMul( FINESINE(angle), speed) >> 8; return EV_DoPolyObjDisplace(&pdd); } // Parses arguments for parameterized polyobject rotate-by-sector-heights specials -static boolean PolyRotDisplace(line_t *line) +static boolean PolyRotDisplace(INT32 *args, line_t *fallback) { polyrotdisplacedata_t pdd; fixed_t anginter, distinter; - pdd.polyObjNum = line->args[0]; - pdd.controlSector = line->frontsector; + pdd.polyObjNum = args[0]; + + if (args[1] == 0) + { + if (fallback == NULL) + { + CONS_Debug(DBG_GAMELOGIC, "PolyRotDisplace: No frontsector to displace from!\n"); + return false; + } + pdd.controlSector = fallback->frontsector; + } + else + { + INT32 destsec = Tag_Iterate_Sectors(args[1], 0); + if (destsec == -1) + { + CONS_Debug(DBG_GAMELOGIC, "PolyRotDisplace: No tagged sector to displace from (tag %d)!\n", args[1]); + return false; + } + pdd.controlSector = §ors[destsec]; + } // Rotate 'anginter' interval for each 'distinter' interval from the control sector. - anginter = line->args[2] << FRACBITS; - distinter = line->args[1] << FRACBITS; + distinter = args[2] << FRACBITS; + anginter = args[3] << FRACBITS; pdd.rotscale = FixedDiv(anginter, distinter); // Same behavior as other rotators when carrying things. - pdd.turnobjs = line->args[3]; + pdd.turnobjs = args[4]; return EV_DoPolyObjRotDisplace(&pdd); } @@ -4259,25 +4301,25 @@ boolean P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, cha case 480: // Polyobj_DoorSlide case 481: // Polyobj_DoorSwing - PolyDoor(line); + PolyDoor(args); break; case 482: // Polyobj_Move - PolyMove(line); + PolyMove(args); break; case 484: // Polyobj_RotateRight - PolyRotate(line); + PolyRotate(args); break; case 488: // Polyobj_Waypoint - PolyWaypoint(line); + PolyWaypoint(args); break; case 489: - PolySetVisibilityTangibility(line); + PolySetVisibilityTangibility(args); break; case 491: - PolyTranslucency(line); + PolyTranslucency(args); break; case 492: - PolyFade(line); + PolyFade(args); break; // SRB2kart @@ -7801,15 +7843,15 @@ void P_SpawnSpecialsThatRequireObjects(boolean fromnetsave) switch (lines[i].special) { case 30: // Polyobj_Flag - PolyFlag(&lines[i]); + PolyFlag(lines[i].args); break; case 31: // Polyobj_Displace - PolyDisplace(&lines[i]); + PolyDisplace(lines[i].args, &lines[i]); break; case 32: // Polyobj_RotDisplace - PolyRotDisplace(&lines[i]); + PolyRotDisplace(lines[i].args, &lines[i]); break; case 80: // Raise tagged things by type to this FOF From 9937592225f9160b1871207eb1244ce882fe961a Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sun, 9 Feb 2025 20:42:34 -0500 Subject: [PATCH 068/117] Fix invisible walls --- src/r_defs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/r_defs.h b/src/r_defs.h index c52b99bfc..1b5b6ffc7 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -376,7 +376,7 @@ typedef enum SSF_REDPOGOSPRING = 1<<11, SSF_YELLOWPOGOSPRING = 1<<12, SSF_FAN = 1<<13, - SSF_FINISHLINE = 1<14, + SSF_FINISHLINE = 1<<14, SSF_ZOOMTUBESTART = 1<<15, SSF_ZOOMTUBEEND = 1<<16, } sectorspecialflags_t; From 034d9df1836278b679df957fad425db8af4e4ccf Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Mon, 10 Feb 2025 01:56:29 +0100 Subject: [PATCH 069/117] Fix Lua HUD interpolation --- src/lua_hooklib.c | 18 +++++++++++++++++- src/lua_hudlib.c | 4 ---- src/lua_hudlib_drawlist.c | 17 ++++++++--------- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index bed747a7c..f186ccabf 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -478,6 +478,21 @@ static int call_mapped(Hook_State *hook, const hook_t *map) return map->numHooks; } +static int call_mapped_hud(Hook_State *hook, const hook_t *map) +{ + int k; + + for (k = 0; k < map->numHooks; ++k) + { + hud_interpolate = hud_interpstring = hud_interplatch = false; + hud_interpcounter++; + get_hook(hook, map->ids, k); + call_single_hook(hook); + } + + return map->numHooks; +} + static int call_string_hooks(Hook_State *hook) { const stringhook_t *map = &stringHooks[hook->hook_type]; @@ -654,10 +669,11 @@ void LUA_HookHUD(huddrawlist_h list, int hook_type) begin_hook_values(&hook); LUA_SetHudHook(hook_type, list); + hud_interpcounter = 0; hud_running = true; // local hook init_hook_call(&hook, 0, res_none); - call_mapped(&hook, map); + call_mapped_hud(&hook, map); hud_running = false; } } diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index cc7004a55..0bfe770fa 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -1419,10 +1419,6 @@ boolean LUA_HudEnabled(enum hud option) void LUA_SetHudHook(int hook, huddrawlist_h list) { lua_getref(gL, lib_draw_ref); - - // Update interpolation - hud_interpolate = hud_interpstring = hud_interplatch = false; - hud_interpcounter++; lua_pushlightuserdata(gL, list); lua_setfield(gL, LUA_REGISTRYINDEX, "HUD_DRAW_LIST"); diff --git a/src/lua_hudlib_drawlist.c b/src/lua_hudlib_drawlist.c index f25e477e6..9a12c7b99 100644 --- a/src/lua_hudlib_drawlist.c +++ b/src/lua_hudlib_drawlist.c @@ -35,6 +35,7 @@ enum drawitem_e { DI_DrawString, DI_FadeScreen, DI_DrawTitleCardString, + DI_DrawTitleCardStringBoss, DI_DrawKartString, DI_MAX, }; @@ -56,21 +57,17 @@ typedef struct drawitem_s { INT32 align; // drawString INT32 num; // drawNum, drawPaddedNum, drawPingNum UINT16 color; // fadeScreen + INT32 timer; // drawTitleCardString }; union { fixed_t vscale; // drawStretched fixed_t h; // drawFill INT32 digits; // drawPaddedNum UINT8 strength; // fadeScreen + INT32 threshold; // drawTitleCardString }; UINT8 *colormap; - union { // for title cards - boolean bossmode; - boolean p4; - INT32 timer; - INT32 threshold; - }; // pointers (and size_t's) last, for potentially better packing union { patch_t *patch; @@ -530,12 +527,11 @@ void LUA_HUD_AddDrawTitleCardString( size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; item->id = GetItemId(); - item->type = DI_DrawTitleCardString; + item->type = bossmode ? DI_DrawTitleCardStringBoss : DI_DrawTitleCardString; item->x = x; item->y = y; item->flags = flags; item->stroffset = CopyString(list, str); - item->bossmode = bossmode; item->timer = timer; item->threshold = threshold; } @@ -688,7 +684,10 @@ void LUA_HUD_DrawList(huddrawlist_h list) V_DrawFadeScreen(item->color, item->strength); break; case DI_DrawTitleCardString: - V_DrawTitleCardString(LERPS(x), LERPS(y), itemstr, item->flags, item->bossmode, item->timer, item->threshold); + V_DrawTitleCardString(LERPS(x), LERPS(y), itemstr, item->flags, false, item->timer, item->threshold); + break; + case DI_DrawTitleCardStringBoss: + V_DrawTitleCardString(LERPS(x), LERPS(y), itemstr, item->flags, true, item->timer, item->threshold); break; case DI_DrawKartString: V_DrawKartString(LERPS(x), LERPS(y), item->flags, itemstr); From cd188a800f9916ec0ed32e93ecb21e7875752b4b Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sun, 9 Feb 2025 23:44:39 +0000 Subject: [PATCH 070/117] Update extras/udmf-spec.txt --- extras/udmf-spec.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extras/udmf-spec.txt b/extras/udmf-spec.txt index df852ee1e..361b051fc 100644 --- a/extras/udmf-spec.txt +++ b/extras/udmf-spec.txt @@ -42,7 +42,7 @@ additional lumps: BEHAVIOR = Compiled ACS code. ZNODES = Compiled extended / GL friendly nodes. These are required. - PICTURE = A Doom graphic lump, expected to be 320x200. Intended to be a + PICTURE = A Doom graphic lump, expected to be 160x100. Intended to be a screenshot of the map itself. This is used by the game for level select menus. MINIMAP = A Doom graphic lump, expected to be 100x100. Intended to be a From 3e8801cc3190a82e94c2726e5cc029ba07697767 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sun, 9 Feb 2025 22:06:27 -0500 Subject: [PATCH 071/117] Use PolyDoorSwing --- src/p_spec.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/p_spec.c b/src/p_spec.c index 9d10b702c..e7a874527 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -4300,9 +4300,11 @@ boolean P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, cha break; case 480: // Polyobj_DoorSlide - case 481: // Polyobj_DoorSwing PolyDoor(args); break; + case 481: // Polyobj_DoorSwing + PolyDoorSwing(args); + break; case 482: // Polyobj_Move PolyMove(args); break; From 628fbd72180955e88dc3591c82aa9ca389237671 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Mon, 10 Feb 2025 20:14:19 +0100 Subject: [PATCH 072/117] Reorganize mapheader_t (prepare for de1f67b) --- src/doomstat.h | 158 +++++++++++++++++++++++++++---------------------- 1 file changed, 86 insertions(+), 72 deletions(-) diff --git a/src/doomstat.h b/src/doomstat.h index 179aa5e0e..8d79bc056 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -348,95 +348,109 @@ struct mapheader_lighting_t */ struct mapheader_t { - char * lumpname; ///< Lump name can be really long - lumpnum_t lumpnum; ///< Lump number for the map - void * thumbnailPic; ///< Lump data for the level select thumbnail. - void * minimapPic; ///< Lump data for the minimap graphic. - 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 - char actnum[3]; ///< SRB2Kart: Now a 2 character long string. - 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 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 + lumpnum_t lumpnum; ///< Lump number for the map - // 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.) + void * thumbnailPic; ///< Lump data for the level select thumbnail. + void * minimapPic; ///< Lump data for the minimap graphic. - 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 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 + char actnum[3]; ///< SRB2Kart: Now a 2 character long string. - 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. + UINT32 typeoflevel; ///< Combination of typeoflevel flags. - // Title card. - char ltzzpatch[8]; ///< Zig zag patch. - char ltzztext[8]; ///< Zig zag text. - char ltactdiamond[8]; ///< Act diamond. + 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. - // 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. + char keywords[33]; ///< Keywords separated by space to search for. 32 characters. - // 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 - - mapheader_lighting_t lighting; ///< Wall and sprite lighting - mapheader_lighting_t lighting_encore; ///< Alternative lighting for Encore mode - boolean use_encore_lighting; ///< Whether to use separate Encore lighting - - boolean use_walltransfer; ///< Whether to use DRRR style wall transfering or not - - // Music stuff. - UINT32 musinterfadeout; ///< Fade out level music on intermission screen in milliseconds - char musintername[7]; ///< Intermission screen music. // Music information char musname[MAXMUSNAMES][7]; ///< Music tracks to play. First dimension is the track number, second is the music string. "" 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. UINT8 musname_size; ///< Number of music tracks defined - char muspostbossname[7]; ///< Post-bossdeath music. - UINT16 muspostbosstrack; ///< Post-bossdeath track. - UINT32 muspostbosspos; ///< Post-bossdeath position - UINT32 muspostbossfadein; ///< Post-bossdeath fade-in milliseconds. + char forcecharacter[17]; ///< (SKINNAMESIZE+1) Skin to switch to or "" to disable. - SINT8 musforcereset; ///< Force resetmusic (-1 for default; 0 for force off; 1 for force on) + 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. - // SRB2Kart: Keeps track of if a map lump exists, so we can tell when a map is being replaced. - boolean alreadyExists; + // 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.) + + 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 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. + + // 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) + + mapheader_lighting_t lighting; ///< Wall and sprite lighting + mapheader_lighting_t lighting_encore; ///< Alternative lighting for Encore mode + boolean use_encore_lighting; ///< Whether to use separate Encore lighting + + // 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. + + boolean alreadyExists; ///< will be removed shortly + // BlanKart + boolean use_walltransfer; ///< Whether to use DRRR style wall transfering or not }; From a1eb4a28654aced6d1e9e8da840a6f3fce2e7bd3 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Mon, 10 Feb 2025 21:25:22 +0100 Subject: [PATCH 073/117] Dehardcode emblems Guess who found out the hard way! --- src/m_cond.c | 121 +-------------------------------------------------- 1 file changed, 2 insertions(+), 119 deletions(-) diff --git a/src/m_cond.c b/src/m_cond.c index fdad03069..fc8931fab 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -30,124 +30,7 @@ UINT32 unlocktriggers; conditionset_t conditionSets[MAXCONDITIONSETS]; // Default Emblem locations -emblem_t emblemlocations[MAXEMBLEMS] = -{ - // GOLD DEV MEDALS - // These values are directly lifted from the Champion ghost, through the power of hex editing! - {ET_TIME, 0, 1, 'A', SKINCOLOR_GOLD, 3021, "", 0}, // Green Hills Zone - 1'26"31 - {ET_TIME, 0, 2, 'A', SKINCOLOR_GOLD, 4466, "", 0}, // Dark Race - 2'07"60 - {ET_TIME, 0, 3, 'A', SKINCOLOR_GOLD, 4337, "", 0}, // Northern District Zone - 2'03"91 - {ET_TIME, 0, 4, 'A', SKINCOLOR_GOLD, 3452, "", 0}, // Darkvile Garden Zone - 1'38"62 - {ET_TIME, 0, 5, 'A', SKINCOLOR_GOLD, 3525, "", 0}, // Daytona Speedway Zone - 1'40"71 - {ET_TIME, 0, 6, 'A', SKINCOLOR_GOLD, 4047, "", 0}, // Egg Zeppelin Zone - 1'55"62 - {ET_TIME, 0, 7, 'A', SKINCOLOR_GOLD, 4041, "", 0}, // Sonic Speedway Zone - 1'55"45 - {ET_TIME, 0, 8, 'A', SKINCOLOR_GOLD, 3281, "", 0}, // Hill Top Zone - 1'33"74 - {ET_TIME, 0, 9, 'A', SKINCOLOR_GOLD, 4764, "", 0}, // Misty Maze Zone - 2'16"11 - {ET_TIME, 0, 10, 'A', SKINCOLOR_GOLD, 4378, "", 0}, // Grand Metropolis - 2'05"08 - {ET_TIME, 0, 11, 'A', SKINCOLOR_GOLD, 3678, "", 0}, // Sunbeam Paradise Zone - 1'45"08 - {ET_TIME, 0, 12, 'A', SKINCOLOR_GOLD, 3928, "", 0}, // Diamond Square Zone - 1'52"22 - {ET_TIME, 0, 13, 'A', SKINCOLOR_GOLD, 3846, "", 0}, // Midnight Meadow Zone - 1'49"88 - {ET_TIME, 0, 14, 'A', SKINCOLOR_GOLD, 3278, "", 0}, // Twinkle Cart - 1'33"65 - {ET_TIME, 0, 15, 'A', SKINCOLOR_GOLD, 3591, "", 0}, // Pleasure Castle - 1'42"60 - {ET_TIME, 0, 16, 'A', SKINCOLOR_GOLD, 5187, "", 0}, // Paradise Hill Zone - 2'28"20 - {ET_TIME, 0, 17, 'A', SKINCOLOR_GOLD, 4976, "", 0}, // Sub-Zero Peak Zone - 2'22"17 - {ET_TIME, 0, 18, 'A', SKINCOLOR_GOLD, 3696, "", 0}, // Sapphire Coast Zone - 1'45"60 - {ET_TIME, 0, 19, 'A', SKINCOLOR_GOLD, 4931, "", 0}, // Sand Valley Zone - 2'20"88 - {ET_TIME, 0, 20, 'A', SKINCOLOR_GOLD, 4220, "", 0}, // Megablock Castle Zone - 2'00"57 - {ET_TIME, 0, 21, 'A', SKINCOLOR_GOLD, 4053, "", 0}, // Canyon Rush Zone - 1'55"80 - {ET_TIME, 0, 22, 'A', SKINCOLOR_GOLD, 3613, "", 0}, // Casino Resort Zone - 1'43"22 - {ET_TIME, 0, 23, 'A', SKINCOLOR_GOLD, 4385, "", 0}, // Silvercloud Island Zone - 2'05"28 - {ET_TIME, 0, 24, 'A', SKINCOLOR_GOLD, 5321, "", 0}, // Blue Mountain Zone - 2'32"02 - {ET_TIME, 0, 25, 'A', SKINCOLOR_GOLD, 4476, "", 0}, // Petroleum Refinery Zone - 2'07"88 - {ET_TIME, 0, 26, 'A', SKINCOLOR_GOLD, 3295, "", 0}, // Desert Palace Zone - 1'34"14 - {ET_TIME, 0, 27, 'A', SKINCOLOR_GOLD, 4765, "", 0}, // Aurora Atoll Zone - 2'16"14 - {ET_TIME, 0, 28, 'A', SKINCOLOR_GOLD, 4670, "", 0}, // Barren Badlands Zone - 2'13"42 - {ET_TIME, 0, 29, 'A', SKINCOLOR_GOLD, 5888, "", 0}, // Red Barrage Area - 2'48"22 - {ET_TIME, 0, 30, 'A', SKINCOLOR_GOLD, 4047, "", 0}, // Midnight Channel - 1'55"62 - {ET_TIME, 0, 31, 'A', SKINCOLOR_GOLD, 4944, "", 0}, // Vanilla Hotel Zone - 2'21"25 - {ET_TIME, 0, 32, 'A', SKINCOLOR_GOLD, 4638, "", 0}, // Toxic Palace Zone - 2'12"51 - {ET_TIME, 0, 33, 'A', SKINCOLOR_GOLD, 4036, "", 0}, // Ancient Tomb Zone - 1'55"31 - {ET_TIME, 0, 34, 'A', SKINCOLOR_GOLD, 3595, "", 0}, // Cloud Cradle Zone K - 1'42"71 - {ET_TIME, 0, 35, 'A', SKINCOLOR_GOLD, 4705, "", 0}, // Volcanic Valley Zone - 2'14"42 - {ET_TIME, 0, 36, 'A', SKINCOLOR_GOLD, 3314, "", 0}, // Kodachrome Void Zone - 1'34"68 - {ET_TIME, 0, 37, 'A', SKINCOLOR_GOLD, 3501, "", 0}, // Boiling Bedrock Zone - 1'40"02 - {ET_TIME, 0, 38, 'A', SKINCOLOR_GOLD, 4920, "", 0}, // Egg Quarters - 2'20"57 - {ET_TIME, 0, 39, 'A', SKINCOLOR_GOLD, 4318, "", 0}, // Virtual Highway Zone - 2'03"37 - {ET_TIME, 0, 40, 'A', SKINCOLOR_GOLD, 3550, "", 0}, // Eggman's Nightclub Zone - 1'41"42 - {ET_TIME, 0, 41, 'A', SKINCOLOR_GOLD, 2572, "", 0}, // KKR Ganbare Dochu 2 - 1'13"48 - {ET_TIME, 0, 42, 'A', SKINCOLOR_GOLD, 3091, "", 0}, // CK Chao Circuit 1 - 1'28"31 - {ET_TIME, 0, 43, 'A', SKINCOLOR_GOLD, 3454, "", 0}, // CK Chao Circuit 2 - 1'38"68 - {ET_TIME, 0, 44, 'A', SKINCOLOR_GOLD, 2958, "", 0}, // CK Cloud Tops 2 - 1'24"51 - {ET_TIME, 0, 45, 'A', SKINCOLOR_GOLD, 3693, "", 0}, // CK Regal Raceway - 1'45"51 - {ET_TIME, 0, 46, 'A', SKINCOLOR_GOLD, 3437, "", 0}, // SD2 Balloon Panic - 1'38"20 - {ET_TIME, 0, 47, 'A', SKINCOLOR_GOLD, 3238, "", 0}, // SM Dimension Heist - 1'32"51 - {ET_TIME, 0, 48, 'A', SKINCOLOR_GOLD, 3063, "", 0}, // MKSC Sky Garden - 1'27"51 - {ET_TIME, 0, 49, 'A', SKINCOLOR_GOLD, 2980, "", 0}, // MKDS Peach Gardens - 1'25"14 - {ET_TIME, 0, 50, 'A', SKINCOLOR_GOLD, 2914, "", 0}, // MKSC Rainbow Road - 1'23"25 - {ET_TIME, 0, 51, 'A', SKINCOLOR_GOLD, 3003, "", 0}, // SMK Donut Plains 1 - 1'25"80 - {ET_TIME, 0, 52, 'A', SKINCOLOR_GOLD, 2930, "", 0}, // SMK Mario Circuit 2 - 1'23"71 - {ET_TIME, 0, 53, 'A', SKINCOLOR_GOLD, 2389, "", 0}, // SMK Ghost Valley 2 - 1'08"25 - {ET_TIME, 0, 54, 'A', SKINCOLOR_GOLD, 4292, "", 0}, // SMK Bowser Castle 3 - 2'02"62 - {ET_TIME, 0, 55, 'A', SKINCOLOR_GOLD, 2346, "", 0}, // SMK Vanilla Lake 2 - 1'07"02 - - // SILVER NORMAL MEDALS - // The general "guideline" of how good we want a player to be at a map. - {ET_TIME, 0, 1, 'B', SKINCOLOR_GREY, 110*TICRATE, "", 0}, // Green Hills Zone - 1'50"00 - {ET_TIME, 0, 2, 'B', SKINCOLOR_GREY, 160*TICRATE, "", 0}, // Dark Race - 2'40"00 - {ET_TIME, 0, 3, 'B', SKINCOLOR_GREY, 160*TICRATE, "", 0}, // Northern District Zone - 2'40"00 - {ET_TIME, 0, 4, 'B', SKINCOLOR_GREY, 120*TICRATE, "", 0}, // Darkvile Garden Zone - 2'00"00 - {ET_TIME, 0, 5, 'B', SKINCOLOR_GREY, 130*TICRATE, "", 0}, // Daytona Speedway Zone - 2'10"00 - {ET_TIME, 0, 6, 'B', SKINCOLOR_GREY, 140*TICRATE, "", 0}, // Egg Zeppelin Zone - 2'20"00 - {ET_TIME, 0, 7, 'B', SKINCOLOR_GREY, 140*TICRATE, "", 0}, // Sonic Speedway Zone - 2'20"00 - {ET_TIME, 0, 8, 'B', SKINCOLOR_GREY, 110*TICRATE, "", 0}, // Hill Top Zone - 1'50"00 - {ET_TIME, 0, 9, 'B', SKINCOLOR_GREY, 170*TICRATE, "", 0}, // Misty Maze Zone - 2'50"00 - {ET_TIME, 0, 10, 'B', SKINCOLOR_GREY, 140*TICRATE, "", 0}, // Grand Metropolis - 2'20"00 - {ET_TIME, 0, 11, 'B', SKINCOLOR_GREY, 120*TICRATE, "", 0}, // Sunbeam Paradise Zone - 2'00"00 - {ET_TIME, 0, 12, 'B', SKINCOLOR_GREY, 130*TICRATE, "", 0}, // Diamond Square Zone - 2'10"00 - {ET_TIME, 0, 13, 'B', SKINCOLOR_GREY, 135*TICRATE, "", 0}, // Midnight Meadow Zone - 2'15"00 - {ET_TIME, 0, 14, 'B', SKINCOLOR_GREY, 120*TICRATE, "", 0}, // Twinkle Cart - 2'00"00 - {ET_TIME, 0, 15, 'B', SKINCOLOR_GREY, 120*TICRATE, "", 0}, // Pleasure Castle - 2'00"00 - {ET_TIME, 0, 16, 'B', SKINCOLOR_GREY, 160*TICRATE, "", 0}, // Paradise Hill Zone - 2'40"00 - {ET_TIME, 0, 17, 'B', SKINCOLOR_GREY, 170*TICRATE, "", 0}, // Sub-Zero Peak Zone - 2'50"00 - {ET_TIME, 0, 18, 'B', SKINCOLOR_GREY, 130*TICRATE, "", 0}, // Sapphire Coast Zone - 2'10"00 - {ET_TIME, 0, 19, 'B', SKINCOLOR_GREY, 170*TICRATE, "", 0}, // Sand Valley Zone - 2'50"00 - {ET_TIME, 0, 20, 'B', SKINCOLOR_GREY, 145*TICRATE, "", 0}, // Megablock Castle Zone - 2'25"00 - {ET_TIME, 0, 21, 'B', SKINCOLOR_GREY, 140*TICRATE, "", 0}, // Canyon Rush Zone - 2'20"00 - {ET_TIME, 0, 22, 'B', SKINCOLOR_GREY, 120*TICRATE, "", 0}, // Casino Resort Zone - 2'00"00 - {ET_TIME, 0, 23, 'B', SKINCOLOR_GREY, 150*TICRATE, "", 0}, // Silvercloud Island Zone - 2'30"00 - {ET_TIME, 0, 24, 'B', SKINCOLOR_GREY, 170*TICRATE, "", 0}, // Blue Mountain Zone - 2'50"00 - {ET_TIME, 0, 25, 'B', SKINCOLOR_GREY, 150*TICRATE, "", 0}, // Petroleum Refinery Zone - 2'30"00 - {ET_TIME, 0, 26, 'B', SKINCOLOR_GREY, 120*TICRATE, "", 0}, // Desert Palace Zone - 2'00"00 - {ET_TIME, 0, 27, 'B', SKINCOLOR_GREY, 160*TICRATE, "", 0}, // Aurora Atoll Zone - 2'40"00 - {ET_TIME, 0, 28, 'B', SKINCOLOR_GREY, 150*TICRATE, "", 0}, // Barren Badlands Zone - 2'30"00 - {ET_TIME, 0, 29, 'B', SKINCOLOR_GREY, 170*TICRATE, "", 0}, // Red Barrage Area - 2'50"00 - {ET_TIME, 0, 30, 'B', SKINCOLOR_GREY, 135*TICRATE, "", 0}, // Midnight Channel - 2'15"00 - {ET_TIME, 0, 31, 'B', SKINCOLOR_GREY, 160*TICRATE, "", 0}, // Vanilla Hotel Zone - 2'40"00 - {ET_TIME, 0, 32, 'B', SKINCOLOR_GREY, 160*TICRATE, "", 0}, // Toxic Palace Zone - 2'40"00 - {ET_TIME, 0, 33, 'B', SKINCOLOR_GREY, 150*TICRATE, "", 0}, // Ancient Tomb Zone - 2'30"00 - {ET_TIME, 0, 34, 'B', SKINCOLOR_GREY, 120*TICRATE, "", 0}, // Cloud Cradle Zone K - 2'00"00 - {ET_TIME, 0, 35, 'B', SKINCOLOR_GREY, 165*TICRATE, "", 0}, // Volcanic Valley Zone - 2'45"00 - {ET_TIME, 0, 36, 'B', SKINCOLOR_GREY, 110*TICRATE, "", 0}, // Kodachrome Void Zone - 1'50"00 - {ET_TIME, 0, 37, 'B', SKINCOLOR_GREY, 130*TICRATE, "", 0}, // Boiling Bedrock Zone - 2'10"00 - {ET_TIME, 0, 38, 'B', SKINCOLOR_GREY, 165*TICRATE, "", 0}, // Egg Quarters - 2'45"00 - {ET_TIME, 0, 39, 'B', SKINCOLOR_GREY, 145*TICRATE, "", 0}, // Virtual Highway Zone - 2'25"00 - {ET_TIME, 0, 40, 'B', SKINCOLOR_GREY, 120*TICRATE, "", 0}, // Eggman's Nightclub Zone - 2'00"00 - {ET_TIME, 0, 41, 'B', SKINCOLOR_GREY, 100*TICRATE, "", 0}, // KKR Ganbare Dochu 2 - 1'40"00 - {ET_TIME, 0, 42, 'B', SKINCOLOR_GREY, 110*TICRATE, "", 0}, // CK Chao Circuit 1 - 1'50"00 - {ET_TIME, 0, 43, 'B', SKINCOLOR_GREY, 120*TICRATE, "", 0}, // CK Chao Circuit 2 - 2'00"00 - {ET_TIME, 0, 44, 'B', SKINCOLOR_GREY, 110*TICRATE, "", 0}, // CK Cloud Tops 2 - 1'50"00 - {ET_TIME, 0, 45, 'B', SKINCOLOR_GREY, 130*TICRATE, "", 0}, // CK Regal Raceway - 2'10"00 - {ET_TIME, 0, 46, 'B', SKINCOLOR_GREY, 110*TICRATE, "", 0}, // SD2 Balloon Panic - 1'50"00 - {ET_TIME, 0, 47, 'B', SKINCOLOR_GREY, 130*TICRATE, "", 0}, // SM Dimension Heist - 2'10"00 - {ET_TIME, 0, 48, 'B', SKINCOLOR_GREY, 110*TICRATE, "", 0}, // MKSC Sky Garden - 1'50"00 - {ET_TIME, 0, 49, 'B', SKINCOLOR_GREY, 105*TICRATE, "", 0}, // MKDS Peach Gardens - 1'45"00 - {ET_TIME, 0, 50, 'B', SKINCOLOR_GREY, 120*TICRATE, "", 0}, // MKSC Rainbow Road - 2'00"00 - {ET_TIME, 0, 51, 'B', SKINCOLOR_GREY, 100*TICRATE, "", 0}, // SMK Donut Plains 1 - 1'40"00 - {ET_TIME, 0, 52, 'B', SKINCOLOR_GREY, 105*TICRATE, "", 0}, // SMK Mario Circuit 2 - 1'45"00 - {ET_TIME, 0, 53, 'B', SKINCOLOR_GREY, 90*TICRATE, "", 0}, // SMK Ghost Valley 2 - 1'30"00 - {ET_TIME, 0, 54, 'B', SKINCOLOR_GREY, 150*TICRATE, "", 0}, // SMK Bowser Castle 3 - 2'30"00 - {ET_TIME, 0, 55, 'B', SKINCOLOR_GREY, 90*TICRATE, "", 0} // SMK Vanilla Lake 2 - 1'30"00 -}; +emblem_t emblemlocations[MAXEMBLEMS] = {0}; // Default Extra Emblems extraemblem_t extraemblems[MAXEXTRAEMBLEMS] = @@ -177,7 +60,7 @@ unlockable_t unlockables[MAXUNLOCKABLES] = }; // Number of emblems and extra emblems -INT32 numemblems = 110; +INT32 numemblems = 0; INT32 numextraemblems = 5; // DEFAULT CONDITION SETS FOR SRB2KART: From a78bfe278576945b661c58ec2e7fb59e8406162a Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Mon, 10 Feb 2025 21:56:07 +0100 Subject: [PATCH 074/117] The rest of the changes from de1f67b --- src/d_main.cpp | 15 ++++++---- src/deh_soc.c | 73 +++++++++++++++++++----------------------------- src/doomstat.h | 16 +++++------ src/f_finale.c | 8 ++++-- src/g_demo.c | 1 + src/g_game.c | 56 ++++++++++++++++++++++++++++--------- src/lua_maplib.c | 4 +-- src/lua_script.c | 6 ++-- src/m_cond.c | 27 +++++++++++++++--- src/m_cond.h | 2 +- src/m_menu.c | 15 ++++++++-- src/p_setup.c | 17 +++++++++-- 12 files changed, 152 insertions(+), 88 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 787485029..c45ab030f 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1792,13 +1792,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 > nummapheaders) - 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/deh_soc.c b/src/deh_soc.c index a6a44456b..f5b2b11fa 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -148,7 +148,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 @@ -1061,11 +1064,14 @@ static mapheader_lighting_t *usemaplighting(INT32 mapnum, const char *word) 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) @@ -1254,6 +1260,14 @@ void readlevelheader(MYFILE *f, char * name) } // Strings that can be truncated + 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, @@ -1278,30 +1292,6 @@ void readlevelheader(MYFILE *f, char * name) deh_strlcpy(mapheaderinfo[num-1]->actnum, word2, sizeof(mapheaderinfo[num-1]->actnum), va("Level header %d: actnum", num)); } - else if (fastcmp(word, "NEXTLEVEL")) - { - if (fastcmp(word2, "TITLE")) i = 1100; - else if (fastcmp(word2, "EVALUATION")) i = 1101; - else if (fastcmp(word2, "CREDITS")) i = 1102; - else if (fastcmp(word2, "ENDING")) i = 1103; - else - - i = G_MapNumber(word2); - - mapheaderinfo[num-1]->nextlevel = (INT16)i; - } - else if (fastcmp(word, "MARATHONNEXT")) - { - if (fastcmp(word2, "TITLE")) i = 1100; - else if (fastcmp(word2, "EVALUATION")) i = 1101; - else if (fastcmp(word2, "CREDITS")) i = 1102; - else if (fastcmp(word2, "ENDING")) i = 1103; - else - - i = G_MapNumber(word2); - - mapheaderinfo[num-1]->marathonnext = (INT16)i; - } else if (fastcmp(word, "TYPEOFLEVEL")) { if (i) // it's just a number @@ -2567,7 +2557,7 @@ void reademblemdata(MYFILE *f, INT32 num) emblemlocations[num-1].tag = (INT16)value; else if (fastcmp(word, "MAPNUM")) { - emblemlocations[num-1].level = (INT16)G_MapNumber(word2); + emblemlocations[num-1].level = Z_StrDup(word2); } else if (fastcmp(word, "SPRITE")) { @@ -2788,6 +2778,7 @@ void readunlockable(MYFILE *f, INT32 num) } else if (fastcmp(word, "VAR")) { + // TODO: different field for level name string unlockables[num].variable = (INT16)G_MapNumber(word2); } else @@ -2866,8 +2857,6 @@ 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 re = G_MapNumber(params[1]); if (re < 0 || re >= NUMMAPS) @@ -2881,9 +2870,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 - x1 = (INT16)G_MapNumber(params[1]); + x1 = G_MapNumber(params[1]); if (x1 < 0 || x1 >= NUMMAPS) { @@ -3086,7 +3073,10 @@ void readmaincfg(MYFILE *f) else if (fastcmp(word, "SPSTAGE_START")) { - spstage_start = (INT16)G_MapNumber(word2); + // 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")) { @@ -3184,7 +3174,7 @@ void readmaincfg(MYFILE *f) } else if (fastcmp(word, "TITLEMAP")) { - titlemap = (INT16)G_MapNumber(word2); + titlemap = Z_StrDup(word2); titlechanged = true; } else if (fastcmp(word, "HIDETITLEPICS") || fastcmp(word, "TITLEPICSHIDE")) @@ -3310,12 +3300,12 @@ void readmaincfg(MYFILE *f) } else if (fastcmp(word, "BOOTMAP")) { - bootmap = (INT16)G_MapNumber(word2); + bootmap = Z_StrDup(word2); //titlechanged = true; } else if (fastcmp(word, "TUTORIALMAP")) { - tutorialmap = (INT16)G_MapNumber(word2); + tutorialmap = Z_StrDup(word2); } else deh_warning("Maincfg: unknown word '%s'", word); @@ -3538,30 +3528,23 @@ void readcupheader(MYFILE *f, cupheader_t *cup) tmp = strtok(word2,","); do { - INT32 map = atoi(tmp); - - 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")) { - i = (INT16)G_MapNumber(word2); - cup->bonusgame = (INT16)i - 1; + cup->bonusgame = Z_StrDup(word2); } else if (fastcmp(word, "SPECIALSTAGE")) { - i = (INT16)G_MapNumber(word2); - cup->specialstage = (INT16)i - 1; + cup->specialstage = Z_StrDup(word2); } else if (fastcmp(word, "EMERALDNUM")) { diff --git a/src/doomstat.h b/src/doomstat.h index 8d79bc056..f96b9377d 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -194,11 +194,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? @@ -361,8 +361,8 @@ struct mapheader_t 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 * nextlevel; ///< Map number of next level, or 1100-1102 to end. + char * 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. @@ -479,10 +479,10 @@ struct cupheader_t 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. cupheader_t *next; ///< Next cup in linked list diff --git a/src/f_finale.c b/src/f_finale.c index ea6efc94f..7d8f26fee 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1118,6 +1118,8 @@ static void F_CacheTitleScreen(void) void F_StartTitleScreen(void) { + const INT32 titleMapNum = titlemap ? G_MapNumber(titlemap) : 0; + if (gamestate != GS_TITLESCREEN && gamestate != GS_WAITINGPLAYERS) { ttuser_count = 0; @@ -1127,14 +1129,14 @@ void F_StartTitleScreen(void) else wipegamestate = GS_TITLESCREEN; - if (titlemap) + if (titlemap && mapheaderinfo[titleMapNum]) { mapthing_t *startpos; gamestate_t prevwipegamestate = wipegamestate; titlemapinaction = TITLEMAP_LOADING; titlemapcameraref = NULL; - gamemap = titlemap; + gamemap = titleMapNum; if (!mapheaderinfo[gamemap-1]) P_AllocMapHeader(gamemap-1); @@ -1143,7 +1145,7 @@ void F_StartTitleScreen(void) 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 287629c07..e56aa6c6e 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -3692,6 +3692,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 714c876bb..a498b7cd1 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -154,11 +154,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? @@ -3787,7 +3787,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) { @@ -3804,16 +3809,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. @@ -3840,9 +3856,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) { @@ -5016,14 +5046,14 @@ INT32 G_FindMapByNameOrCode(const char *mapname, char **realmapnamep) return gamemap; else if (mapname[0] == '+' && mapheaderinfo[gamemap-1]) // next map { - newmapnum = mapheaderinfo[gamemap-1]->nextlevel; - if (newmapnum < 1 || newmapnum > NUMMAPS) + newmapnum = G_MapNumber(mapheaderinfo[gamemap-1]->nextlevel); + if (!mapheaderinfo[newmapnum]) { CONS_Alert(CONS_ERROR, M_GetText("NextLevel (%d) is not a valid map.\n"), newmapnum); return 0; } else - return newmapnum; + return newmapnum-1; } } diff --git a/src/lua_maplib.c b/src/lua_maplib.c index fac13ca65..1391ad98d 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -2511,9 +2511,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")) // we create a table here because it saves us from a userdata nightmare diff --git a/src/lua_script.c b/src/lua_script.c index 0f40b6a7d..72e41a56a 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -232,16 +232,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 fc8931fab..9844bcf71 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -350,10 +350,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) @@ -383,10 +390,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; @@ -539,7 +553,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 c23d8ff72..dfa34dc8d 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -80,7 +80,7 @@ struct emblem_t { 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 c68ae8ebb..2bae68dc5 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -2239,6 +2239,7 @@ static void Dummystaff_OnChange(void) dummystaffname[0] = '\0'; + // TODO: Use map header to determine lump name if ((l = W_CheckNumForName(va("%sS01",G_BuildMapName(cv_nextmap.value)))) == LUMPERROR) { CV_StealthSetValue(&cv_dummystaff, 0); @@ -6614,8 +6615,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) @@ -7780,6 +7788,7 @@ static void M_GrandPrixTemp(INT32 choice) static void M_StartGrandPrix(INT32 choice) { cupheader_t *gpcup = kartcupheaders; + INT32 levelNum; (void)choice; @@ -7831,9 +7840,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 diff --git a/src/p_setup.c b/src/p_setup.c index b29fb3e48..bf4bcb6e1 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -410,6 +410,18 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) mapheaderinfo[num]->minimapPic = 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'; @@ -419,8 +431,6 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) mapheaderinfo[num]->ltactdiamond[0] = '\0'; mapheaderinfo[num]->actnum[0] = '\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; @@ -493,6 +503,8 @@ 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++; @@ -8051,6 +8063,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_CheckNumForName(va("%sS%02u",G_BuildMapName(gamemap),j))) != LUMPERROR) { G_AddGhost(va("%sS%02u",G_BuildMapName(gamemap),j)); From bec03f0a7ab2ee64229ba60249afb86e154131f7 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Mon, 10 Feb 2025 18:09:29 -0500 Subject: [PATCH 075/117] repair 'Change scroller direction' --- src/p_setup.c | 1 + src/p_spec.c | 38 +++++++++++++++++++++++++++++++------- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index bf4bcb6e1..703ce5949 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -6073,6 +6073,7 @@ static void P_ConvertBinaryLinedefTypes(void) case 435: //Change plane scroller direction lines[i].args[0] = tag; lines[i].args[1] = R_PointToDist2(lines[i].v2->x, lines[i].v2->y, lines[i].v1->x, lines[i].v1->y) >> FRACBITS; + lines[i].args[2] = AngleFixed(R_PointToAngle2(lines[i].v2->x, lines[i].v2->y, lines[i].v1->x, lines[i].v1->y)) >> FRACBITS; break; case 436: //Shatter FOF lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; diff --git a/src/p_spec.c b/src/p_spec.c index 725189401..345f7df12 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -3172,10 +3172,15 @@ boolean P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, cha scroll_t *scroller; thinker_t *th; - fixed_t length = R_PointToDist2(line->v2->x, line->v2->y, line->v1->x, line->v1->y); - fixed_t speed = args[1] << FRACBITS; - fixed_t dx = FixedMul(FixedMul(FixedDiv(line->dx, length), speed) >> SCROLL_SHIFT, CARRYFACTOR); - fixed_t dy = FixedMul(FixedMul(FixedDiv(line->dy, length), speed) >> SCROLL_SHIFT, CARRYFACTOR); + fixed_t speed; + angle_t angle; + fixed_t dx; + fixed_t dy; + + speed = args[1] << FRACBITS; + angle = FixedAngle(args[2] << FRACBITS) >> ANGLETOFINESHIFT; + dx = FixedMul(FINECOSINE(angle), speed) >> SCROLL_SHIFT; + dy = FixedMul( FINESINE(angle), speed) >> SCROLL_SHIFT; for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next) { @@ -3183,11 +3188,30 @@ boolean P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, cha continue; scroller = (scroll_t *)th; - if (!Tag_Find(§ors[scroller->affectee].tags, args[0])) + + const taglist_t* taglist = (scroller->type == sc_side) + ? &sides[scroller->affectee].line->tags + : §ors[scroller->affectee].tags; + + if (!Tag_Find(taglist, args[0])) continue; - scroller->dx = dx; - scroller->dy = dy; + switch (scroller->type) + { + case sc_carry: + case sc_carry_ceiling: + { + scroller->dx = FixedMul(-dx, CARRYFACTOR); + scroller->dy = FixedMul(dy, CARRYFACTOR); + break; + } + default: + { + scroller->dx = dx; + scroller->dy = dy; + break; + } + } } } break; From 6a2553cf571301968a91668a62604df61dd9df7d Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 16 Sep 2022 22:51:02 +0100 Subject: [PATCH 076/117] 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.cpp | 2 +- src/deh_soc.c | 221 ++++++++++++++++++++++++++----------------------- src/f_finale.c | 3 +- src/g_game.c | 12 +-- src/p_setup.c | 87 ++----------------- src/p_setup.h | 3 - src/r_patch.c | 2 +- src/w_wad.c | 16 ---- 8 files changed, 134 insertions(+), 212 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index c45ab030f..2a198bf34 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1792,7 +1792,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 f5b2b11fa..4223b1733 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -161,12 +161,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); } static boolean findFreeSlot(INT32 *num) @@ -1051,13 +1061,13 @@ static mapheader_lighting_t *usemaplighting(INT32 mapnum, const char *word) { if (fastncmp(word, "ENCORE", 6)) { - mapheaderinfo[mapnum-1]->use_encore_lighting = true; + mapheaderinfo[mapnum]->use_encore_lighting = true; - return &mapheaderinfo[mapnum-1]->lighting_encore; + return &mapheaderinfo[mapnum]->lighting_encore; } else { - return &mapheaderinfo[mapnum-1]->lighting; + return &mapheaderinfo[mapnum]->lighting; } } @@ -1074,14 +1084,14 @@ void readlevelheader(MYFILE *f, char * name) const INT32 num = G_MapNumber(name); - if (num > NUMMAPS) + if (num >= NUMMAPS) { I_Error("Too many maps!"); } if (num >= nummapheaders) { - P_AllocMapHeader((INT16)(num -1)); + P_AllocMapHeader((INT16)(num)); } else if (f->wad > mainwads) { @@ -1089,9 +1099,9 @@ void readlevelheader(MYFILE *f, char * name) G_SetGameModified(multiplayer, true); } - 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 @@ -1130,16 +1140,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; } @@ -1161,19 +1171,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'; @@ -1189,33 +1199,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; @@ -1229,7 +1239,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! { @@ -1242,17 +1252,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); @@ -1262,40 +1272,40 @@ 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 < 20) // 0 for no act number, TTL1 through TTL19 - mapheaderinfo[num-1]->actnum = (UINT8)i; + mapheaderinfo[num]->actnum = (UINT8)i; else deh_warning("Level header %d: invalid act number %d", num, i);*/ - deh_strlcpy(mapheaderinfo[num-1]->actnum, word2, - sizeof(mapheaderinfo[num-1]->actnum), va("Level header %d: actnum", num)); + deh_strlcpy(mapheaderinfo[num]->actnum, word2, + sizeof(mapheaderinfo[num]->actnum), va("Level header %d: actnum", num)); } 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; @@ -1308,20 +1318,20 @@ 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] = 0; // becomes empty string - mapheaderinfo[num-1]->musname_size = 0; + mapheaderinfo[num]->musname[0][0] = 0; // becomes empty string + mapheaderinfo[num]->musname_size = 0; } else { @@ -1330,71 +1340,71 @@ void readlevelheader(MYFILE *f, char * name) do { if (j >= MAXMUSNAMES) break; - deh_strlcpy(mapheaderinfo[num-1]->musname[j], tmp, - sizeof(mapheaderinfo[num-1]->musname[j]), va("Level header %d: music", num)); + deh_strlcpy(mapheaderinfo[num]->musname[j], tmp, + sizeof(mapheaderinfo[num]->musname[j]), va("Level header %d: music", num)); j++; } while ((tmp = strtok(NULL,",")) != NULL); if (tmp != NULL) deh_warning("Level header %d: additional music slots past %d discarded", num, MAXMUSNAMES); - mapheaderinfo[num-1]->musname_size = j; + mapheaderinfo[num]->musname_size = j; } } 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, "SKYNUM")) - deh_strlcpy(mapheaderinfo[num-1]->skytexture, va("SKY%s", word2), - sizeof(mapheaderinfo[num-1]->skytexture), va("Level header %d: sky texture", num)); + deh_strlcpy(mapheaderinfo[num]->skytexture, va("SKY%s", 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, "LEVELSELECT")) - mapheaderinfo[num-1]->levelselect = (UINT8)i; + mapheaderinfo[num]->levelselect = (UINT8)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")) { usemaplighting(num, word)->light_contrast = (UINT8)i; @@ -1422,76 +1432,76 @@ void readlevelheader(MYFILE *f, char * name) 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, "NOVISITNEEDED")) { 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 if (fastcmp(word, "WALLTRANSFER") || fastcmp(word, "WALLRUNNING")) { if (i || word2[0] == 'T' || word2[0] == 'Y') - mapheaderinfo[num-1]->use_walltransfer = true; + mapheaderinfo[num]->use_walltransfer = true; else - mapheaderinfo[num-1]->use_walltransfer = false; + mapheaderinfo[num]->use_walltransfer = false; } else deh_warning("Level header %d: unknown word '%s'", num, word); @@ -3534,8 +3544,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 7d8f26fee..c44515d45 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1118,7 +1118,7 @@ static void F_CacheTitleScreen(void) void F_StartTitleScreen(void) { - const INT32 titleMapNum = titlemap ? G_MapNumber(titlemap) : 0; + const INT32 titleMapNum = titlemap ? G_MapNumber(titlemap)+1 : 0; if (gamestate != GS_TITLESCREEN && gamestate != GS_WAITINGPLAYERS) { @@ -1133,6 +1133,7 @@ void F_StartTitleScreen(void) { mapthing_t *startpos; + 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 a498b7cd1..b835074de 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -734,7 +734,7 @@ INT32 G_MapNumber(const char * name) } } - return map + 1; + return map; } /** Clips the console player's mouse aiming to the current view. @@ -3791,7 +3791,7 @@ static void G_DoCompleted(void) if (mapheaderinfo[mNextNum]) { - nextmap = (INT16)(mNextNum-1); + nextmap = (INT16)mNextNum; } } else if (grandprixinfo.gp == true) @@ -3826,7 +3826,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 } @@ -3862,7 +3862,7 @@ static void G_DoCompleted(void) if (!mapheaderinfo[mNextNum]) cm = -1; // guarantee error execution else - cm = (INT16)(mNextNum-1); + cm = (INT16)mNextNum; } else { @@ -3871,7 +3871,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) @@ -5070,7 +5070,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 703ce5949..9c4ef78e3 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -398,29 +398,17 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) const INT16 num = (INT16)(i-1); boolean exists = (mapheaderinfo[gamemap-1]->alreadyExists == true); - 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'; @@ -843,65 +831,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_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 int cmp_loopends(const void *a, const void *b) { const mapthing_t diff --git a/src/p_setup.h b/src/p_setup.h index 590d1db87..22f6bdca1 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -103,9 +103,6 @@ extern size_t nummapthings; extern mapthing_t *mapthings; 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); void P_PostLoadLevel(void); 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 044fb1e35..6de1fe115 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_MapNumber #include "k_terrain.h" @@ -308,19 +305,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; - INT16 mapnum = (INT16)G_MapNumber(name); - P_ScanThings(mapnum, wadnum, lump + ML_THINGS); - } - } -#endif } static inline boolean CheckCompatFilename(const char *filename) From 78fb4df0545e4c1c7307ec2cc2dbba0811702ed1 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 16 Sep 2022 23:13:54 +0100 Subject: [PATCH 077/117] 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 4223b1733..923e7b448 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -3546,7 +3546,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 f8b4ad70ea2ba7c6fdd8edea51e63a4768b85ac9 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 16 Sep 2022 23:40:42 +0100 Subject: [PATCH 078/117] 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.cpp | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 2a198bf34..e8ed26a90 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1792,19 +1792,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 bda189ac5bd50b298f3d6fd30aeb92bb77e98c41 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 17 Sep 2022 00:43:26 +0100 Subject: [PATCH 079/117] 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 9c4ef78e3..c4d030f33 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -398,12 +398,6 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) const INT16 num = (INT16)(i-1); boolean exists = (mapheaderinfo[gamemap-1]->alreadyExists == true); - 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 b92c1259281dcae5e2440488e56de7dc89a5fbc2 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 17 Sep 2022 13:07:48 +0100 Subject: [PATCH 080/117] 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 | 35 +--------------------------- src/d_netcmd.c | 20 +++++++++++----- src/deh_soc.c | 58 +++++++++++++++++++++++------------------------ src/g_game.c | 32 ++++++++++---------------- src/lua_baselib.c | 6 ++--- src/lua_maplib.c | 6 ++--- src/m_menu.c | 4 ++-- src/p_saveg.c | 8 +++---- src/y_inter.c | 4 ++-- 9 files changed, 69 insertions(+), 104 deletions(-) diff --git a/src/command.c b/src/command.c index 29039d574..9a29966f9 100644 --- a/src/command.c +++ b/src/command.c @@ -1992,42 +1992,9 @@ 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; - } - } #define MINVAL 0 #define MAXVAL 1 - else if (var->PossibleValue[MINVAL].strvalue && !strcmp(var->PossibleValue[MINVAL].strvalue, "MIN")) + if (var->PossibleValue[MINVAL].strvalue && !strcmp(var->PossibleValue[MINVAL].strvalue, "MIN")) { #ifdef PARANOIA if (!var->PossibleValue[MAXVAL].strvalue) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index dbadef71f..149c8835e 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -5384,8 +5384,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) @@ -5398,13 +5399,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 923e7b448..0e94eea05 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -142,41 +142,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 } static boolean findFreeSlot(INT32 *num) @@ -2827,7 +2825,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; } @@ -2847,7 +2845,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; } } @@ -2869,9 +2867,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; } } @@ -2882,9 +2880,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; } } @@ -2897,7 +2895,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; } } @@ -2915,7 +2913,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; } } @@ -2927,7 +2925,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; } } @@ -2939,13 +2937,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_game.c b/src/g_game.c index b835074de..2e0716c20 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3455,13 +3455,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; @@ -3493,7 +3493,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) @@ -3637,7 +3637,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--) @@ -3846,7 +3846,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)); @@ -3874,7 +3874,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. @@ -3899,7 +3899,7 @@ static void G_DoCompleted(void) nextmap = cm; } - 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) @@ -3924,7 +3924,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); @@ -4772,11 +4772,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; @@ -4813,11 +4808,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, "")) { diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 0ff37d383..dd1a8c04a 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -3165,12 +3165,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 1391ad98d..e1bc3892e 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -2468,8 +2468,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); @@ -2487,7 +2487,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/m_menu.c b/src/m_menu.c index 2bae68dc5..d1dd737a9 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -4535,7 +4535,7 @@ static INT32 M_CountLevelsToShowInList(void) { INT32 mapnum, count = 0; - for (mapnum = 0; mapnum < NUMMAPS; mapnum++) + for (mapnum = 0; mapnum < nummapheaders; mapnum++) if (M_CanShowLevelInList(mapnum, -1)) count++; @@ -4546,7 +4546,7 @@ static INT32 M_GetFirstLevelInList(void) { INT32 mapnum; - for (mapnum = 0; mapnum < NUMMAPS; mapnum++) + for (mapnum = 0; mapnum < nummapheaders; mapnum++) if (M_CanShowLevelInList(mapnum, -1)) return mapnum + 1; diff --git a/src/p_saveg.c b/src/p_saveg.c index 859418d99..0efd5a250 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -4888,8 +4888,8 @@ static inline void P_UnArchiveSPGame(savebuffer_t *save, 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; @@ -5077,8 +5077,8 @@ FUNCINLINE static ATTRINLINE boolean P_NetUnArchiveMisc(savebuffer_t *save, bool // 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 a25e3ba7c..db7f30f64 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -1035,8 +1035,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 4c109c7161cd0c8c8eaa99154d3eb7106c74723f Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 17 Sep 2022 14:08:11 +0100 Subject: [PATCH 081/117] 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 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index 2e0716c20..74f6667bd 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3514,7 +3514,7 @@ tryagain: { boolean isokmap = true; - if (!mapheaderinfo[ix]) + if (!mapheaderinfo[ix] || mapheaderinfo[ix]->lumpnum == LUMPERROR) continue; if ((mapheaderinfo[ix]->typeoflevel & tolflags) != tolflags From e76f92e5db93df76eed6b6fa5106bfa369f46852 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 28 Aug 2022 23:15:45 +0100 Subject: [PATCH 082/117] Port Gametype Preference and associated changes Notably, makes the PWR-based Encore scrambling component of G_SometimesGetDifferentGametype WAY less spaghettified. --- src/d_clisrv.c | 5 ++- src/d_netcmd.c | 43 +++++++++++++++++++------ src/d_netcmd.h | 1 + src/g_game.c | 86 ++++++++++++++++++++++++++++---------------------- src/g_game.h | 3 +- src/k_kart.c | 1 + src/y_inter.c | 9 +++--- 7 files changed, 95 insertions(+), 53 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index c8041d431..3ae992525 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -909,6 +909,9 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime) UINT8 *p; size_t mirror_length; const char *httpurl = cv_httpsource.string; + UINT8 prefgametype = (cv_kartgametypepreference.value == -1) + ? gametype + : cv_kartgametypepreference.value; netbuffer->packettype = PT_SERVERINFO; netbuffer->u.serverinfo._255 = 255; @@ -933,7 +936,7 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime) else netbuffer->u.serverinfo.refusereason = 0; - strncpy(netbuffer->u.serverinfo.gametypename, Gametype_Names[gametype], + strncpy(netbuffer->u.serverinfo.gametypename, Gametype_Names[prefgametype], sizeof netbuffer->u.serverinfo.gametypename); netbuffer->u.serverinfo.modifiedgame = (UINT8)modifiedgame; netbuffer->u.serverinfo.cheatsenabled = CV_CheatsEnabled(); diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 149c8835e..03985dd96 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -399,6 +399,8 @@ static CV_PossibleValue_t kartencore_cons_t[] = {{-1, "Auto"}, {0, "Off"}, {1, " consvar_t cv_kartencore = CVAR_INIT ("kartencore", "Auto", CV_NETVAR|CV_CALL|CV_NOINIT, kartencore_cons_t, KartEncore_OnChange); static CV_PossibleValue_t kartvoterulechanges_cons_t[] = {{0, "Never"}, {1, "Sometimes"}, {2, "Frequent"}, {3, "Always"}, {0, NULL}}; consvar_t cv_kartvoterulechanges = CVAR_INIT ("kartvoterulechanges", "Frequent", CV_NETVAR, kartvoterulechanges_cons_t, NULL); +static CV_PossibleValue_t kartgametypepreference_cons_t[] = {{-1, "None"}, {GT_RACE, "Race"}, {GT_BATTLE, "Battle"}, {0, NULL}}; +consvar_t cv_kartgametypepreference = CVAR_INIT ("kartgametypepreference", "None", CV_NETVAR, kartgametypepreference_cons_t, NULL); static CV_PossibleValue_t kartspeedometer_cons_t[] = {{0, "Off"}, {1, "Kilometers"}, {2, "Miles"}, {3, "Fracunits"}, {4, "Percentage"}, {0, NULL}}; consvar_t cv_kartspeedometer = CVAR_INIT ("kartdisplayspeed", "Percentage", CV_SAVE, kartspeedometer_cons_t, NULL); // use tics in display static CV_PossibleValue_t kartvoices_cons_t[] = {{0, "Never"}, {1, "Tasteful"}, {2, "Meme"}, {0, NULL}}; @@ -2650,27 +2652,28 @@ void D_SetupVote(void) UINT8 buf[5*2]; // four UINT16 maps (at twice the width of a UINT8), and two gametypes UINT8 *p = buf; INT32 i; - UINT8 secondgt = G_SometimesGetDifferentGametype(); + UINT8 gt = (cv_kartgametypepreference.value == -1) ? gametype : cv_kartgametypepreference.value; + UINT8 secondgt = G_SometimesGetDifferentGametype(gt); INT16 votebuffer[4] = {-1,-1,-1,0}; - if ((cv_kartencore.value == 1) && (gametyperules & GTR_CIRCUIT)) - WRITEUINT8(p, (gametype|0x80)); + if ((cv_kartencore.value == 1) && (gametypedefaultrules[gt] & GTR_CIRCUIT)) + WRITEUINT8(p, (gt|VOTEMODIFIER_ENCORE)); else - WRITEUINT8(p, gametype); + WRITEUINT8(p, gt); WRITEUINT8(p, secondgt); - secondgt &= ~0x80; + secondgt &= ~VOTEMODIFIER_ENCORE; for (i = 0; i < 4; i++) { UINT16 m; if (i == 2) // sometimes a different gametype m = G_RandMap(G_TOLFlag(secondgt), prevmap, ((secondgt != gametype) ? 2 : 0), 0, true, votebuffer); - else if (i >= 3) // unknown-random and force-unknown MAP HELL - m = G_RandMap(G_TOLFlag(gametype), prevmap, 0, (i-2), (i < 4), votebuffer); + else if (i >= 3) // unknown-random and formerly force-unknown MAP HELL + m = G_RandMap(G_TOLFlag(gt), prevmap, 0, (i-2), (i < 4), votebuffer); else - m = G_RandMap(G_TOLFlag(gametype), prevmap, 0, 0, true, votebuffer); + m = G_RandMap(G_TOLFlag(gt), prevmap, 0, 0, true, votebuffer); if (i < 3) - votebuffer[i] = m; // min() is a dumb workaround for gcc 4.4 array-bounds error + votebuffer[i] = m; WRITEUINT16(p, m); } @@ -5397,6 +5400,13 @@ static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum) gt = (UINT8)READUINT8(*cp); secondgt = (UINT8)READUINT8(*cp); + // Strip illegal Encore flag. + if ((gt & VOTEMODIFIER_ENCORE) + && !(gametypedefaultrules[(gt & ~VOTEMODIFIER_ENCORE)] & GTR_CIRCUIT)) + { + gt &= ~VOTEMODIFIER_ENCORE; + } + for (i = 0; i < 4; i++) { tempvotelevels[i][0] = (UINT16)READUINT16(*cp); @@ -5414,6 +5424,21 @@ static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum) memcpy(votelevels, tempvotelevels, sizeof(votelevels)); + // If third entry has an illelegal Encore flag... (illelegal!?) + if ((secondgt & VOTEMODIFIER_ENCORE) + && !(gametypedefaultrules[(secondgt & ~VOTEMODIFIER_ENCORE)] & GTR_CIRCUIT)) + { + secondgt &= ~VOTEMODIFIER_ENCORE; + // Apply it to the second entry instead, gametype permitting! + if (gametypedefaultrules[gt] & GTR_CIRCUIT) + { + votelevels[1][1] |= VOTEMODIFIER_ENCORE; + } + } + + // Finally, set third entry's gametype/Encore status. + votelevels[2][1] = secondgt; + G_SetGamestate(GS_VOTING); Y_StartVote(); } diff --git a/src/d_netcmd.h b/src/d_netcmd.h index b624b9d6e..72f0a8890 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -84,6 +84,7 @@ extern consvar_t cv_kartfrantic; extern consvar_t cv_kartcomeback; extern consvar_t cv_kartencore; extern consvar_t cv_kartvoterulechanges; +extern consvar_t cv_kartgametypepreference; extern consvar_t cv_kartspeedometer; extern consvar_t cv_kartvoices; extern consvar_t cv_kartbot; diff --git a/src/g_game.c b/src/g_game.c index 74f6667bd..09be65cb5 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3364,51 +3364,53 @@ boolean G_GametypeHasSpectators(void) // // Oh, yeah, and we sometimes flip encore mode on here too. // -INT16 G_SometimesGetDifferentGametype(void) +INT16 G_SometimesGetDifferentGametype(UINT8 prefgametype) { - boolean encorepossible = ((M_SecretUnlocked(SECRET_ENCORE) || encorescramble == 1) && (gametyperules & GTR_CIRCUIT)); + // Most of the gametype references in this condition are intentionally not prefgametype. + // This is so a server CAN continue playing a gametype if they like the taste of it. + // The encore check needs prefgametype so can't use G_RaceGametype... + boolean encorepossible = ((M_SecretUnlocked(SECRET_ENCORE) || encorescramble == 1) + && ((gametyperules|gametypedefaultrules[prefgametype]) & GTR_CIRCUIT)); + UINT8 encoremodifier = 0; - if (!cv_kartvoterulechanges.value // never - && encorescramble != 1) // destroying the code for this one instance - return gametype; - - if (randmapbuffer[NUMMAPS] > 0 && (encorepossible || cv_kartvoterulechanges.value != 3)) + if (encorepossible) { - randmapbuffer[NUMMAPS]--; - if (encorepossible) + if (encorescramble != -1) { - if (encorescramble != -1) - encorepossible = (boolean)encorescramble; // FORCE to what was scrambled on intermission - else - { - switch (cv_kartvoterulechanges.value) - { - case 3: // always - randmapbuffer[NUMMAPS] = 0; // gotta prep this in case it isn't already set - break; - case 2: // frequent - encorepossible = M_RandomChance(FRACUNIT>>1); - break; - case 1: // sometimes - default: - encorepossible = M_RandomChance(FRACUNIT>>2); - break; - } - } - if (encorepossible != (cv_kartencore.value == 1)) - return (gametype|0x80); + encorepossible = (boolean)encorescramble; // FORCE to what was scrambled on intermission } - return gametype; + else + { + switch (cv_kartvoterulechanges.value) + { + case 3: // always + encorepossible = true; + break; + case 2: // frequent + encorepossible = M_RandomChance(FRACUNIT>>1); + break; + case 1: // sometimes + encorepossible = M_RandomChance(FRACUNIT>>2); + break; + default: + break; + } + } + if (encorepossible != (cv_kartencore.value == 1)) + encoremodifier = VOTEMODIFIER_ENCORE; } - if (!cv_kartvoterulechanges.value) // never (again) - return gametype; + if (!cv_kartvoterulechanges.value) // never + return (gametype|encoremodifier); + + if (randmapbuffer[NUMMAPS] > 0 && (cv_kartvoterulechanges.value != 3)) + { + randmapbuffer[NUMMAPS]--; + return (gametype|encoremodifier); + } switch (cv_kartvoterulechanges.value) // okay, we're having a gametype change! when's the next one, luv? { - case 3: // always - randmapbuffer[NUMMAPS] = 1; // every other vote (or always if !encorepossible) - break; case 1: // sometimes randmapbuffer[NUMMAPS] = 5; // per "cup" break; @@ -3419,9 +3421,17 @@ INT16 G_SometimesGetDifferentGametype(void) break; } - if (gametype == GT_BATTLE) - return GT_RACE; - return GT_BATTLE; + // Only this response is prefgametype-based. + // todo custom gametypes + if (prefgametype == GT_BATTLE) + { + // Intentionally does not use encoremodifier! + if (cv_kartencore.value == 1) + return (GT_RACE|VOTEMODIFIER_ENCORE); + return (GT_RACE); + } + // This might appear wrong HERE, but the game will display the Encore possibility on the second voting choice instead. + return (GT_BATTLE|encoremodifier); } // diff --git a/src/g_game.h b/src/g_game.h index 3352ce069..e9e911271 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -205,7 +205,8 @@ boolean G_IsSpecialStage(INT32 mapnum); boolean G_GametypeUsesLives(void); boolean G_GametypeHasTeams(void); boolean G_GametypeHasSpectators(void); -INT16 G_SometimesGetDifferentGametype(void); +#define VOTEMODIFIER_ENCORE 0x80 +INT16 G_SometimesGetDifferentGametype(UINT8 prefgametype); UINT8 G_GetGametypeColor(INT16 gt); void G_BeginLevelExit(void); void G_FinishExitLevel(void); diff --git a/src/k_kart.c b/src/k_kart.c index 57d9d83de..02789b821 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -222,6 +222,7 @@ void K_RegisterKartStuff(void) CV_RegisterVar(&cv_kartcomeback); CV_RegisterVar(&cv_kartencore); CV_RegisterVar(&cv_kartvoterulechanges); + CV_RegisterVar(&cv_kartgametypepreference); CV_RegisterVar(&cv_kartspeedometer); CV_RegisterVar(&cv_kartvoices); CV_RegisterVar(&cv_kartbot); diff --git a/src/y_inter.c b/src/y_inter.c index db7f30f64..6abf9f8d8 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -1742,6 +1742,7 @@ void Y_VoteTicker(void) void Y_StartVote(void) { INT32 i = 0; + boolean battlemode = ((votelevels[0][1] & ~VOTEMODIFIER_ENCORE) == GT_BATTLE); // todo gametyperules votetic = -1; @@ -1752,8 +1753,8 @@ void Y_StartVote(void) Y_AnimatedVoteScreenCheck(); - widebgpatch = W_CachePatchName(((gametype == GT_BATTLE) ? "BATTLSCW" : "INTERSCW"), PU_STATIC); - bgpatch = W_CachePatchName(((gametype == GT_BATTLE) ? "BATTLSCR" : "INTERSCR"), PU_STATIC); + widebgpatch = W_CachePatchName((battlemode ? "BATTLSCW" : "INTERSCW"), PU_STATIC); + bgpatch = W_CachePatchName((battlemode ? "BATTLSCR" : "INTERSCR"), PU_STATIC); cursor = W_CachePatchName("M_CURSOR", PU_STATIC); cursor1 = W_CachePatchName("P1CURSOR", PU_STATIC); cursor2 = W_CachePatchName("P2CURSOR", PU_STATIC); @@ -1785,8 +1786,8 @@ void Y_StartVote(void) for (i = 0; i < 4; i++) { // set up the encore - levelinfo[i].encore = (votelevels[i][1] & 0x80); - votelevels[i][1] &= ~0x80; + levelinfo[i].encore = (votelevels[i][1] & VOTEMODIFIER_ENCORE); + votelevels[i][1] &= ~VOTEMODIFIER_ENCORE; // set up the levelstring if (mapheaderinfo[votelevels[i][0]]->levelflags & LF_NOZONE || !mapheaderinfo[votelevels[i][0]]->zonttl[0]) From 4f7c632e9c554630c767028774f0c5d43a7985af Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 17 Sep 2022 16:13:50 +0100 Subject: [PATCH 083/117] 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 09be65cb5..d3c33dd73 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -325,7 +325,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; @@ -3373,6 +3391,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) @@ -3403,21 +3425,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; } @@ -3500,6 +3522,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"); @@ -3578,11 +3603,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; @@ -3600,15 +3625,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; } @@ -3625,8 +3650,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 @@ -3647,19 +3672,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"); } } @@ -4676,7 +4712,6 @@ cleanup: // void G_DeferedInitNew(boolean pencoremode, INT32 map, INT32 pickedchar, UINT8 ssplayers, boolean FLS) { - INT32 i; UINT16 color = SKINCOLOR_NONE; paused = false; @@ -4686,8 +4721,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(); @@ -4729,7 +4763,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 4b12f8a7296858db5916d8c96725fddc6f3a5c18 Mon Sep 17 00:00:00 2001 From: toaster Date: Sat, 17 Sep 2022 19:10:04 +0100 Subject: [PATCH 084/117] 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.cpp | 2 +- src/deh_soc.c | 28 +++++++++---- src/f_finale.c | 17 ++++---- src/g_game.c | 112 +++++++++++++++++++++++++++++++------------------ src/g_game.h | 12 ++++++ src/m_cond.c | 8 ++-- 6 files changed, 116 insertions(+), 63 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index e8ed26a90..775e78b19 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1794,7 +1794,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 0e94eea05..2a5feb326 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -2867,7 +2867,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; @@ -2880,7 +2880,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; @@ -3084,21 +3084,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 c44515d45..b14360630 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1118,7 +1118,7 @@ static void F_CacheTitleScreen(void) void F_StartTitleScreen(void) { - const INT32 titleMapNum = titlemap ? G_MapNumber(titlemap)+1 : 0; + INT32 titleMapNum; if (gamestate != GS_TITLESCREEN && gamestate != GS_WAITINGPLAYERS) { @@ -1129,21 +1129,20 @@ void F_StartTitleScreen(void) else wipegamestate = GS_TITLESCREEN; - if (titlemap && mapheaderinfo[titleMapNum]) + 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; - if (!mapheaderinfo[gamemap-1]) - P_AllocMapHeader(gamemap-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 d3c33dd73..ef81660fe 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -738,21 +738,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. @@ -3850,17 +3864,22 @@ static void G_DoCompleted(void) { if (grandprixinfo.roundnum >= grandprixinfo.cup->numlevels) // On final map { - nextmap = 1101; // ceremonymap + //nextmap = NEXTMAP_CEREMONY; // ceremonymap + nextmap = NEXTMAP_TITLE; // G: F_StartEnding is gone, sorry } 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++; } @@ -3874,7 +3893,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 } } @@ -3886,48 +3905,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 ((W_CheckNumForName(G_BuildMapName(cm + 1)) == LUMPERROR)) + if (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; } @@ -3938,22 +3955,15 @@ 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; } - - 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 (!(grandprixinfo.gp == true)) { if (cv_advancemap.value == 0) // Stay on same map. @@ -3969,7 +3979,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 @@ -4036,7 +4046,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(); @@ -4177,6 +4187,26 @@ void G_EndGame(void) if (demo.recording && (modeattacking || demo.savemode != DSM_NOTSAVING)) G_SaveDemo(); + // Only do evaluation and credits in coop games. + if (grandprixinfo.gp == true) + { + /*if (nextmap == NEXTMAP_CEREMONY) // end game with ending + { + F_StartEnding(); + return; + }*/ + if (nextmap == NEXTMAP_CREDITS) // end game with credits + { + F_StartCredits(); + return; + } + if (nextmap == NEXTMAP_EVALUATION) // end game with evaluation + { + F_StartGameEvaluation(); + return; + } + } + // 1100 or competitive multiplayer, so go back to title screen. D_StartTitle(); } diff --git a/src/g_game.h b/src/g_game.h index e9e911271..78f31b41a 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -40,6 +40,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/m_cond.c b/src/m_cond.c index 9844bcf71..0ba429827 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -357,7 +357,7 @@ UINT8 M_CheckLevelEmblems(void) checkLevel = G_MapNumber(emblemlocations[i].level); - if (!mapheaderinfo[checkLevel]) + if (checkLevel >= nummapheaders || !mapheaderinfo[checkLevel]) continue; levelnum = checkLevel; @@ -397,7 +397,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; @@ -519,7 +519,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; @@ -555,7 +555,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 88ae398eea1578d5e4e8b3462b0e1082e8b56db2 Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 18 Sep 2022 20:00:28 +0100 Subject: [PATCH 085/117] 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.cpp | 10 +- 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 | 394 +++++++++++++++++++++++++++-------------------- src/g_game.h | 1 + src/lua_maplib.c | 29 ---- src/p_setup.c | 120 --------------- src/p_setup.h | 5 - src/p_user.c | 7 - 13 files changed, 237 insertions(+), 439 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 775e78b19..3b001a0dd 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -986,10 +986,12 @@ void D_StartTitle(void) if (server) { - if (server) - { - COM_BufAddText(va("map %s\n", G_BuildMapName(spstage_start))); - } + 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 0f9132935..01ea87625 100644 --- a/src/deh_lua.c +++ b/src/deh_lua.c @@ -621,18 +621,6 @@ static int ScanConstants(lua_State *L, boolean mathlib, const char *word) } 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]) - { - CacheAndPushConstant(L, word, i); - return 1; - } - if (mathlib) return luaL_error(L, "NiGHTS grade '%s' could not be found.\n", word); - return 0; - } else if (fastncmp("MN_",word,3)) { p = word+3; for (i = 0; i < NUMMENUTYPES; i++) diff --git a/src/deh_soc.c b/src/deh_soc.c index 2a5feb326..f2e32e148 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -159,12 +159,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); @@ -1140,7 +1137,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 @@ -1268,14 +1264,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, @@ -1471,12 +1459,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")) { @@ -4297,19 +4285,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 e901efd31..a0e920249 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -35,17 +35,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 629d0ce87..484cb281b 100644 --- a/src/deh_tables.h +++ b/src/deh_tables.h @@ -57,7 +57,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 f96b9377d..ee4b1c838 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -321,12 +321,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 struct customoption_t { @@ -361,9 +355,6 @@ struct mapheader_t UINT32 typeoflevel; ///< Combination of typeoflevel flags. - char * nextlevel; ///< Map number of next level, or 1100-1102 to end. - char * 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. // Music information @@ -399,42 +390,18 @@ struct mapheader_t 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 UINT8 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. - - // 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) - mapheader_lighting_t lighting; ///< Wall and sprite lighting mapheader_lighting_t lighting_encore; ///< Alternative lighting for Encore mode boolean use_encore_lighting; ///< Whether to use separate Encore lighting @@ -607,26 +574,6 @@ struct recorddata_t //UINT16 rings; ///< Rings when the level was finished. }; -/** 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 b14360630..ff3690ea1 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1611,7 +1611,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 ef81660fe..8439f9ecf 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -742,7 +742,9 @@ const char *G_BuildMapName(INT32 map) */ INT32 G_MapNumber(const char * name) { +#ifdef NEXTMAPINSOC if (strncasecmp("NEXTMAP_", name, 8) != 0) +#endif { INT32 map; @@ -757,6 +759,7 @@ INT32 G_MapNumber(const char * name) return map; } +#ifdef NEXTMAPINSOC name += 8; if (strcasecmp("EVALUATION", name) == 0) @@ -767,6 +770,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. @@ -3501,20 +3505,56 @@ UINT32 G_TOLFlag(INT32 pgametype) return gametypetol[pgametype]; } -static INT32 TOLMaps(UINT32 tolflags) +INT16 G_GetFirstMapOfGametype(UINT8 pgametype) +{ + INT16 mapnum = nummapheaders; + + /* G: not sure what to do with this + 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; @@ -3687,7 +3727,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; @@ -3753,7 +3793,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 @@ -3776,6 +3816,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 (grandprixinfo.gp == true) + { + 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 // @@ -3837,155 +4038,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 - nextmap = NEXTMAP_TITLE; // G: F_StartEnding is gone, sorry - } - 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; - } - } - - if (!(grandprixinfo.gp == true)) - { - 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(); @@ -4010,17 +4073,10 @@ void G_AfterIntermission(void) { Y_CleanupScreenBuffer(); - 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) { @@ -4042,8 +4098,8 @@ void G_AfterIntermission(void) return; } - if (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 (grandprixinfo.gp == true && 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) @@ -4187,14 +4243,14 @@ void G_EndGame(void) if (demo.recording && (modeattacking || demo.savemode != DSM_NOTSAVING)) G_SaveDemo(); - // Only do evaluation and credits in coop games. - if (grandprixinfo.gp == true) + // Only do evaluation and credits in singleplayer contexts + if (!netgame && grandprixinfo.gp == true) { - /*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 { F_StartCredits(); @@ -4207,7 +4263,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(); } @@ -5110,6 +5166,7 @@ INT32 G_FindMapByNameOrCode(const char *mapname, char **realmapnamep) { if (mapname[0] == '*') // current map return gamemap; + /* else if (mapname[0] == '+' && mapheaderinfo[gamemap-1]) // next map { newmapnum = G_MapNumber(mapheaderinfo[gamemap-1]->nextlevel); @@ -5121,6 +5178,7 @@ INT32 G_FindMapByNameOrCode(const char *mapname, char **realmapnamep) else return newmapnum-1; } + */ } /* Now detect map number in base 10, which no one asked for. */ diff --git a/src/g_game.h b/src/g_game.h index 78f31b41a..7ad053594 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -280,6 +280,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/lua_maplib.c b/src/lua_maplib.c index e1bc3892e..b779014bf 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -2510,10 +2510,6 @@ static int mapheaderinfo_get(lua_State *L) lua_pushstring(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")) // we create a table here because it saves us from a userdata nightmare @@ -2537,20 +2533,6 @@ static int mapheaderinfo_get(lua_State *L) lua_pushinteger(L, header->muspos); else if (fastcmp(field,"musname_size")) lua_pushinteger(L, header->musname_size); - 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")) @@ -2586,16 +2568,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")) @@ -2610,7 +2582,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_setup.c b/src/p_setup.c index c4d030f33..c4c4a5dee 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -398,19 +398,9 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) const INT16 num = (INT16)(i-1); boolean exists = (mapheaderinfo[gamemap-1]->alreadyExists == true); - 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] = '\0'; mapheaderinfo[num]->typeoflevel = 0; mapheaderinfo[num]->startrings = 0; @@ -423,13 +413,6 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) mapheaderinfo[num]->musname[i][0] = 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]->musname_size = 0; mapheaderinfo[num]->weather = PRECIP_NONE; @@ -449,8 +432,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; @@ -463,7 +444,6 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) #else // equivalent to "FlickyList = NONE" P_DeleteFlickies(num); #endif - P_DeleteGrades(num); // see p_setup.c - prevents replacing maps in addons with different versions mapheaderinfo[num]->alreadyExists = exists; @@ -485,112 +465,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 22f6bdca1..e4d33d9c0 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -154,11 +154,6 @@ 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); #ifdef __cplusplus } // extern "C" diff --git a/src/p_user.c b/src/p_user.c index beab7153d..577aee586 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4293,14 +4293,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 95b98e414746085a62b26d17946931f0d2ce5ede Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 18 Sep 2022 20:43:15 +0100 Subject: [PATCH 086/117] 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 4a361a3f0..6a87c6895 100644 --- a/src/discord.c +++ b/src/discord.c @@ -545,6 +545,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 { @@ -552,7 +553,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 18fdd8fa9ac6ab935344da6720fc7dd29362f33e Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 21 Sep 2022 19:22:05 +0100 Subject: [PATCH 087/117] Repair D_StartTitle component of netgame title fallthrough prevention --- src/d_main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 3b001a0dd..925d2c852 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -986,12 +986,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 b9da47c13d1bf582f5c2d2cf3d323134f5e7a178 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 21 Sep 2022 19:22:33 +0100 Subject: [PATCH 088/117] 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 6a87c6895..590446227 100644 --- a/src/discord.c +++ b/src/discord.c @@ -442,7 +442,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]; @@ -545,7 +547,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 03d847d416f90366d66518e396edfff4b93bc2fd Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Tue, 11 Feb 2025 02:38:20 +0100 Subject: [PATCH 089/117] oops, forgot menu changes --- src/m_menu.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index d1dd737a9..67c04b690 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -4459,6 +4459,8 @@ static void M_PrepareLevelSelect(void) // boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt) { + UINT32 tolflag = G_TOLFlag(gt); + // Random map! if (mapnum == -1) return (levellistmode == LLM_CREATESERVER); @@ -4471,6 +4473,10 @@ boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt) if (!mapheaderinfo[mapnum]->lvlttl[0]) return false; + // Does the map have a LUMP? + if (mapheaderinfo[mapnum]->lumpnum == LUMPERROR) + return false; + switch (levellistmode) { case LLM_CREATESERVER: @@ -4481,10 +4487,11 @@ boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt) if (M_MapLocked(mapnum+1)) return false; // not unlocked - if (gt >= 0 && gt < gametypecount && mapheaderinfo[mapnum]->typeoflevel & gametypetol[gt]) - return true; + // Check for TOL + if (!(mapheaderinfo[mapnum]->typeoflevel & tolflag)) + return false; - return false; + return true; /*case LLM_LEVELSELECT: if (mapheaderinfo[mapnum]->levelselect != maplistoption) From 07c1fbf426fd79c5a20436714c2be4867d06cf0f Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 21 Sep 2022 22:12:36 +0100 Subject: [PATCH 090/117] 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 | 153 ++++++++++++++++++++++++++++--------------------- src/g_game.h | 1 - src/k_battle.c | 2 +- src/k_hud.c | 2 +- src/m_cond.c | 27 ++++++--- src/m_menu.c | 16 +++--- src/p_setup.c | 9 ++- 10 files changed, 148 insertions(+), 108 deletions(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index f2e32e148..150d954dd 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -2551,7 +2551,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 ee4b1c838..b43acf77b 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -107,6 +107,23 @@ extern preciptype_t precip_freeslot; extern preciptype_t globalweather; extern preciptype_t curWeather; +/** Time attack information, currently a very small structure. + */ +struct recorddata_t +{ + 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. +}; + +// 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; @@ -410,6 +427,10 @@ struct mapheader_t 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. @@ -564,27 +585,6 @@ extern INT32 luabanks[NUM_LUABANKS]; extern INT32 nummaprings; //keep track of spawned rings/coins -/** Time attack information, currently a very small structure. - */ -struct recorddata_t -{ - 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. -}; - -//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 e56aa6c6e..eb81253b7 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -3510,7 +3510,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 8439f9ecf..05ed3af40 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -210,12 +210,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; @@ -539,21 +533,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]) { @@ -566,20 +562,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; } */ @@ -595,7 +593,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) @@ -603,20 +601,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! @@ -3759,20 +3757,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) @@ -4053,7 +4050,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(); @@ -4285,18 +4284,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) { - INT32 i, j; + UINT32 i, j; UINT8 modded = false; UINT8 rtemp; savebuffer_t save = {0}; //For records - tic_t rectime; - tic_t reclap; + UINT32 numgamedatamapheaders; // Clear things so previously read gamedata doesn't transfer // to new gamedata @@ -4327,7 +4327,7 @@ void G_LoadGameData(void) return; // Version check - if (READUINT32(save.p) != 0xFCAFE211) + if (READUINT32(save.p) != GD_VERSIONCHECK) { const char *gdfolder = "the SRB2Kart folder"; if (strcmp(srb2home,".")) @@ -4355,11 +4355,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;) { @@ -4393,16 +4388,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[MAXMAPLUMPNAME]; + 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); } } @@ -4439,12 +4462,12 @@ void G_SaveGameData(void) if (!gamedataloaded) return; // If never loaded (-nodata), don't save - length = 4+4+4+(PWRLV_NUMTYPES*2)+1+(NUMMAPS) + length = 4+4+4+(PWRLV_NUMTYPES*2)+1 + BIT_ARRAY_SIZE(MAXEMBLEMS) + BIT_ARRAY_SIZE(MAXEXTRAEMBLEMS) + BIT_ARRAY_SIZE(MAXUNLOCKABLES) + BIT_ARRAY_SIZE(MAXCONDITIONSETS) - + 4+(NUMMAPS*9); + + 4+4+(nummapheaders*(MAXMAPLUMPNAME+1+4+4)); if (P_SaveBufferAlloc(&save, length) == false) { @@ -4463,22 +4486,18 @@ 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 for (i = 0; i < PWRLV_NUMTYPES; i++) WRITEUINT16(save.p, vspowerlevel[i]); - 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;) // BIT_ARRAY_SIZE(MAXEMBLEMS) { btemp = 0; for (j = 0; j < 8 && j+i < MAXEMBLEMS; ++j) @@ -4486,7 +4505,7 @@ void G_SaveGameData(void) WRITEUINT8(save.p, btemp); i += j; } - for (i = 0; i < MAXEXTRAEMBLEMS;) + for (i = 0; i < MAXEXTRAEMBLEMS;) // BIT_ARRAY_SIZE(MAXEXTRAEMBLEMS) { btemp = 0; for (j = 0; j < 8 && j+i < MAXEXTRAEMBLEMS; ++j) @@ -4494,7 +4513,7 @@ void G_SaveGameData(void) WRITEUINT8(save.p, btemp); i += j; } - for (i = 0; i < MAXUNLOCKABLES;) + for (i = 0; i < MAXUNLOCKABLES;) // BIT_ARRAY_SIZE(MAXUNLOCKABLES) { btemp = 0; for (j = 0; j < 8 && j+i < MAXUNLOCKABLES; ++j) @@ -4502,7 +4521,7 @@ void G_SaveGameData(void) WRITEUINT8(save.p, btemp); i += j; } - for (i = 0; i < MAXCONDITIONSETS;) + for (i = 0; i < MAXCONDITIONSETS;) // BIT_ARRAY_SIZE(MAXCONDITIONSETS) { btemp = 0; for (j = 0; j < 8 && j+i < MAXCONDITIONSETS; ++j) @@ -4511,22 +4530,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 * (MAXMAPLUMPNAME+1+4+4) { - if (mainrecords[i]) + // For figuring out which header to assing it to on load + WRITESTRING(save.p, mapheaderinfo[i]->lumpname); + + 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 - save.buffer; diff --git a/src/g_game.h b/src/g_game.h index 7ad053594..a2fcebbe0 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -27,7 +27,6 @@ extern "C" { 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 d554d0bdf..482bf3b74 100644 --- a/src/k_battle.c +++ b/src/k_battle.c @@ -241,7 +241,7 @@ void K_CheckBumpers(void) winnerscoreadd -= players[i].roundscore; } - if (bossinfo.boss) + if (K_CanChangeRules() == false) { if (nobumpers) { diff --git a/src/k_hud.c b/src/k_hud.c index 15c626d2c..0e5af2687 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -1454,7 +1454,7 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UI else if ((drawtime/TICRATE) & 1) V_DrawKartString(TX, TY+3, splitflags, va("99'59\"99")); - if (emblemmap && (modeattacking || (mode == 1)) && !demo.playback) // emblem time! + if ((modeattacking || (mode == 1)) && !demo.playback) // emblem time! { INT32 workx = TX + 96, worky = TY+18; SINT8 curemb = 0; diff --git a/src/m_cond.c b/src/m_cond.c index 0ba429827..e9d2c71b2 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -146,7 +146,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; @@ -181,11 +184,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 @@ -407,7 +418,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) @@ -524,9 +535,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; @@ -545,7 +556,7 @@ emblem_t *M_GetLevelEmblems(INT32 mapnum) static INT32 map = -1; static INT32 i = -1; - if (mapnum > 0) + if (mapnum >= 0) { map = mapnum; i = numemblems; diff --git a/src/m_menu.c b/src/m_menu.c index 67c04b690..b13e0c1c6 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -4519,7 +4519,7 @@ boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt) if (mapheaderinfo[mapnum]->menuflags & LF2_HIDEINMENU) return false; // map hell - if ((mapheaderinfo[mapnum]->menuflags & LF2_VISITNEEDED) && !mapvisited[mapnum]) + if ((mapheaderinfo[mapnum]->menuflags & LF2_VISITNEEDED) && !mapheaderinfo[mapnum]->mapvisited) return false; return true; @@ -7712,13 +7712,13 @@ static void M_DrawLevelStats(void) if (!mapheaderinfo[i] || (mapheaderinfo[i]->menuflags & LF2_NOTIMEATTACK)) continue; - if (!mainrecords[i] || mainrecords[i]->time <= 0) + if (!mapheaderinfo[i]->mainrecord || mapheaderinfo[i]->mainrecord->time <= 0) { mapsunfinished++; continue; } - besttime += mainrecords[i]->time; + besttime += mapheaderinfo[i]->mainrecord->time; } V_DrawString(20, 70, highlightflags, "Combined time records:"); @@ -7957,10 +7957,10 @@ void M_DrawTimeAttackMenu(void) { INT32 dupadjust = (vid.width/vid.dupx); tic_t lap = 0, time = 0; - if (mainrecords[cv_nextmap.value-1]) + if (mapheaderinfo[cv_nextmap.value-1]->mainrecord) { - lap = mainrecords[cv_nextmap.value-1]->lap; - time = mainrecords[cv_nextmap.value-1]->time; + lap = mapheaderinfo[cv_nextmap.value-1]->mainrecord->lap; + time = mapheaderinfo[cv_nextmap.value-1]->mainrecord->time; } V_DrawFill((BASEVIDWIDTH - dupadjust)>>1, 78, dupadjust, 36, 159); @@ -7968,11 +7968,11 @@ void M_DrawTimeAttackMenu(void) if (levellistmode != LLM_ITEMBREAKER) { V_DrawRightAlignedString(149, 80, highlightflags, "BEST LAP:"); - K_drawKartTimestamp(lap, 19, 86, 0, 2); + K_drawKartTimestamp(lap, 19, 86, -1, 2); } V_DrawRightAlignedString(292, 80, highlightflags, "BEST TIME:"); - K_drawKartTimestamp(time, 162, 86, cv_nextmap.value, 1); + K_drawKartTimestamp(time, 162, 86, cv_nextmap.value-1, 1); } /*{ char beststr[40]; diff --git a/src/p_setup.c b/src/p_setup.c index c4c4a5dee..bdfc513d5 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -448,6 +448,10 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) // see p_setup.c - prevents replacing maps in addons with different versions mapheaderinfo[num]->alreadyExists = exists; + mapheaderinfo[num]->mapvisited = 0; + Z_Free(mapheaderinfo[num]->mainrecord); + mapheaderinfo[num]->mainrecord = NULL; + mapheaderinfo[num]->customopts = NULL; mapheaderinfo[num]->numCustomOptions = 0; } @@ -466,6 +470,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); @@ -8398,9 +8403,9 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) R_PrecacheLevel(); 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 a9f1408376a0a9f30b92151a291dcbde0722244d Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 21 Sep 2022 22:19:51 +0100 Subject: [PATCH 091/117] 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 3ae992525..da5453605 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -948,7 +948,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 25899b77c..2bf1148de 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -284,7 +284,6 @@ struct serverinfo_pak 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 d2c481d87..aab76b8fe 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -924,9 +924,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 13dacbb162929fe5c3f758985a447272bf5f71b3 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 21 Sep 2022 22:37:30 +0100 Subject: [PATCH 092/117] 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 | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/g_demo.c b/src/g_demo.c index eb81253b7..1a56a66c1 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -2079,7 +2079,7 @@ void G_BeginRecording(void) // game data M_Memcpy(demobuf.p, "PLAY", 4); demobuf.p += 4; - WRITEINT16(demobuf.p,gamemap); + WRITESTRINGN(demobuf.p, mapheaderinfo[gamemap-1]->lumpname, 255); M_Memcpy(demobuf.p, mapmd5, 16); demobuf.p += 16; WRITEUINT8(demobuf.p, demoflags); @@ -2502,6 +2502,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"); @@ -2522,7 +2523,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 @@ -2580,7 +2581,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 @@ -2972,7 +2973,8 @@ void G_DoPlayDemo(char *defdemoname) } demobuf.p += 4; // "PLAY" - gamemap = READINT16(demobuf.p); + READSTRINGN(demobuf.p, mapname, sizeof(mapname)); // gamemap + gamemap = G_MapNumber(mapname)+1; demobuf.p += 16; // mapmd5 demoflags = READUINT8(demobuf.p); @@ -3293,7 +3295,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; @@ -3382,7 +3384,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); @@ -3581,6 +3583,7 @@ void G_UpdateStaffGhostName(lumpnum_t l) UINT8 *buffer,*p; UINT16 ghostversion; UINT8 flags; + char discard[255]; buffer = p = W_CacheLumpNum(l, PU_CACHE); @@ -3614,7 +3617,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 4d5cfc38bbd3fc3b93ce7a3113c75e5bf421fc36 Mon Sep 17 00:00:00 2001 From: toaster Date: Wed, 21 Sep 2022 23:01:58 +0100 Subject: [PATCH 093/117] 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 150d954dd..0352fc710 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -1079,11 +1079,6 @@ void readlevelheader(MYFILE *f, char * name) const INT32 num = G_MapNumber(name); - if (num >= NUMMAPS) - { - I_Error("Too many maps!"); - } - if (num >= nummapheaders) { P_AllocMapHeader((INT16)(num)); diff --git a/src/doomdata.h b/src/doomdata.h index a8a0e387e..f08e61e6a 100644 --- a/src/doomdata.h +++ b/src/doomdata.h @@ -289,8 +289,6 @@ struct mapthing_t #define ZSHIFT 4 -#define NUMMAPS 1035 - /* slope thing types */ enum { diff --git a/src/doomstat.h b/src/doomstat.h index b43acf77b..ad12065b1 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -453,8 +453,8 @@ struct mapheader_t #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,basenummapheaders; +extern mapheader_t** mapheaderinfo; +extern INT32 nummapheaders, basenummapheaders, mapallocsize; #define MAXMAPLUMPNAME 64 // includes \0, for cleaner savedata diff --git a/src/g_game.c b/src/g_game.c index 05ed3af40..b7f1e7613 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -182,8 +182,8 @@ UINT8 skipstats; struct quake quake; // Map Header Information -mapheader_t* mapheaderinfo[NUMMAPS] = {NULL}; -INT32 nummapheaders = 0; +mapheader_t** mapheaderinfo = {NULL}; +INT32 nummapheaders, mapallocsize = 0; INT32 basenummapheaders = 0; // Kart cup definitions diff --git a/src/p_setup.c b/src/p_setup.c index bdfc513d5..348ceb675 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -462,9 +462,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 79e311627700ff9e885bfd3ee5e72dab44929c90 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Tue, 11 Feb 2025 15:50:58 +0100 Subject: [PATCH 094/117] And STAY DEAD --- src/acs/call-funcs.cpp | 4 ++-- src/g_game.c | 14 +------------- src/m_menu.c | 21 +++++++++++++-------- 3 files changed, 16 insertions(+), 23 deletions(-) diff --git a/src/acs/call-funcs.cpp b/src/acs/call-funcs.cpp index b2e9c9e72..a2582ab3d 100644 --- a/src/acs/call-funcs.cpp +++ b/src/acs/call-funcs.cpp @@ -3054,7 +3054,7 @@ bool CallFunc_MapWarp(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Wor const char *levelName = NULL; size_t levelLen = 0; - UINT16 nextmap = NUMMAPS; + UINT16 nextmap = UINT16_MAX; (void)argC; @@ -3078,7 +3078,7 @@ bool CallFunc_MapWarp(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Wor nextmap = G_MapNumber(levelName); - if (nextmap == NUMMAPS) + if (nextmap == UINT16_MAX) { CONS_Alert(CONS_WARNING, "MapWarp level %s is not valid or loaded.\n", levelName); return false; diff --git a/src/g_game.c b/src/g_game.c index b7f1e7613..030350d1f 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -710,19 +710,7 @@ void G_SetGameModified(boolean silent, boolean major) */ const char *G_BuildMapName(INT32 map) { - - 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; - } - - if (map > 0 && map <= NUMMAPS && mapheaderinfo[map - 1] != NULL) + if (map > 0 && map <= nummapheaders && mapheaderinfo[map - 1] != NULL) { return mapheaderinfo[map - 1]->lumpname; } diff --git a/src/m_menu.c b/src/m_menu.c index b13e0c1c6..1f0baf535 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -425,7 +425,7 @@ consvar_t cv_showfocuslost = CVAR_INIT ("showfocuslost", "Yes", CV_SAVE, CV_YesN static CV_PossibleValue_t map_cons_t[] = { {0,"MIN"}, - {NUMMAPS, "MAX"}, + {INT16_MAX, "MAX"}, // TODO: kill nextmap {0, NULL} }; consvar_t cv_nextmap = CVAR_INIT ("nextmap", "1", CV_HIDEN|CV_CALL, map_cons_t, Nextmap_OnChange); @@ -7555,7 +7555,8 @@ static void M_ChoosePlayer(INT32 choice) static INT32 statsLocation; static INT32 statsMax; -static INT16 statsMapList[NUMMAPS+1]; +static INT16 *statsMapList = NULL; +static INT16 statsMapListLen; static void M_Statistics(INT32 choice) { @@ -7563,9 +7564,13 @@ static void M_Statistics(INT32 choice) (void)choice; - memset(statsMapList, 0, sizeof(statsMapList)); + if (!statsMapList || nummapheaders != statsMapListLen) + { + statsMapList = Z_Realloc(statsMapList, nummapheaders * sizeof(*statsMapList), PU_LEVEL, NULL); + statsMapListLen = nummapheaders; + } - for (i = 0; i < NUMMAPS; i++) + for (i = 0; i < nummapheaders; i++) { if (!mapheaderinfo[i] || mapheaderinfo[i]->lvlttl[0] == '\0') continue; @@ -7707,7 +7712,7 @@ static void M_DrawLevelStats(void) V_DrawRightAlignedString(BASEVIDWIDTH-16, 52, 0, va("Race: %i", vspowerlevel[PWRLV_RACE])); V_DrawRightAlignedString(BASEVIDWIDTH-16, 60, 0, va("Battle: %i", vspowerlevel[PWRLV_BATTLE])); - for (i = 0; i < NUMMAPS; i++) + for (i = 0; i < nummapheaders; i++) { if (!mapheaderinfo[i] || (mapheaderinfo[i]->menuflags & LF2_NOTIMEATTACK)) continue; @@ -8891,7 +8896,7 @@ static INT32 M_FindFirstMap(INT32 gtype) if (mapheaderinfo[gamemap] && (mapheaderinfo[gamemap]->typeoflevel & gametypetol[gtype])) return gamemap; - for (i = 0; i < NUMMAPS; i++) + for (i = 0; i < nummapheaders; i++) { if (!mapheaderinfo[i]) continue; @@ -9013,7 +9018,7 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) { i--; if (i == -2) - i = NUMMAPS-1; + i = nummapheaders-1; if (i == oldval) return; @@ -9048,7 +9053,7 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) do { i++; - if (i == NUMMAPS) + if (i == nummapheaders) i = -1; if (i == oldval) From c159102ebeb39721ec24b931ba887e492d3eb1e4 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Tue, 11 Feb 2025 15:55:57 +0100 Subject: [PATCH 095/117] I told you I'd forget about it --- src/doomstat.h | 1 - src/p_setup.c | 4 ---- 2 files changed, 5 deletions(-) diff --git a/src/doomstat.h b/src/doomstat.h index ad12065b1..3b8244277 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -436,7 +436,6 @@ struct mapheader_t UINT8 numCustomOptions; ///< Internal. For Lua custom value support. customoption_t *customopts; ///< Custom options. Allocated dynamically for space reasons. Be careful. - boolean alreadyExists; ///< will be removed shortly // BlanKart boolean use_walltransfer; ///< Whether to use DRRR style wall transfering or not }; diff --git a/src/p_setup.c b/src/p_setup.c index 348ceb675..58fd74f53 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -396,7 +396,6 @@ static void P_ClearMapHeaderLighting(mapheader_lighting_t *lighting) 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]->subttl[0] = '\0'; @@ -445,9 +444,6 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) P_DeleteFlickies(num); #endif - // see p_setup.c - prevents replacing maps in addons with different versions - mapheaderinfo[num]->alreadyExists = exists; - mapheaderinfo[num]->mapvisited = 0; Z_Free(mapheaderinfo[num]->mainrecord); mapheaderinfo[num]->mainrecord = NULL; From e8f582555d44893563ddb2a68c5f7899aeb0232f Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 22 Sep 2022 12:47:59 +0100 Subject: [PATCH 096/117] Adjust P_AllocMapHeader and associated - Prints with more info - No weird increment/decrement --- src/p_setup.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index 58fd74f53..dd7132ba7 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -393,10 +393,8 @@ static void P_ClearMapHeaderLighting(mapheader_lighting_t *lighting) * \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'; @@ -408,7 +406,7 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) mapheaderinfo[num]->gravity = DEFAULT_GRAVITY; mapheaderinfo[num]->use_walltransfer = false; mapheaderinfo[num]->keywords[0] = '\0'; - for (i = 0; i < MAXMUSNAMES; i++) + for (int i = 0; i < MAXMUSNAMES; i++) mapheaderinfo[num]->musname[i][0] = 0; mapheaderinfo[num]->mustrack = 0; mapheaderinfo[num]->muspos = 0; @@ -493,7 +491,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; @@ -503,7 +501,7 @@ void P_AllocMapHeader(INT16 i) mapheaderinfo[i]->mainrecord = NULL; nummapheaders++; } - P_ClearSingleMapHeaderInfo(i + 1); + P_ClearSingleMapHeaderInfo(i); } // From 92af45dac528985b275104cd447a7c1808343133 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Tue, 11 Feb 2025 16:14:11 +0100 Subject: [PATCH 097/117] Oh boy, another mapheader_t shuffle --- src/doomstat.h | 72 ++++++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 38 deletions(-) diff --git a/src/doomstat.h b/src/doomstat.h index 3b8244277..8eaf86de1 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -359,21 +359,31 @@ struct mapheader_lighting_t */ struct mapheader_t { - char * lumpname; ///< Lump name can be really long + char *lumpname; ///< Lump name can be really long lumpnum_t lumpnum; ///< Lump number for the map - void * thumbnailPic; ///< Lump data for the level select thumbnail. - void * minimapPic; ///< Lump data for the minimap graphic. + void *thumbnailPic; ///< Lump data for the level select thumbnail. + void *minimapPic; ///< Lump data for the minimap graphic. + + UINT8 mapvisited; ///< A set of flags that says what we've done in the map. + recorddata_t *mainrecord; ///< Stores best time attack data 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 char actnum[3]; ///< SRB2Kart: Now a 2 character long string. - UINT32 typeoflevel; ///< Combination of typeoflevel flags. - 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? + UINT8 menuflags; ///< LF2_flags: options that affect record attack / nights mode menus + + 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[MAXMUSNAMES][7]; ///< Music tracks to play. First dimension is the track number, second is the music string. "" for no music. UINT16 mustrack; ///< Subsong to play. Only really relevant for music modules and specific formats supported by GME. 0 to ignore. @@ -391,45 +401,31 @@ struct mapheader_t // 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? - - 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 - - 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. - UINT8 numFlickies; ///< Internal. For freed flicky support. - mobjtype_t *flickies; ///< List of freeable flickies in this level. Allocated dynamically for space reasons. Be careful. - - mapheader_lighting_t lighting; ///< Wall and sprite lighting - mapheader_lighting_t lighting_encore; ///< Alternative lighting for Encore mode - boolean use_encore_lighting; ///< Whether to use separate Encore lighting - // 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 - // 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 + UINT16 palette; ///< PAL lump to use on this map + UINT16 encorepal; ///< PAL for encore mode + mapheader_lighting_t lighting; ///< Wall and sprite lighting + mapheader_lighting_t lighting_encore; ///< Alternative lighting for Encore mode + boolean use_encore_lighting; ///< Whether to use separate Encore lighting + + UINT16 startrings; ///< Number of rings players start with. + INT32 sstimer; ///< Timer for special stages. + UINT32 ssspheres; ///< Sphere requirement in special stages. + + // 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. + + 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. // Lua stuff. // (This is not ifdeffed so the map header structure can stay identical, just in case.) From 66f965c2c0276fba2d56490e9f8026c4cbd6658e Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Tue, 11 Feb 2025 16:53:21 +0100 Subject: [PATCH 098/117] Get rid of basenummapheaders More oddball differences causing merge conflicts... --- src/d_main.cpp | 5 ++--- src/doomstat.h | 2 +- src/g_game.c | 1 - src/p_setup.c | 15 ++++++++++++--- src/p_setup.h | 2 +- 5 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 925d2c852..15d5729c9 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1506,8 +1506,7 @@ void D_SRB2Main(void) // conversion sometimes needs the palette V_ReloadPalette(); - P_InitMapData(); - basenummapheaders = nummapheaders; + P_InitMapData(false); CON_SetLoadingProgress(LOADED_IWAD); @@ -1566,7 +1565,7 @@ void D_SRB2Main(void) // // search for pwad maps // - P_InitMapData(); + P_InitMapData(true); HU_LoadGraphics(); } diff --git a/src/doomstat.h b/src/doomstat.h index 8eaf86de1..12739ce25 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -449,7 +449,7 @@ struct mapheader_t #define LF2_VISITNEEDED (1<<3) ///< Not available in Time Attack modes until you visit the level extern mapheader_t** mapheaderinfo; -extern INT32 nummapheaders, basenummapheaders, mapallocsize; +extern INT32 nummapheaders, mapallocsize; #define MAXMAPLUMPNAME 64 // includes \0, for cleaner savedata diff --git a/src/g_game.c b/src/g_game.c index 030350d1f..dd4176fd5 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -184,7 +184,6 @@ struct quake quake; // Map Header Information mapheader_t** mapheaderinfo = {NULL}; INT32 nummapheaders, mapallocsize = 0; -INT32 basenummapheaders = 0; // Kart cup definitions cupheader_t *kartcupheaders = NULL; diff --git a/src/p_setup.c b/src/p_setup.c index dd7132ba7..43425c35a 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -8674,7 +8674,7 @@ lumpnum_t wadnamelump = LUMPERROR; INT16 wadnamemap = 0; // gamemap based // Initialising map data... -UINT8 P_InitMapData(void) +UINT8 P_InitMapData(boolean existingmapheaders) { UINT8 ret = 0; INT32 i; @@ -8691,7 +8691,15 @@ UINT8 P_InitMapData(void) // Doesn't exist? if (maplump == INT16_MAX) + { +#ifndef DEVELOP + if (!existingmapheaders) + { + I_Error("P_InitMapData: Base map %s has a header but no level\n", name); + } +#endif continue; + } // No change? if (mapheaderinfo[i]->lumpnum == maplump) @@ -8701,7 +8709,7 @@ UINT8 P_InitMapData(void) { ret |= MAPRET_ADDED; - if (basenummapheaders) + if (existingmapheaders) { CONS_Printf("%s\n", name); @@ -8714,6 +8722,7 @@ UINT8 P_InitMapData(void) ret |= MAPRET_CURRENTREPLACED; } } + mapheaderinfo[i]->lumpnum = maplump; if (maplump == wadnamelump) wadnamemap = i+1; @@ -9008,7 +9017,7 @@ boolean P_MultiSetupWadFiles(boolean fullsetup) if (partadd_stage == 2) { - UINT8 mapsadded = P_InitMapData(); + UINT8 mapsadded = P_InitMapData(true); if (!mapsadded) CONS_Printf(M_GetText("No maps added\n")); diff --git a/src/p_setup.h b/src/p_setup.h index e4d33d9c0..70b93d532 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -113,7 +113,7 @@ boolean P_AddWadFile(const char *wadfilename, wadcompat_t compat); #define MAPRET_ADDED (1) #define MAPRET_CURRENTREPLACED (1<<1) -UINT8 P_InitMapData(void); +UINT8 P_InitMapData(boolean existingmapheaders); extern lumpnum_t wadnamelump; extern INT16 wadnamemap; #define WADNAMECHECK(name) (!strncmp(name, "WADNAME", 7)) From 1475feb7341c5b54274c409f28c5ee7a038da6f2 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 22 Sep 2022 17:14:41 +0100 Subject: [PATCH 099/117] 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 | 51 +++++++++++++-------------- src/doomstat.h | 86 +++++++++++++++++++++------------------------ src/g_game.c | 60 ++++++++++---------------------- src/g_game.h | 3 +- src/lua_maplib.c | 18 +--------- src/lua_script.c | 12 ------- src/m_menu.c | 3 -- src/p_mobj.c | 2 +- src/p_saveg.c | 10 ------ src/p_setup.c | 90 ++++++++++++++++++------------------------------ src/p_spec.c | 9 ----- src/p_user.c | 17 ++++----- src/r_skins.c | 6 ---- 14 files changed, 129 insertions(+), 240 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 03985dd96..2cc507cb8 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1428,7 +1428,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 0352fc710..91c9a5b4d 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -160,6 +160,8 @@ void clear_levels(void) P_DeleteFlickies(nummapheaders); + Z_Free(mapheaderinfo[nummapheaders]->mainrecord); + Patch_Free(mapheaderinfo[nummapheaders]->thumbnailPic); Patch_Free(mapheaderinfo[nummapheaders]->minimapPic); @@ -169,7 +171,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 } @@ -1077,11 +1094,11 @@ void readlevelheader(MYFILE *f, char * name) char *tmp; INT32 i; - const INT32 num = G_MapNumber(name); + INT32 num = G_MapNumber(name); if (num >= nummapheaders) { - P_AllocMapHeader((INT16)(num)); + P_AllocMapHeader((INT16)(num = nummapheaders)); } else if (f->wad > mainwads) { @@ -1337,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")) @@ -3077,24 +3089,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); @@ -3538,16 +3532,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 12739ce25..7c5c0b15b 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -209,7 +209,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; @@ -224,8 +223,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; struct scene_t @@ -316,8 +313,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). @@ -355,12 +350,36 @@ struct mapheader_lighting_t #define MAXMUSNAMES 3 // maximum definable music tracks per level +// 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 + +struct cupheader_t +{ + 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. + cupheader_t *next; ///< Next cup in linked list +}; + +extern cupheader_t *kartcupheaders; // Start of cup linked list +extern UINT16 numkartcupheaders; + /** Map header information. */ struct mapheader_t { + // Core game information, not user-modifiable directly char *lumpname; ///< Lump name can be really long - lumpnum_t lumpnum; ///< Lump number for the map + 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. @@ -368,17 +387,22 @@ struct mapheader_t 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 char actnum[3]; ///< SRB2Kart: Now a 2 character long string. + // 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? - UINT8 menuflags; ///< LF2_flags: options that affect record attack / nights mode menus + UINT8 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. @@ -390,45 +414,37 @@ struct mapheader_t UINT32 muspos; ///< Music position to jump to. UINT8 musname_size; ///< Number of music tracks defined - 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. - - INT16 countdown; ///< Countdown until level end? - - // SRB2kart - fixed_t mobj_scale; ///< Replacement for TOL_ERZ3 + // 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 mapheader_lighting_t lighting; ///< Wall and sprite lighting mapheader_lighting_t lighting_encore; ///< Alternative lighting for Encore mode boolean use_encore_lighting; ///< Whether to use separate Encore lighting - UINT16 startrings; ///< Number of rings players start with. - INT32 sstimer; ///< Timer for special stages. - UINT32 ssspheres; ///< Sphere requirement in special stages. - - // 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. + // 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) + // Cutscene information UINT8 precutscenenum; ///< Cutscene number to play BEFORE a level starts. UINT8 cutscenenum; ///< Cutscene number to use, 0 for none. - // 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. @@ -453,27 +469,6 @@ extern INT32 nummapheaders, mapallocsize; #define MAXMAPLUMPNAME 64 // includes \0, for cleaner savedata -// 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 - -struct cupheader_t -{ - 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 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. - cupheader_t *next; ///< Next cup in linked list -}; - -extern cupheader_t *kartcupheaders; // Start of cup linked list -extern UINT16 numkartcupheaders; - // Gametypes #define NUMGAMETYPEFREESLOTS 128 @@ -584,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 dd4176fd5..c330b6ce3 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -147,12 +147,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; @@ -169,8 +167,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]; @@ -202,9 +198,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; @@ -735,13 +728,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 @@ -3306,18 +3299,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; } // @@ -3492,12 +3482,12 @@ UINT32 G_TOLFlag(INT32 pgametype) INT16 G_GetFirstMapOfGametype(UINT8 pgametype) { - INT16 mapnum = nummapheaders; + INT16 mapnum = NEXTMAP_INVALID; /* G: not sure what to do with this if ((gametypedefaultrules[pgametype] & GTR_CAMPAIGN) && kartcupheaders) { - mapnum = G_MapNumber(kartcupheaders->levellist[0]); + mapnum = kartcupheaders->cachedlevels[0]; } */ @@ -3825,7 +3815,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]) { @@ -3851,19 +3841,14 @@ static void G_GetNextMap(void) if (grandprixinfo.gp == true) { 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 @@ -3955,9 +3940,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); } @@ -4261,11 +4244,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 a2fcebbe0..4ff12b60a 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -48,7 +48,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/lua_maplib.c b/src/lua_maplib.c index b779014bf..c8ace0efe 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -2499,7 +2499,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")) @@ -2533,8 +2532,6 @@ static int mapheaderinfo_get(lua_State *L) lua_pushinteger(L, header->muspos); else if (fastcmp(field,"musname_size")) lua_pushinteger(L, header->musname_size); - 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")) @@ -2545,12 +2542,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); @@ -2558,8 +2550,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")) @@ -2574,12 +2564,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 72e41a56a..cb610ddeb 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -219,18 +219,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/m_menu.c b/src/m_menu.c index 1f0baf535..f73efa7f2 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -2198,9 +2198,6 @@ void Nextmap_OnChange(void) itemOn = tastart; } - if (mapheaderinfo[cv_nextmap.value-1] && mapheaderinfo[cv_nextmap.value-1]->forcecharacter[0] != '\0') - CV_Set(&cv_chooseskin, mapheaderinfo[cv_nextmap.value-1]->forcecharacter); - free(gpath); } } diff --git a/src/p_mobj.c b/src/p_mobj.c index cfc99ad13..da6a02d1d 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -10540,7 +10540,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 0efd5a250..7b8b9363e 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -4944,7 +4944,6 @@ static void P_NetArchiveMisc(savebuffer_t *save, boolean resending) WRITEUINT8(save->p, mapmusrng); WRITEUINT32(save->p, leveltime); - WRITEUINT32(save->p, ssspheres); WRITEINT16(save->p, lastmap); WRITEUINT16(save->p, bossdisabled); WRITEUINT8(save->p, ringsdisabled); @@ -4971,7 +4970,6 @@ static void P_NetArchiveMisc(savebuffer_t *save, boolean resending) } WRITEUINT32(save->p, token); - WRITEINT32(save->p, sstimer); WRITEUINT32(save->p, bluescore); WRITEUINT32(save->p, redscore); @@ -5004,9 +5002,6 @@ static void P_NetArchiveMisc(savebuffer_t *save, 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); @@ -5114,7 +5109,6 @@ FUNCINLINE static ATTRINLINE boolean P_NetUnArchiveMisc(savebuffer_t *save, bool // get the time leveltime = READUINT32(save->p); - ssspheres = READUINT32(save->p); lastmap = READINT16(save->p); bossdisabled = READUINT16(save->p); ringsdisabled = READUINT8(save->p); @@ -5138,7 +5132,6 @@ FUNCINLINE static ATTRINLINE boolean P_NetUnArchiveMisc(savebuffer_t *save, bool } token = READUINT32(save->p); - sstimer = READINT32(save->p); bluescore = READUINT32(save->p); redscore = READUINT32(save->p); @@ -5171,9 +5164,6 @@ FUNCINLINE static ATTRINLINE boolean P_NetUnArchiveMisc(savebuffer_t *save, bool 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 43425c35a..40cc5250f 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -400,9 +400,6 @@ static void P_ClearSingleMapHeaderInfo(INT16 num) mapheaderinfo[num]->zonttl[0] = '\0'; mapheaderinfo[num]->actnum[0] = '\0'; mapheaderinfo[num]->typeoflevel = 0; - mapheaderinfo[num]->startrings = 0; - mapheaderinfo[num]->sstimer = 90; - mapheaderinfo[num]->ssspheres = 1; mapheaderinfo[num]->gravity = DEFAULT_GRAVITY; mapheaderinfo[num]->use_walltransfer = false; mapheaderinfo[num]->keywords[0] = '\0'; @@ -410,7 +407,6 @@ static void P_ClearSingleMapHeaderInfo(INT16 num) mapheaderinfo[num]->musname[i][0] = 0; mapheaderinfo[num]->mustrack = 0; mapheaderinfo[num]->muspos = 0; - mapheaderinfo[num]->forcecharacter[0] = '\0'; mapheaderinfo[num]->musname_size = 0; mapheaderinfo[num]->weather = PRECIP_NONE; snprintf(mapheaderinfo[num]->skytexture, 5, "SKY1"); @@ -418,12 +414,10 @@ static void P_ClearSingleMapHeaderInfo(INT16 num) 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; @@ -497,8 +491,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); @@ -7614,19 +7609,9 @@ static void P_InitLevelSettings(boolean reloadinggamestate) // 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; - // circuit, race and competition stuff circuitmap = false; numstarposts = 0; - ssspheres = 0; numbosswaypoints = 0; if (!reloadinggamestate) timeinmap = 0; @@ -7782,43 +7767,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; @@ -8104,9 +8052,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; @@ -8768,6 +8713,37 @@ UINT8 P_InitMapData(boolean existingmapheaders) } 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 345f7df12..ce096b13b 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -6714,10 +6714,6 @@ void P_InitSpecials(void) maplighting.directional = lighting->use_light_angle; maplighting.angle = lighting->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 @@ -6868,11 +6864,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! if (udmf) break; diff --git a/src/p_user.c b/src/p_user.c index 577aee586..53a0da17d 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -303,11 +303,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; } // @@ -2098,9 +2102,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 867b205c1..96a21e9bc 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -198,12 +198,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 2c7e7b8aa8dc2eb9632e758822c2d39044db3547 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 14 Oct 2022 13:19:20 +0100 Subject: [PATCH 100/117] Fix replacing cups' map lists not properly reassigning the cachedlevels --- src/deh_soc.c | 2 ++ src/p_setup.c | 64 ++++++++++++++++++++++++++------------------------- 2 files changed, 35 insertions(+), 31 deletions(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index 91c9a5b4d..01f18c527 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -3539,10 +3539,12 @@ void readcupheader(MYFILE *f, cupheader_t *cup) else if (fastcmp(word, "BONUSGAME")) { cup->levellist[CUPCACHE_BONUS] = Z_StrDup(word2); + cup->cachedlevels[CUPCACHE_BONUS] = NEXTMAP_INVALID; } else if (fastcmp(word, "SPECIALSTAGE")) { cup->levellist[CUPCACHE_SPECIAL] = Z_StrDup(word2); + cup->cachedlevels[CUPCACHE_SPECIAL] = NEXTMAP_INVALID; } else if (fastcmp(word, "EMERALDNUM")) { diff --git a/src/p_setup.c b/src/p_setup.c index 40cc5250f..3a8661a08 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -8646,6 +8646,39 @@ UINT8 P_InitMapData(boolean existingmapheaders) continue; } + // Always check for cup cache reassociations. + // (The core assumption is that cups < headers.) + { + cupheader_t *cup = kartcupheaders; + INT32 j; + + mapheaderinfo[i]->cup = NULL; + + 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) + { + 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; + } + } + // No change? if (mapheaderinfo[i]->lumpnum == maplump) continue; @@ -8713,37 +8746,6 @@ UINT8 P_InitMapData(boolean existingmapheaders) } 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; - } - } } } From 551c5531d59e9561f6a49e85b63ab07a6087c30c Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 22 Sep 2022 17:34:02 +0100 Subject: [PATCH 101/117] Enforce maximum length of 63 for map lumpname Also, in g_demo.c, use SKIPSTRING (instead of READSTRINGN into a discard buffer) --- src/doomstat.h | 4 ++-- src/g_demo.c | 14 ++++++-------- src/g_game.c | 2 +- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/doomstat.h b/src/doomstat.h index 7c5c0b15b..231d8ef81 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -373,6 +373,8 @@ struct cupheader_t extern cupheader_t *kartcupheaders; // Start of cup linked list extern UINT16 numkartcupheaders; +#define MAXMAPLUMPNAME 64 // includes \0, for cleaner savedata + /** Map header information. */ struct mapheader_t @@ -467,8 +469,6 @@ struct mapheader_t extern mapheader_t** mapheaderinfo; extern INT32 nummapheaders, mapallocsize; -#define MAXMAPLUMPNAME 64 // includes \0, for cleaner savedata - // Gametypes #define NUMGAMETYPEFREESLOTS 128 diff --git a/src/g_demo.c b/src/g_demo.c index 1a56a66c1..8795b7123 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -2079,7 +2079,7 @@ void G_BeginRecording(void) // game data M_Memcpy(demobuf.p, "PLAY", 4); demobuf.p += 4; - WRITESTRINGN(demobuf.p, mapheaderinfo[gamemap-1]->lumpname, 255); + WRITESTRINGN(demobuf.p, mapheaderinfo[gamemap-1]->lumpname, MAXMAPLUMPNAME); M_Memcpy(demobuf.p, mapmd5, 16); demobuf.p += 16; WRITEUINT8(demobuf.p, demoflags); @@ -2502,7 +2502,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"); @@ -2523,7 +2522,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 @@ -2581,7 +2580,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 @@ -3295,7 +3294,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; @@ -3384,7 +3383,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); @@ -3583,7 +3582,6 @@ void G_UpdateStaffGhostName(lumpnum_t l) UINT8 *buffer,*p; UINT16 ghostversion; UINT8 flags; - char discard[255]; buffer = p = W_CacheLumpNum(l, PU_CACHE); @@ -3617,7 +3615,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 c330b6ce3..26fbd54b1 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4503,7 +4503,7 @@ void G_SaveGameData(void) for (i = 0; i < nummapheaders; i++) // nummapheaders * (MAXMAPLUMPNAME+1+4+4) { // For figuring out which header to assing it to on load - WRITESTRING(save.p, mapheaderinfo[i]->lumpname); + WRITESTRINGN(save.p, mapheaderinfo[i]->lumpname, MAXMAPLUMPNAME); WRITEUINT8(save.p, (mapheaderinfo[i]->mapvisited & MV_MAX)); From 342f6294ebf5f3edbe161c6487d11517c8e8a7be Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 23 Sep 2022 13:07:59 +0100 Subject: [PATCH 102/117] 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 01f18c527..30a1f17d6 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -3073,22 +3073,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 231d8ef81..4e9d297f3 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -207,9 +207,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 26fbd54b1..f2be997e3 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -150,8 +150,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 @@ -3781,7 +3779,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 @@ -4242,9 +4240,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 cb610ddeb..67c8b9b7e 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -213,12 +213,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 d5418e4bdbac9317253f94a99a52b3083bf900f9 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Tue, 11 Feb 2025 20:41:54 +0100 Subject: [PATCH 103/117] You win this time, cv_nextmap... --- src/m_menu.c | 51 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index f73efa7f2..494b3ccdb 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -424,12 +424,14 @@ static void Dummystaff_OnChange(void); consvar_t cv_showfocuslost = CVAR_INIT ("showfocuslost", "Yes", CV_SAVE, CV_YesNo, NULL); static CV_PossibleValue_t map_cons_t[] = { - {0,"MIN"}, - {INT16_MAX, "MAX"}, // TODO: kill nextmap + {-1,"MIN"}, + {NEXTMAP_SPECIAL, "MAX"}, // TODO: kill nextmap (can't do that i'm afraid!) {0, NULL} }; consvar_t cv_nextmap = CVAR_INIT ("nextmap", "1", CV_HIDEN|CV_CALL, map_cons_t, Nextmap_OnChange); +static INT16 lastnextmap = 1; + static CV_PossibleValue_t skins_cons_t[MAXSKINS+1] = {{1, DEFAULTSKIN}}; consvar_t cv_chooseskin = CVAR_INIT ("chooseskin", DEFAULTSKIN, CV_HIDEN|CV_CALL, skins_cons_t, Nextmap_OnChange); @@ -2110,21 +2112,46 @@ static INT32 M_GetFirstLevelInList(void); void Nextmap_OnChange(void) { char *leveltitle; - UINT8 active; - const char *gamemode = (levellistmode == LLM_ITEMBREAKER) ? "IB" : "RA"; + + // welp, we're stuck with nextmap for the time being. so just make the damn thing work + if (cv_nextmap.value != lastnextmap) + { + boolean increment = cv_nextmap.value > lastnextmap; + INT16 oldvalue = cv_nextmap.value - 1; + INT16 newvalue = oldvalue; + INT32 gt = cv_newgametype.value; + while (!M_CanShowLevelInList(newvalue, gt)) + { + if (increment) // Going up! + { + if (++newvalue == nummapheaders) + newvalue = -1; + } + else // Going down! + { + if (--newvalue == -2) + newvalue = nummapheaders-1; + } + + if (newvalue == oldvalue) + break; // don't loop forever if there's none of a certain gametype + } + cv_nextmap.value = lastnextmap = newvalue + 1; + } // Update the string in the consvar. Z_Free(cv_nextmap.zstring); - leveltitle = G_BuildMapTitle(cv_nextmap.value); - cv_nextmap.string = cv_nextmap.zstring = leveltitle ? leveltitle : Z_StrDup(G_BuildMapName(cv_nextmap.value)); - + leveltitle = cv_nextmap.value ? G_BuildMapTitle(cv_nextmap.value) : Z_StrDup("Random"); + cv_nextmap.string = cv_nextmap.zstring = leveltitle; if (currentMenu == &SP_TimeAttackDef) { // see also p_setup.c's P_LoadRecordGhosts + const char *gamemode = (levellistmode == LLM_ITEMBREAKER) ? "IB" : "RA"; const size_t glen = strlen(srb2home)+1+strlen("media")+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1; char *gpath = malloc(glen); INT32 i; + UINT8 active = 0; if (!gpath) return; @@ -4463,7 +4490,7 @@ boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt) return (levellistmode == LLM_CREATESERVER); // Does the map exist? - if (!mapheaderinfo[mapnum]) + if (mapnum < 0 || mapnum >= nummapheaders || !mapheaderinfo[mapnum]) return false; // Does the map have a name? @@ -6254,14 +6281,10 @@ static boolean M_ExitPandorasBox(void) static void M_ChangeLevel(INT32 choice) { - char mapname[MAXMAPLUMPNAME-1]; (void)choice; - - strlcpy(mapname, G_BuildMapName(cv_nextmap.value), sizeof (mapname)); - strlwr(mapname); - + INT16 map = cv_nextmap.value ? cv_nextmap.value : G_RandMap(G_TOLFlag(cv_newgametype.value), gamestate == GS_LEVEL ? gamemap : prevmap, 0, 0, false, NULL); M_ClearMenus(true); - COM_BufAddText(va("map %s -gametype \"%s\"\n", mapname, cv_newgametype.string)); + COM_BufAddText(va("map %d -gametype \"%s\"\n", map, cv_newgametype.string)); } static void M_ConfirmSpectate(INT32 choice) From 27d51b370f84451a03cb255cc358c796ba5b513d Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Tue, 11 Feb 2025 21:12:47 +0100 Subject: [PATCH 104/117] Restore 'map +' command --- src/acs/call-funcs.cpp | 4 +-- src/g_game.c | 60 ++++++++++++++++++------------------------ src/m_menu.c | 2 +- 3 files changed, 29 insertions(+), 37 deletions(-) diff --git a/src/acs/call-funcs.cpp b/src/acs/call-funcs.cpp index a2582ab3d..8dff2e811 100644 --- a/src/acs/call-funcs.cpp +++ b/src/acs/call-funcs.cpp @@ -3054,7 +3054,7 @@ bool CallFunc_MapWarp(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Wor const char *levelName = NULL; size_t levelLen = 0; - UINT16 nextmap = UINT16_MAX; + UINT16 nextmap = NEXTMAP_INVALID; (void)argC; @@ -3078,7 +3078,7 @@ bool CallFunc_MapWarp(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Wor nextmap = G_MapNumber(levelName); - if (nextmap == UINT16_MAX) + if (nextmap == NEXTMAP_INVALID) { CONS_Alert(CONS_WARNING, "MapWarp level %s is not valid or loaded.\n", levelName); return false; diff --git a/src/g_game.c b/src/g_game.c index f2be997e3..24b6256c3 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -3788,27 +3788,28 @@ static void G_HandleSaveLevel(void) G_SaveGame((UINT32)cursaveslot, lastmap+1); // not nextmap+1 to route around special stages } -static void G_GetNextMap(void) +static INT16 G_GetNextMap(boolean advancemap) { INT32 i; + INT16 newmap, curmap = gamestate == GS_LEVEL ? gamemap-1 : prevmap; // go to next level // nextmap is 0-based, unlike gamemap if (nextmapoverride != 0) { - nextmap = (INT16)(nextmapoverride-1); + newmap = (INT16)(nextmapoverride-1); } else if (grandprixinfo.gp == true) { if (grandprixinfo.roundnum == 0 || grandprixinfo.cup == NULL) // Single session { - nextmap = prevmap; // Same map + newmap = curmap; // Same map } else { if (grandprixinfo.roundnum >= grandprixinfo.cup->numlevels) // On final map { - nextmap = NEXTMAP_CEREMONY; // ceremonymap + newmap = NEXTMAP_CEREMONY; // ceremonymap } else { @@ -3817,11 +3818,11 @@ static void G_GetNextMap(void) if (cupLevelNum < nummapheaders && mapheaderinfo[cupLevelNum]) { - nextmap = cupLevelNum; + newmap = cupLevelNum; } else { - nextmap = prevmap; // Prevent uninitialised use + newmap = curmap; // Prevent uninitialised use } grandprixinfo.roundnum++; @@ -3830,7 +3831,7 @@ static void G_GetNextMap(void) } else if (bossinfo.boss == true) { - nextmap = NEXTMAP_TITLE; // temporary + newmap = NEXTMAP_TITLE; // temporary } else { @@ -3858,13 +3859,13 @@ static void G_GetNextMap(void) // Grab the first valid after the map you're on if (gettingresult) { - nextmap = cm; + newmap = cm; gettingresult = 2; break; } // Not the map you're on? - if (cm != prevmap) + if (cm != curmap) { continue; } @@ -3888,21 +3889,21 @@ static void G_GetNextMap(void) { if (marathonmode) { - nextmap = NEXTMAP_CEREMONY; // ceremonymap + newmap = NEXTMAP_CEREMONY; // ceremonymap } else { - nextmap = NEXTMAP_TITLE; + newmap = NEXTMAP_TITLE; } } } else { - i = prevmap; + i = curmap; if (++i >= nummapheaders) i = 0; - while (i != prevmap) + while (i != curmap) { if (!mapheaderinfo[i] || mapheaderinfo[i]->lumpnum == LUMPERROR @@ -3917,29 +3918,31 @@ static void G_GetNextMap(void) break; } - nextmap = i; + newmap = i; } - if (!marathonmode) + if (advancemap && !marathonmode) { if (cv_advancemap.value == 0) // Stay on same map. { - nextmap = prevmap; + newmap = curmap; } else if (cv_advancemap.value == 2) // Go to random map. { - nextmap = G_RandMap(G_TOLFlag(gametype), prevmap, 0, 0, false, NULL); + newmap = G_RandMap(G_TOLFlag(gametype), curmap, 0, 0, false, NULL); } else if (nextmap >= NEXTMAP_SPECIAL) // Loop back around { - nextmap = G_GetFirstMapOfGametype(gametype); + newmap = G_GetFirstMapOfGametype(gametype); } } } // We are committed to this map now. - 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); + if (newmap == NEXTMAP_INVALID || (newmap < NEXTMAP_SPECIAL && (newmap >= nummapheaders || !mapheaderinfo[newmap] || mapheaderinfo[newmap]->lumpnum == LUMPERROR))) + I_Error("G_GetNextMap: Internal map ID %d not found (nummapheaders = %d)\n", newmap, nummapheaders); + + return newmap; } // @@ -4005,7 +4008,7 @@ static void G_DoCompleted(void) if (!demo.playback) { - G_GetNextMap(); + nextmap = G_GetNextMap(true); // Remember last map for when you come out of the special stage. if (!spec) @@ -5151,19 +5154,8 @@ INT32 G_FindMapByNameOrCode(const char *mapname, char **realmapnamep) { if (mapname[0] == '*') // current map return gamemap; - /* - else if (mapname[0] == '+' && mapheaderinfo[gamemap-1]) // next map - { - newmapnum = G_MapNumber(mapheaderinfo[gamemap-1]->nextlevel); - if (!mapheaderinfo[newmapnum]) - { - CONS_Alert(CONS_ERROR, M_GetText("NextLevel (%d) is not a valid map.\n"), newmapnum); - return 0; - } - else - return newmapnum-1; - } - */ + else if (mapname[0] == '+') // next map + return G_GetNextMap(false)+1; } /* Now detect map number in base 10, which no one asked for. */ diff --git a/src/m_menu.c b/src/m_menu.c index 494b3ccdb..c9651b99e 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -6282,7 +6282,7 @@ static boolean M_ExitPandorasBox(void) static void M_ChangeLevel(INT32 choice) { (void)choice; - INT16 map = cv_nextmap.value ? cv_nextmap.value : G_RandMap(G_TOLFlag(cv_newgametype.value), gamestate == GS_LEVEL ? gamemap : prevmap, 0, 0, false, NULL); + INT16 map = cv_nextmap.value ? cv_nextmap.value : G_RandMap(G_TOLFlag(cv_newgametype.value), gamestate == GS_LEVEL ? gamemap-1 : prevmap, 0, 0, false, NULL); M_ClearMenus(true); COM_BufAddText(va("map %d -gametype \"%s\"\n", map, cv_newgametype.string)); } From 4697a69bd98729646decaea8574d6f8b3e0aec53 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Tue, 11 Feb 2025 21:33:12 +0100 Subject: [PATCH 105/117] Ignore old SOC map header fields --- src/deh_soc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/deh_soc.c b/src/deh_soc.c index 30a1f17d6..555f91dda 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -1496,6 +1496,9 @@ void readlevelheader(MYFILE *f, char * name) else mapheaderinfo[num]->use_walltransfer = false; } + // ignored for compatibility + else if (fastcmp(word, "NEXTLEVEL") || fastcmp(word, "TIMEATTACK") || fastcmp(word, "RECORDATTACK")) + continue; else deh_warning("Level header %d: unknown word '%s'", num, word); } From ec5f317f282f7c2d2d6c0ae1a445b2de81db61c5 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Wed, 12 Feb 2025 01:00:10 +0100 Subject: [PATCH 106/117] Oops, forgot about G_LoadDemoInfo --- src/g_demo.c | 4 +++- src/m_menu.c | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/g_demo.c b/src/g_demo.c index 8795b7123..b4467afa8 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -2626,6 +2626,7 @@ void G_LoadDemoInfo(menudemo_t *pdemo) UINT8 *infobuffer, *info_p, *extrainfo_p; UINT8 version, subversion, pdemoflags; UINT16 pdemoversion, count; + char mapname[MAXMAPLUMPNAME]; if (!FIL_ReadFile(pdemo->filepath, &infobuffer)) { @@ -2685,7 +2686,8 @@ void G_LoadDemoInfo(menudemo_t *pdemo) return; } info_p += 4; // "PLAY" - pdemo->map = READINT16(info_p); + READSTRINGN(info_p, mapname, sizeof(mapname)); + pdemo->map = G_MapNumber(mapname); info_p += 16; // mapmd5 pdemoflags = READUINT8(info_p); diff --git a/src/m_menu.c b/src/m_menu.c index c9651b99e..cf2a23b14 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -5643,8 +5643,8 @@ static void DrawReplayHutReplayInfo(void) x += 85; - if (mapheaderinfo[demolist[dir_on[menudepthleft]].map-1]) - V_DrawString(x, y, V_SNAPTOTOP, G_BuildMapTitle(demolist[dir_on[menudepthleft]].map)); + if (demolist[dir_on[menudepthleft]].map != NEXTMAP_INVALID) + V_DrawString(x, y, V_SNAPTOTOP, G_BuildMapTitle(demolist[dir_on[menudepthleft]].map+1)); else V_DrawString(x, y, V_SNAPTOTOP|V_ALLOWLOWERCASE|V_TRANSLUCENT, "Level is not loaded."); From 6db125c0f32e544128e6d4bc87b274e40dc412f4 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Wed, 12 Feb 2025 01:04:52 +0100 Subject: [PATCH 107/117] Introducing... M_GetMapThumbnail and arbitrarily scaled thumbnails * only supports two sizes --- src/hu_stuff.c | 4 +++ src/m_menu.c | 75 ++++++++++++++++++++++---------------------------- src/m_menu.h | 2 ++ src/r_defs.h | 2 ++ src/y_inter.c | 55 +++++++++++------------------------- 5 files changed, 57 insertions(+), 81 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 624085591..e6cbcbda9 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -99,6 +99,8 @@ static char hu_tick; patch_t *missingpat; patch_t *blanklvl; +patch_t *randomlvl; +patch_t *nolvl; // song credits static patch_t *songcreditbg; @@ -188,6 +190,8 @@ void HU_LoadGraphics(void) Font_Load(); HU_UpdatePatch(&blanklvl, "BLANKLVL"); + HU_UpdatePatch(&randomlvl, "RANDOMLV"); + HU_UpdatePatch(&nolvl, "M_NOLVL"); HU_UpdatePatch(&songcreditbg, "K_SONGCR"); diff --git a/src/m_menu.c b/src/m_menu.c index cf2a23b14..675c376d0 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -1785,6 +1785,23 @@ INT32 HU_GetHighlightColor(void) return highlightflags; } +fixed_t M_GetMapThumbnail(INT16 mapnum, patch_t **out) +{ + patch_t *patch = NULL; + if (mapnum == -1) + patch = randomlvl; + else if (mapnum >= 0 && mapnum < nummapheaders && mapheaderinfo[mapnum]) + patch = mapheaderinfo[mapnum]->thumbnailPic; + + if (!patch) + patch = blanklvl; + + *out = patch; + + // check width instead of height because haha big winton + return patch->width >= 320 ? FRACUNIT/4 : FRACUNIT/2; +} + // Sky Room menu_t SR_PandoraDef = { @@ -5619,19 +5636,18 @@ static void DrawReplayHutReplayInfo(void) // Draw level stuff x = 15; y = 15; - // A 160x100 image of the level //CONS_Printf("%d %s\n", demolist[dir_on[menudepthleft]].map, G_BuildMapName(demolist[dir_on[menudepthleft]].map)); - patch = mapheaderinfo[demolist[dir_on[menudepthleft]].map-1] - ? mapheaderinfo[demolist[dir_on[menudepthleft]].map-1]->thumbnailPic - : W_CachePatchName("M_NOLVL", PU_CACHE); + fixed_t scale = M_GetMapThumbnail(demolist[dir_on[menudepthleft]].map, &patch); + if (patch == blanklvl) + patch = nolvl; if (!(demolist[dir_on[menudepthleft]].kartspeed & DF_ENCORE)) - V_DrawSmallScaledPatch(x, y, V_SNAPTOTOP, patch); + V_DrawFixedPatch(x<width); - h = SHORT(patch->height); - V_DrawSmallScaledPatch(x+(w>>1), y, V_SNAPTOTOP|V_FLIP, patch); + w = FixedMul(SHORT(patch->width), scale); + h = FixedMul(SHORT(patch->height), scale); + V_DrawFixedPatch((x+(w>>1))<>1; + fixed_t scale = M_GetMapThumbnail(cv_nextmap.value-1, &PictureOfLevel); - // A 160x100 image of the level - if (cv_nextmap.value) - { - PictureOfLevel = mapheaderinfo[cv_nextmap.value-1]->thumbnailPic; - if (!PictureOfLevel) - PictureOfLevel = blanklvl; - } - else - PictureOfLevel = W_CachePatchName("RANDOMLV", PU_CACHE); - - w = SHORT(PictureOfLevel->width)/2; - i = SHORT(PictureOfLevel->height)/2; + w = FixedMul(SHORT(PictureOfLevel->width), scale); + i = FixedMul(SHORT(PictureOfLevel->height), scale); x = BASEVIDWIDTH/2 - w/2; y = currentMenu->y + 130 + 8 - i; @@ -9007,14 +9014,14 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) V_DrawFill(x-1, y-1, w+2, i+2, trans); // variable reuse... if ((cv_kartencore.value != 1) || gamestate == GS_TIMEATTACK || cv_newgametype.value != GT_RACE) - V_DrawSmallScaledPatch(x, y, 0, PictureOfLevel); + V_DrawFixedPatch(x<= 0) - { - PictureOfLevel = mapheaderinfo[i]->thumbnailPic; - if (!PictureOfLevel) - PictureOfLevel = blanklvl; - } - else - PictureOfLevel = W_CachePatchName("RANDOMLV", PU_CACHE); + scale = M_GetMapThumbnail(i, &PictureOfLevel)/2; x -= horizspac + w/2; - V_DrawTinyScaledPatch(x, y, trans, PictureOfLevel); + V_DrawFixedPatch(x< horizspac-dupadjust); x = (BASEVIDWIDTH + w)/2 + horizspac; @@ -9084,17 +9083,9 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) } while (!M_CanShowLevelInList(i, cv_newgametype.value)); - // A 160x100 image of the level as entry MAPxxP - if (i >= 0) - { - PictureOfLevel = mapheaderinfo[i]->thumbnailPic; - if (!PictureOfLevel) - PictureOfLevel = blanklvl; - } - else - PictureOfLevel = W_CachePatchName("RANDOMLV", PU_CACHE); + scale = M_GetMapThumbnail(i, &PictureOfLevel)/2; - V_DrawTinyScaledPatch(x, y, trans, PictureOfLevel); + V_DrawFixedPatch(x<thumbnailPic; - } - - if (!pic) - { - pic = blanklvl; - } + mapnum = votelevels[i][0]; } + scale = M_GetMapThumbnail(mapnum, &pic); if (selected[i]) { @@ -1342,10 +1334,10 @@ void Y_VoteDrawer(void) } if (!levelinfo[i].encore) - V_DrawSmallScaledPatch(BASEVIDWIDTH-100, y, V_SNAPTORIGHT, pic); + V_DrawFixedPatch((BASEVIDWIDTH-100)<= 3 && (i != pickedvote || voteendtic == -1)) - { - pic = randomlvl; - } + mapnum = -1; // randomlvl else - { - pic = NULL; + mapnum = votelevels[votes[i]][0]; - if (mapheaderinfo[votelevels[votes[i]][0]]) - { - pic = mapheaderinfo[votelevels[votes[i]][0]]->thumbnailPic; - } - - if (!pic) - { - pic = blanklvl; - } - } + scale = M_GetMapThumbnail(mapnum, &pic)/2; if (!timer && i == voteclient.ranim) { @@ -1425,10 +1404,10 @@ void Y_VoteDrawer(void) } if (!levelinfo[votes[i]].encore) - V_DrawTinyScaledPatch(x, y, V_SNAPTOLEFT, pic); + V_DrawFixedPatch(x<width, scale))< Date: Mon, 13 Mar 2023 16:18:07 +0000 Subject: [PATCH 108/117] "Monitor" parameter for cups - Defaults to 1, AKA Sonic 1/2 monitor - Set to 2 for Sonic 3k monitor - Supports a range of 1-9 and A-Z - Permits fine-grained rapid-prototype stretch goal Chaotix monitor stuff later in development --- src/deh_soc.c | 11 ++++++++++- src/dehacked.c | 1 + src/doomstat.h | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index 555f91dda..e6645e98a 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -3501,7 +3501,16 @@ void readcupheader(MYFILE *f, cupheader_t *cup) i = atoi(word2); // used for numerical settings strupr(word2); - if (fastcmp(word, "ICON")) + if (fastcmp(word, "MONITOR")) + { + if (i > 0 && i < 10) + cup->monitor = i; + else if (!word2[0] || word2[1] != '\0' || word2[0] == '0') + deh_warning("%s Cup: Invalid monitor type \"%s\" (should be 1-9 or A-Z)\n", cup->name, word2); + else + cup->monitor = (word2[0] - 'A') + 10; + } + else if (fastcmp(word, "ICON")) { deh_strlcpy(cup->icon, word2, sizeof(cup->icon), va("%s Cup: icon", cup->name)); diff --git a/src/dehacked.c b/src/dehacked.c index 6943c5c47..3faa7b7e9 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -534,6 +534,7 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile) { cup = Z_Calloc(sizeof (cupheader_t), PU_STATIC, NULL); cup->id = numkartcupheaders; + cup->monitor = 1; deh_strlcpy(cup->name, word2, sizeof(cup->name), va("Cup header %s: name", word2)); if (prev != NULL) diff --git a/src/doomstat.h b/src/doomstat.h index 4e9d297f3..754f85e98 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -357,6 +357,7 @@ struct mapheader_lighting_t struct cupheader_t { UINT16 id; ///< Cup ID + UINT8 monitor; ///< Monitor graphic 1-9 or A-Z 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 From 4e559aed87948d4a616d38e05dcf044e9169ae44 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 23 May 2023 17:41:32 +0100 Subject: [PATCH 109/117] Level and cup header information: Hashing for referencing by name Foundational assistive work. Also guarantees a consistent cup name length in memory, as some places read/wrote 15 bytes, and some places read/wrote 16 bytes. We settle on the latter (including null terminator) for the broadest backwards compatibility. G: partial merge, missing lots of cup stuff --- src/deh_soc.c | 1 + src/dehacked.c | 64 ++++++++++++++++++++++++++++++-------------------- src/doomstat.h | 8 ++++++- src/g_game.c | 6 ++++- 4 files changed, 51 insertions(+), 28 deletions(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index e6645e98a..8843cb099 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -1109,6 +1109,7 @@ void readlevelheader(MYFILE *f, char * name) if (mapheaderinfo[num]->lumpname == NULL) { mapheaderinfo[num]->lumpname = Z_StrDup(name); + mapheaderinfo[num]->lumpnamehash = quickncasehash(mapheaderinfo[num]->lumpname, MAXMAPLUMPNAME); } do diff --git a/src/dehacked.c b/src/dehacked.c index 3faa7b7e9..9ce541cb4 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -513,39 +513,51 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile) // else if (fastcmp(word, "CUP")) { - cupheader_t *cup = kartcupheaders; - cupheader_t *prev = NULL; - - while (cup) + size_t len = strlen(word2); + if (len <= MAXCUPNAME-1) { - if (fastcmp(cup->name, word2)) + cupheader_t *cup = kartcupheaders; + cupheader_t *prev = NULL; + UINT32 hash = quickncasehash(word2, MAXCUPNAME); + + while (cup) { - // Only a major mod if editing stuff that isn't your own! - G_SetGameModified(multiplayer, true); - break; + if (hash == cup->namehash && fastcmp(cup->name, word2)) + { + // Only a major mod if editing stuff that isn't your own! + G_SetGameModified(multiplayer, true); + break; + } + + prev = cup; + cup = cup->next; } - prev = cup; - cup = cup->next; - } + // Nothing found, add to the end. + if (!cup) + { + cup = Z_Calloc(sizeof (cupheader_t), PU_STATIC, NULL); + cup->id = numkartcupheaders; + cup->monitor = 1; + deh_strlcpy(cup->name, word2, + sizeof(cup->name), va("Cup header %s: name", word2)); + cup->namehash = hash; + if (prev != NULL) + prev->next = cup; + if (kartcupheaders == NULL) + kartcupheaders = cup; + numkartcupheaders++; + CONS_Printf("Added cup %d ('%s')\n", cup->id, cup->name); + } - // Nothing found, add to the end. - if (!cup) + readcupheader(f, cup); + + } + else { - cup = Z_Calloc(sizeof (cupheader_t), PU_STATIC, NULL); - cup->id = numkartcupheaders; - cup->monitor = 1; - deh_strlcpy(cup->name, word2, - sizeof(cup->name), va("Cup header %s: name", word2)); - if (prev != NULL) - prev->next = cup; - if (kartcupheaders == NULL) - kartcupheaders = cup; - numkartcupheaders++; - CONS_Printf("Added cup %d ('%s')\n", cup->id, cup->name); + deh_warning("Cup header's name %s is too long (%s characters VS %d max)", word2, sizeu1(len), (MAXCUPNAME-1)); + ignorelines(f); } - - readcupheader(f, cup); } else if (fastcmp(word, "WEATHER") || fastcmp(word, "PRECIP") || fastcmp(word, "PRECIPITATION")) { diff --git a/src/doomstat.h b/src/doomstat.h index 754f85e98..7c1ce5491 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -354,11 +354,16 @@ struct mapheader_lighting_t #define CUPCACHE_SPECIAL MAXLEVELLIST+1 #define CUPCACHE_MAX CUPCACHE_SPECIAL+1 +#define MAXCUPNAME 16 // includes \0, for cleaner savedata + struct cupheader_t { UINT16 id; ///< Cup ID UINT8 monitor; ///< Monitor graphic 1-9 or A-Z - char name[15]; ///< Cup title (14 chars) + + char name[MAXCUPNAME]; ///< Cup title + UINT32 namehash; ///< Cup title hash + 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 @@ -379,6 +384,7 @@ struct mapheader_t { // Core game information, not user-modifiable directly char *lumpname; ///< Lump name can be really long + UINT32 lumpnamehash; ///< quickncasehash(->lumpname, MAXMAPLUMPNAME) lumpnum_t lumpnum; ///< Lump number for the map, used by vres_GetMap void *thumbnailPic; ///< Lump data for the level select thumbnail. diff --git a/src/g_game.c b/src/g_game.c index 24b6256c3..ae864ea73 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -723,9 +723,13 @@ INT32 G_MapNumber(const char * name) #endif { INT32 map; + UINT32 hash = quickncasehash(name, MAXMAPLUMPNAME); for (map = 0; map < nummapheaders; ++map) { + if (hash != mapheaderinfo[map]->lumpnamehash) + continue; + if (strcasecmp(mapheaderinfo[map]->lumpname, name) != 0) continue; @@ -4388,7 +4392,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 5f063aa0148c59de0a101779918f629526d14ef2 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Wed, 12 Feb 2025 01:56:39 +0100 Subject: [PATCH 110/117] I'm sick of cherry-picking, just silence this warning --- 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 ae864ea73..250d6823c 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4392,7 +4392,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\n", mapname); + //CONS_Alert(CONS_WARNING, "Map with lumpname %s does not exist, time record data will be discarded\n", mapname); } } From e9795f5271db5e05e4986fae6454945df6d1acba Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Wed, 12 Feb 2025 03:24:11 +0100 Subject: [PATCH 111/117] Expose map thumbnails and minimaps to Lua ... LET'S FUCKING GOOOOOOOOOOOOOOOOOOOOOOOOO --- src/lua_hudlib.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 0bfe770fa..810dc2b24 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -22,6 +22,7 @@ #include "p_local.h" // camera_t #include "screen.h" // screen width/height #include "m_random.h" // m_random +#include "m_menu.h" // M_GetMapThumbnail #include "v_video.h" #include "w_wad.h" #include "z_zone.h" @@ -1090,6 +1091,41 @@ static int libd_getStringColormap(lua_State *L) return 0; } +static int libd_getMapThumbnail(lua_State *L) +{ + INT16 mapnum; + patch_t *patch = NULL; + HUDONLY + if (lua_type(L, 1) == LUA_TNUMBER) + mapnum = luaL_checkinteger(L, 1) - 1; + else + mapnum = G_MapNumber(luaL_checkstring(L, 1)); + + fixed_t scale = M_GetMapThumbnail(mapnum, &patch); + LUA_PushUserdata(L, patch, META_PATCH); + lua_pushfixed(L, scale); + return 2; +} + +static int libd_getMapMinimap(lua_State *L) +{ + INT16 mapnum; + patch_t *patch = NULL; + HUDONLY + if (lua_type(L, 1) == LUA_TNUMBER) + mapnum = luaL_checkinteger(L, 1) - 1; + else + mapnum = G_MapNumber(luaL_checkstring(L, 1)); + + if (mapnum >= 0 && mapnum < nummapheaders && mapheaderinfo[mapnum]) + patch = mapheaderinfo[mapnum]->minimapPic; + if (!patch) + patch = missingpat; + + LUA_PushUserdata(L, patch, META_PATCH); + return 1; +} + static int libd_width(lua_State *L) { HUDONLY @@ -1257,6 +1293,8 @@ static luaL_Reg lib_draw[] = { {"getSprite2Patch", libd_getSprite2Patch}, {"getColormap", libd_getColormap}, {"getStringColormap", libd_getStringColormap}, + {"getMapThumbnail", libd_getMapThumbnail}, + {"getMapMinimap", libd_getMapMinimap}, // drawing {"draw", libd_draw}, {"drawScaled", libd_drawScaled}, From 3adaceab0bf537a5c8ca9d543d0b83a1d2c2492d Mon Sep 17 00:00:00 2001 From: NepDisk Date: Wed, 12 Feb 2025 15:32:16 +0000 Subject: [PATCH 112/117] Update extras/udmf-spec.txt --- extras/udmf-spec.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extras/udmf-spec.txt b/extras/udmf-spec.txt index 361b051fc..97c6bff44 100644 --- a/extras/udmf-spec.txt +++ b/extras/udmf-spec.txt @@ -42,7 +42,7 @@ additional lumps: BEHAVIOR = Compiled ACS code. ZNODES = Compiled extended / GL friendly nodes. These are required. - PICTURE = A Doom graphic lump, expected to be 160x100. Intended to be a + PICTURE = A Doom graphic lump, expected to be 320x240 or 160x100. Intended to be a screenshot of the map itself. This is used by the game for level select menus. MINIMAP = A Doom graphic lump, expected to be 100x100. Intended to be a From 1c1b72bd6c4b361200e6022eebbbf2f190b82d80 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Mon, 17 Feb 2025 18:07:37 +0100 Subject: [PATCH 113/117] Change thumbnail reference scale to 320x200 Seems more sensible than "it was more convenient at the time" --- src/m_menu.c | 10 +++++----- src/y_inter.c | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 675c376d0..ae509484f 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -1799,7 +1799,7 @@ fixed_t M_GetMapThumbnail(INT16 mapnum, patch_t **out) *out = patch; // check width instead of height because haha big winton - return patch->width >= 320 ? FRACUNIT/4 : FRACUNIT/2; + return patch->width >= 320 ? FRACUNIT : FRACUNIT*2; } // Sky Room @@ -5637,7 +5637,7 @@ static void DrawReplayHutReplayInfo(void) x = 15; y = 15; //CONS_Printf("%d %s\n", demolist[dir_on[menudepthleft]].map, G_BuildMapName(demolist[dir_on[menudepthleft]].map)); - fixed_t scale = M_GetMapThumbnail(demolist[dir_on[menudepthleft]].map, &patch); + fixed_t scale = M_GetMapThumbnail(demolist[dir_on[menudepthleft]].map, &patch)/4; if (patch == blanklvl) patch = nolvl; @@ -8999,7 +8999,7 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) { patch_t *PictureOfLevel; INT32 x, y, w, i, oldval, trans, dupadjust = ((vid.width/vid.dupx) - BASEVIDWIDTH)>>1; - fixed_t scale = M_GetMapThumbnail(cv_nextmap.value-1, &PictureOfLevel); + fixed_t scale = M_GetMapThumbnail(cv_nextmap.value-1, &PictureOfLevel)/4; w = FixedMul(SHORT(PictureOfLevel->width), scale); i = FixedMul(SHORT(PictureOfLevel->height), scale); @@ -9055,7 +9055,7 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) } while (!M_CanShowLevelInList(i, cv_newgametype.value)); - scale = M_GetMapThumbnail(i, &PictureOfLevel)/2; + scale = M_GetMapThumbnail(i, &PictureOfLevel)/8; x -= horizspac + w/2; @@ -9083,7 +9083,7 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) } while (!M_CanShowLevelInList(i, cv_newgametype.value)); - scale = M_GetMapThumbnail(i, &PictureOfLevel)/2; + scale = M_GetMapThumbnail(i, &PictureOfLevel)/8; V_DrawFixedPatch(x< Date: Mon, 17 Feb 2025 20:32:18 +0100 Subject: [PATCH 114/117] xva: dynamically allocated va --- src/doomdef.h | 1 + src/m_misc.cpp | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/doomdef.h b/src/doomdef.h index 5c6702db1..75487e48a 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -344,6 +344,7 @@ extern char liveeventbackup[256]; void M_StartupLocale(void); void *M_Memcpy(void* dest, const void* src, size_t n); char *va(const char *format, ...) FUNCPRINTF; +char *xva(const char *format, ...) FUNCPRINTF; char *M_GetToken(const char *inputString); void M_UnGetToken(void); diff --git a/src/m_misc.cpp b/src/m_misc.cpp index b4da15099..c0f1ba187 100644 --- a/src/m_misc.cpp +++ b/src/m_misc.cpp @@ -1713,6 +1713,32 @@ char *va(const char *format, ...) return string; } +/** Allocates and returns a string made out of varargs. + * + * \param format Format string. + * \return Pointer to the resulting string. + */ +char *xva(const char *format, ...) +{ + va_list argptr; + char *string; + + va_start(argptr, format); + int size = vsnprintf(NULL, 0, format, argptr); + if (size < 0) + I_Error("xva: can't format string"); + string = static_cast(malloc((unsigned)size+1)); + if (!string) + I_Error("xva: out of memory"); + va_end(argptr); + + va_start(argptr, format); + vsprintf(string, format, argptr); + va_end(argptr); + + return string; +} + /** Creates a string in the first argument that is the second argument followed * by the third argument followed by the first argument. * Useful for making filenames with full path. s1 = s2+s3+s1 From 723164152fec2e5c1fb129489ac8027092e627e6 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Mon, 17 Feb 2025 21:43:12 +0100 Subject: [PATCH 115/117] Salvage the remaining parts of 8f68a21 I'm keeping the screenshot mapname tho :^) --- src/d_main.cpp | 5 +---- src/discord.c | 13 ------------- src/g_game.c | 4 ++-- src/m_menu.c | 6 +++--- src/m_misc.cpp | 4 ++-- src/p_setup.c | 4 ++-- 6 files changed, 10 insertions(+), 26 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 15d5729c9..ede869228 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1893,14 +1893,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/discord.c b/src/discord.c index 590446227..4e8af70eb 100644 --- a/src/discord.c +++ b/src/discord.c @@ -442,9 +442,6 @@ 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]; @@ -547,16 +544,6 @@ void DRPC_UpdatePresence(void) if ((gamestate == GS_LEVEL || gamestate == GS_INTERMISSION) // Map info && !(demo.playback && demo.title)) { -#ifdef USEMAPIMG - if ((gamemap >= 1 && gamemap <= 60) // supported race maps - || (gamemap >= 136 && gamemap <= 164)) // supported battle maps - { - snprintf(mapimg, 8, "%s", G_BuildMapName(gamemap)); - strlwr(mapimg); - discordPresence.largeImageKey = mapimg; // Map image - } - else -#endif if (mapheaderinfo[gamemap-1]->menuflags & LF2_HIDEINMENU) { // Hell map, use the method that got you here :P diff --git a/src/g_game.c b/src/g_game.c index 250d6823c..3b4670eb4 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1354,7 +1354,7 @@ void G_DoLoadLevel(boolean resetplayer) // cleanup if (titlemapinaction == TITLEMAP_LOADING) { - if (W_CheckNumForName(G_BuildMapName(gamemap)) == LUMPERROR) + if (gamemap < 1 || gamemap > nummapheaders) { titlemap = 0; // let's not infinite recursion ok Command_ExitGame_f(); @@ -3606,7 +3606,7 @@ tryagain: break; } - if (vLump == NULL && ((l = W_CheckNumForName(va("%sS01",mapheaderinfo[ix+1]->lumpname))) == LUMPERROR)) + if (vLump == NULL && ((l = W_CheckNumForLongName(va("%sS01",mapheaderinfo[ix+1]->lumpname))) == LUMPERROR)) { vres_Free(vRes); continue; diff --git a/src/m_menu.c b/src/m_menu.c index ae509484f..3d9985ced 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -2281,7 +2281,7 @@ static void Dummystaff_OnChange(void) dummystaffname[0] = '\0'; // TODO: Use map header to determine lump name - 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; @@ -2290,7 +2290,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) @@ -2298,7 +2298,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); diff --git a/src/m_misc.cpp b/src/m_misc.cpp index c0f1ba187..bbdb9efbd 100644 --- a/src/m_misc.cpp +++ b/src/m_misc.cpp @@ -793,7 +793,7 @@ static void M_PNGText(png_structp png_ptr, png_infop png_info_ptr, PNG_CONST png "Unknown"; #endif char rendermodetxt[9]; - char maptext[8]; + char maptext[MAXMAPLUMPNAME]; char lvlttltext[48]; char locationtxt[40]; char ctrevision[40]; @@ -814,7 +814,7 @@ static void M_PNGText(png_structp png_ptr, png_infop png_info_ptr, PNG_CONST png } if (gamestate == GS_LEVEL) - snprintf(maptext, 8, "%s", G_BuildMapName(gamemap)); + snprintf(maptext, MAXMAPLUMPNAME, "%s", G_BuildMapName(gamemap)); else snprintf(maptext, 8, "Unknown"); diff --git a/src/p_setup.c b/src/p_setup.c index 3a8661a08..dd6b453a5 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -7849,7 +7849,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_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++; @@ -7991,7 +7991,7 @@ static void P_InitGametype(void) #else strcpy(ver, VERSIONSTRING); #endif - sprintf(buf, "%s"PATHSEP"media"PATHSEP"replay"PATHSEP"online"PATHSEP"%s"PATHSEP"%d-%s", + snprintf(buf, sizeof buf, "%s"PATHSEP"media"PATHSEP"replay"PATHSEP"online"PATHSEP"%s"PATHSEP"%d-%s", srb2home, ver, (int) (time(NULL)), G_BuildMapName(gamemap)); parts = M_PathParts(buf); From 8d3083cefe362c242b48ef54e2a652e935a61111 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Mon, 17 Feb 2025 21:44:23 +0100 Subject: [PATCH 116/117] Fix some G_BuildMapName string formats more like "flex xva" but ok --- src/g_game.c | 15 ++++++--------- src/m_menu.c | 8 +------- src/p_setup.c | 4 ++-- 3 files changed, 9 insertions(+), 18 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 3b4670eb4..0a203217c 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -581,6 +581,7 @@ static void G_UpdateRecordReplays(void) char *gpath; char lastdemo[256], bestdemo[256]; UINT8 earnedEmblems; + int parts; // Record new best time if (!mapheaderinfo[gamemap-1]->mainrecord) @@ -613,17 +614,13 @@ static void G_UpdateRecordReplays(void) G_SetDemoTime(players[consoleplayer].realtime, bestlap); G_CheckDemoStatus(); - gpath = va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s", - srb2home, timeattackfolder); - M_MkdirEach(gpath, M_PathParts(gpath) - 3, 0755); - - strcat(gpath, PATHSEP); - strcat(gpath, G_BuildMapName(gamemap)); + gpath = xva("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", + srb2home, timeattackfolder, G_BuildMapName(gamemap)); + parts = M_PathParts(gpath); + M_MkdirEachUntil(gpath, parts - 4, parts - 1, 0755); snprintf(lastdemo, 255, "%s-%s-last.lmp", gpath, cv_chooseskin.string); - gpath = Z_StrDup(gpath); - if (FIL_FileExists(lastdemo)) { UINT8 *buf; @@ -655,7 +652,7 @@ static void G_UpdateRecordReplays(void) Z_Free(buf); } - Z_Free(gpath); + free(gpath); // Check emblems when level data is updated if ((earnedEmblems = M_CheckLevelEmblems())) diff --git a/src/m_menu.c b/src/m_menu.c index 3d9985ced..dbdf900fa 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -2165,16 +2165,10 @@ void Nextmap_OnChange(void) { // see also p_setup.c's P_LoadRecordGhosts const char *gamemode = (levellistmode == LLM_ITEMBREAKER) ? "IB" : "RA"; - const size_t glen = strlen(srb2home)+1+strlen("media")+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1; - char *gpath = malloc(glen); + char *gpath = xva("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value)); INT32 i; UINT8 active = 0; - if (!gpath) - return; - - sprintf(gpath,"%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value)); - CV_StealthSetValue(&cv_dummystaff, 0); active = 0; diff --git a/src/p_setup.c b/src/p_setup.c index dd6b453a5..03ce5a8fb 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -7795,7 +7795,7 @@ static void P_LoadRecordGhosts(void) INT32 i; const char *gamemode = (modeattacking & ATTACKING_ITEMBREAK) ? "IB" : "RA"; - gpath = Z_StrDup(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap))); + gpath = xva("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap)); // Best Time ghost if (cv_ghost_besttime.value) @@ -7856,7 +7856,7 @@ static void P_LoadRecordGhosts(void) } } - Z_Free(gpath); + free(gpath); } static void P_SetupCamera(UINT8 pnum, camera_t *cam) From dc9a3b4d312ae86bd88c0dede2672c3bd84d837c Mon Sep 17 00:00:00 2001 From: NepDisk Date: Mon, 17 Feb 2025 17:24:19 -0500 Subject: [PATCH 117/117] Use final version of 'W_CheckNumForMapPwad' --- src/w_wad.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/w_wad.c b/src/w_wad.c index 6de1fe115..37cc1dea8 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -539,20 +539,30 @@ static lumpinfo_t* ResGetLumpsWad (FILE* handle, UINT16* nlmp, const char* filen trimname = strrchr(filename, PATHSEP[0]); #if defined (_WIN32) // For Zone Builder support, work around temporary filenames. - if (trimname != 0) + // They're annoyingly randomised, BUT they follow \Temp\8\8.3... + // AND they're always guaranteed to follow the map file, which + // should already have a WADNAME in it for us to piggyback off. + // EXAMPLE: // \Temp\gj3l7w7n\4f926789.wad + + if (trimname != 0 + && wadnamelump != LUMPERROR + && strlen(trimname+1) == 8+1+3) { const char *temp = trimname-1; while (temp >= filename+5 && *temp != PATHSEP[0]) temp--; - if (temp-filename >= 5 && !strncmp(temp-5, PATHSEP"Temp", 5)) + if (((trimname-1) - temp) == 8 + && temp >= filename+5 + && !strncmp(temp-5, PATHSEP"Temp", 5)) { - filename = wadfiles[numwadfiles-1]->filename; + filename = wadfiles[ + ((wadnamelump & ~UINT16_MAX) >> 16) + ]->filename; trimname = strrchr(filename, PATHSEP[0]); } } #endif - // Strip away file address if (trimname != 0) trimname++; @@ -570,6 +580,8 @@ static lumpinfo_t* ResGetLumpsWad (FILE* handle, UINT16* nlmp, const char* filen strncpy(lump_p->longname, trimname, namelen); lump_p->longname[namelen-1] = '\0'; + CONS_Debug(DBG_SETUP, "WADNAME handling:\n -- path %s\n -- interpreted lumpname %s\n", filename, lump_p->longname); + // Grab the hash from the first part lump_p->hash = quickncasehash(lump_p->longname, 8); @@ -579,16 +591,12 @@ static lumpinfo_t* ResGetLumpsWad (FILE* handle, UINT16* nlmp, const char* filen { // Set up true hash lump_p->hash = quickncasehash(lump_p->name, 8); + // Allocate the lump's long and full name (save on memory). lump_p->longname = lump_p->fullname = Z_Malloc(9 * sizeof(char), PU_STATIC, NULL); strncpy(lump_p->longname, fileinfo->name, 8); lump_p->longname[8] = '\0'; } - - // Allocate the lump's full name. - lump_p->fullname = Z_Malloc(9 * sizeof(char), PU_STATIC, NULL); - strncpy(lump_p->fullname, fileinfo->name, 8); - lump_p->fullname[8] = '\0'; } free(fileinfov); *nlmp = numlumps;