Merge branch 'master' into projectile-sanity

This commit is contained in:
Sally Coolatta 2022-09-25 13:25:55 -04:00
commit 928d9116da
53 changed files with 2103 additions and 3439 deletions

File diff suppressed because it is too large Load diff

View file

@ -2085,42 +2085,6 @@ void CV_AddValue(consvar_t *var, INT32 increment)
if (var->PossibleValue)
{
/*
if (var == &cv_nextmap)
{
// Special case for the nextmap variable, used only directly from the menu
INT32 oldvalue = var->value - 1, gt;
gt = cv_newgametype.value;
{
newvalue = var->value - 1;
do
{
if(increment > 0) // Going up!
{
if (++newvalue == NUMMAPS)
newvalue = -1;
}
else // Going down!
{
if (--newvalue == -2)
newvalue = NUMMAPS-1;
}
if (newvalue == oldvalue)
break; // don't loop forever if there's none of a certain gametype
if(!mapheaderinfo[newvalue])
continue; // Don't allocate the header. That just makes memory usage skyrocket.
} while (!M_CanShowLevelInList(newvalue, gt));
var->value = newvalue + 1;
var->func();
return;
}
}
else
*/
#define MINVAL 0
#define MAXVAL 1
if (var->PossibleValue[MINVAL].strvalue && !strcmp(var->PossibleValue[MINVAL].strvalue, "MIN"))

View file

@ -933,7 +933,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);

View file

@ -279,7 +279,6 @@ typedef struct
tic_t time;
tic_t leveltime;
char servername[MAXSERVERNAME];
char mapname[8];
char maptitle[33];
unsigned char mapmd5[16];
UINT8 actnum;

View file

@ -353,7 +353,7 @@ static void D_Display(void)
if (gamestate != GS_LEVEL && rendermode != render_none)
{
V_SetPaletteLump("PLAYPAL"); // Reset the palette
R_ReInitColormaps(0, LUMPERROR);
R_ReInitColormaps(0, NULL, 0);
}
F_WipeStartScreen();
@ -939,20 +939,16 @@ void D_StartTitle(void)
if (netgame)
{
if (gametyperules & GTR_CAMPAIGN)
G_SetGamestate(GS_WAITINGPLAYERS); // hack to prevent a command repeat
if (server)
{
G_SetGamestate(GS_WAITINGPLAYERS); // hack to prevent a command repeat
i = G_GetFirstMapOfGametype(gametype)+1;
if (server)
{
char mapname[6];
if (i > nummapheaders)
I_Error("D_StartTitle: No valid map ID found!?");
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(i)));
}
return;
@ -1196,13 +1192,10 @@ D_ConvertVersionNumbers (void)
//
void D_SRB2Main(void)
{
INT32 i;
UINT16 wadnum;
lumpinfo_t *lumpinfo;
char *name;
INT32 p;
INT32 numbasemapheaders;
INT32 pstartmap = 1;
boolean autostart = false;
@ -1445,31 +1438,16 @@ void D_SRB2Main(void)
#endif //ifndef DEVELOP
//
// 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;
// Do it before P_InitMapData because PNG patch
// conversion sometimes needs the palette
V_ReloadPalette();
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]);
//
// search for mainwad maps
//
P_InitMapData(0);
// we want to record whether this map exists. if it doesn't have a header, we can assume it's not relephant
if (num <= NUMMAPS && mapheaderinfo[num - 1])
{
mapheaderinfo[num - 1]->alreadyExists = true;
}
}
}
}
numbasemapheaders = nummapheaders;
CON_SetLoadingProgress(LOADED_IWAD);
@ -1478,37 +1456,9 @@ void D_SRB2Main(void)
D_CleanFile(startuppwads);
//
// search for maps... again.
// search for pwad maps
//
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)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;
}
CONS_Printf("%s\n", name);
}
}
}
P_InitMapData(numbasemapheaders);
CON_SetLoadingProgress(LOADED_PWAD);
@ -1765,14 +1715,14 @@ void D_SRB2Main(void)
// rei/miru: bootmap (Idea: starts the game on a predefined map)
if (bootmap && !(M_CheckParm("-warp") && M_IsNextParm()))
{
pstartmap = bootmap;
pstartmap = G_MapNumber(bootmap)+1;
if (pstartmap < 1 || pstartmap > NUMMAPS)
I_Error("Cannot warp to map %d (out of range)\n", pstartmap);
else
if (pstartmap > nummapheaders)
{
autostart = true;
I_Error("Cannot warp to map %s (not found)\n", bootmap);
}
autostart = true;
}
// Has to be done before anything else so skin, color, etc in command buffer has an affect.
@ -1869,14 +1819,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
{

View file

@ -911,9 +911,9 @@ static void DebugPrintpacket(const char *header)
netbuffer->u.servercfg.modifiedgame);
break;
case PT_SERVERINFO:
fprintf(debugfile, " '%s' player %d/%d, map %s, filenum %d, time %u \n",
fprintf(debugfile, " '%s' player %d/%d, filenum %d, time %u \n",
netbuffer->u.serverinfo.servername, netbuffer->u.serverinfo.numberofplayer,
netbuffer->u.serverinfo.maxplayer, netbuffer->u.serverinfo.mapname,
netbuffer->u.serverinfo.maxplayer,
netbuffer->u.serverinfo.fileneedednum,
(UINT32)LONG(netbuffer->u.serverinfo.time));
fprintfstringnewline((char *)netbuffer->u.serverinfo.fileneeded,

View file

@ -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.
@ -2510,8 +2510,7 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pencoremode, boolean r
if (delay != 2)
{
UINT8 flags = 0;
const char *mapname = G_BuildMapName(mapnum);
I_Assert(W_CheckNumForName(mapname) != LUMPERROR);
//I_Assert(W_CheckNumForName(G_BuildMapName(mapnum)) != LUMPERROR);
buf_p = buf;
if (pencoremode)
flags |= 1;
@ -2526,7 +2525,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)
@ -2969,11 +2968,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;
@ -3010,7 +3009,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));
@ -3018,7 +3017,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"));
}
@ -3034,7 +3033,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)
@ -5255,8 +5254,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)
@ -5276,10 +5276,15 @@ 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;
}
// If third entry has an illelegal Encore flag... (illelegal!?)
@ -5290,12 +5295,14 @@ static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum)
// Apply it to the second entry instead, gametype permitting!
if (gametypedefaultrules[gt] & GTR_CIRCUIT)
{
votelevels[1][1] |= VOTEMODIFIER_ENCORE;
tempvotelevels[1][1] |= VOTEMODIFIER_ENCORE;
}
}
// Finally, set third entry's gametype/Encore status.
votelevels[2][1] = secondgt;
tempvotelevels[2][1] = secondgt;
memcpy(votelevels, tempvotelevels, sizeof(votelevels));
G_SetGamestate(GS_VOTING);
Y_StartVote();

View file

