From 48e9138ddaf91814f9265a420af539992a166e16 Mon Sep 17 00:00:00 2001 From: toaster Date: Thu, 22 Sep 2022 17:14:41 +0100 Subject: [PATCH] Refactoring ahoy * Instead of doing constant G_MapNumbers when finding the relationship between maps and cups... * Add a cache of level IDs to cups, to go with the strings. * Add a cache of the cup pointer to maps, so we don't have to search through all cups to find our map. (done in P_InitMapData) * Pre-emptive work: G_IsSpecialStage and P_GetNextEmerald now reference cup data instead of a hardcoded ID set. * Remove a bunch of old stuff from mapheaderinfo_t/associated, and reorder what stays * Countdowntimer? :boom: * Startrings? :boom: * sstimer/ssspheres? :boom: * forcecharacter? :boom: (distinct from forceskin) * interscreen? :boom: * sstage_start/end and smpstage_start/end? :boom::boom::boom::boom: * You've been blocked * G_MapNumber now returns a special NEXTMAP_INVALID if not found, for more consistent reference. * Incorporate a good chunk of the `edit-headers` branch. Can't clear maps individually because of the new restrictions on sequential mapheaders, but we can add a "disable in vote screen, not even for map hell/archive" flag to a map at some future juncture for equivalent functionality... --- src/d_netcmd.c | 2 +- src/deh_soc.c | 58 +++++++++----------- src/doomstat.h | 140 ++++++++++++++++++++++------------------------- src/g_game.c | 60 +++++++------------- src/g_game.h | 3 +- src/k_menudraw.c | 2 +- src/k_menufunc.c | 25 +++------ src/lua_maplib.c | 18 +----- src/lua_script.c | 12 ---- src/p_mobj.c | 2 +- src/p_saveg.c | 10 ---- src/p_setup.c | 93 ++++++++++++------------------- src/p_spec.c | 9 --- src/p_user.c | 17 +++--- src/r_skins.c | 6 -- 15 files changed, 168 insertions(+), 289 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 5d76385f3..fdd6e75e4 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1394,7 +1394,7 @@ UINT8 CanChangeSkin(INT32 playernum) return true; // Force skin in effect. - if ((cv_forceskin.value != -1) || (mapheaderinfo[gamemap-1] && mapheaderinfo[gamemap-1]->forcecharacter[0] != '\0')) + if (cv_forceskin.value != -1) return false; // Can change skin in intermission and whatnot. diff --git a/src/deh_soc.c b/src/deh_soc.c index 030b7f644..ac22781ed 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -158,6 +158,8 @@ void clear_levels(void) P_DeleteFlickies(nummapheaders); + Z_Free(mapheaderinfo[nummapheaders]->mainrecord); + Patch_Free(mapheaderinfo[nummapheaders]->thumbnailPic); Patch_Free(mapheaderinfo[nummapheaders]->minimapPic); @@ -167,7 +169,22 @@ void clear_levels(void) mapheaderinfo[nummapheaders] = NULL; } - // Realloc the one for the current gamemap as a safeguard + // Clear out the cache + { + cupheader_t *cup = kartcupheaders; + UINT8 i; + + while (cup) + { + for (i = 0; i < CUPCACHE_MAX; i++) + { + cup->cachedlevels[i] = NEXTMAP_INVALID; + } + cup = cup->next; + } + } + + // Exit the current gamemap as a safeguard if (Playing()) COM_BufAddText("exitgame"); // Command_ExitGame_f() but delayed } @@ -1093,17 +1110,18 @@ void readlevelheader(MYFILE *f, char * name) char *tmp; INT32 i; - const INT32 num = G_MapNumber(name); + INT32 num = G_MapNumber(name); - if (f->wad > mainwads && num < nummapheaders) + if (num >= nummapheaders) + { + P_AllocMapHeader((INT16)(num = nummapheaders)); + } + else if (f->wad > mainwads) { // only mark as a major mod if it replaces an already-existing mapheaderinfo G_SetGameModified(multiplayer, true); } - // Reset all previous map header information - P_AllocMapHeader((INT16)(num)); - if (mapheaderinfo[num]->lumpname == NULL) { mapheaderinfo[num]->lumpname = Z_StrDup(name); @@ -1336,11 +1354,6 @@ void readlevelheader(MYFILE *f, char * name) mapheaderinfo[num]->mustrack = ((UINT16)i - 1); else if (fastcmp(word, "MUSICPOS")) mapheaderinfo[num]->muspos = (UINT32)get_number(word2); - else if (fastcmp(word, "FORCECHARACTER")) - { - strlcpy(mapheaderinfo[num]->forcecharacter, word2, SKINNAMESIZE+1); - strlwr(mapheaderinfo[num]->forcecharacter); // skin names are lowercase - } else if (fastcmp(word, "WEATHER")) mapheaderinfo[num]->weather = get_precip(word2); else if (fastcmp(word, "SKYTEXTURE")) @@ -2860,24 +2873,6 @@ void readmaincfg(MYFILE *f) if (maptmp <= nummapheaders) spmarathon_start = maptmp; } - else if (fastcmp(word, "SSTAGE_START")) - { - INT16 maptmp = G_MapNumber(word2)+1; - if (maptmp <= nummapheaders) - { - sstage_start = maptmp; - sstage_end = (sstage_start+13); // 14 special stages - } - } - else if (fastcmp(word, "SMPSTAGE_START")) - { - INT16 maptmp = G_MapNumber(word2)+1; - if (maptmp <= nummapheaders) - { - smpstage_start = maptmp; - smpstage_end = (smpstage_start+13); // 14 special stages - } - } else if (fastcmp(word, "REDTEAM")) { skincolor_redteam = (UINT16)get_number(word2); @@ -3323,16 +3318,17 @@ void readcupheader(MYFILE *f, cupheader_t *cup) } cup->levellist[cup->numlevels] = Z_StrDup(tmp); + cup->cachedlevels[cup->numlevels] = NEXTMAP_INVALID; cup->numlevels++; } while((tmp = strtok(NULL,",")) != NULL); } else if (fastcmp(word, "BONUSGAME")) { - cup->bonusgame = Z_StrDup(word2); + cup->levellist[CUPCACHE_BONUS] = Z_StrDup(word2); } else if (fastcmp(word, "SPECIALSTAGE")) { - cup->specialstage = Z_StrDup(word2); + cup->levellist[CUPCACHE_SPECIAL] = Z_StrDup(word2); } else if (fastcmp(word, "EMERALDNUM")) { diff --git a/src/doomstat.h b/src/doomstat.h index 807aec2d6..0ed88b1aa 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -207,7 +207,6 @@ extern boolean splitscreen_partied[MAXPLAYERS]; // Maps of special importance extern INT16 spstage_start, spmarathon_start; -extern INT16 sstage_start, sstage_end, smpstage_start, smpstage_end; extern char * titlemap; extern boolean hidetitlepics; @@ -221,8 +220,6 @@ extern boolean looptitle; // CTF colors. extern UINT16 skincolor_redteam, skincolor_blueteam, skincolor_redring, skincolor_bluering; -extern tic_t countdowntimer; -extern boolean countdowntimeup; extern boolean exitfadestarted; typedef struct @@ -313,8 +310,6 @@ extern textprompt_t *textprompts[MAX_PROMPTS]; extern INT16 nextmapoverride; extern UINT8 skipstats; -extern UINT32 ssspheres; // Total # of spheres in a level - // Fun extra stuff extern INT16 lastmap; // Last level you were at (returning from special stages). extern mobj_t *redflag, *blueflag; // Pointers to physical flags @@ -340,91 +335,108 @@ extern struct quake } quake; // Custom Lua values -// (This is not ifdeffed so the map header structure can stay identical, just in case.) typedef struct { char option[32]; // 31 usable characters char value[256]; // 255 usable characters. If this seriously isn't enough then wtf. } customoption_t; +// This could support more, but is that a good idea? +// Keep in mind that it may encourage people making overly long cups just because they "can", and would be a waste of memory. +#define MAXLEVELLIST 5 +#define CUPCACHE_BONUS MAXLEVELLIST +#define CUPCACHE_SPECIAL MAXLEVELLIST+1 +#define CUPCACHE_MAX CUPCACHE_SPECIAL+1 + +typedef struct cupheader_s +{ + UINT16 id; ///< Cup ID + char name[15]; ///< Cup title (14 chars) + char icon[9]; ///< Name of the icon patch + char *levellist[CUPCACHE_MAX]; ///< List of levels that belong to this cup + INT16 cachedlevels[CUPCACHE_MAX]; ///< IDs in levellist, bonusgame, and specialstage + UINT8 numlevels; ///< Number of levels defined in levellist + UINT8 emeraldnum; ///< ID of Emerald to use for special stage (1-7 for Chaos Emeralds, 8-14 for Super Emeralds, 0 for no emerald) + SINT8 unlockrequired; ///< An unlockable is required to select this cup. -1 for no unlocking required. + struct cupheader_s *next; ///< Next cup in linked list +} cupheader_t; + +extern cupheader_t *kartcupheaders; // Start of cup linked list +extern UINT16 numkartcupheaders; + /** Map header information. */ typedef struct { - char * lumpname; ///< Lump name can be really long - lumpnum_t lumpnum; ///< Lump number for the map, used by vres_GetMap + // Core game information, not user-modifiable directly + char *lumpname; ///< Lump name can be really long + lumpnum_t lumpnum; ///< Lump number for the map, used by vres_GetMap - void * thumbnailPic; ///< Lump data for the level select thumbnail. - void * minimapPic; ///< Lump data for the minimap graphic. - void * encoreLump; ///< Lump data for the Encore Mode remap. - void * tweakLump; ///< Lump data for the palette tweak remap. + void *thumbnailPic; ///< Lump data for the level select thumbnail. + void *minimapPic; ///< Lump data for the minimap graphic. + void *encoreLump; ///< Lump data for the Encore Mode remap. + void *tweakLump; ///< Lump data for the palette tweak remap. + UINT8 mapvisited; ///< A set of flags that says what we've done in the map. + recorddata_t *mainrecord; ///< Stores best time attack data + + cupheader_t *cup; ///< Cached cup + + // Titlecard information char lvlttl[22]; ///< Level name without "Zone". (21 character limit instead of 32, 21 characters can display on screen max anyway) char subttl[33]; ///< Subtitle for level char zonttl[22]; ///< "ZONE" replacement name UINT8 actnum; ///< Act number or 0 for none. - UINT32 typeoflevel; ///< Combination of typeoflevel flags. - + // Selection metadata char keywords[33]; ///< Keywords separated by space to search for. 32 characters. + SINT8 unlockrequired; ///< Is an unlockable required to play this level? -1 if no. + UINT8 levelselect; ///< Is this map available in the level select? If so, which map list is it available in? + UINT16 menuflags; ///< LF2_flags: options that affect record attack menus + + // Operational metadata + UINT16 levelflags; ///< LF_flags: merged booleans into one UINT16 for space, see below + UINT32 typeoflevel; ///< Combination of typeoflevel flags. + UINT8 numlaps; ///< Number of laps in circuit mode, unless overridden. + fixed_t gravity; ///< Map-wide gravity. + + // Music information char musname[7]; ///< Music track to play. "" for no music. UINT16 mustrack; ///< Subsong to play. Only really relevant for music modules and specific formats supported by GME. 0 to ignore. UINT32 muspos; ///< Music position to jump to. - char forcecharacter[17]; ///< (SKINNAMESIZE+1) Skin to switch to or "" to disable. - - UINT8 weather; ///< 0 = sunny day, 1 = storm, 2 = snow, 3 = rain, 4 = blank, 5 = thunder w/o rain, 6 = rain w/o lightning, 7 = heat wave. + // Sky information + UINT8 weather; ///< See preciptype_t char skytexture[9]; ///< Sky texture to use. INT16 skybox_scalex; ///< Skybox X axis scale. (0 = no movement, 1 = 1:1 movement, 16 = 16:1 slow movement, -4 = 1:4 fast movement, etc.) INT16 skybox_scaley; ///< Skybox Y axis scale. INT16 skybox_scalez; ///< Skybox Z axis scale. - // Extra information. - char interscreen[8]; ///< 320x200 patch to display at intermission. - - char runsoc[33]; ///< SOC to execute at start of level (32 character limit instead of 63) - char scriptname[33]; ///< Script to use when the map is switched to. (32 character limit instead of 191) - - UINT8 precutscenenum; ///< Cutscene number to play BEFORE a level starts. - UINT8 cutscenenum; ///< Cutscene number to use, 0 for none. - - INT16 countdown; ///< Countdown until level end? + // Distance information + fixed_t mobj_scale; ///< Defines the size all object calculations are relative to + fixed_t default_waypoint_radius; ///< 0 is a special value for DEFAULT_WAYPOINT_RADIUS, but scaled with mobjscale + // Visual information UINT16 palette; ///< PAL lump to use on this map UINT16 encorepal; ///< PAL for encore mode + UINT8 light_contrast; ///< Range of wall lighting. 0 is no lighting. + boolean use_light_angle; ///< When false, wall lighting is evenly distributed. When true, wall lighting is directional. + angle_t light_angle; ///< Angle of directional wall lighting. - UINT8 numlaps; ///< Number of laps in circuit mode, unless overridden. - - SINT8 unlockrequired; ///< Is an unlockable required to play this level? -1 if no. - UINT8 levelselect; ///< Is this map available in the level select? If so, which map list is it available in? - - UINT16 levelflags; ///< LF_flags: merged booleans into one UINT16 for space, see below - UINT16 menuflags; ///< LF2_flags: options that affect record attack / nights mode menus - - UINT16 startrings; ///< Number of rings players start with. - INT32 sstimer; ///< Timer for special stages. - UINT32 ssspheres; ///< Sphere requirement in special stages. - fixed_t gravity; ///< Map-wide gravity. - - // Freed animals stuff. + // Freed animal information UINT8 numFlickies; ///< Internal. For freed flicky support. mobjtype_t *flickies; ///< List of freeable flickies in this level. Allocated dynamically for space reasons. Be careful. - UINT8 light_contrast; ///< Range of wall lighting. 0 is no lighting. - boolean use_light_angle; ///< When false, wall lighting is evenly distributed. When true, wall lighting is directional. - angle_t light_angle; ///< Angle of directional wall lighting. + // Script information + char runsoc[33]; ///< SOC to execute at start of level (32 character limit instead of 63) + char scriptname[33]; ///< Script to use when the map is switched to. (32 character limit instead of 191) - // SRB2kart - fixed_t mobj_scale; ///< Replacement for TOL_ERZ3 - fixed_t default_waypoint_radius; ///< 0 is a special value for DEFAULT_WAYPOINT_RADIUS, but scaled with mobjscale + // Cutscene information + UINT8 precutscenenum; ///< Cutscene number to play BEFORE a level starts. + UINT8 cutscenenum; ///< Cutscene number to use, 0 for none. - // Record data (modified liberally, saved to gamedata) - UINT8 mapvisited; ///< A set of flags that says what we've done in the map. - recorddata_t *mainrecord; ///< Stores best time attack data - - // Lua stuff. - // (This is not ifdeffed so the map header structure can stay identical, just in case.) + // Lua information UINT8 numCustomOptions; ///< Internal. For Lua custom value support. customoption_t *customopts; ///< Custom options. Allocated dynamically for space reasons. Be careful. } mapheader_t; @@ -443,27 +455,6 @@ typedef struct extern mapheader_t** mapheaderinfo; extern INT32 nummapheaders, mapallocsize; -// This could support more, but is that a good idea? -// Keep in mind that it may encourage people making overly long cups just because they "can", and would be a waste of memory. -#define MAXLEVELLIST 5 - -typedef struct cupheader_s -{ - UINT16 id; ///< Cup ID - char name[15]; ///< Cup title (14 chars) - char icon[9]; ///< Name of the icon patch - char *levellist[MAXLEVELLIST]; ///< List of levels that belong to this cup - UINT8 numlevels; ///< Number of levels defined in levellist - char *bonusgame; ///< Map name to use for bonus game - char *specialstage; ///< Map name to use for special stage - UINT8 emeraldnum; ///< ID of Emerald to use for special stage (1-7 for Chaos Emeralds, 8-14 for Super Emeralds, 0 for no emerald) - SINT8 unlockrequired; ///< An unlockable is required to select this cup. -1 for no unlocking required. - struct cupheader_s *next; ///< Next cup in linked list -} cupheader_t; - -extern cupheader_t *kartcupheaders; // Start of cup linked list -extern UINT16 numkartcupheaders; - // Gametypes #define NUMGAMETYPEFREESLOTS 128 @@ -588,7 +579,6 @@ extern UINT32 token; ///< Number of tokens collected in a level extern UINT32 tokenlist; ///< List of tokens collected extern boolean gottoken; ///< Did you get a token? Used for end of act extern INT32 tokenbits; ///< Used for setting token bits -extern INT32 sstimer; ///< Time allotted in the special stage extern UINT32 bluescore; ///< Blue Team Scores extern UINT32 redscore; ///< Red Team Scores diff --git a/src/g_game.c b/src/g_game.c index 21e30df41..7d75245e1 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -151,12 +151,10 @@ INT32 g_localplayers[MAXSPLITSCREENPLAYERS]; tic_t gametic; tic_t levelstarttic; // gametic at level start -UINT32 ssspheres; // old special stage INT16 lastmap; // last level you were at (returning from special stages) tic_t timeinmap; // Ticker for time spent in level (used for levelcard display) INT16 spstage_start, spmarathon_start; -INT16 sstage_start, sstage_end, smpstage_start, smpstage_end; char * titlemap = NULL; boolean hidetitlepics = false; @@ -172,8 +170,6 @@ UINT16 skincolor_blueteam = SKINCOLOR_BLUE; UINT16 skincolor_redring = SKINCOLOR_RASPBERRY; UINT16 skincolor_bluering = SKINCOLOR_PERIWINKLE; -tic_t countdowntimer = 0; -boolean countdowntimeup = false; boolean exitfadestarted = false; cutscene_t *cutscenes[128]; @@ -212,9 +208,6 @@ UINT32 tokenlist; // List of tokens collected boolean gottoken; // Did you get a token? Used for end of act INT32 tokenbits; // Used for setting token bits -// Old Special Stage -INT32 sstimer; // Time allotted in the special stage - tic_t totalplaytime; UINT32 matchesplayed; // SRB2Kart boolean gamedataloaded = false; @@ -673,13 +666,13 @@ INT32 G_MapNumber(const char * name) for (map = 0; map < nummapheaders; ++map) { - if (strcasecmp(mapheaderinfo[map]->lumpname, name) == 0) - { - break; - } + if (strcasecmp(mapheaderinfo[map]->lumpname, name) != 0) + continue; + + return map; } - return map; + return NEXTMAP_INVALID; } #ifdef NEXTMAPINSOC @@ -3201,18 +3194,15 @@ INT32 G_GetGametypeByName(const char *gametypestr) // boolean G_IsSpecialStage(INT32 mapnum) { -#if 1 - (void)mapnum; -#else - if (modeattacking == ATTACKING_TIME) - return false; - if (mapnum >= sstage_start && mapnum <= sstage_end) - return true; - if (mapnum >= smpstage_start && mapnum <= smpstage_end) - return true; -#endif + mapnum--; // gamemap-based to 0 indexed - return false; + if (mapnum > nummapheaders || !mapheaderinfo[mapnum]) + return false; + + if (!mapheaderinfo[mapnum]->cup || mapheaderinfo[mapnum]->cup->cachedlevels[CUPCACHE_SPECIAL] != mapnum) + return false; + + return true; } // @@ -3386,11 +3376,11 @@ UINT32 G_TOLFlag(INT32 pgametype) INT16 G_GetFirstMapOfGametype(UINT8 pgametype) { - INT16 mapnum = nummapheaders; + INT16 mapnum = NEXTMAP_INVALID; if ((gametypedefaultrules[pgametype] & GTR_CAMPAIGN) && kartcupheaders) { - mapnum = G_MapNumber(kartcupheaders->levellist[0]); + mapnum = kartcupheaders->cachedlevels[0]; } if (mapnum >= nummapheaders) @@ -3699,7 +3689,7 @@ static void G_GetNextMap(void) else { // Proceed to next map - const INT32 cupLevelNum = G_MapNumber(grandprixinfo.cup->levellist[grandprixinfo.roundnum]); + const INT32 cupLevelNum =grandprixinfo.cup->cachedlevels[grandprixinfo.roundnum]; if (cupLevelNum < nummapheaders && mapheaderinfo[cupLevelNum]) { @@ -3725,19 +3715,14 @@ static void G_GetNextMap(void) if (gametyperules & GTR_CAMPAIGN) { register INT16 cm; - cupheader_t *cup = kartcupheaders; + cupheader_t *cup = mapheaderinfo[gamemap-1]->cup; UINT8 gettingresult = 0; - // While this can't produce an infinite loop IN THE ITERATION, it - // is technically possible for you to keep cycling inside a lousy - // cul-de-sac of the same maps over and over while marathonning - // them all, if the same map is present in the cup list multiple - // times. There is no good solution. Don't dupe maps between cups! while (cup) { for (i = 0; i < cup->numlevels; i++) { - cm = G_MapNumber(cup->levellist[i]); + cm = cup->cachedlevels[i]; // Not valid? if (cm >= nummapheaders @@ -3829,9 +3814,7 @@ static void G_GetNextMap(void) } // We are committed to this map now. - // We may as well allocate its header if it doesn't exist - // (That is, if it's a real map) - if (nextmap < NEXTMAP_SPECIAL && (nextmap >= nummapheaders || !mapheaderinfo[nextmap] || mapheaderinfo[nextmap]->lumpnum == LUMPERROR)) + if (nextmap == NEXTMAP_INVALID || (nextmap < NEXTMAP_SPECIAL && (nextmap >= nummapheaders || !mapheaderinfo[nextmap] || mapheaderinfo[nextmap]->lumpnum == LUMPERROR))) I_Error("G_GetNextMap: Internal map ID %d not found (nummapheaders = %d)\n", nextmap, nummapheaders); } @@ -4135,11 +4118,6 @@ void G_LoadGameSettings(void) { // defaults spstage_start = spmarathon_start = 1; - sstage_start = 50; - sstage_end = 56; // 7 special stages in vanilla SRB2 - sstage_end++; // plus one weirdo - smpstage_start = 60; - smpstage_end = 66; // 7 multiplayer special stages too // initialize free sfx slots for skin sounds S_InitRuntimeSounds(); diff --git a/src/g_game.h b/src/g_game.h index 3cc0963cf..fbd423963 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -44,7 +44,8 @@ typedef enum NEXTMAP_EVALUATION = INT16_MAX-2, NEXTMAP_CREDITS = INT16_MAX-3, NEXTMAP_CEREMONY = INT16_MAX-4, - NEXTMAP_SPECIAL = NEXTMAP_CEREMONY + NEXTMAP_INVALID = INT16_MAX-5, // Always last (swap with NEXTMAP_RESERVED when removing that) + NEXTMAP_SPECIAL = NEXTMAP_INVALID } nextmapspecial_t; extern INT32 gameovertics; diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 598ad9b48..cd5fcbaf1 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -1846,7 +1846,7 @@ static void M_DrawCupPreview(INT16 y, cupheader_t *cup) i = (cupgrid.previewanim / 82) % cup->numlevels; while (x < BASEVIDWIDTH + pad) { - INT32 cupLevelNum = G_MapNumber(cup->levellist[i]); + INT32 cupLevelNum = cup->cachedlevels[i]; patch_t *PictureOfLevel = NULL; if (cupLevelNum < nummapheaders && mapheaderinfo[cupLevelNum]) diff --git a/src/k_menufunc.c b/src/k_menufunc.c index c119cfe7d..0fad3451a 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -3207,23 +3207,10 @@ boolean M_CanShowLevelInList(INT16 mapnum, UINT8 gt) if (levellist.timeattack && (mapheaderinfo[mapnum]->menuflags & LF2_NOTIMEATTACK)) return false; - if (gametypedefaultrules[gt] & GTR_CAMPAIGN) + if (gametypedefaultrules[gt] & GTR_CAMPAIGN && levellist.selectedcup) { - if (levellist.selectedcup && levellist.selectedcup->numlevels) - { - UINT8 i; - - for (i = 0; i < levellist.selectedcup->numlevels; i++) - { - const INT32 cupLevelNum = G_MapNumber(levellist.selectedcup->levellist[i]); - - if (mapnum == cupLevelNum) - break; - } - - if (i == levellist.selectedcup->numlevels) - return false; - } + if (mapheaderinfo[mapnum]->cup != levellist.selectedcup) + return false; } // Survived our checks. @@ -3413,7 +3400,9 @@ void M_CupSelectHandler(INT32 choice) { M_SetMenuDelay(pid); - if ((!newcup) || (newcup && newcup->unlockrequired != -1 && !unlockables[newcup->unlockrequired].unlocked)) + if ((!newcup) + || (newcup && newcup->unlockrequired != -1 && !unlockables[newcup->unlockrequired].unlocked) + || (newcup->cachedlevels[0] == NEXTMAP_INVALID)) { S_StartSound(NULL, sfx_s3kb2); return; @@ -3465,7 +3454,7 @@ void M_CupSelectHandler(INT32 choice) netgame = levellist.netgame; // ^ ditto. } - levelNum = G_MapNumber(grandprixinfo.cup->levellist[0]); + levelNum = grandprixinfo.cup->cachedlevels[0]; D_MapChange( levelNum + 1, diff --git a/src/lua_maplib.c b/src/lua_maplib.c index b1bc68236..16e26069f 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -2116,7 +2116,6 @@ static int mapheaderinfo_get(lua_State *L) { mapheader_t *header = *((mapheader_t **)luaL_checkudata(L, 1, META_MAPHEADER)); const char *field = luaL_checkstring(L, 2); - INT16 i; if (fastcmp(field,"lvlttl")) lua_pushstring(L, header->lvlttl); else if (fastcmp(field,"subttl")) @@ -2135,8 +2134,6 @@ static int mapheaderinfo_get(lua_State *L) lua_pushinteger(L, header->mustrack); else if (fastcmp(field,"muspos")) lua_pushinteger(L, header->muspos); - else if (fastcmp(field,"forcecharacter")) - lua_pushstring(L, header->forcecharacter); else if (fastcmp(field,"weather")) lua_pushinteger(L, header->weather); else if (fastcmp(field,"skytexture")) @@ -2147,12 +2144,7 @@ static int mapheaderinfo_get(lua_State *L) lua_pushinteger(L, header->skybox_scaley); else if (fastcmp(field,"skybox_scalez")) lua_pushinteger(L, header->skybox_scalez); - else if (fastcmp(field,"interscreen")) { - for (i = 0; i < 8; i++) - if (!header->interscreen[i]) - break; - lua_pushlstring(L, header->interscreen, i); - } else if (fastcmp(field,"runsoc")) + else if (fastcmp(field,"runsoc")) lua_pushstring(L, header->runsoc); else if (fastcmp(field,"scriptname")) lua_pushstring(L, header->scriptname); @@ -2160,8 +2152,6 @@ static int mapheaderinfo_get(lua_State *L) lua_pushinteger(L, header->precutscenenum); else if (fastcmp(field,"cutscenenum")) lua_pushinteger(L, header->cutscenenum); - else if (fastcmp(field,"countdown")) - lua_pushinteger(L, header->countdown); else if (fastcmp(field,"palette")) lua_pushinteger(L, header->palette); else if (fastcmp(field,"numlaps")) @@ -2176,12 +2166,6 @@ static int mapheaderinfo_get(lua_State *L) lua_pushinteger(L, header->menuflags); else if (fastcmp(field,"mobj_scale")) lua_pushfixed(L, header->mobj_scale); - else if (fastcmp(field,"startrings")) - lua_pushinteger(L, header->startrings); - else if (fastcmp(field, "sstimer")) - lua_pushinteger(L, header->sstimer); - else if (fastcmp(field, "ssspheres")) - lua_pushinteger(L, header->ssspheres); else if (fastcmp(field, "gravity")) lua_pushfixed(L, header->gravity); else { diff --git a/src/lua_script.c b/src/lua_script.c index 14c066bc0..33dbe9fc3 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -217,18 +217,6 @@ int LUA_PushGlobals(lua_State *L, const char *word) } else if (fastcmp(word,"spmarathon_start")) { lua_pushinteger(L, spmarathon_start); return 1; - } else if (fastcmp(word,"sstage_start")) { - lua_pushinteger(L, sstage_start); - return 1; - } else if (fastcmp(word,"sstage_end")) { - lua_pushinteger(L, sstage_end); - return 1; - } else if (fastcmp(word,"smpstage_start")) { - lua_pushinteger(L, smpstage_start); - return 1; - } else if (fastcmp(word,"smpstage_end")) { - lua_pushinteger(L, smpstage_end); - return 1; } else if (fastcmp(word,"titlemap")) { lua_pushstring(L, titlemap); return 1; diff --git a/src/p_mobj.c b/src/p_mobj.c index 28b596e2e..d2eeca805 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11281,7 +11281,7 @@ void P_SpawnPlayer(INT32 playernum) else if (p->bot) { /* - if (bonusgame || specialstage) + if (bonusgame || specialstage || boss) { // Bots should avoid p->spectator = true; diff --git a/src/p_saveg.c b/src/p_saveg.c index 5578814f4..337efd5a8 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -4476,7 +4476,6 @@ static void P_NetArchiveMisc(boolean resending) WRITEUINT8(save_p, encoremode); WRITEUINT32(save_p, leveltime); - WRITEUINT32(save_p, ssspheres); WRITEINT16(save_p, lastmap); WRITEUINT16(save_p, bossdisabled); @@ -4502,7 +4501,6 @@ static void P_NetArchiveMisc(boolean resending) } WRITEUINT32(save_p, token); - WRITEINT32(save_p, sstimer); WRITEUINT32(save_p, bluescore); WRITEUINT32(save_p, redscore); @@ -4531,9 +4529,6 @@ static void P_NetArchiveMisc(boolean resending) WRITEFIXED(save_p, gravity); WRITEFIXED(save_p, mapobjectscale); - WRITEUINT32(save_p, countdowntimer); - WRITEUINT8(save_p, countdowntimeup); - // SRB2kart WRITEINT32(save_p, numgotboxes); WRITEUINT8(save_p, numtargets); @@ -4642,7 +4637,6 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading) // get the time leveltime = READUINT32(save_p); - ssspheres = READUINT32(save_p); lastmap = READINT16(save_p); bossdisabled = READUINT16(save_p); @@ -4665,7 +4659,6 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading) } token = READUINT32(save_p); - sstimer = READINT32(save_p); bluescore = READUINT32(save_p); redscore = READUINT32(save_p); @@ -4694,9 +4687,6 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading) gravity = READFIXED(save_p); mapobjectscale = READFIXED(save_p); - countdowntimer = (tic_t)READUINT32(save_p); - countdowntimeup = (boolean)READUINT8(save_p); - // SRB2kart numgotboxes = READINT32(save_p); numtargets = READUINT8(save_p); diff --git a/src/p_setup.c b/src/p_setup.c index 0c9879370..fa4adff30 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -366,28 +366,22 @@ static void P_ClearSingleMapHeaderInfo(INT16 num) mapheaderinfo[num]->zonttl[0] = '\0'; mapheaderinfo[num]->actnum = 0; mapheaderinfo[num]->typeoflevel = 0; - mapheaderinfo[num]->startrings = 0; - mapheaderinfo[num]->sstimer = 90; - mapheaderinfo[num]->ssspheres = 1; mapheaderinfo[num]->gravity = DEFAULT_GRAVITY; mapheaderinfo[num]->keywords[0] = '\0'; - sprintf(mapheaderinfo[num]->musname, "%.5sM", G_BuildMapName(i)); + sprintf(mapheaderinfo[num]->musname, "%.5sM", G_BuildMapName(num)); mapheaderinfo[num]->musname[6] = 0; mapheaderinfo[num]->mustrack = 0; mapheaderinfo[num]->muspos = 0; - mapheaderinfo[num]->forcecharacter[0] = '\0'; mapheaderinfo[num]->weather = PRECIP_NONE; snprintf(mapheaderinfo[num]->skytexture, 5, "SKY1"); mapheaderinfo[num]->skytexture[4] = 0; mapheaderinfo[num]->skybox_scalex = 16; mapheaderinfo[num]->skybox_scaley = 16; mapheaderinfo[num]->skybox_scalez = 16; - mapheaderinfo[num]->interscreen[0] = '#'; mapheaderinfo[num]->runsoc[0] = '#'; mapheaderinfo[num]->scriptname[0] = '#'; mapheaderinfo[num]->precutscenenum = 0; mapheaderinfo[num]->cutscenenum = 0; - mapheaderinfo[num]->countdown = 0; mapheaderinfo[num]->palette = UINT16_MAX; mapheaderinfo[num]->encorepal = UINT16_MAX; mapheaderinfo[num]->numlaps = NUMLAPS_DEFAULT; @@ -461,8 +455,9 @@ void P_AllocMapHeader(INT16 i) mapheaderinfo[i]->lumpname = NULL; mapheaderinfo[i]->thumbnailPic = NULL; mapheaderinfo[i]->minimapPic = NULL; - mapheaderinfo[i]->flickies = NULL; + mapheaderinfo[i]->cup = NULL; mapheaderinfo[i]->mainrecord = NULL; + mapheaderinfo[i]->flickies = NULL; nummapheaders++; } P_ClearSingleMapHeaderInfo(i); @@ -3523,15 +3518,6 @@ static void P_InitLevelSettings(void) // emerald hunt hunt1 = hunt2 = hunt3 = NULL; - // map time limit - if (mapheaderinfo[gamemap-1]->countdown) - { - countdowntimer = mapheaderinfo[gamemap-1]->countdown * TICRATE; - } - else - countdowntimer = 0; - countdowntimeup = false; - // clear ctf pointers redflag = blueflag = NULL; rflagpoint = bflagpoint = NULL; @@ -3539,7 +3525,7 @@ static void P_InitLevelSettings(void) // circuit, race and competition stuff circuitmap = false; numstarposts = 0; - ssspheres = timeinmap = 0; + timeinmap = 0; // special stage stagefailed = true; // assume failed unless proven otherwise - P_GiveEmerald or emerald touchspecial @@ -3683,43 +3669,6 @@ static void P_RunLevelScript(const char *scriptname) COM_BufExecute(); // Run it! } -static void P_ForceCharacter(const char *forcecharskin) -{ - UINT8 i; - - if (netgame) - { - char skincmd[33]; - - for (i = 0; i <= splitscreen; i++) - { - const char *num = ""; - - if (i > 0) - num = va("%d", i+1); - - sprintf(skincmd, "skin%s %s\n", num, forcecharskin); - CV_Set(&cv_skin[i], forcecharskin); - } - - COM_BufAddText(skincmd); - } - else - { - for (i = 0; i <= splitscreen; i++) - { - SetPlayerSkin(g_localplayers[i], forcecharskin); - - // normal player colors in single player - if ((unsigned)cv_playercolor[i].value != skins[players[g_localplayers[i]].skin].prefcolor && !modeattacking) - { - CV_StealthSetValue(&cv_playercolor[i], skins[players[g_localplayers[i]].skin].prefcolor); - players[g_localplayers[i]].skincolor = skins[players[g_localplayers[i]].skin].prefcolor; - } - } - } -} - static void P_ResetSpawnpoints(void) { UINT8 i; @@ -3991,9 +3940,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) for (i = 0; i <= r_splitscreen; i++) postimgtype[i] = postimg_none; - if (mapheaderinfo[gamemap-1]->forcecharacter[0] != '\0') - P_ForceCharacter(mapheaderinfo[gamemap-1]->forcecharacter); - // Initial height of PointOfView // will be set by player think. players[consoleplayer].viewz = 1; @@ -4566,6 +4512,37 @@ UINT8 P_InitMapData(INT32 numexistingmapheaders) } vres_Free(virtmap); + + // Now associate it with a cup cache. + // (The core assumption is that cups < headers.) + if (i >= numexistingmapheaders) + { + cupheader_t *cup = kartcupheaders; + INT32 j; + while (cup) + { + for (j = 0; j < CUPCACHE_MAX; j++) + { + // Already discovered? + if (cup->cachedlevels[j] != NEXTMAP_INVALID) + continue; + + if (!cup->levellist[j] || strcasecmp(cup->levellist[j], name) != 0) + continue; + + // Only panic about back-reference for non-bonus material. + if (j < MAXLEVELLIST || j == CUPCACHE_SPECIAL) + { + if (mapheaderinfo[i]->cup) + I_Error("P_InitMapData: Map %s cannot appear in cups multiple times! (First in %s, now in %s)", name, mapheaderinfo[i]->cup->name, cup->name); + mapheaderinfo[i]->cup = cup; + } + + cup->cachedlevels[j] = i; + } + cup = cup->next; + } + } } } diff --git a/src/p_spec.c b/src/p_spec.c index e0ea77c63..859b35fe1 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -5931,10 +5931,6 @@ void P_InitSpecials(void) maplighting.directional = mapheaderinfo[gamemap-1]->use_light_angle; maplighting.angle = mapheaderinfo[gamemap-1]->light_angle; - // Defaults in case levels don't have them set. - sstimer = mapheaderinfo[gamemap-1]->sstimer*TICRATE + 6; - ssspheres = mapheaderinfo[gamemap-1]->ssspheres; - CheckForBustableBlocks = CheckForBouncySector = CheckForQuicksand = CheckForMarioBlocks = CheckForFloatBob = CheckForReverseGravity = false; // Set weather @@ -6026,11 +6022,6 @@ void P_SpawnSpecials(boolean fromnetsave) // Process Section 2 switch(GETSECSPECIAL(sector->special, 2)) { - case 10: // Time for special stage - sstimer = (sector->floorheight>>FRACBITS) * TICRATE + 6; // Time to finish - ssspheres = sector->ceilingheight>>FRACBITS; // Ring count for special stage - break; - case 11: // Custom global gravity! gravity = sector->floorheight/1000; break; diff --git a/src/p_user.c b/src/p_user.c index 1185c2033..53014038f 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -300,11 +300,15 @@ boolean P_PlayerMoving(INT32 pnum) // UINT8 P_GetNextEmerald(void) { - if (gamemap >= sstage_start && gamemap <= sstage_end) - return (UINT8)(gamemap - sstage_start); - if (gamemap >= smpstage_start || gamemap <= smpstage_end) - return (UINT8)(gamemap - smpstage_start); - return 0; + INT16 mapnum = gamemap-1; + + if (mapnum > nummapheaders || !mapheaderinfo[mapnum]) + return 0; + + if (!mapheaderinfo[mapnum]->cup || mapheaderinfo[mapnum]->cup->cachedlevels[CUPCACHE_SPECIAL] != mapnum) + return 0; + + return mapheaderinfo[mapnum]->cup->emeraldnum; } // @@ -2144,9 +2148,6 @@ void P_MovePlayer(player_t *player) fixed_t runspd; - if (countdowntimeup) - return; - cmd = &player->cmd; runspd = 14*player->mo->scale; //srb2kart diff --git a/src/r_skins.c b/src/r_skins.c index ae5e0363c..f8410c15f 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -191,12 +191,6 @@ boolean R_SkinUsable(INT32 playernum, INT32 skinnum) return true; } - if (Playing() && (R_SkinAvailable(mapheaderinfo[gamemap-1]->forcecharacter) == skinnum)) - { - // Being forced to play as this character by the level - return true; - } - if (netgame && (cv_forceskin.value == skinnum)) { // Being forced to play as this character by the server