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.
This commit is contained in:
toaster 2022-09-18 20:00:28 +01:00 committed by GenericHeroGuy
parent 4b12f8a729
commit 88ae398eea
13 changed files with 237 additions and 439 deletions

View file

@ -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;

View file

@ -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++)

View file

@ -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);

View file

@ -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)

View file

@ -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[];

View file

@ -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];

View file

@ -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();

View file

@ -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. */

View file

@ -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);

View file

@ -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!)

View file

@ -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
//

View file

@ -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"

View file

@ -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)
{