@ -24,6 +24,7 @@
#include "dehacked.h"
#include "deh_lua.h"
#include "deh_tables.h"
#include "deh_soc.h" // freeslotusage
// freeslot takes a name (string only!)
// and allocates it to the appropriate free slot.
@ -474,18 +475,6 @@ static inline int lib_getenum(lua_State *L)
}
return luaL_error(L, "skincolor '%s' could not be found.\n", word);
}
else if (fastncmp("GRADE_",word,6))
{
p = word+6;
for (i = 0; NIGHTSGRADE_LIST[i]; i++)
if (*p == NIGHTSGRADE_LIST[i])
{
lua_pushinteger(L, i);
return 1;
}
if (mathlib) return luaL_error(L, "NiGHTS grade '%s' could not be found.\n", word);
return 0;
}
else if (fastncmp("PRECIP_",word,7)) {
p = word+7;
for (i = 0; i < MAXPRECIP; i++)

View file

@ -140,28 +140,50 @@ 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] || i == (tutorialmap-1))
nummapheaders--;
if (!mapheaderinfo[nummapheaders])
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);
Z_Free(mapheaderinfo[i]);
mapheaderinfo[i] = NULL;
Z_Free(mapheaderinfo[nummapheaders]->mainrecord);
Patch_Free(mapheaderinfo[nummapheaders]->thumbnailPic);
Patch_Free(mapheaderinfo[nummapheaders]->minimapPic);
Z_Free(mapheaderinfo[nummapheaders]->lumpname);
Z_Free(mapheaderinfo[nummapheaders]);
mapheaderinfo[nummapheaders] = NULL;
}
// Realloc the one for the current gamemap as a safeguard
P_AllocMapHeader(gamemap-1);
// 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
}
// TODO: Figure out how to do undolines for this....
@ -838,17 +860,33 @@ void readgametype(MYFILE *f, char *gtname)
CONS_Printf("Added gametype %s\n", Gametype_Names[newgtidx]);
}
void readlevelheader(MYFILE *f, INT32 num)
void readlevelheader(MYFILE *f, char * name)
{
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
char *word;
char *word2;
//char *word3; // Non-uppercase version of word2
char *tmp;
INT32 i;
// Reset all previous map header information
P_AllocMapHeader((INT16)(num-1));
INT32 num = G_MapNumber(name);
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);
}
if (mapheaderinfo[num]->lumpname == NULL)
{
mapheaderinfo[num]->lumpname = Z_StrDup(name);
}
do
{
@ -886,16 +924,15 @@ void readlevelheader(MYFILE *f, INT32 num)
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));
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;
}
@ -917,19 +954,19 @@ void readlevelheader(MYFILE *f, INT32 num)
}
// 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';
@ -945,33 +982,33 @@ void readlevelheader(MYFILE *f, INT32 num)
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;
@ -985,7 +1022,7 @@ void readlevelheader(MYFILE *f, INT32 num)
//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!
{
@ -998,17 +1035,17 @@ void readlevelheader(MYFILE *f, INT32 num)
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);
@ -1018,62 +1055,30 @@ void readlevelheader(MYFILE *f, INT32 num)
// Strings that can be truncated
else if (fastcmp(word, "ZONETITLE"))
{
deh_strlcpy(mapheaderinfo[num-1]->zonttl, word2,
sizeof(mapheaderinfo[num-1]->zonttl), va("Level header %d: zonetitle", num));
deh_strlcpy(mapheaderinfo[num]->zonttl, word2,
sizeof(mapheaderinfo[num]->zonttl), va("Level header %d: zonetitle", num));
}
else if (fastcmp(word, "SCRIPTNAME"))
{
deh_strlcpy(mapheaderinfo[num-1]->scriptname, word2,
sizeof(mapheaderinfo[num-1]->scriptname), va("Level header %d: scriptname", num));
deh_strlcpy(mapheaderinfo[num]->scriptname, word2,
sizeof(mapheaderinfo[num]->scriptname), va("Level header %d: scriptname", num));
}
else if (fastcmp(word, "RUNSOC"))
{
deh_strlcpy(mapheaderinfo[num-1]->runsoc, word2,
sizeof(mapheaderinfo[num-1]->runsoc), va("Level header %d: runsoc", num));
deh_strlcpy(mapheaderinfo[num]->runsoc, word2,
sizeof(mapheaderinfo[num]->runsoc), va("Level header %d: runsoc", num));
}
else if (fastcmp(word, "ACT"))
{
if (i >= 0 && i <= 99) // 0 for no act number
mapheaderinfo[num-1]->actnum = (UINT8)i;
mapheaderinfo[num]->actnum = (UINT8)i;
else
deh_warning("Level header %d: invalid act number %d", num, i);
}
else if (fastcmp(word, "NEXTLEVEL"))
{
if (fastcmp(word2, "TITLE")) i = 1100;
else if (fastcmp(word2, "EVALUATION")) i = 1101;
else if (fastcmp(word2, "CREDITS")) i = 1102;
else if (fastcmp(word2, "ENDING")) i = 1103;
else
// Support using the actual map name,
// i.e., Nextlevel = AB, Nextlevel = FZ, etc.
// Convert to map number
if (word2[0] >= 'A' && word2[0] <= 'Z' && word2[2] == '\0')
i = M_MapNumber(word2[0], word2[1]);
mapheaderinfo[num-1]->nextlevel = (INT16)i;
}
else if (fastcmp(word, "MARATHONNEXT"))
{
if (fastcmp(word2, "TITLE")) i = 1100;
else if (fastcmp(word2, "EVALUATION")) i = 1101;
else if (fastcmp(word2, "CREDITS")) i = 1102;
else if (fastcmp(word2, "ENDING")) i = 1103;
else
// Support using the actual map name,
// i.e., MarathonNext = AB, MarathonNext = FZ, etc.
// Convert to map number
if (word2[0] >= 'A' && word2[0] <= 'Z' && word2[2] == '\0')
i = M_MapNumber(word2[0], word2[1]);
mapheaderinfo[num-1]->marathonnext = (INT16)i;
}
else if (fastcmp(word, "TYPEOFLEVEL"))
{
if (i) // it's just a number
mapheaderinfo[num-1]->typeoflevel = (UINT32)i;
mapheaderinfo[num]->typeoflevel = (UINT32)i;
else
{
UINT32 tol = 0;
@ -1086,152 +1091,147 @@ void readlevelheader(MYFILE *f, INT32 num)
deh_warning("Level header %d: unknown typeoflevel flag %s\n", num, tmp);
tol |= TYPEOFLEVEL[i].flag;
} while((tmp = strtok(NULL,",")) != NULL);
mapheaderinfo[num-1]->typeoflevel = tol;
mapheaderinfo[num]->typeoflevel = tol;
}
}
else if (fastcmp(word, "KEYWORDS"))
{
deh_strlcpy(mapheaderinfo[num-1]->keywords, word2,
sizeof(mapheaderinfo[num-1]->keywords), va("Level header %d: keywords", num));
deh_strlcpy(mapheaderinfo[num]->keywords, word2,
sizeof(mapheaderinfo[num]->keywords), va("Level header %d: keywords", num));
}
else if (fastcmp(word, "MUSIC"))
{
if (fastcmp(word2, "NONE"))
mapheaderinfo[num-1]->musname[0] = 0; // becomes empty string
mapheaderinfo[num]->musname[0] = 0; // becomes empty string
else
{
deh_strlcpy(mapheaderinfo[num-1]->musname, word2,
sizeof(mapheaderinfo[num-1]->musname), va("Level header %d: music", num));
deh_strlcpy(mapheaderinfo[num]->musname, word2,
sizeof(mapheaderinfo[num]->musname), va("Level header %d: music", num));
}
}
else if (fastcmp(word, "MUSICSLOT"))
deh_warning("Level header %d: MusicSlot parameter is deprecated and will be removed.\nUse \"Music\" instead.", num);
else if (fastcmp(word, "MUSICTRACK"))
mapheaderinfo[num-1]->mustrack = ((UINT16)i - 1);
mapheaderinfo[num]->mustrack = ((UINT16)i - 1);
else if (fastcmp(word, "MUSICPOS"))
mapheaderinfo[num-1]->muspos = (UINT32)get_number(word2);
else if (fastcmp(word, "FORCECHARACTER"))
{
strlcpy(mapheaderinfo[num-1]->forcecharacter, word2, SKINNAMESIZE+1);
strlwr(mapheaderinfo[num-1]->forcecharacter); // skin names are lowercase
}
mapheaderinfo[num]->muspos = (UINT32)get_number(word2);
else if (fastcmp(word, "WEATHER"))
mapheaderinfo[num-1]->weather = get_precip(word2);
mapheaderinfo[num]->weather = get_precip(word2);
else if (fastcmp(word, "SKYTEXTURE"))
deh_strlcpy(mapheaderinfo[num-1]->skytexture, word2,
sizeof(mapheaderinfo[num-1]->skytexture), va("Level header %d: sky texture", num));
deh_strlcpy(mapheaderinfo[num]->skytexture, word2,
sizeof(mapheaderinfo[num]->skytexture), va("Level header %d: sky texture", num));
else if (fastcmp(word, "PRECUTSCENENUM"))
mapheaderinfo[num-1]->precutscenenum = (UINT8)i;
mapheaderinfo[num]->precutscenenum = (UINT8)i;
else if (fastcmp(word, "CUTSCENENUM"))
mapheaderinfo[num-1]->cutscenenum = (UINT8)i;
mapheaderinfo[num]->cutscenenum = (UINT8)i;
else if (fastcmp(word, "PALETTE"))
mapheaderinfo[num-1]->palette = (UINT16)i;
mapheaderinfo[num]->palette = (UINT16)i;
else if (fastcmp(word, "ENCOREPAL"))
mapheaderinfo[num-1]->encorepal = (UINT16)i;
mapheaderinfo[num]->encorepal = (UINT16)i;
else if (fastcmp(word, "NUMLAPS"))
mapheaderinfo[num-1]->numlaps = (UINT8)i;
mapheaderinfo[num]->numlaps = (UINT8)i;
else if (fastcmp(word, "UNLOCKABLE"))
{
if (i >= 0 && i <= MAXUNLOCKABLES) // 0 for no unlock required, anything else requires something
mapheaderinfo[num-1]->unlockrequired = (SINT8)i - 1;
mapheaderinfo[num]->unlockrequired = (SINT8)i - 1;
else
deh_warning("Level header %d: invalid unlockable number %d", num, i);
}
else if (fastcmp(word, "SKYBOXSCALE"))
mapheaderinfo[num-1]->skybox_scalex = mapheaderinfo[num-1]->skybox_scaley = mapheaderinfo[num-1]->skybox_scalez = (INT16)i;
mapheaderinfo[num]->skybox_scalex = mapheaderinfo[num]->skybox_scaley = mapheaderinfo[num]->skybox_scalez = (INT16)i;
else if (fastcmp(word, "SKYBOXSCALEX"))
mapheaderinfo[num-1]->skybox_scalex = (INT16)i;
mapheaderinfo[num]->skybox_scalex = (INT16)i;
else if (fastcmp(word, "SKYBOXSCALEY"))
mapheaderinfo[num-1]->skybox_scaley = (INT16)i;
mapheaderinfo[num]->skybox_scaley = (INT16)i;
else if (fastcmp(word, "SKYBOXSCALEZ"))
mapheaderinfo[num-1]->skybox_scalez = (INT16)i;
mapheaderinfo[num]->skybox_scalez = (INT16)i;
else if (fastcmp(word, "LEVELFLAGS"))
mapheaderinfo[num-1]->levelflags = get_number(word2);
mapheaderinfo[num]->levelflags = get_number(word2);
else if (fastcmp(word, "MENUFLAGS"))
mapheaderinfo[num-1]->menuflags = get_number(word2);
mapheaderinfo[num]->menuflags = get_number(word2);
// SRB2Kart
else if (fastcmp(word, "MOBJSCALE"))
mapheaderinfo[num-1]->mobj_scale = get_number(word2);
mapheaderinfo[num]->mobj_scale = get_number(word2);
else if (fastcmp(word, "DEFAULTWAYPOINTRADIUS"))
mapheaderinfo[num-1]->default_waypoint_radius = get_number(word2);
mapheaderinfo[num]->default_waypoint_radius = get_number(word2);
else if (fastcmp(word, "LIGHTCONTRAST"))
{
mapheaderinfo[num-1]->light_contrast = (UINT8)i;
mapheaderinfo[num]->light_contrast = (UINT8)i;
}
else if (fastcmp(word, "LIGHTANGLE"))
{
if (fastcmp(word2, "EVEN"))
{
mapheaderinfo[num-1]->use_light_angle = false;
mapheaderinfo[num-1]->light_angle = 0;
mapheaderinfo[num]->use_light_angle = false;
mapheaderinfo[num]->light_angle = 0;
}
else
{
mapheaderinfo[num-1]->use_light_angle = true;
mapheaderinfo[num-1]->light_angle = FixedAngle(FloatToFixed(atof(word2)));
mapheaderinfo[num]->use_light_angle = true;
mapheaderinfo[num]->light_angle = FixedAngle(FloatToFixed(atof(word2)));
}
}
// Individual triggers for level flags, for ease of use (and 2.0 compatibility)
else if (fastcmp(word, "SCRIPTISFILE"))
{
if (i || word2[0] == 'T' || word2[0] == 'Y')
mapheaderinfo[num-1]->levelflags |= LF_SCRIPTISFILE;
mapheaderinfo[num]->levelflags |= LF_SCRIPTISFILE;
else
mapheaderinfo[num-1]->levelflags &= ~LF_SCRIPTISFILE;
mapheaderinfo[num]->levelflags &= ~LF_SCRIPTISFILE;
}
else if (fastcmp(word, "NOZONE"))
{
if (i || word2[0] == 'T' || word2[0] == 'Y')
mapheaderinfo[num-1]->levelflags |= LF_NOZONE;
mapheaderinfo[num]->levelflags |= LF_NOZONE;
else
mapheaderinfo[num-1]->levelflags &= ~LF_NOZONE;
mapheaderinfo[num]->levelflags &= ~LF_NOZONE;
}
else if (fastcmp(word, "SECTIONRACE"))
{
if (i || word2[0] == 'T' || word2[0] == 'Y')
mapheaderinfo[num-1]->levelflags |= LF_SECTIONRACE;
mapheaderinfo[num]->levelflags |= LF_SECTIONRACE;
else
mapheaderinfo[num-1]->levelflags &= ~LF_SECTIONRACE;
mapheaderinfo[num]->levelflags &= ~LF_SECTIONRACE;
}
else if (fastcmp(word, "SUBTRACTNUM"))
{
if (i || word2[0] == 'T' || word2[0] == 'Y')
mapheaderinfo[num-1]->levelflags |= LF_SUBTRACTNUM;
mapheaderinfo[num]->levelflags |= LF_SUBTRACTNUM;
else
mapheaderinfo[num-1]->levelflags &= ~LF_SUBTRACTNUM;
mapheaderinfo[num]->levelflags &= ~LF_SUBTRACTNUM;
}
// Individual triggers for menu flags
else if (fastcmp(word, "HIDDEN"))
{
if (i || word2[0] == 'T' || word2[0] == 'Y')
mapheaderinfo[num-1]->menuflags |= LF2_HIDEINMENU;
mapheaderinfo[num]->menuflags |= LF2_HIDEINMENU;
else
mapheaderinfo[num-1]->menuflags &= ~LF2_HIDEINMENU;
mapheaderinfo[num]->menuflags &= ~LF2_HIDEINMENU;
}
else if (fastcmp(word, "HIDEINSTATS"))
{
if (i || word2[0] == 'T' || word2[0] == 'Y')
mapheaderinfo[num-1]->menuflags |= LF2_HIDEINSTATS;
mapheaderinfo[num]->menuflags |= LF2_HIDEINSTATS;
else
mapheaderinfo[num-1]->menuflags &= ~LF2_HIDEINSTATS;
mapheaderinfo[num]->menuflags &= ~LF2_HIDEINSTATS;
}
else if (fastcmp(word, "TIMEATTACK") || fastcmp(word, "RECORDATTACK"))
else if (fastcmp(word, "NOTIMEATTACK") || fastcmp(word, "NORECORDATTACK"))
{ // RECORDATTACK is an accepted alias
if (i || word2[0] == 'T' || word2[0] == 'Y')
mapheaderinfo[num-1]->menuflags &= ~LF2_NOTIMEATTACK;
mapheaderinfo[num]->menuflags |= LF2_NOTIMEATTACK;
else
mapheaderinfo[num-1]->menuflags |= LF2_NOTIMEATTACK;
mapheaderinfo[num]->menuflags &= ~LF2_NOTIMEATTACK;
}
else if (fastcmp(word, "VISITNEEDED"))
{
if (i || word2[0] == 'T' || word2[0] == 'Y')
mapheaderinfo[num-1]->menuflags |= LF2_VISITNEEDED;
mapheaderinfo[num]->menuflags |= LF2_VISITNEEDED;
else
mapheaderinfo[num-1]->menuflags &= ~LF2_VISITNEEDED;
mapheaderinfo[num]->menuflags &= ~LF2_VISITNEEDED;
}
else if (fastcmp(word, "GRAVITY"))
mapheaderinfo[num-1]->gravity = FLOAT_TO_FIXED(atof(word2));
mapheaderinfo[num]->gravity = FLOAT_TO_FIXED(atof(word2));
else
deh_warning("Level header %d: unknown word '%s'", num, word);
}
@ -2103,16 +2103,9 @@ 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"))
{
// Support using the actual map name,
// i.e., Level AB, Level FZ, etc.
// Convert to map number
if (word2[0] >= 'A' && word2[0] <= 'Z')
value = M_MapNumber(word2[0], word2[1]);
emblemlocations[num-1].level = (INT16)value;
emblemlocations[num-1].level = Z_StrDup(word2);
}
else if (fastcmp(word, "SPRITE"))
{
@ -2333,13 +2326,7 @@ void readunlockable(MYFILE *f, INT32 num)
}
else if (fastcmp(word, "VAR"))
{
// Support using the actual map name,
// i.e., Level AB, Level FZ, etc.
// Convert to map number
if (word2[0] >= 'A' && word2[0] <= 'Z')
i = M_MapNumber(word2[0], word2[1]);
// TODO: different field for level name string
unlockables[num].variable = (INT16)i;
}
else
@ -2378,7 +2365,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;
}
@ -2398,7 +2385,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;
}
}
@ -2418,16 +2405,11 @@ static void readcondition(UINT8 set, UINT32 id, char *word2)
{
PARAMCHECK(1);
ty = UC_MAPVISITED + offset;
re = G_MapNumber(params[1]);
// 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]);
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;
}
}
@ -2436,16 +2418,11 @@ static void readcondition(UINT8 set, UINT32 id, char *word2)
PARAMCHECK(2);
ty = UC_MAPTIME;
re = atoi(params[2]);
x1 = G_MapNumber(params[1]);
// 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]);
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;
}
}
@ -2458,7 +2435,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;
}
}
@ -2476,7 +2453,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;
}
}
@ -2488,7 +2465,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;
}
}
@ -2500,13 +2477,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;
}
@ -2641,61 +2618,6 @@ void readmaincfg(MYFILE *f)
COM_BufInsertText(W_CacheLumpNum(lumpnum, PU_CACHE));
}
}
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;
}
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;
}
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_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_end = (INT16)(smpstage_start+6); // 7 special stages total
}
else if (fastcmp(word, "REDTEAM"))
{
skincolor_redteam = (UINT16)get_number(word2);
@ -2778,16 +2700,7 @@ void readmaincfg(MYFILE *f)
}
else if (fastcmp(word, "TITLEMAP"))
{
// Support using the actual map name,
// i.e., Level AB, Level FZ, etc.
// Convert to map number
if (word2[0] >= 'A' && word2[0] <= 'Z')
value = M_MapNumber(word2[0], word2[1]);
else
value = get_number(word2);
titlemap = (INT16)value;
titlemap = Z_StrDup(word2);
titlechanged = true;
}
else if (fastcmp(word, "HIDETITLEPICS") || fastcmp(word, "TITLEPICSHIDE"))
@ -2915,30 +2828,12 @@ void readmaincfg(MYFILE *f)
}
else if (fastcmp(word, "BOOTMAP"))
{
// Support using the actual map name,
// i.e., Level AB, Level FZ, etc.
// Convert to map number
if (word2[0] >= 'A' && word2[0] <= 'Z')
value = M_MapNumber(word2[0], word2[1]);
else
value = get_number(word2);
bootmap = (INT16)value;
bootmap = Z_StrDup(word2);
//titlechanged = true;
}
else if (fastcmp(word, "TUTORIALMAP"))
{
// Support using the actual map name,
// i.e., Level AB, Level FZ, etc.
// Convert to map number
if (word2[0] >= 'A' && word2[0] <= 'Z')
value = M_MapNumber(word2[0], word2[1]);
else
value = get_number(word2);
tutorialmap = (INT16)value;
tutorialmap = Z_StrDup(word2);
}
else
deh_warning("Maincfg: unknown word '%s'", word);
@ -3161,37 +3056,24 @@ void readcupheader(MYFILE *f, cupheader_t *cup)
tmp = strtok(word2,",");
do {
INT32 map = atoi(tmp);
if (tmp[0] >= 'A' && tmp[0] <= 'Z' && tmp[2] == '\0')
map = M_MapNumber(tmp[0], tmp[1]);
if (!map)
break;
if (cup->numlevels >= MAXLEVELLIST)
{
deh_warning("%s Cup: reached max levellist (%d)\n", cup->name, MAXLEVELLIST);
break;
}
cup->levellist[cup->numlevels] = map - 1;
cup->levellist[cup->numlevels] = Z_StrDup(tmp);
cup->cachedlevels[cup->numlevels] = NEXTMAP_INVALID;
cup->numlevels++;
} while((tmp = strtok(NULL,",")) != NULL);
}
else if (fastcmp(word, "BONUSGAME"))
{
// Convert to map number
if (word2[0] >= 'A' && word2[0] <= 'Z' && word2[2] == '\0')
i = M_MapNumber(word2[0], word2[1]);
cup->bonusgame = (INT16)i - 1;
cup->levellist[CUPCACHE_BONUS] = Z_StrDup(word2);
}
else if (fastcmp(word, "SPECIALSTAGE"))
{
// Convert to map number
if (word2[0] >= 'A' && word2[0] <= 'Z' && word2[2] == '\0')
i = M_MapNumber(word2[0], word2[1]);
cup->specialstage = (INT16)i - 1;
cup->levellist[CUPCACHE_SPECIAL] = Z_StrDup(word2);
}
else if (fastcmp(word, "EMERALDNUM"))
{
@ -3902,19 +3784,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

@ -68,7 +68,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

View file

@ -32,17 +32,6 @@ char *FREE_MOBJS[NUMMOBJFREESLOTS];
char *FREE_SKINCOLORS[NUMCOLORFREESLOTS];
UINT8 used_spr[(NUMSPRITEFREESLOTS / 8) + 1]; // Bitwise flag for sprite freeslot in use! I would use ceil() here if I could, but it only saves 1 byte of memory anyway.
const char NIGHTSGRADE_LIST[] = {
'F', // GRADE_F
'E', // GRADE_E
'D', // GRADE_D
'C', // GRADE_C
'B', // GRADE_B
'A', // GRADE_A
'S', // GRADE_S
'\0'
};
struct flickytypes_s FLICKYTYPES[] = {
{"BLUEBIRD", MT_FLICKY_01}, // Flicky (Flicky)
{"RABBIT", MT_FLICKY_02}, // Pocky (1)

View file

@ -53,7 +53,6 @@ struct int_const_s {
lua_Integer v;
};
extern const char NIGHTSGRADE_LIST[];
extern struct flickytypes_s FLICKYTYPES[];
extern actionpointer_t actionpointers[]; // Array mapping action names to action functions.
extern const char *const STATE_LIST[];

View file

@ -358,25 +358,14 @@ 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);
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);
}
}

View file

@ -405,7 +405,9 @@ void DRPC_UpdatePresence(void)
{
char detailstr[48+1];
#ifdef USEMAPIMG
char mapimg[8+1];
#endif
char mapname[5+21+21+2+1];
char charimg[4+SKINNAMESIZE+1];
@ -508,14 +510,18 @@ 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));
//FIXME
//snprintf(mapimg, 8, "%s", G_BuildMapName(gamemap));
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";

View file

@ -218,8 +218,6 @@ typedef struct
#define ZSHIFT 4
#define NUMMAPS 1035
/* slope thing types */
enum
{

View file

@ -25,6 +25,9 @@
// We need the player data structure as well.
#include "d_player.h"
// For lumpnum_t.
#include "w_wad.h"
// =============================
// Selected map etc.
// =============================
@ -102,6 +105,23 @@ extern preciptype_t precip_freeslot;
extern preciptype_t globalweather;
extern preciptype_t curWeather;
/** Time attack information, currently a very small structure.
*/
typedef struct
{
tic_t time; ///< Time in which the level was finished.
tic_t lap; ///< Best lap time for this level.
//UINT32 score; ///< Score when the level was finished.
//UINT16 rings; ///< Rings when the level was finished.
} recorddata_t;
// mapvisited is now a set of flags that says what we've done in the map.
#define MV_VISITED (1)
#define MV_BEATEN (1<<1)
#define MV_ENCORE (1<<2)
#define MV_MAX (MV_VISITED|MV_BEATEN|MV_ENCORE)
#define MV_MP ((MV_MAX+1)<<1)
// Set if homebrew PWAD stuff has been added.
extern boolean modifiedgame;
extern boolean majormods;
@ -185,15 +205,11 @@ 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 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 boolean looptitle;
@ -201,8 +217,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
@ -293,8 +307,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
@ -319,106 +331,113 @@ extern struct quake
fixed_t radius, intensity;
} quake;
// NiGHTS grades
typedef struct
{
UINT32 grade[6]; // D, C, B, A, S, X (F: failed to reach any of these)
} nightsgrades_t;
// Custom Lua values
// (This is not ifdeffed so the map header structure can stay identical, just in case.)
typedef struct
{
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;
#define MAXMAPLUMPNAME 64 // includes \0, for cleaner savedata
/** Map header information.
*/
typedef struct
{
// The original eight, plus one.
char lvlttl[22]; ///< Level name without "Zone". (21 character limit instead of 32, 21 characters can display on screen max anyway)
char subttl[33]; ///< Subtitle for level
char zonttl[22]; ///< "ZONE" replacement name
UINT8 actnum; ///< Act number or 0 for none.
UINT32 typeoflevel; ///< Combination of typeoflevel flags.
INT16 nextlevel; ///< Map number of next level, or 1100-1102 to end.
INT16 marathonnext; ///< See nextlevel, but for Marathon mode. Necessary to support hub worlds ala SUGOI.
char keywords[33]; ///< Keywords separated by space to search for. 32 characters.
char musname[7]; ///< Music track to play. "" for no music.
UINT16 mustrack; ///< Subsong to play. Only really relevant for music modules and specific formats supported by GME. 0 to ignore.
UINT32 muspos; ///< Music position to jump to.
char forcecharacter[17]; ///< (SKINNAMESIZE+1) Skin to switch to or "" to disable.
UINT8 weather; ///< 0 = sunny day, 1 = storm, 2 = snow, 3 = rain, 4 = blank, 5 = thunder w/o rain, 6 = rain w/o lightning, 7 = heat wave.
char skytexture[9]; ///< Sky texture to use.
INT16 skybox_scalex; ///< Skybox X axis scale. (0 = no movement, 1 = 1:1 movement, 16 = 16:1 slow movement, -4 = 1:4 fast movement, etc.)
INT16 skybox_scaley; ///< Skybox Y axis scale.
INT16 skybox_scalez; ///< Skybox Z axis scale.
// 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
// 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.
void *encoreLump; ///< Lump data for the Encore Mode remap.
void *tweakLump; ///< Lump data for the palette tweak remap.
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
UINT8 mapvisited; ///< A set of flags that says what we've done in the map.
recorddata_t *mainrecord; ///< Stores best time attack data
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.
cupheader_t *cup; ///< Cached cup
// Title card.
char ltzzpatch[8]; ///< Zig zag patch.
char ltzztext[8]; ///< Zig zag text.
char ltactdiamond[8]; ///< Act diamond.
// 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.
// 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.
// Selection metadata
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.
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
// 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
// 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.
UINT8 light_contrast; ///< Range of wall lighting. 0 is no lighting.
boolean use_light_angle; ///< When false, wall lighting is evenly distributed. When true, wall lighting is directional.
angle_t light_angle; ///< Angle of directional wall lighting.
// Music 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.
// Music stuff.
UINT32 musinterfadeout; ///< Fade out level music on intermission screen in milliseconds
char musintername[7]; ///< Intermission screen music.
// 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.
char muspostbossname[7]; ///< Post-bossdeath music.
UINT16 muspostbosstrack; ///< Post-bossdeath track.
UINT32 muspostbosspos; ///< Post-bossdeath position
UINT32 muspostbossfadein; ///< Post-bossdeath fade-in milliseconds.
// 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
SINT8 musforcereset; ///< Force resetmusic (-1 for default; 0 for force off; 1 for force on)
// 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.
// SRB2Kart: Keeps track of if a map lump exists, so we can tell when a map is being replaced.
boolean alreadyExists;
// 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.
// 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.
// 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 information
UINT8 numCustomOptions; ///< Internal. For Lua custom value support.
customoption_t *customopts; ///< Custom options. Allocated dynamically for space reasons. Be careful.
} mapheader_t;
// level flags
@ -432,28 +451,8 @@ typedef struct
#define LF2_NOTIMEATTACK (1<<2) ///< Hide this map in Time Attack modes
#define LF2_VISITNEEDED (1<<3) ///< Not available in Time Attack modes until you visit the level
extern mapheader_t* mapheaderinfo[NUMMAPS];
// 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
INT16 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
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;
extern mapheader_t** mapheaderinfo;
extern INT32 nummapheaders, mapallocsize;
// Gametypes
#define NUMGAMETYPEFREESLOTS 128
@ -575,52 +574,10 @@ extern INT32 luabanks[NUM_LUABANKS];
extern INT32 nummaprings; //keep track of spawned rings/coins
/** Time attack information, currently a very small structure.
*/
typedef struct
{
tic_t time; ///< Time in which the level was finished.
tic_t lap; ///< Best lap time for this level.
//UINT32 score; ///< Score when the level was finished.
//UINT16 rings; ///< Rings when the level was finished.
} recorddata_t;
/** 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];
// 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
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

View file

@ -1837,6 +1837,7 @@ static void F_CacheTitleScreen(void)
void F_StartTitleScreen(void)
{
INT32 titleMapNum;
setup_numplayers = 0;
if (gamestate != GS_TITLESCREEN && gamestate != GS_WAITINGPLAYERS)
@ -1848,20 +1849,20 @@ void F_StartTitleScreen(void)
else
wipegamestate = GS_TITLESCREEN;
if (titlemap)
if (titlemap
&& ((titleMapNum = G_MapNumber(titlemap)) < nummapheaders)
&& mapheaderinfo[titleMapNum]
&& mapheaderinfo[titleMapNum]->lumpnum != LUMPERROR)
{
mapthing_t *startpos;
gamestate_t prevwipegamestate = wipegamestate;
titlemapinaction = TITLEMAP_LOADING;
titlemapcameraref = NULL;
gamemap = titlemap;
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 (!titlemap)
@ -2196,12 +2197,14 @@ void F_TitleScreenTicker(boolean run)
return;
}
#ifdef STAFFGHOSTS
// is it time?
if (!(--demoIdleLeft))
{
//static boolean use_netreplay = false;
char dname[9];
char *dname2 = dname;
lumpnum_t l;
const char *mapname;
UINT8 numstaff;
@ -2231,41 +2234,16 @@ void F_TitleScreenTicker(boolean run)
return;
}
// Replay intro when done cycling through demos
/*
if (curDemo == numDemos) -- uuuh... we have a LOT of maps AND a big devteam... probably not gonna see a repeat unless you're super unlucky :V
{
curDemo = 0;
F_StartIntro();
return;
}
*/
mapname = G_BuildMapName(G_RandMap(TOL_RACE, -2, 0, 0, false, NULL)+1);
numstaff = 1;
while (numstaff < 99 && (l = W_CheckNumForName(va("%sS%02u",mapname,numstaff+1))) != LUMPERROR)
while (numstaff < 99 && (l = W_CheckNumForLongName(va("%sS%02u",mapname,numstaff+1))) != LUMPERROR)
numstaff++;
#if 0 // turns out this isn't how we're gonna organise 'em
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);
dname2 = Z_StrDup(va("%sS%02u", mapname, numstaff));
/*if ((l = W_CheckNumForName(dname)) == LUMPERROR) -- we KNOW it exists now
{
@ -2278,8 +2256,14 @@ loadreplay:
demo.title = demo.fromtitle = true;
demo.ignorefiles = true;
demo.loadfiles = false;
G_DoPlayDemo(dname);
G_DoPlayDemo(dname2);
if (dname2 != dname)
{
Z_Free(dname2);
}
}
#endif //#ifdef STAFFGHOSTS
}
void F_TitleDemoTicker(void)
@ -2409,7 +2393,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

@ -1994,7 +1994,7 @@ void G_BeginRecording(void)
// game data
M_Memcpy(demo_p, "PLAY", 4); demo_p += 4;
WRITEINT16(demo_p,gamemap);
WRITESTRINGN(demo_p, mapheaderinfo[gamemap-1]->lumpname, MAXMAPLUMPNAME);
M_Memcpy(demo_p, mapmd5, 16); demo_p += 16;
WRITEUINT8(demo_p, demoflags);
@ -2426,7 +2426,7 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
p += 16; // demo checksum
I_Assert(!memcmp(p, "PLAY", 4));
p += 4; // PLAY
p += 2; // gamemap
SKIPSTRING(p); // gamemap
p += 16; // map md5
flags = READUINT8(p); // demoflags
p++; // gametype
@ -2484,7 +2484,7 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
Z_Free(buffer);
return UINT8_MAX;
} p += 4; // "PLAY"
p += 2; // gamemap
SKIPSTRING(p); // gamemap
p += 16; // mapmd5
flags = READUINT8(p);
p++; // gametype
@ -2703,7 +2703,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];
@ -2824,7 +2824,8 @@ void G_DoPlayDemo(char *defdemoname)
return;
}
demo_p += 4; // "PLAY"
gamemap = READINT16(demo_p);
READSTRINGN(demo_p, mapname, sizeof(mapname)); // gamemap
gamemap = G_MapNumber(mapname)+1;
demo_p += 16; // mapmd5
demoflags = READUINT8(demo_p);
@ -2918,7 +2919,7 @@ void G_DoPlayDemo(char *defdemoname)
demo_p += 4; // Extrainfo location
// ...*map* not loaded?
if (!gamemap || (gamemap > NUMMAPS) || !mapheaderinfo[gamemap-1] || !(mapheaderinfo[gamemap-1]->alreadyExists == true))
if (!gamemap || (gamemap > 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);
@ -3118,7 +3119,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++)
{
@ -3233,7 +3234,7 @@ void G_AddGhost(char *defdemoname)
} p += 4; // "PLAY"
p += 2; // gamemap
SKIPSTRING(p); // gamemap
p += 16; // mapmd5 (possibly check for consistency?)
flags = READUINT8(p);
@ -3358,7 +3359,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;
@ -3462,7 +3463,7 @@ void G_UpdateStaffGhostName(lumpnum_t l)
}
p += 4; // "PLAY"
p += 2; // gamemap
SKIPSTRING(p); // gamemap
p += 16; // mapmd5 (possibly check for consistency?)
flags = READUINT8(p);
@ -3540,6 +3541,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"));

File diff suppressed because it is too large Load diff

View file

@ -23,7 +23,6 @@
extern char gamedatafilename[64];
extern char timeattackfolder[64];
extern char customversionstring[32];
#define GAMEDATASIZE (4*8192)
extern char player_names[MAXPLAYERS][MAXPLAYERNAME+1];
extern INT32 player_name_changes[MAXPLAYERS];
@ -36,6 +35,19 @@ 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_INVALID = INT16_MAX-5, // Always last (swap with NEXTMAP_RESERVED when removing that)
NEXTMAP_SPECIAL = NEXTMAP_INVALID
} nextmapspecial_t;
extern INT32 gameovertics;
extern UINT8 ammoremovaltics;
extern tic_t timeinmap; // Ticker for time spent in level (used for levelcard display)
@ -81,8 +93,8 @@ extern consvar_t cv_resume;
#define MAXPLMOVE (50)
#define SLOWTURNTICS (6)
// build an internal map name MAPxx from map number
const char *G_BuildMapName(INT32 map);
INT32 G_MapNumber(const char *mapname);
void G_ResetAnglePrediction(player_t *player);
void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer);
@ -112,7 +124,7 @@ boolean G_PlayerInputDown(UINT8 p, INT32 gc, UINT8 menuPlayers);
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);
@ -150,7 +162,7 @@ void G_SpawnPlayer(INT32 playernum);
// Can be called by the startup code or M_Responder.
// A normal game starts at map 1, but a warp test can start elsewhere
void G_DeferedInitNew(boolean pencoremode, const char *mapname, INT32 pickedchar,
void G_DeferedInitNew(boolean pencoremode, INT32 map, INT32 pickedchar,
UINT8 ssplayers, boolean FLS);
void G_DoLoadLevel(boolean resetplayer);
@ -244,6 +256,7 @@ FUNCMATH INT32 G_TicsToMilliseconds(tic_t tics);
// Don't split up TOL handling
UINT32 G_TOLFlag(INT32 pgametype);
INT16 G_GetFirstMapOfGametype(UINT8 pgametype);
INT16 G_RandMap(UINT32 tolflags, INT16 pprevmap, UINT8 ignorebuffer, UINT8 maphell, boolean callagainsoon, INT16 *extbuffer);
void G_AddMapToBuffer(INT16 map);

View file

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

View file

@ -17,6 +17,7 @@
#include "s_sound.h"
#include "m_random.h"
#include "r_sky.h" // skyflatnum
#include "k_grandprix.h" // K_CanChangeRules
// Battle overtime info
struct battleovertime battleovertime;
@ -126,7 +127,7 @@ void K_CheckBumpers(void)
winnerscoreadd -= players[i].roundscore;
}
if (bossinfo.boss)
if (K_CanChangeRules() == false)
{
if (nobumpers)
{

View file

@ -3320,7 +3320,6 @@ static void K_drawKartMinimapIcon(fixed_t objx, fixed_t objy, INT32 hudx, INT32
static void K_drawKartMinimap(void)
{
INT32 lumpnum;
patch_t *AutomapPic;
INT32 i = 0;
INT32 x, y;
@ -3344,12 +3343,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
{

View file

@ -218,6 +218,15 @@ extern menu_t PLAY_LevelSelectDef;
extern menuitem_t PLAY_TimeAttack[];
extern menu_t PLAY_TimeAttackDef;
typedef enum
{
ta_replay = 0,
ta_guest,
ta_ghosts,
ta_spacer,
ta_start,
} ta_e;
extern menuitem_t PLAY_TAReplay[];
extern menu_t PLAY_TAReplayDef;

View file

@ -204,6 +204,7 @@ menu_t PLAY_LevelSelectDef = {
NULL
};
// see ta_e
menuitem_t PLAY_TimeAttack[] =
{
{IT_STRING | IT_SUBMENU, "Replay...", NULL, NULL, {.submenu = &PLAY_TAReplayDef}, 0, 0},

View file

@ -1846,14 +1846,16 @@ static void M_DrawCupPreview(INT16 y, cupheader_t *cup)
i = (cupgrid.previewanim / 82) % cup->numlevels;
while (x < BASEVIDWIDTH + pad)
{
lumpnum_t lumpnum;
patch_t *PictureOfLevel;
INT32 cupLevelNum = cup->cachedlevels[i];
patch_t *PictureOfLevel = NULL;
lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(cup->levellist[i]+1)));
if (lumpnum != LUMPERROR)
PictureOfLevel = W_CachePatchNum(lumpnum, PU_CACHE);
else
PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE);
if (cupLevelNum < nummapheaders && mapheaderinfo[cupLevelNum])
{
PictureOfLevel = mapheaderinfo[cupLevelNum]->thumbnailPic;
}
if (!PictureOfLevel)
PictureOfLevel = blanklvl;
V_DrawSmallScaledPatch(x + 1, y+2, 0, PictureOfLevel);
i = (i+1) % cup->numlevels;
@ -2073,18 +2075,19 @@ static void M_DrawHighLowLevelTitle(INT16 x, INT16 y, INT16 map)
static void M_DrawLevelSelectBlock(INT16 x, INT16 y, INT16 map, boolean redblink, boolean greyscale)
{
lumpnum_t lumpnum;
patch_t *PictureOfLevel;
patch_t *PictureOfLevel = NULL;
UINT8 *colormap = NULL;
if (greyscale)
colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_GREY, GTC_MENUCACHE);
lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(map+1)));
if (lumpnum != LUMPERROR)
PictureOfLevel = W_CachePatchNum(lumpnum, PU_CACHE);
else
PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE);
if (mapheaderinfo[map])
{
PictureOfLevel = mapheaderinfo[map]->thumbnailPic;
}
if (!PictureOfLevel)
PictureOfLevel = blanklvl;
if (redblink)
V_DrawScaledPatch(3+x, y, 0, W_CachePatchName("LVLSEL2", PU_CACHE));
@ -2114,10 +2117,10 @@ void M_DrawLevelSelect(void)
{
INT16 lvlx = t, lvly = y;
while (!M_CanShowLevelInList(map, levellist.newgametype) && map < NUMMAPS)
while (!M_CanShowLevelInList(map, levellist.newgametype) && map < nummapheaders)
map++;
if (map >= NUMMAPS)
if (map >= nummapheaders)
break;
if (i == levellist.cursor && tatransition)
@ -2146,7 +2149,7 @@ void M_DrawTimeAttack(void)
INT16 rightedge = 149+t+155;
INT16 opty = 140;
INT32 w;
lumpnum_t lumpnum;
patch_t *minimap = NULL;
UINT8 i;
consvar_t *cv;
@ -2156,17 +2159,34 @@ void M_DrawTimeAttack(void)
V_DrawScaledPatch(149+t, 70, 0, W_CachePatchName("BESTTIME", PU_CACHE));
if (currentMenu == &PLAY_TimeAttackDef)
if (currentMenu == &PLAY_TimeAttackDef && mapheaderinfo[map])
{
lumpnum = W_CheckNumForName(va("%sR", G_BuildMapName(map+1)));
if (lumpnum != LUMPERROR)
V_DrawScaledPatch(24-t, 82, 0, W_CachePatchNum(lumpnum, PU_CACHE));
tic_t timerec = 0;
tic_t laprec = 0;
UINT32 timeheight = 82;
V_DrawRightAlignedString(rightedge-12, 82, highlightflags, "BEST LAP:");
K_drawKartTimestamp(0, 162+t, 88, 0, 2);
if ((minimap = mapheaderinfo[map]->minimapPic))
V_DrawScaledPatch(24-t, 82, 0, minimap);
V_DrawRightAlignedString(rightedge-12, 112, highlightflags, "BEST TIME:");
K_drawKartTimestamp(0, 162+t, 118, map, 1);
if (mapheaderinfo[map]->mainrecord)
{
timerec = mapheaderinfo[map]->mainrecord->time;
laprec = mapheaderinfo[map]->mainrecord->lap;
}
if (levellist.newgametype != GT_BATTLE)
{
V_DrawRightAlignedString(rightedge-12, timeheight, highlightflags, "BEST LAP:");
K_drawKartTimestamp(laprec, 162+t, timeheight+6, 0, 2);
timeheight += 30;
}
else
{
timeheight += 15;
}
V_DrawRightAlignedString(rightedge-12, timeheight, highlightflags, "BEST TIME:");
K_drawKartTimestamp(timerec, 162+t, timeheight+6, map, 1);
}
else
opty = 80;
@ -3789,8 +3809,7 @@ void M_DrawPlaybackMenu(void)
#define SCALEDVIEWHEIGHT (vid.height/vid.dupy)
void M_DrawReplayHutReplayInfo(void)
{
lumpnum_t lumpnum;
patch_t *patch;
patch_t *patch = NULL;
UINT8 *colormap;
INT32 x, y, w, h;
@ -3816,11 +3835,19 @@ void M_DrawReplayHutReplayInfo(void)
// A 160x100 image of the level as entry MAPxxP
//CONS_Printf("%d %s\n", extrasmenu.demolist[dir_on[menudepthleft]].map, G_BuildMapName(extrasmenu.demolist[dir_on[menudepthleft]].map));
lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(extrasmenu.demolist[dir_on[menudepthleft]].map)));
if (lumpnum != LUMPERROR)
patch = W_CachePatchNum(lumpnum, PU_CACHE);
else
if (mapheaderinfo[extrasmenu.demolist[dir_on[menudepthleft]].map])
{
patch = mapheaderinfo[extrasmenu.demolist[dir_on[menudepthleft]].map]->thumbnailPic;
if (!patch)
{
patch = blanklvl;
}
}
else if (!patch)
{
patch = W_CachePatchName("M_NOLVL", PU_CACHE);
}
if (!(extrasmenu.demolist[dir_on[menudepthleft]].kartspeed & DF_ENCORE))
V_DrawSmallScaledPatch(x, y, V_SNAPTOTOP, patch);

View file

@ -249,7 +249,7 @@ static void Dummymenuplayer_OnChange(void)
static void Dummystaff_OnChange(void)
{
#if 0
#ifdef STAFFGHOSTS
lumpnum_t l;
dummystaffname[0] = '\0';
@ -281,7 +281,7 @@ static void Dummystaff_OnChange(void)
sprintf(temp, " - %d", cv_dummystaff.value);
}
#endif
#endif //#ifdef STAFFGHOSTS
}
void Screenshot_option_Onchange(void)
@ -3182,6 +3182,8 @@ void M_SetupDifficultySelect(INT32 choice)
//
boolean M_CanShowLevelInList(INT16 mapnum, UINT8 gt)
{
UINT32 tolflag = G_TOLFlag(gt);
// Does the map exist?
if (!mapheaderinfo[mapnum])
return false;
@ -3190,48 +3192,40 @@ boolean M_CanShowLevelInList(INT16 mapnum, UINT8 gt)
if (!mapheaderinfo[mapnum]->lvlttl[0])
return false;
// Does the map have a LUMP?
if (mapheaderinfo[mapnum]->lumpnum == LUMPERROR)
return false;
if (M_MapLocked(mapnum+1))
return false; // not unlocked
// Check for TOL
if (!(mapheaderinfo[mapnum]->typeoflevel & tolflag))
return false;
// Should the map be hidden?
if (mapheaderinfo[mapnum]->menuflags & LF2_HIDEINMENU /*&& mapnum+1 != gamemap*/)
if (mapheaderinfo[mapnum]->menuflags & LF2_HIDEINMENU)
return false;
// I don't know why, but some may have exceptions.
if (levellist.timeattack && (mapheaderinfo[mapnum]->menuflags & LF2_NOTIMEATTACK))
return false;
if (gt == GT_BATTLE && (mapheaderinfo[mapnum]->typeoflevel & TOL_BATTLE))
return true;
if (gt == GT_RACE && (mapheaderinfo[mapnum]->typeoflevel & TOL_RACE))
if (gametypedefaultrules[gt] & GTR_CAMPAIGN && levellist.selectedcup)
{
if (levellist.selectedcup && levellist.selectedcup->numlevels)
{
UINT8 i;
for (i = 0; i < levellist.selectedcup->numlevels; i++)
{
if (mapnum == levellist.selectedcup->levellist[i])
break;
}
if (i == levellist.selectedcup->numlevels)
return false;
}
return true;
if (mapheaderinfo[mapnum]->cup != levellist.selectedcup)
return false;
}
// Hmm? Couldn't decide?
return false;
// Survived our checks.
return true;
}
INT16 M_CountLevelsToShowInList(UINT8 gt)
{
INT16 mapnum, count = 0;
for (mapnum = 0; mapnum < NUMMAPS; mapnum++)
for (mapnum = 0; mapnum < nummapheaders; mapnum++)
if (M_CanShowLevelInList(mapnum, gt))
count++;
@ -3242,7 +3236,7 @@ INT16 M_GetFirstLevelInList(UINT8 gt)
{
INT16 mapnum;
for (mapnum = 0; mapnum < NUMMAPS; mapnum++)
for (mapnum = 0; mapnum < nummapheaders; mapnum++)
if (M_CanShowLevelInList(mapnum, gt))
return mapnum;
@ -3410,7 +3404,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;
@ -3418,7 +3414,7 @@ void M_CupSelectHandler(INT32 choice)
if (cupgrid.grandprix == true)
{
INT32 levelNum;
UINT8 ssplayers = cv_splitplayers.value-1;
S_StartSound(NULL, sfx_s3k63);
@ -3462,8 +3458,10 @@ void M_CupSelectHandler(INT32 choice)
netgame = levellist.netgame; // ^ ditto.
}
levelNum = grandprixinfo.cup->cachedlevels[0];
D_MapChange(
grandprixinfo.cup->levellist[0] + 1,
levelNum + 1,
GT_RACE,
grandprixinfo.encore,
true,
@ -3549,16 +3547,16 @@ void M_LevelSelectHandler(INT32 choice)
{
map++;
while (!M_CanShowLevelInList(map, levellist.newgametype) && map < NUMMAPS)
while (!M_CanShowLevelInList(map, levellist.newgametype) && map < nummapheaders)
map++;
if (map >= NUMMAPS)
if (map >= nummapheaders)
break;
add--;
}
if (map >= NUMMAPS)
if (map >= nummapheaders)
{
// This shouldn't happen
return;

View file

@ -33,7 +33,6 @@
#include "k_hud.h"
#include "d_netcmd.h" // IsPlayerAdmin
#include "k_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
@ -378,23 +377,6 @@ static int lib_pGetEffectiveFollowerColor(lua_State *L)
return 1;
}
// M_MISC
//////////////
static int lib_mMapNumber(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;
}
// M_RANDOM
//////////////
@ -2499,9 +2481,8 @@ static int lib_sStopSoundByID(lua_State *L)
static int lib_sChangeMusic(lua_State *L)
{
UINT32 position, prefadems, fadeinms;
const char *music_name = luaL_checkstring(L, 1);
UINT32 position, prefadems, fadeinms;
boolean looping = (boolean)lua_opttrueboolean(L, 2);
player_t *player = NULL;
UINT16 music_flags = 0;
@ -3065,12 +3046,12 @@ static int lib_gBuildMapTitle(lua_State *L)
{
INT32 map = Lcheckmapnumber(L, 1, "G_BuildMapTitle");
char *name;
if (map < 1 || map > NUMMAPS)
if (map < 1 || map > nummapheaders)
{
return luaL_error(L,
"map number %d out of range (1 - %d)",
"map ID %d out of range (1 - %d)",
map,
NUMMAPS
nummapheaders
);
}
name = G_BuildMapTitle(map);
@ -3838,9 +3819,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},

View file

@ -574,6 +574,7 @@ static int libd_drawStretched(lua_State *L)
}
// KART: draw patch on minimap from x, y coordinates on the map
// Sal: Let's please just merge the relevant info into the actual function, and have Lua call that...
static int libd_drawOnMinimap(lua_State *L)
{
fixed_t x, y, scale; // coordinates of the object
@ -583,7 +584,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;
@ -669,12 +669,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);

View file

@ -2085,8 +2085,8 @@ static int lib_getMapheaderinfo(lua_State *L)
lua_remove(L, 1); // dummy userdata table is unused.
if (lua_isnumber(L, 1))
{
size_t i = lua_tointeger(L, 1)-1;
if (i >= NUMMAPS)
INT32 i = lua_tointeger(L, 1)-1;
if (i < 0 || i >= nummapheaders)
return 0;
LUA_PushUserdata(L, mapheaderinfo[i], META_MAPHEADER);
//CONS_Printf(mapheaderinfo[i]->lvlttl);
@ -2104,7 +2104,7 @@ static int lib_getMapheaderinfo(lua_State *L)
static int lib_nummapheaders(lua_State *L)
{
lua_pushinteger(L, NUMMAPS);
lua_pushinteger(L, nummapheaders);
return 1;
}
@ -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"))
@ -2127,10 +2126,6 @@ static int mapheaderinfo_get(lua_State *L)
lua_pushinteger(L, header->actnum);
else if (fastcmp(field,"typeoflevel"))
lua_pushinteger(L, header->typeoflevel);
else if (fastcmp(field,"nextlevel"))
lua_pushinteger(L, header->nextlevel);
else if (fastcmp(field,"marathonnext"))
lua_pushinteger(L, header->marathonnext);
else if (fastcmp(field,"keywords"))
lua_pushstring(L, header->keywords);
else if (fastcmp(field,"musname"))
@ -2139,22 +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,"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"))
lua_pushinteger(L, header->weather);
else if (fastcmp(field,"skytexture"))
@ -2165,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);
@ -2178,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"))
@ -2188,31 +2160,14 @@ 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"))
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);
// 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

@ -211,35 +211,17 @@ 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,"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_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);

View file

@ -81,7 +81,10 @@ void M_ClearSecrets(void)
{
INT32 i;
memset(mapvisited, 0, sizeof(mapvisited));
for (i = 0; i < nummapheaders; ++i)
{
mapheaderinfo[i]->mapvisited = 0;
}
for (i = 0; i < MAXEMBLEMS; ++i)
emblemlocations[i].collected = false;
@ -129,11 +132,19 @@ UINT8 M_CheckCondition(condition_t *cn)
case UC_OVERALLTIME: // Requires overall time <= x
return (M_GotLowEnoughTime(cn->requirement));
case UC_MAPVISITED: // Requires map x to be visited
return ((mapvisited[cn->requirement - 1] & MV_VISITED) == MV_VISITED);
case UC_MAPBEATEN: // Requires map x to be beaten
return ((mapvisited[cn->requirement - 1] & MV_BEATEN) == MV_BEATEN);
case UC_MAPENCORE: // Requires map x to be beaten in encore
return ((mapvisited[cn->requirement - 1] & MV_ENCORE) == MV_ENCORE);
{
UINT8 mvtype = MV_VISITED;
if (cn->type == UC_MAPBEATEN)
mvtype = MV_BEATEN;
else if (cn->type == UC_MAPENCORE)
mvtype = MV_ENCORE;
return ((cn->requirement < nummapheaders)
&& (mapheaderinfo[cn->requirement])
&& ((mapheaderinfo[cn->requirement]->mapvisited & mvtype) == mvtype));
}
case UC_MAPTIME: // Requires time on map <= x
return (G_GetBestTime(cn->extrainfo1) <= (unsigned)cn->requirement);
case UC_TRIGGER: // requires map trigger set
@ -298,10 +309,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 (checkLevel >= nummapheaders || !mapheaderinfo[checkLevel])
continue;
levelnum = checkLevel;
valToReach = emblemlocations[i].var;
switch (emblemlocations[i].type)
@ -331,17 +349,24 @@ 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 (checkLevel >= nummapheaders || !mapheaderinfo[checkLevel])
continue;
levelnum = checkLevel;
embtype = emblemlocations[i].var;
flags = MV_BEATEN;
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)
@ -407,7 +432,8 @@ UINT8 M_MapLocked(INT32 mapnum)
if (1)
return false;
#endif
if (!mapnum || mapnum > nummapheaders)
return false;
if (!mapheaderinfo[mapnum-1] || mapheaderinfo[mapnum-1]->unlockrequired < 0)
return false;
if (!unlockables[mapheaderinfo[mapnum-1]->unlockrequired].unlocked)
@ -458,14 +484,14 @@ 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;
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;
@ -492,7 +518,12 @@ emblem_t *M_GetLevelEmblems(INT32 mapnum)
while (--i >= 0)
{
if (emblemlocations[i].level == map)
INT32 checkLevel = G_MapNumber(emblemlocations[i].level);
if (checkLevel >= nummapheaders || !mapheaderinfo[checkLevel])
continue;
if (checkLevel == map)
return &emblemlocations[i];
}
return NULL;

View file

@ -73,7 +73,7 @@ typedef struct
{
UINT8 type; ///< Emblem type
INT16 tag; ///< Tag of emblem mapthing
INT16 level; ///< Level on which this emblem can be found.
char * level; ///< Level on which this emblem can be found.
UINT8 sprite; ///< emblem sprite to use, 0 - 25
UINT16 color; ///< skincolor to use
INT32 var; ///< If needed, specifies information on the target amount to achieve (or target skin)

View file

@ -226,32 +226,6 @@ void M_AddToJoinedIPs(char *address, char *servname)
strcpy(joinedIPlist[0][1], servname);
}
/** 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
// ==========================================================================
@ -956,9 +930,11 @@ static void M_PNGText(png_structp png_ptr, png_infop png_info_ptr, PNG_CONST png
break;
}
#if 0
if (gamestate == GS_LEVEL)
snprintf(maptext, 8, "%s", G_BuildMapName(gamemap));
else
#endif
snprintf(maptext, 8, "Unknown");
if (gamestate == GS_LEVEL && mapheaderinfo[gamemap-1]->lvlttl[0] != '\0')

View file

@ -61,8 +61,6 @@ void M_AddToJoinedIPs(char *address, char *servname);
void M_SaveJoinedIPs(void);
void M_LoadJoinedIPs(void);
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)

View file

@ -3460,28 +3460,6 @@ void A_BossDeath(mobj_t *mo)
EV_DoElevator(&junk, elevateUp, false);
Tag_FSet(&junk.tags, LE_CAPSULE2);
EV_DoElevator(&junk, elevateHighest, false);
if (mapheaderinfo[gamemap-1]->muspostbossname[0] &&
S_MusicExists(mapheaderinfo[gamemap-1]->muspostbossname))
{
// Touching the egg trap button calls P_DoPlayerExit, which calls P_RestoreMusic.
// So just park ourselves in the mapmus variables.
// But don't change the mapmus variables if they were modified from their level header values (e.g., TUNES).
boolean changed = strnicmp(mapheaderinfo[gamemap-1]->musname, S_MusicName(), 7);
if (!strnicmp(mapheaderinfo[gamemap-1]->musname, mapmusname, 7))
{
strncpy(mapmusname, mapheaderinfo[gamemap-1]->muspostbossname, 7);
mapmusname[6] = 0;
mapmusflags = (mapheaderinfo[gamemap-1]->muspostbosstrack & MUSIC_TRACKMASK) | MUSIC_RELOADRESET;
mapmusposition = mapheaderinfo[gamemap-1]->muspostbosspos;
}
// don't change if we're in another tune
// but in case we're in jingle, use our parked mapmus variables so the correct track restores
if (!changed)
S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, (1*MUSICRATE)+(MUSICRATE/2),
mapheaderinfo[gamemap-1]->muspostbossfadein);
}
}
bossjustdie:

View file

@ -11069,7 +11069,7 @@ void P_SpawnPlayer(INT32 playernum)
else if (p->bot)
{
/*
if (bonusgame || specialstage)
if (bonusgame || specialstage || boss)
{
// Bots should avoid
p->spectator = true;

View file

@ -4427,8 +4427,8 @@ static inline void P_UnArchiveSPGame(INT16 mapoverride)
// gamemap changed; we assume that its map header is always valid,
// so make it so
if(!mapheaderinfo[gamemap-1])
P_AllocMapHeader(gamemap-1);
if (!gamemap || gamemap > nummapheaders || !mapheaderinfo[gamemap-1])
I_Error("P_UnArchiveSPGame: Internal map ID %d not found (nummapheaders = %d)", gamemap-1, nummapheaders);
//lastmapsaved = gamemap;
lastmaploaded = gamemap;
@ -4482,7 +4482,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);
@ -4508,7 +4507,6 @@ static void P_NetArchiveMisc(boolean resending)
}
WRITEUINT32(save_p, token);
WRITEINT32(save_p, sstimer);
WRITEUINT32(save_p, bluescore);
WRITEUINT32(save_p, redscore);
@ -4537,9 +4535,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);
@ -4614,8 +4609,8 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading)
// gamemap changed; we assume that its map header is always valid,
// so make it so
if(!mapheaderinfo[gamemap-1])
P_AllocMapHeader(gamemap-1);
if (!gamemap || gamemap > nummapheaders || !mapheaderinfo[gamemap-1])
I_Error("P_NetUnArchiveMisc: Internal map ID %d not found (nummapheaders = %d)", gamemap-1, nummapheaders);
// tell the sound code to reset the music since we're skipping what
// normally sets this flag
@ -4649,7 +4644,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);
@ -4672,7 +4666,6 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading)
}
token = READUINT32(save_p);
sstimer = READINT32(save_p);
bluescore = READUINT32(save_p);
redscore = READUINT32(save_p);
@ -4701,9 +4694,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);
@ -4880,7 +4870,7 @@ boolean P_LoadGame(INT16 mapoverride)
return false;
// Only do this after confirming savegame is ok
G_DeferedInitNew(false, G_BuildMapName(gamemap), savedata.skin, 0, true);
G_DeferedInitNew(false, gamemap, savedata.skin, 0, true);
COM_BufAddText("dummyconsvar 1\n"); // G_DeferedInitNew doesn't do this
return true;

View file

@ -134,6 +134,8 @@ boolean stoppedclock;
boolean levelloading;
UINT8 levelfadecol;
virtres_t *curmapvirt;
// BLOCKMAP
// Created from axis aligned bounding box
// of the map, a rectangular array of
@ -312,11 +314,19 @@ boolean P_IsDegeneratedTubeWaypointSequence(UINT8 sequence)
FUNCNORETURN static ATTRNORETURN void CorruptMapError(const char *msg)
{
// don't use va() because the calling function probably uses it
char mapnum[10];
char mapname[MAXMAPLUMPNAME];
sprintf(mapnum, "%hd", gamemap);
if (gamemap > 0 && gamemap <= nummapheaders && mapheaderinfo[gamemap-1])
{
sprintf(mapname, "%s", mapheaderinfo[gamemap-1]->lumpname);
}
else
{
sprintf(mapname, "ID %d", gamemap-1);
}
CON_LogMessage("Map ");
CON_LogMessage(mapnum);
CON_LogMessage(mapname);
CON_LogMessage(" is corrupt: ");
CON_LogMessage(msg);
CON_LogMessage("\n");
@ -357,59 +367,34 @@ void P_DeleteFlickies(INT16 i)
* \param i Map number to clear header for.
* \sa P_ClearMapHeaderInfo
*/
static void P_ClearSingleMapHeaderInfo(INT16 i)
static void P_ClearSingleMapHeaderInfo(INT16 num)
{
const INT16 num = (INT16)(i-1);
boolean exists = (mapheaderinfo[gamemap-1]->alreadyExists == true);
mapheaderinfo[num]->lvlttl[0] = '\0';
mapheaderinfo[num]->selectheading[0] = '\0';
mapheaderinfo[num]->subttl[0] = '\0';
mapheaderinfo[num]->zonttl[0] = '\0';
mapheaderinfo[num]->ltzzpatch[0] = '\0';
mapheaderinfo[num]->ltzztext[0] = '\0';
mapheaderinfo[num]->ltactdiamond[0] = '\0';
mapheaderinfo[num]->actnum = 0;
mapheaderinfo[num]->typeoflevel = 0;
mapheaderinfo[num]->nextlevel = (INT16)(i + 1);
mapheaderinfo[num]->marathonnext = 0;
mapheaderinfo[num]->startrings = 0;
mapheaderinfo[num]->sstimer = 90;
mapheaderinfo[num]->ssspheres = 1;
mapheaderinfo[num]->gravity = DEFAULT_GRAVITY;
mapheaderinfo[num]->keywords[0] = '\0';
snprintf(mapheaderinfo[num]->musname, 7, "%sM", G_BuildMapName(i));
sprintf(mapheaderinfo[num]->musname, "%.5sM", G_BuildMapName(num+1));
mapheaderinfo[num]->musname[6] = 0;
mapheaderinfo[num]->mustrack = 0;
mapheaderinfo[num]->muspos = 0;
mapheaderinfo[num]->musinterfadeout = 0;
mapheaderinfo[num]->musintername[0] = 0;
mapheaderinfo[num]->muspostbossname[0] = 0;
mapheaderinfo[num]->muspostbosstrack = 0;
mapheaderinfo[num]->muspostbosspos = 0;
mapheaderinfo[num]->muspostbossfadein = 0;
mapheaderinfo[num]->musforcereset = -1;
mapheaderinfo[num]->forcecharacter[0] = '\0';
mapheaderinfo[num]->weather = PRECIP_NONE;
snprintf(mapheaderinfo[num]->skytexture, 5, "SKY1");
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;
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;
@ -422,10 +407,10 @@ 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;
mapheaderinfo[num]->mapvisited = 0;
Z_Free(mapheaderinfo[num]->mainrecord);
mapheaderinfo[num]->mainrecord = NULL;
mapheaderinfo[num]->customopts = NULL;
mapheaderinfo[num]->numCustomOptions = 0;
@ -437,110 +422,53 @@ static void P_ClearSingleMapHeaderInfo(INT16 i)
*/
void P_AllocMapHeader(INT16 i)
{
if (!mapheaderinfo[i])
if (i > nummapheaders)
I_Error("P_AllocMapHeader: Called on %d, should be %d", i, nummapheaders);
if (i >= NEXTMAP_SPECIAL)
{
mapheaderinfo[i] = Z_Malloc(sizeof(mapheader_t), PU_STATIC, NULL);
mapheaderinfo[i]->flickies = NULL;
mapheaderinfo[i]->grades = NULL;
}
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);
I_Error("P_AllocMapHeader: Too many maps!");
}
for (g = 0; g < 6; ++g)
if (i >= mapallocsize)
{
// Allow "partial" grading systems
if (spos != NULL)
if (!mapallocsize)
{
mapheaderinfo[i]->grades[mare].grade[g] = atoi(spos);
CONS_Debug(DBG_SETUP, "%u ", atoi(spos));
// Grab next comma
spos = strchr(spos, ',');
if (spos)
++spos;
mapallocsize = 16;
}
else
{
// Grade not reachable
mapheaderinfo[i]->grades[mare].grade[g] = UINT32_MAX;
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);
}
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)
if (!mapheaderinfo[i])
{
INT32 pgrade = 0;
for (i = 0; i < 6; ++i)
{
if (pscore >= mapheaderinfo[map-1]->grades[mare].grade[i])
++pgrade;
}
return (UINT8)pgrade;
mapheaderinfo[i] = Z_Malloc(sizeof(mapheader_t), PU_STATIC, NULL);
if (!mapheaderinfo[i])
I_Error("P_AllocMapHeader: Not enough memory to allocate new mapheader (ID %d)", i);
mapheaderinfo[i]->lumpnum = LUMPERROR;
mapheaderinfo[i]->lumpname = NULL;
mapheaderinfo[i]->thumbnailPic = NULL;
mapheaderinfo[i]->minimapPic = NULL;
mapheaderinfo[i]->cup = NULL;
mapheaderinfo[i]->mainrecord = NULL;
mapheaderinfo[i]->flickies = NULL;
nummapheaders++;
}
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];
P_ClearSingleMapHeaderInfo(i);
}
//
@ -736,69 +664,6 @@ void P_ReloadRings(void)
}
}
#ifdef SCANTHINGS
void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum)
{
size_t i, n;
UINT8 *data, *datastart;
UINT16 type, maprings;
INT16 tol;
UINT32 flags;
tol = mapheaderinfo[mapnum-1]->typeoflevel;
flags = mapheaderinfo[mapnum-1]->levelflags;
n = W_LumpLengthPwad(wadnum, lumpnum) / (5 * sizeof (INT16));
//CONS_Printf("%u map things found!\n", n);
maprings = 0;
data = datastart = W_CacheLumpNumPwad(wadnum, lumpnum, PU_STATIC);
for (i = 0; i < n; i++)
{
data += 3 * sizeof (INT16); // skip x y position, angle
type = READUINT16(data) & 4095;
data += sizeof (INT16); // skip options
if (mt->type == mobjinfo[MT_RANDOMITEM].doomednum)
{
nummapboxes++;
}
else if (mt->type == mobjinfo[MT_BATTLECAPSULE].doomednum)
{
maptargets++;
}
else if (mt->type == mobjinfo[MT_RING].doomednum)
{
maprings++;
}
else
{
switch (type)
{
case 603: // 10 diagonal rings
maprings += 10;
break;
case 600: // 5 vertical rings
case 601: // 5 vertical rings
case 602: // 5 diagonal rings
maprings += 5;
break;
case 604: // 8 circle rings
maprings += 8;
break;
case 605: // 16 circle rings
maprings += 16;
break;
}
}
}
Z_Free(datastart);
if (maprings)
CONS_Printf("%s has %u rings\n", G_BuildMapName(mapnum), maprings);
}
#endif
static void P_SpawnMapThings(boolean spawnemblems)
{
size_t i;
@ -847,6 +712,7 @@ static void P_SpawnMapThings(boolean spawnemblems)
// Experimental groovy write function!
void P_WriteThings(void)
{
const char * filename;
size_t i, length;
mapthing_t *mt;
UINT8 *savebuffer, *savebuf_p;
@ -875,11 +741,13 @@ void P_WriteThings(void)
length = savebuf_p - savebuffer;
FIL_WriteFile(va("newthings%d.lmp", gamemap), savebuffer, length);
filename = va("newthings-%s.lmp", G_BuildMapName(gamemap));
FIL_WriteFile(filename, savebuffer, length);
free(savebuffer);
savebuf_p = NULL;
CONS_Printf(M_GetText("newthings%d.lmp saved.\n"), gamemap);
CONS_Printf(M_GetText("%s saved.\n"), filename);
}
//
@ -3560,15 +3428,14 @@ static void P_MakeMapMD5(virtres_t *virt, void *dest)
static boolean P_LoadMapFromFile(void)
{
virtres_t *virt = vres_GetMap(lastloadedmaplumpnum);
virtlump_t *textmap = vres_Find(virt, "TEXTMAP");
virtlump_t *textmap = vres_Find(curmapvirt, "TEXTMAP");
size_t i;
udmf = textmap != NULL;
if (!P_LoadMapData(virt))
if (!P_LoadMapData(curmapvirt))
return false;
P_LoadMapBSP(virt);
P_LoadMapLUT(virt);
P_LoadMapBSP(curmapvirt);
P_LoadMapLUT(curmapvirt);
P_LinkMapData();
@ -3593,9 +3460,9 @@ static boolean P_LoadMapFromFile(void)
if (sectors[i].tags.count)
spawnsectors[i].tags.tags = memcpy(Z_Malloc(sectors[i].tags.count*sizeof(mtag_t), PU_LEVEL, NULL), sectors[i].tags.tags, sectors[i].tags.count*sizeof(mtag_t));
P_MakeMapMD5(virt, &mapmd5);
P_MakeMapMD5(curmapvirt, &mapmd5);
vres_Free(virt);
vres_Free(curmapvirt);
return true;
}
@ -3659,15 +3526,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;
@ -3675,7 +3533,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
@ -3819,43 +3677,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;
@ -3939,17 +3760,20 @@ static void P_LoadRecordGhosts(void)
if (cv_ghost_guest.value && FIL_FileExists(va("%s-guest.lmp", gpath)))
G_AddGhost(va("%s-guest.lmp", gpath));
#ifdef STAFFGHOSTS
// Staff Attack ghosts
if (cv_ghost_staff.value)
{
lumpnum_t l;
UINT8 j = 1;
while (j <= 99 && (l = W_CheckNumForName(va("%sS%02u",G_BuildMapName(gamemap),j))) != LUMPERROR)
// TODO: Use map header to determine lump name
while (j <= 99 && (l = W_CheckNumForLongName(va("%sS%02u",G_BuildMapName(gamemap),j))) != LUMPERROR)
{
G_AddGhost(va("%sS%02u",G_BuildMapName(gamemap),j));
j++;
}
}
#endif //#ifdef STAFFGHOSTS
free(gpath);
}
@ -4096,6 +3920,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;
@ -4133,9 +3958,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;
@ -4317,13 +4139,33 @@ 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);
R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette,
W_CheckNumForName(va("%s%c", maplumpname, (encoremode ? 'E' : 'T'))));
curmapvirt = vres_GetMap(lastloadedmaplumpnum);
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);
}
else
{
R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette, NULL, 0);
}
CON_SetupBackColormap();
// SRB2 determines the sky texture to be used depending on the map header.
@ -4424,9 +4266,9 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
skipstats = 0;
if (!(netgame || multiplayer || demo.playback) && !majormods)
mapvisited[gamemap-1] |= MV_VISITED;
mapheaderinfo[gamemap-1]->mapvisited |= MV_VISITED;
else if (!demo.playback)
mapvisited[gamemap-1] |= MV_MP; // you want to record that you've been there this session, but not permanently
mapheaderinfo[gamemap-1]->mapvisited |= MV_MP; // you want to record that you've been there this session, but not permanently
G_AddMapToBuffer(gamemap-1);
@ -4613,6 +4455,118 @@ static lumpinfo_t* FindFolder(const char *folName, UINT16 *start, UINT16 *end, l
return lumpinfo;
}
// Initialising map data (and catching replacements)...
UINT8 P_InitMapData(INT32 numexistingmapheaders)
{
UINT8 ret = 0;
INT32 i;
lumpnum_t maplump;
virtres_t *virtmap;
virtlump_t *minimap, *thumbnailPic;
char *name;
for (i = 0; i < nummapheaders; ++i)
{
name = mapheaderinfo[i]->lumpname;
maplump = W_CheckNumForMap(name);
// Doesn't exist?
if (maplump == INT16_MAX)
{
#ifndef DEVELOP
if (!numexistingmapheaders)
{
I_Error("P_InitMapData: Base map %s has a header but no level\n", name);
}
#endif
continue;
}
// No change?
if (mapheaderinfo[i]->lumpnum == maplump)
continue;
// Okay, it does...
{
ret |= MAPRET_ADDED;
CONS_Printf("%s\n", name);
if (numexistingmapheaders && mapheaderinfo[i]->lumpnum != LUMPERROR)
{
G_SetGameModified(multiplayer, true); // oops, double-defined - no record attack privileges for you
//If you replaced the map you're on, end the level when done.
if (i == gamemap - 1)
ret |= MAPRET_CURRENTREPLACED;
}
mapheaderinfo[i]->lumpnum = maplump;
// Get map thumbnail and minimap
virtmap = vres_GetMap(mapheaderinfo[i]->lumpnum);
thumbnailPic = vres_Find(virtmap, "PICTURE");
minimap = vres_Find(virtmap, "MINIMAP");
// Clear out existing graphics...
if (mapheaderinfo[i]->thumbnailPic)
{
Patch_Free(mapheaderinfo[i]->thumbnailPic);
}
if (mapheaderinfo[i]->minimapPic)
{
Patch_Free(mapheaderinfo[i]->minimapPic);
}
// Now apply the new ones!
if (thumbnailPic)
{
mapheaderinfo[i]->thumbnailPic = vres_GetPatch(thumbnailPic, PU_STATIC);
}
if (minimap)
{
mapheaderinfo[i]->minimapPic = vres_GetPatch(minimap, PU_STATIC);
}
vres_Free(virtmap);
// 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;
}
}
}
}
return ret;
}
UINT16 p_adding_file = INT16_MAX;
//
@ -4622,13 +4576,13 @@ UINT16 p_adding_file = INT16_MAX;
boolean P_AddWadFile(const char *wadfilename)
{
size_t i, j, sreplaces = 0, mreplaces = 0, digmreplaces = 0;
INT32 numexistingmapheaders = nummapheaders;
UINT16 numlumps, wadnum;
char *name;
lumpinfo_t *lumpinfo;
//boolean texturechange = false; ///\todo Useless; broken when back-frontporting PK3 changes?
boolean mapsadded = false;
boolean replacedcurrentmap = false;
UINT8 mapsadded = 0;
// Vars to help us with the position start and amount of each resource type.
// Useful for PK3s since they use folders.
@ -4778,36 +4732,8 @@ boolean P_AddWadFile(const char *wadfilename)
//
// 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]);
mapsadded = P_InitMapData(numexistingmapheaders);
// 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 you replaced the map you're on, end the level when done.
if (num == gamemap)
replacedcurrentmap = true;
CONS_Printf("%s\n", name);
mapsadded = true;
}
}
if (!mapsadded)
CONS_Printf(M_GetText("No maps added\n"));
@ -4825,7 +4751,7 @@ boolean P_AddWadFile(const char *wadfilename)
if (cursaveslot > 0)
cursaveslot = 0;
if (replacedcurrentmap && gamestate == GS_LEVEL && (netgame || multiplayer))
if ((mapsadded & MAPRET_CURRENTREPLACED) && gamestate == GS_LEVEL && (netgame || multiplayer))
{
CONS_Printf(M_GetText("Current map %d replaced by added file, ending the level to ensure consistency.\n"), gamemap);
if (server)

View file

@ -99,15 +99,17 @@ extern mapthing_t *mapthings;
extern UINT16 p_adding_file;
void P_SetupLevelSky(const char *skytexname, boolean global);
#ifdef SCANTHINGS
void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum);
#endif
void P_RespawnThings(void);
boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate);
#ifdef HWRENDER
void HWR_LoadLevel(void);
#endif
boolean P_AddWadFile(const char *wadfilename);
#define MAPRET_ADDED (1)
#define MAPRET_CURRENTREPLACED (1<<1)
UINT8 P_InitMapData(INT32 numexistingmapheaders);
boolean P_RunSOC(const char *socfilename);
void P_LoadSoundsRange(UINT16 wadnum, UINT16 first, UINT16 num);
void P_LoadMusicsRange(UINT16 wadnum, UINT16 first, UINT16 num);
@ -123,10 +125,5 @@ void P_DeleteFlickies(INT16 i);
// Needed for NiGHTS
void P_ReloadRings(void);
void P_DeleteGrades(INT16 i);
void P_AddGradesForMare(INT16 i, UINT8 mare, char *gtext);
UINT8 P_GetGrade(UINT32 pscore, INT16 map, UINT8 mare);
UINT8 P_HasGrades(INT16 map, UINT8 mare);
UINT32 P_GetScoreForGrade(INT16 map, UINT8 mare, UINT8 grade);
#endif

View file

@ -2522,6 +2522,9 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
break;
case 415: // Run a script
// FIXME: cursed
CONS_Alert(CONS_WARNING, "Linedef special 415 is currently broken! Fix it later, BYE.\n");
#if 0
if (cv_runscripts.value)
{
INT32 scrnum;
@ -2556,6 +2559,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
else
COM_BufInsertText(W_CacheLumpNum(lumpnum, PU_CACHE));
}
#endif
break;
case 416: // Spawn adjustable fire flicker
@ -5927,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
@ -6022,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;

View file

@ -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
@ -4288,14 +4289,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)
{

View file

@ -286,7 +286,7 @@ void R_InitColormaps(void)
#endif
}
void R_ReInitColormaps(UINT16 num, lumpnum_t newencoremap)
void R_ReInitColormaps(UINT16 num, void *newencoremap, size_t encoremapsize)
{
char colormap[9] = "COLORMAP";
lumpnum_t lump;
@ -309,13 +309,13 @@ void R_ReInitColormaps(UINT16 num, lumpnum_t newencoremap)
W_ReadLumpHeader(lump, colormaps, W_LumpLength(basecolormaplump), 0U);
// Encore mode.
if (newencoremap != LUMPERROR)
if (newencoremap)
{
lighttable_t *colormap_p, *colormap_p2;
size_t p, i;
encoremap = Z_MallocAlign(256 + 10, PU_LEVEL, NULL, 8);
W_ReadLump(newencoremap, encoremap);
M_Memcpy(encoremap, newencoremap, encoremapsize);
colormap_p = colormap_p2 = colormaps;
colormap_p += COLORMAP_REMAPOFFSET;

View file

@ -55,7 +55,7 @@ extern size_t flatmemory, spritememory, texturememory;
//#define COLORMAPREVERSELIST
void R_InitColormaps(void);
void R_ReInitColormaps(UINT16 num, lumpnum_t newencoremap);
void R_ReInitColormaps(UINT16 num, void *newencoremap, size_t encoremapsize);
void R_ClearColormaps(void);
extracolormap_t *R_CreateDefaultColormap(boolean lighttable);
extracolormap_t *R_GetDefaultColormap(void);

View file

@ -698,6 +698,7 @@ typedef struct
} patch_t;
extern patch_t *missingpat;
extern patch_t *blanklvl;
#if defined(_MSC_VER)
#pragma pack(1)

View file

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

View file

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

View file

@ -386,7 +386,6 @@ void S_StopSoundByID(void *origin, sfxenum_t sfx_id)
if (channels[cnum].sfxinfo == &S_sfx[sfx_id] && channels[cnum].origin == origin)
{
S_StopChannel(cnum);
break;
}
}
}
@ -407,7 +406,6 @@ void S_StopSoundByNum(sfxenum_t sfxnum)
if (channels[cnum].sfxinfo == &S_sfx[sfxnum])
{
S_StopChannel(cnum);
break;
}
}
}
@ -763,7 +761,6 @@ void S_StopSound(void *origin)
if (channels[cnum].sfxinfo && channels[cnum].origin == origin)
{
S_StopChannel(cnum);
break;
}
}
}
@ -2394,6 +2391,7 @@ void S_StartEx(boolean reset)
music_stack_fadein = JINGLEPOSTFADE;
}
// TODO: fix this function, needs better support for map names
static void Command_Tunes_f(void)
{
const char *tunearg;

View file

@ -404,7 +404,7 @@ const char *GetPalette(void)
return "PLAYPAL";
}
static void LoadMapPalette(void)
void V_ReloadPalette(void)
{
LoadPalette(GetPalette());
}
@ -416,7 +416,7 @@ static void LoadMapPalette(void)
void V_SetPalette(INT32 palettenum)
{
if (!pLocalPalette)
LoadMapPalette();
V_ReloadPalette();
#ifdef HWRENDER
if (rendermode == render_opengl)
@ -449,7 +449,7 @@ void V_SetPaletteLump(const char *pal)
static void CV_palette_OnChange(void)
{
// reload palette
LoadMapPalette();
V_ReloadPalette();
V_SetPalette(0);
}
@ -2980,8 +2980,6 @@ void V_Init(void)
UINT8 *base = vid.buffer;
const INT32 screensize = vid.rowbytes * vid.height;
LoadMapPalette();
for (i = 0; i < NUMSCREENS; i++)
screens[i] = NULL;

View file

@ -56,6 +56,9 @@ void InitColorLUT(colorlookup_t *lut, RGBA_t *palette, boolean makecolors);
UINT8 GetColorLUT(colorlookup_t *lut, UINT8 r, UINT8 g, UINT8 b);
UINT8 GetColorLUTDirect(colorlookup_t *lut, UINT8 r, UINT8 g, UINT8 b);
// Loads the correct palette into memory
void V_ReloadPalette(void);
// Set the current RGB palette lookup to use for palettized graphics
void V_SetPalette(INT32 palettenum);

View file

@ -64,10 +64,6 @@
#include "i_system.h"
#include "md5.h"
#include "lua_script.h"
#ifdef SCANTHINGS
#include "p_setup.h" // P_ScanThings
#endif
#include "m_misc.h" // M_MapNumber
#include "g_game.h" // G_SetGameModified
#include "k_terrain.h"
@ -94,10 +90,12 @@ typedef struct
// Must be a power of two
#define LUMPNUMCACHESIZE 64
#define LUMPNUMCACHENAME 32
typedef struct lumpnum_cache_s
{
char lumpname[32];
char lumpname[LUMPNUMCACHENAME];
UINT32 lumphash;
lumpnum_t lumpnum;
} lumpnum_cache_t;
@ -273,22 +271,6 @@ static inline void W_LoadDehackedLumps(UINT16 wadnum, boolean mainfile)
DEH_LoadDehackedLumpPwad(wadnum, lump, mainfile);
}
}
#ifdef SCANTHINGS
// Scan maps for emblems 'n shit
{
lumpinfo_t *lump_p = wadfiles[wadnum]->lumpinfo;
for (lump = 0; lump < wadfiles[wadnum]->numlumps; lump++, lump_p++)
{
const char *name = lump_p->name;
if (name[0] == 'M' && name[1] == 'A' && name[2] == 'P' && name[5]=='\0')
{
INT16 mapnum = (INT16)M_MapNumber(name[3], name[4]);
P_ScanThings(mapnum, wadnum, lump + ML_THINGS);
}
}
}
#endif
}
/** Compute MD5 message digest for bytes read from STREAM of this filname.
@ -975,6 +957,53 @@ UINT16 W_FindNextEmptyInPwad(UINT16 wad, UINT16 startlump)
return INT16_MAX;
}
// Get a map marker for WADs, and a standalone WAD file lump inside PK3s.
UINT16 W_CheckNumForMapPwad(const char *name, UINT16 wad, UINT16 startlump)
{
UINT16 i, end;
if (wadfiles[wad]->type == RET_WAD)
{
for (i = startlump; i < wadfiles[wad]->numlumps; i++)
{
// Not the name?
if (strcasecmp(name, (wadfiles[wad]->lumpinfo + i)->name))
continue;
// Not a header?
if (W_LumpLength(i | (wad << 16)) > 0)
continue;
return i;
}
}
else if (wadfiles[wad]->type == RET_PK3)
{
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 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
@ -1114,8 +1143,12 @@ UINT16 W_CheckNumForFullNamePK3(const char *name, UINT16 wad, UINT16 startlump)
//
lumpnum_t W_CheckNumForName(const char *name)
{
INT32 i;
lumpnum_t check = INT16_MAX;
UINT32 hash = quickncasehash(name, 8);
INT32 i;
if (name == NULL)
return LUMPERROR;
if (!*name) // some doofus gave us an empty string?
return LUMPERROR;
@ -1125,6 +1158,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);
@ -1140,14 +1174,18 @@ lumpnum_t W_CheckNumForName(const char *name)
break; //found it
}
if (check == INT16_MAX) return LUMPERROR;
if (check == INT16_MAX)
{
return LUMPERROR;
}
else
{
// Update the cache.
lumpnumcacheindex = (lumpnumcacheindex + 1) & (LUMPNUMCACHESIZE - 1);
memset(lumpnumcache[lumpnumcacheindex].lumpname, '\0', 32);
memset(lumpnumcache[lumpnumcacheindex].lumpname, '\0', LUMPNUMCACHENAME);
strncpy(lumpnumcache[lumpnumcacheindex].lumpname, name, 8);
lumpnumcache[lumpnumcacheindex].lumpnum = (i<<16)+check;
lumpnumcache[lumpnumcacheindex].lumpnum = (i << 16) + check;
lumpnumcache[lumpnumcacheindex].lumphash = hash;
return lumpnumcache[lumpnumcacheindex].lumpnum;
}
@ -1161,8 +1199,12 @@ lumpnum_t W_CheckNumForName(const char *name)
//
lumpnum_t W_CheckNumForLongName(const char *name)
{
INT32 i;
lumpnum_t check = INT16_MAX;
UINT32 hash = quickncasehash(name, LUMPNUMCACHENAME);
INT32 i;
if (name == NULL)
return LUMPERROR;
if (!*name) // some doofus gave us an empty string?
return LUMPERROR;
@ -1171,7 +1213,8 @@ lumpnum_t W_CheckNumForLongName(const char *name)
// most recent entries first
for (i = lumpnumcacheindex + LUMPNUMCACHESIZE; i > lumpnumcacheindex; i--)
{
if (strcmp(lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumpname, name) == 0)
if (lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumphash == hash
&& strcmp(lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumpname, name) == 0)
{
lumpnumcacheindex = i & (LUMPNUMCACHESIZE - 1);
return lumpnumcache[lumpnumcacheindex].lumpnum;
@ -1186,16 +1229,20 @@ lumpnum_t W_CheckNumForLongName(const char *name)
break; //found it
}
if (check == INT16_MAX) return LUMPERROR;
if (check == INT16_MAX)
{
return LUMPERROR;
}
else
{
if (strlen(name) < 32)
if (strlen(name) < LUMPNUMCACHENAME)
{
// Update the cache.
lumpnumcacheindex = (lumpnumcacheindex + 1) & (LUMPNUMCACHESIZE - 1);
memset(lumpnumcache[lumpnumcacheindex].lumpname, '\0', 32);
strlcpy(lumpnumcache[lumpnumcacheindex].lumpname, name, 32);
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;
@ -1204,45 +1251,50 @@ 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 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;
for (i = numwadfiles - 1; i >= 0; i--)
{
check = W_CheckNumForMapPwad(name, (UINT16)i, 0);
if (check != INT16_MAX)
break; // found it
}
if (check == INT16_MAX)
{
return LUMPERROR;
}
else
{
if (strlen(name) < 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;
}
}
//
@ -1714,6 +1766,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)
{
void *ptr, *dest;
size_t len = size;
ptr = lumpdata;
#ifndef NO_PNG_LUMPS
if (Picture_IsLumpPNG((UINT8 *)lumpdata, len))
{
ptr = Picture_PNGConvert((UINT8 *)lumpdata, PICFMT_DOOMPATCH, NULL, NULL, NULL, NULL, len, &len, 0);
}
#endif
dest = Z_Calloc(sizeof(patch_t), tag, cache);
Patch_Create(ptr, len, dest);
return dest;
}
void *W_CacheSoftwarePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag)
{
lumpcache_t *lumpcache = NULL;
@ -1726,21 +1799,13 @@ void *W_CacheSoftwarePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag)
if (!lumpcache[lump])
{
size_t len = W_LumpLengthPwad(wad, lump);
void *ptr, *dest, *lumpdata = Z_Malloc(len, PU_STATIC, NULL);
void *lumpdata = Z_Malloc(len, PU_STATIC, NULL);
// read the lump in full
W_ReadLumpHeaderPwad(wad, lump, lumpdata, 0, 0);
ptr = lumpdata;
#ifndef NO_PNG_LUMPS
if (Picture_IsLumpPNG((UINT8 *)lumpdata, len))
ptr = Picture_PNGConvert((UINT8 *)lumpdata, PICFMT_DOOMPATCH, NULL, NULL, NULL, NULL, len, &len, 0);
#endif
dest = Z_Calloc(sizeof(patch_t), tag, &lumpcache[lump]);
Patch_Create(ptr, len, dest);
Z_Free(ptr);
MakePatch(lumpdata, len, tag, &lumpcache[lump]);
Z_Free(lumpdata);
}
else
Z_ChangeTag(lumpcache[lump], tag);
@ -2206,32 +2271,56 @@ 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
{
// Count number of lumps until the end of resource OR up until next "MAPXX" lump.
// Count number of lumps until the end of resource OR up until next 0-length lump.
lumpnum_t lumppos = lumpnum + 1;
for (i = LUMPNUM(lumppos); i < wadfiles[WADFILENUM(lumpnum)]->numlumps; i++, lumppos++, numlumps++)
if (memcmp(W_CheckNameForNum(lumppos), "MAP", 3) == 0)
break;
{
if (W_LumpLength(lumppos) > 0)
continue;
break;
}
numlumps++;
vlumps = Z_Malloc(sizeof(virtlump_t)*numlumps, PU_LEVEL, NULL);
@ -2257,7 +2346,12 @@ virtres_t* vres_GetMap(lumpnum_t lumpnum)
void vres_Free(virtres_t* vres)
{
while (vres->numlumps--)
Z_Free(vres->vlumps[vres->numlumps].data);
{
if (vres->vlumps[vres->numlumps].data)
{
Z_Free(vres->vlumps[vres->numlumps].data);
}
}
Z_Free(vres->vlumps);
Z_Free(vres);
}
@ -2288,3 +2382,30 @@ 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;
patch = MakePatch(vlump->data, vlump->size, tag, NULL);
#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
}

View file

@ -92,6 +92,7 @@ typedef struct {
virtres_t* vres_GetMap(lumpnum_t);
void vres_Free(virtres_t*);
virtlump_t* vres_Find(const virtres_t*, const char*);
void* vres_GetPatch(virtlump_t *vlump, INT32 tag);
// =========================================================================
// DYNAMIC WAD LOADING
@ -154,6 +155,7 @@ const char *W_CheckNameForNum(lumpnum_t lumpnum);
UINT16 W_FindNextEmptyInPwad(UINT16 wad, UINT16 startlump); // checks only in one pwad
UINT16 W_CheckNumForMapPwad(const char *name, UINT16 wad, UINT16 startlump);
UINT16 W_CheckNumForNamePwad(const char *name, UINT16 wad, UINT16 startlump); // checks only in one pwad
UINT16 W_CheckNumForLongNamePwad(const char *name, UINT16 wad, UINT16 startlump);

View file

@ -111,7 +111,6 @@ typedef struct
char str[62];
UINT8 gtc;
const char *gts;
patch_t *pic;
boolean encore;
} y_votelvlinfo;
@ -834,8 +833,8 @@ void Y_StartIntermission(void)
//if (dedicated) return;
// This should always exist, but just in case...
if (!mapheaderinfo[prevmap])
P_AllocMapHeader(prevmap);
if (prevmap >= nummapheaders || !mapheaderinfo[prevmap])
I_Error("Y_StartIntermission: Internal map ID %d not found (nummapheaders = %d)", prevmap, nummapheaders);
switch (intertype)
{
@ -1011,7 +1010,18 @@ void Y_VoteDrawer(void)
else
{
str = levelinfo[i].str;
pic = levelinfo[i].pic;
pic = NULL;
if (mapheaderinfo[votelevels[i][0]])
{
pic = mapheaderinfo[votelevels[i][0]]->thumbnailPic;
}
if (!pic)
{
pic = blanklvl;
}
}
if (selected[i])
@ -1131,9 +1141,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)
{
@ -1492,8 +1516,6 @@ void Y_StartVote(void)
for (i = 0; i < 4; i++)
{
lumpnum_t lumpnum;
// set up the encore
levelinfo[i].encore = (votelevels[i][1] & VOTEMODIFIER_ENCORE);
votelevels[i][1] &= ~VOTEMODIFIER_ENCORE;
@ -1534,13 +1556,6 @@ void Y_StartVote(void)
levelinfo[i].gts = Gametype_Names[votelevels[i][1]];
else
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);
else
levelinfo[i].pic = W_CachePatchName("BLANKLVL", PU_STATIC);
}
voteclient.loaded = true;
@ -1561,8 +1576,6 @@ void Y_EndVote(void)
//
static void Y_UnloadVoteData(void)
{
UINT8 i;
voteclient.loaded = false;
if (rendermode != render_soft)
@ -1577,28 +1590,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
}
}
//