Merge pull request 'Add support for longmapnames' (#22) from longmapnames into ACS2

Reviewed-on: https://codeberg.org/NepDisk/blankart/pulls/22
This commit is contained in:
NepDisk 2025-02-17 22:38:05 +00:00
commit dcb3570475
57 changed files with 2249 additions and 2199 deletions

View file

@ -42,7 +42,7 @@ additional lumps:
BEHAVIOR = Compiled ACS code.
ZNODES = Compiled extended / GL friendly nodes. These are required.
PICTURE = A Doom graphic lump, expected to be 160x100. Intended to be a
PICTURE = A Doom graphic lump, expected to be 320x240 or 160x100. Intended to be a
screenshot of the map itself. This is used by the game for level
select menus.
MINIMAP = A Doom graphic lump, expected to be 100x100. Intended to be a

View file

@ -3054,7 +3054,7 @@ bool CallFunc_MapWarp(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Wor
const char *levelName = NULL;
size_t levelLen = 0;
UINT16 nextmap = NUMMAPS;
UINT16 nextmap = NEXTMAP_INVALID;
(void)argC;
@ -3075,13 +3075,10 @@ bool CallFunc_MapWarp(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Wor
{
CONS_Alert(CONS_WARNING, "MapWarp level name was not provided.\n");
}
if (levelName[0] == 'M' && levelName[1] == 'A' && levelName[2] == 'P' && levelName[5]=='\0')
{
levelName = va("MAP%d",M_MapNumber(levelName[3], levelName[4]));
}
if (nextmap >= NUMMAPS)
nextmap = G_MapNumber(levelName);
if (nextmap == NEXTMAP_INVALID)
{
CONS_Alert(CONS_WARNING, "MapWarp level %s is not valid or loaded.\n", levelName);
return false;

View file

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

View file

@ -909,6 +909,9 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime)
UINT8 *p;
size_t mirror_length;
const char *httpurl = cv_httpsource.string;
UINT8 prefgametype = (cv_kartgametypepreference.value == -1)
? gametype
: cv_kartgametypepreference.value;
netbuffer->packettype = PT_SERVERINFO;
netbuffer->u.serverinfo._255 = 255;
@ -933,7 +936,7 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime)
else
netbuffer->u.serverinfo.refusereason = 0;
strncpy(netbuffer->u.serverinfo.gametypename, Gametype_Names[gametype],
strncpy(netbuffer->u.serverinfo.gametypename, Gametype_Names[prefgametype],
sizeof netbuffer->u.serverinfo.gametypename);
netbuffer->u.serverinfo.modifiedgame = (UINT8)modifiedgame;
netbuffer->u.serverinfo.cheatsenabled = CV_CheatsEnabled();
@ -945,7 +948,6 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime)
CopyCaretColors(netbuffer->u.serverinfo.servername, cv_servername.string,
MAXSERVERNAME);
strncpy(netbuffer->u.serverinfo.mapname, G_BuildMapName(gamemap), 7);
M_Memcpy(netbuffer->u.serverinfo.mapmd5, mapmd5, 16);
@ -1158,35 +1160,32 @@ static boolean SV_ResendingSavegameToAnyone(void)
static void SV_SendSaveGame(INT32 node, boolean resending)
{
size_t length, compressedlen;
savebuffer_t save;
savebuffer_t save = {0};
UINT8 *compressedsave;
UINT8 *buffertosend;
// first save it in a malloced buffer
save.size = NETSAVEGAMESIZE;
save.buffer = (UINT8 *)malloc(save.size);
if (!save.buffer)
if (P_SaveBufferAlloc(&save, NETSAVEGAMESIZE) == false)
{
CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n"));
return;
}
// Leave room for the uncompressed length.
save.p = save.buffer + sizeof(UINT32);
save.end = save.buffer + save.size;
save.p += sizeof(UINT32);
P_SaveNetGame(&save, resending);
length = save.p - save.buffer;
if (length > NETSAVEGAMESIZE)
{
free(save.buffer);
P_SaveBufferFree(&save);
I_Error("Savegame buffer overrun");
}
// Allocate space for compressed save: one byte fewer than for the
// uncompressed data to ensure that the compression is worthwhile.
compressedsave = malloc(length - 1);
compressedsave = Z_Malloc(length - 1, PU_STATIC, NULL);
if (!compressedsave)
{
CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n"));
@ -1197,7 +1196,7 @@ static void SV_SendSaveGame(INT32 node, boolean resending)
if ((compressedlen = lzf_compress(save.buffer + sizeof(UINT32), length - sizeof(UINT32), compressedsave + sizeof(UINT32), length - sizeof(UINT32) - 1)))
{
// Compressing succeeded; send compressed data
free(save.buffer);
P_SaveBufferFree(&save);
// State that we're compressed.
buffertosend = compressedsave;
@ -1207,14 +1206,14 @@ static void SV_SendSaveGame(INT32 node, boolean resending)
else
{
// Compression failed to make it smaller; send original
free(compressedsave);
Z_Free(compressedsave);
// State that we're not compressed
buffertosend = save.buffer;
WRITEUINT32(save.buffer, 0);
}
AddRamToSendQueue(node, buffertosend, length, SF_RAM, 0);
AddRamToSendQueue(node, buffertosend, length, SF_Z_RAM, 0);
// Remember when we started sending the savegame so we can handle timeouts
sendingsavegame[node] = true;
@ -1228,7 +1227,7 @@ static consvar_t cv_dumpconsistency = CVAR_INIT ("dumpconsistency", "Off", CV_SA
static void SV_SavedGame(void)
{
size_t length;
savebuffer_t save;
savebuffer_t save = {0};
char tmpsave[256];
if (!cv_dumpconsistency.value)
@ -1237,22 +1236,18 @@ static void SV_SavedGame(void)
sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home);
// first save it in a malloced buffer
save.size = NETSAVEGAMESIZE;
save.p = save.buffer = (UINT8 *)malloc(save.size);
if (!save.p)
if (P_SaveBufferAlloc(&save, NETSAVEGAMESIZE) == false)
{
CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n"));
return;
}
save.end = save.buffer + save.size;
P_SaveNetGame(&save, false);
length = save.p - save.buffer;
if (length > NETSAVEGAMESIZE)
{
free(save.buffer);
P_SaveBufferFree(&save);
I_Error("Savegame buffer overrun");
}
@ -1260,7 +1255,7 @@ static void SV_SavedGame(void)
if (!FIL_WriteFile(tmpsave, save.buffer, length))
CONS_Printf(M_GetText("Didn't save %s for netgame"), tmpsave);
free(save.buffer);
P_SaveBufferFree(&save);
}
#undef TMPSAVENAME
@ -1270,37 +1265,31 @@ static void SV_SavedGame(void)
static void CL_LoadReceivedSavegame(boolean reloading)
{
savebuffer_t save;
savebuffer_t save = {0};
size_t length, decompressedlen;
char tmpsave[256];
sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home);
length = FIL_ReadFile(tmpsave, &save.buffer);
CONS_Printf(M_GetText("Loading savegame length %s\n"), sizeu1(length));
if (!length)
if (P_SaveBufferFromFile(&save, tmpsave) == false)
{
I_Error("Can't read savegame sent");
return;
}
save.p = save.buffer;
save.size = length;
save.end = save.buffer + save.size;
length = save.size;
CONS_Printf(M_GetText("Loading savegame length %s\n"), sizeu1(length));
// Decompress saved game if necessary.
decompressedlen = READUINT32(save.p);
if(decompressedlen > 0)
if (decompressedlen > 0)
{
UINT8 *decompressedbuffer = Z_Malloc(decompressedlen, PU_STATIC, NULL);
lzf_decompress(save.p, length - sizeof(UINT32), decompressedbuffer, decompressedlen);
Z_Free(save.buffer);
save.p = save.buffer = decompressedbuffer;
save.size = decompressedlen;
save.end = save.buffer + decompressedlen;
P_SaveBufferFree(&save);
P_SaveBufferFromExisting(&save, decompressedbuffer, decompressedlen);
}
paused = false;
@ -1332,10 +1321,13 @@ static void CL_LoadReceivedSavegame(boolean reloading)
}
// done
Z_Free(save.buffer);
save.p = NULL;
P_SaveBufferFree(&save);
if (unlink(tmpsave) == -1)
{
CONS_Alert(CONS_ERROR, M_GetText("Can't delete %s\n"), tmpsave);
}
consistancy[gametic%BACKUPTICS] = Consistancy();
CON_ToggleOff();
@ -6134,7 +6126,7 @@ void CL_ClearRewinds(void)
rewind_t *CL_SaveRewindPoint(size_t demopos)
{
savebuffer_t save;
savebuffer_t save = {0};
rewind_t *rewind;
if (rewindhead && rewindhead->leveltime + REWIND_POINT_INTERVAL > leveltime)
@ -6144,10 +6136,7 @@ rewind_t *CL_SaveRewindPoint(size_t demopos)
if (!rewind)
return NULL;
save.buffer = save.p = rewind->savebuffer;
save.size = NETSAVEGAMESIZE;
save.end = save.buffer + save.size;
P_SaveBufferFromExisting(&save, rewind->savebuffer, NETSAVEGAMESIZE);
P_SaveNetGame(&save, false);
rewind->leveltime = leveltime;
@ -6160,7 +6149,7 @@ rewind_t *CL_SaveRewindPoint(size_t demopos)
rewind_t *CL_RewindToTime(tic_t time)
{
savebuffer_t save;
savebuffer_t save = {0};
rewind_t *rewind;
while (rewindhead && rewindhead->leveltime > time)
@ -6173,10 +6162,7 @@ rewind_t *CL_RewindToTime(tic_t time)
if (!rewindhead)
return NULL;
save.buffer = save.p = rewindhead->savebuffer;
save.size = NETSAVEGAMESIZE;
save.end = save.buffer + save.size;
P_SaveBufferFromExisting(&save, rewindhead->savebuffer, NETSAVEGAMESIZE);
P_LoadNetGame(&save, false);
wipegamestate = gamestate; // No fading back in!

View file

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

View file

@ -347,7 +347,7 @@ static bool D_Display(void)
if (gamestate != GS_LEVEL && rendermode != render_none)
{
V_SetPaletteLump("PLAYPAL"); // Reset the palette
R_ReInitColormaps(0, LUMPERROR);
R_ReInitColormaps(0, NULL, 0, false);
}
F_WipeStartScreen();
@ -986,13 +986,12 @@ void D_StartTitle(void)
if (server)
{
char mapname[6];
i = G_GetFirstMapOfGametype(gametype)+1;
strlcpy(mapname, G_BuildMapName(spstage_start), sizeof (mapname));
strlwr(mapname);
mapname[5] = '\0';
if (i > nummapheaders)
I_Error("D_StartTitle: No valid map ID found!?");
COM_BufAddText(va("map %s\n", mapname));
COM_BufAddText(va("map %s\n", G_BuildMapName(i)));
}
return;
@ -1247,11 +1246,6 @@ D_ConvertVersionNumbers (void)
//
void D_SRB2Main(void)
{
INT32 i;
UINT16 wadnum;
lumpinfo_t *lumpinfo;
char *name;
INT32 p;
INT32 pstartmap = 0;
@ -1512,31 +1506,7 @@ void D_SRB2Main(void)
// conversion sometimes needs the palette
V_ReloadPalette();
//
// search for maps
//
for (wadnum = 0; wadnum <= mainwads; wadnum++)
{
lumpinfo = wadfiles[wadnum]->lumpinfo;
for (i = 0; i < wadfiles[wadnum]->numlumps; i++, lumpinfo++)
{
name = lumpinfo->name;
if (name[0] == 'M' && name[1] == 'A' && name[2] == 'P') // Ignore the headers
{
INT16 num;
if (name[5] != '\0')
continue;
num = (INT16)M_MapNumber(name[3], name[4]);
// we want to record whether this map exists. if it doesn't have a header, we can assume it's not relephant
if (num <= NUMMAPS && mapheaderinfo[num - 1])
{
mapheaderinfo[num - 1]->alreadyExists = true;
}
}
}
}
P_InitMapData(false);
CON_SetLoadingProgress(LOADED_IWAD);
@ -1595,39 +1565,7 @@ void D_SRB2Main(void)
//
// search for pwad maps
//
//
// search for maps... again.
//
for (wadnum = mainwads+1; wadnum < numwadfiles; wadnum++)
{
lumpinfo = wadfiles[wadnum]->lumpinfo;
for (i = 0; i < wadfiles[wadnum]->numlumps; i++, lumpinfo++)
{
name = lumpinfo->name;
if (name[0] == 'M' && name[1] == 'A' && name[2] == 'P') // Ignore the headers
{
INT16 num;
if (name[5] != '\0')
continue;
num = (INT16)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(true);
HU_LoadGraphics();
}
@ -1730,33 +1668,41 @@ void D_SRB2Main(void)
{
const char *word = M_GetNextParm();
pstartmap = G_FindMapByNameOrCode(word, 0);
if (! pstartmap)
I_Error("Cannot find a map remotely named '%s'\n", word);
if (WADNAMECHECK(word))
{
if (!(pstartmap = wadnamemap))
I_Error("Bad '%s' level warp.\n"
#if defined (_WIN32)
"Are you using MSDOS 8.3 filenames in Zone Builder?\n"
#endif
, word);
}
else
{
if (!M_CheckParm("-server") && !M_CheckParm("-dedicated") && !M_CheckParm("-nograndprix"))
{
G_SetGameModified(true, true);
// Start up a "minor" grand prix session
memset(&grandprixinfo, 0, sizeof(struct grandprixinfo));
grandprixinfo.gamespeed = KARTSPEED_NORMAL;
grandprixinfo.encore = false;
grandprixinfo.masterbots = false;
grandprixinfo.gp = true;
grandprixinfo.roundnum = 0;
grandprixinfo.cup = NULL;
grandprixinfo.wonround = false;
grandprixinfo.initalize = true;
}
autostart = true;
if (!(pstartmap = G_FindMapByNameOrCode(word, 0)))
I_Error("Cannot find a map remotely named '%s'\n", word);
}
if (!M_CheckParm("-server") && !M_CheckParm("-dedicated") && !M_CheckParm("-nograndprix"))
{
G_SetGameModified(true, true);
// Start up a "minor" grand prix session
memset(&grandprixinfo, 0, sizeof(struct grandprixinfo));
grandprixinfo.gamespeed = KARTSPEED_NORMAL;
grandprixinfo.encore = false;
grandprixinfo.masterbots = false;
grandprixinfo.gp = true;
grandprixinfo.roundnum = 0;
grandprixinfo.cup = NULL;
grandprixinfo.wonround = false;
grandprixinfo.initalize = true;
}
autostart = true;
}
// Set up splitscreen players before joining!
@ -1847,14 +1793,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;
}
if (autostart || netgame)
@ -1947,14 +1893,11 @@ void D_SRB2Main(void)
if (server && !M_CheckParm("+map"))
{
// Prevent warping to nonexistent levels
if (W_CheckNumForName(G_BuildMapName(pstartmap)) == LUMPERROR)
I_Error("Could not warp to %s (map not found)\n", G_BuildMapName(pstartmap));
// Prevent warping to locked levels
// ... unless you're in a dedicated server. Yes, technically this means you can view any level by
// running a dedicated server and joining it yourself, but that's better than making dedicated server's
// lives hell.
else if (!dedicated && M_MapLocked(pstartmap))
if (!dedicated && M_MapLocked(pstartmap))
I_Error("You need to unlock this level before you can warp to it!\n");
else
{

View file

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

View file

@ -399,6 +399,8 @@ static CV_PossibleValue_t kartencore_cons_t[] = {{-1, "Auto"}, {0, "Off"}, {1, "
consvar_t cv_kartencore = CVAR_INIT ("kartencore", "Auto", CV_NETVAR|CV_CALL|CV_NOINIT, kartencore_cons_t, KartEncore_OnChange);
static CV_PossibleValue_t kartvoterulechanges_cons_t[] = {{0, "Never"}, {1, "Sometimes"}, {2, "Frequent"}, {3, "Always"}, {0, NULL}};
consvar_t cv_kartvoterulechanges = CVAR_INIT ("kartvoterulechanges", "Frequent", CV_NETVAR, kartvoterulechanges_cons_t, NULL);
static CV_PossibleValue_t kartgametypepreference_cons_t[] = {{-1, "None"}, {GT_RACE, "Race"}, {GT_BATTLE, "Battle"}, {0, NULL}};
consvar_t cv_kartgametypepreference = CVAR_INIT ("kartgametypepreference", "None", CV_NETVAR, kartgametypepreference_cons_t, NULL);
static CV_PossibleValue_t kartspeedometer_cons_t[] = {{0, "Off"}, {1, "Kilometers"}, {2, "Miles"}, {3, "Fracunits"}, {4, "Percentage"}, {0, NULL}};
consvar_t cv_kartspeedometer = CVAR_INIT ("kartdisplayspeed", "Percentage", CV_SAVE, kartspeedometer_cons_t, NULL); // use tics in display
static CV_PossibleValue_t kartvoices_cons_t[] = {{0, "Never"}, {1, "Tasteful"}, {2, "Meme"}, {0, NULL}};
@ -840,6 +842,7 @@ void D_RegisterServerCommands(void)
CV_RegisterVar(&cv_recordmultiplayerdemos);
CV_RegisterVar(&cv_netdemosyncquality);
CV_RegisterVar(&cv_netdemosize);
CV_RegisterVar(&cv_shoutname);
CV_RegisterVar(&cv_shoutcolor);
@ -1425,7 +1428,7 @@ UINT8 CanChangeSkin(INT32 playernum)
return true;
// Force skin in effect.
if ((cv_forceskin.value != -1) || (mapheaderinfo[gamemap-1] && mapheaderinfo[gamemap-1]->forcecharacter[0] != '\0'))
if (cv_forceskin.value != -1)
return false;
// Can change skin in intermission and whatnot.
@ -2603,8 +2606,7 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pencoremode, boolean r
if (delay != 2)
{
UINT8 flags = 0;
const char *mapname = G_BuildMapName(mapnum);
I_Assert(W_CheckNumForName(mapname) != LUMPERROR);
//I_Assert(W_CheckNumForName(mapname) != LUMPERROR);
buf_p = buf;
if (pencoremode)
flags |= 1;
@ -2619,7 +2621,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)
@ -2650,27 +2652,28 @@ void D_SetupVote(void)
UINT8 buf[5*2]; // four UINT16 maps (at twice the width of a UINT8), and two gametypes
UINT8 *p = buf;
INT32 i;
UINT8 secondgt = G_SometimesGetDifferentGametype();
UINT8 gt = (cv_kartgametypepreference.value == -1) ? gametype : cv_kartgametypepreference.value;
UINT8 secondgt = G_SometimesGetDifferentGametype(gt);
INT16 votebuffer[4] = {-1,-1,-1,0};
if ((cv_kartencore.value == 1) && (gametyperules & GTR_CIRCUIT))
WRITEUINT8(p, (gametype|0x80));
if ((cv_kartencore.value == 1) && (gametypedefaultrules[gt] & GTR_CIRCUIT))
WRITEUINT8(p, (gt|VOTEMODIFIER_ENCORE));
else
WRITEUINT8(p, gametype);
WRITEUINT8(p, gt);
WRITEUINT8(p, secondgt);
secondgt &= ~0x80;
secondgt &= ~VOTEMODIFIER_ENCORE;
for (i = 0; i < 4; i++)
{
UINT16 m;
if (i == 2) // sometimes a different gametype
m = G_RandMap(G_TOLFlag(secondgt), prevmap, ((secondgt != gametype) ? 2 : 0), 0, true, votebuffer);
else if (i >= 3) // unknown-random and force-unknown MAP HELL
m = G_RandMap(G_TOLFlag(gametype), prevmap, 0, (i-2), (i < 4), votebuffer);
else if (i >= 3) // unknown-random and formerly force-unknown MAP HELL
m = G_RandMap(G_TOLFlag(gt), prevmap, 0, (i-2), (i < 4), votebuffer);
else
m = G_RandMap(G_TOLFlag(gametype), prevmap, 0, 0, true, votebuffer);
m = G_RandMap(G_TOLFlag(gt), prevmap, 0, 0, true, votebuffer);
if (i < 3)
votebuffer[i] = m; // min() is a dumb workaround for gcc 4.4 array-bounds error
votebuffer[i] = m;
WRITEUINT16(p, m);
}
@ -3075,11 +3078,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;
@ -3116,7 +3119,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));
@ -3124,7 +3127,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"));
}
@ -3140,7 +3143,11 @@ 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);
// clear this demo before recording a new one
if (demo.recording && !modeattacking)
G_CheckDemoStatus();
G_InitNew(pencoremode, mapnumber, resetplayer, skipprecutscene, FLS);
if (demo.playback && !demo.timing)
precache = true;
if (demo.timing)
@ -5380,8 +5387,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)
@ -5392,14 +5400,43 @@ static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum)
gt = (UINT8)READUINT8(*cp);
secondgt = (UINT8)READUINT8(*cp);
for (i = 0; i < 4; i++)
// Strip illegal Encore flag.
if ((gt & VOTEMODIFIER_ENCORE)
&& !(gametypedefaultrules[(gt & ~VOTEMODIFIER_ENCORE)] & GTR_CIRCUIT))
{
votelevels[i][0] = (UINT16)READUINT16(*cp);
votelevels[i][1] = gt;
if (!mapheaderinfo[votelevels[i][0]])
P_AllocMapHeader(votelevels[i][0]);
gt &= ~VOTEMODIFIER_ENCORE;
}
for (i = 0; i < 4; i++)
{
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;
}
tempvotelevels[2][1] = secondgt;
memcpy(votelevels, tempvotelevels, sizeof(votelevels));
// If third entry has an illelegal Encore flag... (illelegal!?)
if ((secondgt & VOTEMODIFIER_ENCORE)
&& !(gametypedefaultrules[(secondgt & ~VOTEMODIFIER_ENCORE)] & GTR_CIRCUIT))
{
secondgt &= ~VOTEMODIFIER_ENCORE;
// Apply it to the second entry instead, gametype permitting!
if (gametypedefaultrules[gt] & GTR_CIRCUIT)
{
votelevels[1][1] |= VOTEMODIFIER_ENCORE;
}
}
// Finally, set third entry's gametype/Encore status.
votelevels[2][1] = secondgt;
G_SetGamestate(GS_VOTING);
@ -5817,7 +5854,7 @@ static void Command_Togglemodified_f(void)
static void Command_Archivetest_f(void)
{
savebuffer_t save;
savebuffer_t save = {0};
UINT32 i, wrote;
thinker_t *th;
if (gamestate != GS_LEVEL)
@ -5833,9 +5870,11 @@ static void Command_Archivetest_f(void)
((mobj_t *)th)->mobjnum = i++;
// allocate buffer
save.size = 1024;
save.buffer = save.p = ZZ_Alloc(save.size);
save.end = save.buffer + save.size;
if (P_SaveBufferAlloc(&save, 1024) == false)
{
CONS_Printf("Unable to allocate buffer.\n");
return;
}
// test archive
CONS_Printf("LUA_Archive...\n");
@ -5853,10 +5892,12 @@ static void Command_Archivetest_f(void)
LUA_UnArchive(&save, true);
i = READUINT8(save.p);
if (i != 0x7F || wrote != (UINT32)(save.p - save.buffer))
{
CONS_Printf("Savegame corrupted. (write %u, read %u)\n", wrote, (UINT32)(save.p - save.buffer));
}
// free buffer
Z_Free(save.buffer);
P_SaveBufferFree(&save);
CONS_Printf("Done. No crash.\n");
}
#endif

View file

@ -84,6 +84,7 @@ extern consvar_t cv_kartfrantic;
extern consvar_t cv_kartcomeback;
extern consvar_t cv_kartencore;
extern consvar_t cv_kartvoterulechanges;
extern consvar_t cv_kartgametypepreference;
extern consvar_t cv_kartspeedometer;
extern consvar_t cv_kartvoices;
extern consvar_t cv_kartbot;

View file

@ -621,18 +621,6 @@ static int ScanConstants(lua_State *L, boolean mathlib, const char *word)
}
return luaL_error(L, "skincolor '%s' could not be found.\n", word);
}
else if (fastncmp("GRADE_",word,6))
{
p = word+6;
for (i = 0; NIGHTSGRADE_LIST[i]; i++)
if (*p == NIGHTSGRADE_LIST[i])
{
CacheAndPushConstant(L, word, i);
return 1;
}
if (mathlib) return luaL_error(L, "NiGHTS grade '%s' could not be found.\n", word);
return 0;
}
else if (fastncmp("MN_",word,3)) {
p = word+3;
for (i = 0; i < NUMMENUTYPES; i++)

View file

@ -142,28 +142,53 @@ 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;
if (strcmp(mapheaderinfo[nummapheaders]->lumpname, tutorialmap) == 0) // Sal: Is this needed...?
continue;
// Custom map header info
// (no need to set num to 0, we're freeing the entire header shortly)
Z_Free(mapheaderinfo[i]->customopts);
Z_Free(mapheaderinfo[nummapheaders]->customopts);
P_DeleteFlickies(i);
P_DeleteGrades(i);
P_DeleteFlickies(nummapheaders);
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
}
static boolean findFreeSlot(INT32 *num)
@ -1048,27 +1073,44 @@ static mapheader_lighting_t *usemaplighting(INT32 mapnum, const char *word)
{
if (fastncmp(word, "ENCORE", 6))
{
mapheaderinfo[mapnum-1]->use_encore_lighting = true;
mapheaderinfo[mapnum]->use_encore_lighting = true;
return &mapheaderinfo[mapnum-1]->lighting_encore;
return &mapheaderinfo[mapnum]->lighting_encore;
}
else
{
return &mapheaderinfo[mapnum-1]->lighting;
return &mapheaderinfo[mapnum]->lighting;
}
}
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);
mapheaderinfo[num]->lumpnamehash = quickncasehash(mapheaderinfo[num]->lumpname, MAXMAPLUMPNAME);
}
do
{
@ -1106,16 +1148,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;
}
@ -1137,19 +1178,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';
@ -1165,33 +1206,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;
@ -1205,7 +1246,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!
{
@ -1218,17 +1259,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);
@ -1238,64 +1279,32 @@ 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 < 20) // 0 for no act number, TTL1 through TTL19
mapheaderinfo[num-1]->actnum = (UINT8)i;
mapheaderinfo[num]->actnum = (UINT8)i;
else
deh_warning("Level header %d: invalid act number %d", num, i);*/
deh_strlcpy(mapheaderinfo[num-1]->actnum, word2,
sizeof(mapheaderinfo[num-1]->actnum), va("Level header %d: actnum", num));
}
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;
deh_strlcpy(mapheaderinfo[num]->actnum, word2,
sizeof(mapheaderinfo[num]->actnum), va("Level header %d: actnum", num));
}
else if (fastcmp(word, "TYPEOFLEVEL"))
{
if (i) // it's just a number
mapheaderinfo[num-1]->typeoflevel = (UINT32)i;
mapheaderinfo[num]->typeoflevel = (UINT32)i;
else
{
UINT32 tol = 0;
@ -1308,20 +1317,20 @@ 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] = 0; // becomes empty string
mapheaderinfo[num-1]->musname_size = 0;
mapheaderinfo[num]->musname[0][0] = 0; // becomes empty string
mapheaderinfo[num]->musname_size = 0;
}
else
{
@ -1330,71 +1339,66 @@ void readlevelheader(MYFILE *f, INT32 num)
do {
if (j >= MAXMUSNAMES)
break;
deh_strlcpy(mapheaderinfo[num-1]->musname[j], tmp,
sizeof(mapheaderinfo[num-1]->musname[j]), va("Level header %d: music", num));
deh_strlcpy(mapheaderinfo[num]->musname[j], tmp,
sizeof(mapheaderinfo[num]->musname[j]), va("Level header %d: music", num));
j++;
} while ((tmp = strtok(NULL,",")) != NULL);
if (tmp != NULL)
deh_warning("Level header %d: additional music slots past %d discarded", num, MAXMUSNAMES);
mapheaderinfo[num-1]->musname_size = j;
mapheaderinfo[num]->musname_size = j;
}
}
else if (fastcmp(word, "MUSICSLOT"))
deh_warning("Level header %d: MusicSlot parameter is deprecated and will be removed.\nUse \"Music\" instead.", num);
else if (fastcmp(word, "MUSICTRACK"))
mapheaderinfo[num-1]->mustrack = ((UINT16)i - 1);
mapheaderinfo[num]->mustrack = ((UINT16)i - 1);
else if (fastcmp(word, "MUSICPOS"))
mapheaderinfo[num-1]->muspos = (UINT32)get_number(word2);
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, "SKYNUM"))
deh_strlcpy(mapheaderinfo[num-1]->skytexture, va("SKY%s", word2),
sizeof(mapheaderinfo[num-1]->skytexture), va("Level header %d: sky texture", num));
deh_strlcpy(mapheaderinfo[num]->skytexture, va("SKY%s", word2),
sizeof(mapheaderinfo[num]->skytexture), va("Level header %d: sky texture", num));
else if (fastcmp(word, "PRECUTSCENENUM"))
mapheaderinfo[num-1]->precutscenenum = (UINT8)i;
mapheaderinfo[num]->precutscenenum = (UINT8)i;
else if (fastcmp(word, "CUTSCENENUM"))
mapheaderinfo[num-1]->cutscenenum = (UINT8)i;
mapheaderinfo[num]->cutscenenum = (UINT8)i;
else if (fastcmp(word, "PALETTE"))
mapheaderinfo[num-1]->palette = (UINT16)i;
mapheaderinfo[num]->palette = (UINT16)i;
else if (fastcmp(word, "ENCOREPAL"))
mapheaderinfo[num-1]->encorepal = (UINT16)i;
mapheaderinfo[num]->encorepal = (UINT16)i;
else if (fastcmp(word, "NUMLAPS"))
mapheaderinfo[num-1]->numlaps = (UINT8)i;
mapheaderinfo[num]->numlaps = (UINT8)i;
else if (fastcmp(word, "UNLOCKABLE"))
{
if (i >= 0 && i <= MAXUNLOCKABLES) // 0 for no unlock required, anything else requires something
mapheaderinfo[num-1]->unlockrequired = (SINT8)i - 1;
mapheaderinfo[num]->unlockrequired = (SINT8)i - 1;
else
deh_warning("Level header %d: invalid unlockable number %d", num, i);
}
else if (fastcmp(word, "LEVELSELECT"))
mapheaderinfo[num-1]->levelselect = (UINT8)i;
mapheaderinfo[num]->levelselect = (UINT8)i;
else if (fastcmp(word, "SKYBOXSCALE"))
mapheaderinfo[num-1]->skybox_scalex = mapheaderinfo[num-1]->skybox_scaley = mapheaderinfo[num-1]->skybox_scalez = (INT16)i;
mapheaderinfo[num]->skybox_scalex = mapheaderinfo[num]->skybox_scaley = mapheaderinfo[num]->skybox_scalez = (INT16)i;
else if (fastcmp(word, "SKYBOXSCALEX"))
mapheaderinfo[num-1]->skybox_scalex = (INT16)i;
mapheaderinfo[num]->skybox_scalex = (INT16)i;
else if (fastcmp(word, "SKYBOXSCALEY"))
mapheaderinfo[num-1]->skybox_scaley = (INT16)i;
mapheaderinfo[num]->skybox_scaley = (INT16)i;
else if (fastcmp(word, "SKYBOXSCALEZ"))
mapheaderinfo[num-1]->skybox_scalez = (INT16)i;
mapheaderinfo[num]->skybox_scalez = (INT16)i;
else if (fastcmp(word, "LEVELFLAGS"))
mapheaderinfo[num-1]->levelflags = get_number(word2);
mapheaderinfo[num]->levelflags = get_number(word2);
else if (fastcmp(word, "MENUFLAGS"))
mapheaderinfo[num-1]->menuflags = get_number(word2);
mapheaderinfo[num]->menuflags = get_number(word2);
// SRB2Kart
else if (fastcmp(word, "MOBJSCALE"))
mapheaderinfo[num-1]->mobj_scale = get_number(word2);
mapheaderinfo[num]->mobj_scale = get_number(word2);
else if (fastcmp(word, "DEFAULTWAYPOINTRADIUS"))
mapheaderinfo[num-1]->default_waypoint_radius = get_number(word2);
mapheaderinfo[num]->default_waypoint_radius = get_number(word2);
else if (fastcmp(word, "LIGHTCONTRAST"))
{
usemaplighting(num, word)->light_contrast = (UINT8)i;
@ -1422,77 +1426,80 @@ void readlevelheader(MYFILE *f, INT32 num)
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, "NOVISITNEEDED"))
{
if (i || word2[0] == 'T' || word2[0] == 'Y')
mapheaderinfo[num-1]->menuflags &= ~LF2_VISITNEEDED;
mapheaderinfo[num]->menuflags &= ~LF2_VISITNEEDED;
else
mapheaderinfo[num-1]->menuflags |= LF2_VISITNEEDED;
mapheaderinfo[num]->menuflags |= LF2_VISITNEEDED;
}
else if (fastcmp(word, "GRAVITY"))
mapheaderinfo[num-1]->gravity = FLOAT_TO_FIXED(atof(word2));
mapheaderinfo[num]->gravity = FLOAT_TO_FIXED(atof(word2));
else if (fastcmp(word, "WALLTRANSFER") || fastcmp(word, "WALLRUNNING"))
{
if (i || word2[0] == 'T' || word2[0] == 'Y')
mapheaderinfo[num-1]->use_walltransfer = true;
mapheaderinfo[num]->use_walltransfer = true;
else
mapheaderinfo[num-1]->use_walltransfer = false;
mapheaderinfo[num]->use_walltransfer = false;
}
// ignored for compatibility
else if (fastcmp(word, "NEXTLEVEL") || fastcmp(word, "TIMEATTACK") || fastcmp(word, "RECORDATTACK"))
continue;
else
deh_warning("Level header %d: unknown word '%s'", num, word);
}
@ -2555,16 +2562,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"))
{
@ -2785,14 +2785,8 @@ void readunlockable(MYFILE *f, INT32 num)
}
else if (fastcmp(word, "VAR"))
{
// Support using the actual map name,
// i.e., Level AB, Level FZ, etc.
// Convert to map number
if (word2[0] >= 'A' && word2[0] <= 'Z')
i = M_MapNumber(word2[0], word2[1]);
unlockables[num].variable = (INT16)i;
// TODO: different field for level name string
unlockables[num].variable = (INT16)G_MapNumber(word2);
}
else
deh_warning("Unlockable %d: unknown word '%s'", num+1, word);
@ -2830,7 +2824,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;
}
@ -2850,7 +2844,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;
}
}
@ -2870,16 +2864,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;
}
}
@ -2888,16 +2877,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;
}
}
@ -2910,7 +2894,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;
}
}
@ -2928,7 +2912,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;
}
}
@ -2940,7 +2924,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;
}
}
@ -2952,13 +2936,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;
}
@ -3093,61 +3077,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);
@ -3230,16 +3159,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"))
@ -3365,30 +3285,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);
@ -3600,7 +3502,16 @@ void readcupheader(MYFILE *f, cupheader_t *cup)
i = atoi(word2); // used for numerical settings
strupr(word2);
if (fastcmp(word, "ICON"))
if (fastcmp(word, "MONITOR"))
{
if (i > 0 && i < 10)
cup->monitor = i;
else if (!word2[0] || word2[1] != '\0' || word2[0] == '0')
deh_warning("%s Cup: Invalid monitor type \"%s\" (should be 1-9 or A-Z)\n", cup->name, word2);
else
cup->monitor = (word2[0] - 'A') + 10;
}
else if (fastcmp(word, "ICON"))
{
deh_strlcpy(cup->icon, word2,
sizeof(cup->icon), va("%s Cup: icon", cup->name));
@ -3611,37 +3522,26 @@ 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);
cup->cachedlevels[CUPCACHE_BONUS] = NEXTMAP_INVALID;
}
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);
cup->cachedlevels[CUPCACHE_SPECIAL] = NEXTMAP_INVALID;
}
else if (fastcmp(word, "EMERALDNUM"))
{
@ -4374,19 +4274,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

@ -73,7 +73,7 @@ void readhuditem(MYFILE *f, INT32 num);
void readmenu(MYFILE *f, INT32 num);
void readtextprompt(MYFILE *f, INT32 num);
void readcutscene(MYFILE *f, INT32 num);
void readlevelheader(MYFILE *f, INT32 num);
void readlevelheader(MYFILE *f, char * name);
void readgametype(MYFILE *f, char *gtname);
void readsprite2(MYFILE *f, INT32 num);
#ifdef HWRENDER

View file

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

View file

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

View file

@ -368,25 +368,19 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
#endif
else if (fastcmp(word, "LEVEL"))
{
// Support using the actual map name,
// i.e., Level AB, Level FZ, etc.
// Convert to map number
if (word2[0] >= 'A' && word2[0] <= 'Z')
i = M_MapNumber(word2[0], word2[1]);
if (i > 0 && i <= NUMMAPS)
size_t len = strlen(word2);
if (len <= MAXMAPLUMPNAME-1)
{
if (mapheaderinfo[i])
{
G_SetGameModified(multiplayer, true); // Only a major mod if editing stuff that isn't your own!
}
readlevelheader(f, i);
if (len == 1)
readlevelheader(f, va("MAP0%s",word2));
else if (len == 2)
readlevelheader(f, va("MAP%s",word2));
else
readlevelheader(f, word2);
}
else
{
deh_warning("Level number %d out of range (1 - %d)", i, NUMMAPS);
deh_warning("Map header's lumpname %s is too long (%s characters VS %d max)", word2, sizeu1(len), (MAXMAPLUMPNAME-1));
ignorelines(f);
}
}
@ -519,38 +513,51 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
//
else if (fastcmp(word, "CUP"))
{
cupheader_t *cup = kartcupheaders;
cupheader_t *prev = NULL;
while (cup)
size_t len = strlen(word2);
if (len <= MAXCUPNAME-1)
{
if (fastcmp(cup->name, word2))
cupheader_t *cup = kartcupheaders;
cupheader_t *prev = NULL;
UINT32 hash = quickncasehash(word2, MAXCUPNAME);
while (cup)
{
// Only a major mod if editing stuff that isn't your own!
G_SetGameModified(multiplayer, true);
break;
if (hash == cup->namehash && fastcmp(cup->name, word2))
{
// Only a major mod if editing stuff that isn't your own!
G_SetGameModified(multiplayer, true);
break;
}
prev = cup;
cup = cup->next;
}
prev = cup;
cup = cup->next;
}
// Nothing found, add to the end.
if (!cup)
{
cup = Z_Calloc(sizeof (cupheader_t), PU_STATIC, NULL);
cup->id = numkartcupheaders;
cup->monitor = 1;
deh_strlcpy(cup->name, word2,
sizeof(cup->name), va("Cup header %s: name", word2));
cup->namehash = hash;
if (prev != NULL)
prev->next = cup;
if (kartcupheaders == NULL)
kartcupheaders = cup;
numkartcupheaders++;
CONS_Printf("Added cup %d ('%s')\n", cup->id, cup->name);
}
// Nothing found, add to the end.
if (!cup)
readcupheader(f, cup);
}
else
{
cup = Z_Calloc(sizeof (cupheader_t), PU_STATIC, NULL);
cup->id = numkartcupheaders;
deh_strlcpy(cup->name, word2,
sizeof(cup->name), va("Cup header %s: name", word2));
if (prev != NULL)
prev->next = cup;
if (kartcupheaders == NULL)
kartcupheaders = cup;
numkartcupheaders++;
CONS_Printf("Added cup %d ('%s')\n", cup->id, cup->name);
deh_warning("Cup header's name %s is too long (%s characters VS %d max)", word2, sizeu1(len), (MAXCUPNAME-1));
ignorelines(f);
}
readcupheader(f, cup);
}
else if (fastcmp(word, "WEATHER") || fastcmp(word, "PRECIP") || fastcmp(word, "PRECIPITATION"))
{

View file

@ -442,7 +442,6 @@ void DRPC_UpdatePresence(void)
char detailstr[48+1];
char mapimg[8+1];
char mapname[5+21+21+2+1];
char charimg[4+SKINNAMESIZE+1];
@ -545,14 +544,7 @@ void DRPC_UpdatePresence(void)
if ((gamestate == GS_LEVEL || gamestate == GS_INTERMISSION) // Map info
&& !(demo.playback && demo.title))
{
if ((gamemap >= 1 && gamemap <= 60) // supported race maps
|| (gamemap >= 136 && gamemap <= 164)) // supported battle maps
{
snprintf(mapimg, 8, "%s", G_BuildMapName(gamemap));
strlwr(mapimg);
discordPresence.largeImageKey = mapimg; // Map image
}
else if (mapheaderinfo[gamemap-1]->menuflags & LF2_HIDEINMENU)
if (mapheaderinfo[gamemap-1]->menuflags & LF2_HIDEINMENU)
{
// Hell map, use the method that got you here :P
discordPresence.largeImageKey = "miscdice";

View file

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

View file

@ -344,6 +344,7 @@ extern char liveeventbackup[256];
void M_StartupLocale(void);
void *M_Memcpy(void* dest, const void* src, size_t n);
char *va(const char *format, ...) FUNCPRINTF;
char *xva(const char *format, ...) FUNCPRINTF;
char *M_GetToken(const char *inputString);
void M_UnGetToken(void);
@ -386,6 +387,7 @@ typedef enum
DBG_SETUP = 0x00000400,
DBG_LUA = 0x00000800,
DBG_RNG = 0x00001000,
DBG_DEMO = 0x00002000,
} debugFlags_t;
struct debugFlagNames_s

View file

@ -107,6 +107,23 @@ extern preciptype_t precip_freeslot;
extern preciptype_t globalweather;
extern preciptype_t curWeather;
/** Time attack information, currently a very small structure.
*/
struct recorddata_t
{
tic_t time; ///< Time in which the level was finished.
tic_t lap; ///< Best lap time for this level.
//UINT32 score; ///< Score when the level was finished.
//UINT16 rings; ///< Rings when the level was finished.
};
// mapvisited is now a set of flags that says what we've done in the map.
#define MV_VISITED (1)
#define MV_BEATEN (1<<1)
#define MV_ENCORE (1<<2)
#define MV_MAX (MV_VISITED|MV_BEATEN|MV_ENCORE)
#define MV_MP ((MV_MAX+1)<<1)
// Set if homebrew PWAD stuff has been added.
extern boolean modifiedgame;
extern boolean majormods;
@ -190,15 +207,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 INT32 tutorialgcs; // which control scheme is loaded?
@ -207,8 +220,6 @@ extern boolean looptitle;
// CTF colors.
extern UINT16 skincolor_redteam, skincolor_blueteam, skincolor_redring, skincolor_bluering;
extern tic_t countdowntimer;
extern boolean countdowntimeup;
extern boolean exitfadestarted;
struct scene_t
@ -299,8 +310,6 @@ extern textprompt_t *textprompts[MAX_PROMPTS];
extern INT16 nextmapoverride;
extern UINT8 skipstats;
extern UINT32 ssspheres; // Total # of spheres in a level
// Fun extra stuff
extern INT16 lastmap; // Last level you were at (returning from special stages).
@ -321,12 +330,6 @@ extern struct quake
fixed_t radius, intensity;
} quake;
// NiGHTS grades
typedef struct
{
UINT32 grade[6]; // D, C, B, A, S, X (F: failed to reach any of these)
} nightsgrades_t;
// Custom Lua values
struct customoption_t
{
@ -344,96 +347,115 @@ struct mapheader_lighting_t
#define MAXMUSNAMES 3 // maximum definable music tracks per level
// This could support more, but is that a good idea?
// Keep in mind that it may encourage people making overly long cups just because they "can", and would be a waste of memory.
#define MAXLEVELLIST 5
#define CUPCACHE_BONUS MAXLEVELLIST
#define CUPCACHE_SPECIAL MAXLEVELLIST+1
#define CUPCACHE_MAX CUPCACHE_SPECIAL+1
#define MAXCUPNAME 16 // includes \0, for cleaner savedata
struct cupheader_t
{
UINT16 id; ///< Cup ID
UINT8 monitor; ///< Monitor graphic 1-9 or A-Z
char name[MAXCUPNAME]; ///< Cup title
UINT32 namehash; ///< Cup title hash
char icon[9]; ///< Name of the icon patch
char *levellist[CUPCACHE_MAX]; ///< List of levels that belong to this cup
INT16 cachedlevels[CUPCACHE_MAX]; ///< IDs in levellist, bonusgame, and specialstage
UINT8 numlevels; ///< Number of levels defined in levellist
UINT8 emeraldnum; ///< ID of Emerald to use for special stage (1-7 for Chaos Emeralds, 8-14 for Super Emeralds, 0 for no emerald)
SINT8 unlockrequired; ///< An unlockable is required to select this cup. -1 for no unlocking required.
cupheader_t *next; ///< Next cup in linked list
};
extern cupheader_t *kartcupheaders; // Start of cup linked list
extern UINT16 numkartcupheaders;
#define MAXMAPLUMPNAME 64 // includes \0, for cleaner savedata
/** Map header information.
*/
struct mapheader_t
{
// 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
char actnum[3]; ///< SRB2Kart: Now a 2 character long string.
UINT32 typeoflevel; ///< Combination of typeoflevel flags.
INT16 nextlevel; ///< Map number of next level, or 1100-1102 to end.
INT16 marathonnext; ///< See nextlevel, but for Marathon mode. Necessary to support hub worlds ala SUGOI.
char keywords[33]; ///< Keywords separated by space to search for. 32 characters.
char forcecharacter[17]; ///< (SKINNAMESIZE+1) Skin to switch to or "" to disable.
UINT8 weather; ///< 0 = sunny day, 1 = storm, 2 = snow, 3 = rain, 4 = blank, 5 = thunder w/o rain, 6 = rain w/o lightning, 7 = heat wave.
char skytexture[9]; ///< Sky texture to use.
INT16 skybox_scalex; ///< Skybox X axis scale. (0 = no movement, 1 = 1:1 movement, 16 = 16:1 slow movement, -4 = 1:4 fast movement, etc.)
INT16 skybox_scaley; ///< Skybox Y axis scale.
INT16 skybox_scalez; ///< Skybox Z axis scale.
// Core game information, not user-modifiable directly
char *lumpname; ///< Lump name can be really long
UINT32 lumpnamehash; ///< quickncasehash(->lumpname, MAXMAPLUMPNAME)
lumpnum_t lumpnum; ///< Lump number for the map, used by vres_GetMap
// Extra information.
char interscreen[8]; ///< 320x200 patch to display at intermission.
char runsoc[33]; ///< SOC to execute at start of level (32 character limit instead of 63)
char scriptname[33]; ///< Script to use when the map is switched to. (32 character limit instead of 191)
UINT8 precutscenenum; ///< Cutscene number to play BEFORE a level starts.
UINT8 cutscenenum; ///< Cutscene number to use, 0 for none.
INT16 countdown; ///< Countdown until level end?
UINT16 palette; ///< PAL lump to use on this map
UINT16 encorepal; ///< PAL for encore mode
UINT8 numlaps; ///< Number of laps in circuit mode, unless overridden.
SINT8 unlockrequired; ///< Is an unlockable required to play this level? -1 if no.
UINT8 levelselect; ///< Is this map available in the level select? If so, which map list is it available in?
SINT8 bonustype; ///< What type of bonus does this level have? (-1 for null.)
SINT8 maxbonuslives; ///< How many bonus lives to award at Intermission? (-1 for unlimited.)
void *thumbnailPic; ///< Lump data for the level select thumbnail.
void *minimapPic; ///< Lump data for the minimap graphic.
UINT16 levelflags; ///< LF_flags: merged booleans into one UINT16 for space, see below
UINT8 menuflags; ///< LF2_flags: options that affect record attack / nights mode menus
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
char actnum[3]; ///< SRB2Kart: Now a 2 character long string.
// 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?
UINT8 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.
mapheader_lighting_t lighting; ///< Wall and sprite lighting
mapheader_lighting_t lighting_encore; ///< Alternative lighting for Encore mode
boolean use_encore_lighting; ///< Whether to use separate Encore lighting
boolean use_walltransfer; ///< Whether to use DRRR style wall transfering or not
// Music stuff.
UINT32 musinterfadeout; ///< Fade out level music on intermission screen in milliseconds
char musintername[7]; ///< Intermission screen music.
// Music information
char musname[MAXMUSNAMES][7]; ///< Music tracks to play. First dimension is the track number, second is the music string. "" for no music.
UINT16 mustrack; ///< Subsong to play. Only really relevant for music modules and specific formats supported by GME. 0 to ignore.
UINT32 muspos; ///< Music position to jump to.
UINT8 musname_size; ///< Number of music tracks defined
char muspostbossname[7]; ///< Post-bossdeath music.
UINT16 muspostbosstrack; ///< Post-bossdeath track.
UINT32 muspostbosspos; ///< Post-bossdeath position
UINT32 muspostbossfadein; ///< Post-bossdeath fade-in milliseconds.
// 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.
SINT8 musforcereset; ///< Force resetmusic (-1 for default; 0 for force off; 1 for force on)
// 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
// SRB2Kart: Keeps track of if a map lump exists, so we can tell when a map is being replaced.
boolean alreadyExists;
// Visual information
UINT16 palette; ///< PAL lump to use on this map
UINT16 encorepal; ///< PAL for encore mode
mapheader_lighting_t lighting; ///< Wall and sprite lighting
mapheader_lighting_t lighting_encore; ///< Alternative lighting for Encore mode
boolean use_encore_lighting; ///< Whether to use separate Encore lighting
// 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.
// Freed animal information
UINT8 numFlickies; ///< Internal. For freed flicky support.
mobjtype_t *flickies; ///< List of freeable flickies in this level. Allocated dynamically for space reasons. Be careful.
// Script information
char runsoc[33]; ///< SOC to execute at start of level (32 character limit instead of 63)
char scriptname[33]; ///< Script to use when the map is switched to. (32 character limit instead of 191)
// Cutscene information
UINT8 precutscenenum; ///< Cutscene number to play BEFORE a level starts.
UINT8 cutscenenum; ///< Cutscene number to use, 0 for none.
// Lua information
UINT8 numCustomOptions; ///< Internal. For Lua custom value support.
customoption_t *customopts; ///< Custom options. Allocated dynamically for space reasons. Be careful.
// BlanKart
boolean use_walltransfer; ///< Whether to use DRRR style wall transfering or not
};
@ -448,28 +470,8 @@ struct mapheader_t
#define LF2_NOTIMEATTACK (1<<2) ///< Hide this map in Time Attack modes
#define LF2_VISITNEEDED (1<<3) ///< Not available in Time Attack modes until you visit the level
extern mapheader_t* mapheaderinfo[NUMMAPS];
// This could support more, but is that a good idea?
// Keep in mind that it may encourage people making overly long cups just because they "can", and would be a waste of memory.
#define MAXLEVELLIST 5
struct cupheader_t
{
UINT16 id; ///< Cup ID
char name[15]; ///< Cup title (14 chars)
char icon[9]; ///< Name of the icon patch
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.
cupheader_t *next; ///< Next cup in linked list
};
extern cupheader_t *kartcupheaders; // Start of cup linked list
extern UINT16 numkartcupheaders;
extern mapheader_t** mapheaderinfo;
extern INT32 nummapheaders, mapallocsize;
// Gametypes
#define NUMGAMETYPEFREESLOTS 128
@ -577,52 +579,10 @@ extern INT32 luabanks[NUM_LUABANKS];
extern INT32 nummaprings; //keep track of spawned rings/coins
/** Time attack information, currently a very small structure.
*/
struct recorddata_t
{
tic_t time; ///< Time in which the level was finished.
tic_t lap; ///< Best lap time for this level.
//UINT32 score; ///< Score when the level was finished.
//UINT16 rings; ///< Rings when the level was finished.
};
/** 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

@ -1118,6 +1118,8 @@ static void F_CacheTitleScreen(void)
void F_StartTitleScreen(void)
{
INT32 titleMapNum;
if (gamestate != GS_TITLESCREEN && gamestate != GS_WAITINGPLAYERS)
{
ttuser_count = 0;
@ -1127,23 +1129,23 @@ 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)
if (!titleMapNum)
return;
players[displayplayers[0]].playerstate = PST_DEAD; // Don't spawn the player in dummy (I'm still a filthy cheater)
@ -1418,20 +1420,17 @@ void F_TitleScreenTicker(boolean run)
// is it time?
if (!(--demoIdleLeft))
{
//static boolean use_netreplay = false;
char dname[9];
lumpnum_t l;
const char *mapname;
char dname[MAXMAPLUMPNAME+1+8+1];
UINT16 mapnum;
UINT8 numstaff;
static boolean use_netreplay = false;
//@TODO uncomment this when this goes into vanilla
/*if ((use_netreplay = !use_netreplay))*/
if ((use_netreplay = !use_netreplay))
{
numstaff = 1;
while ((l = W_CheckNumForName(va("TDEMO%03u", numstaff))) != LUMPERROR)
lumpnum_t l = LUMPERROR;
numstaff = 0;
while (numstaff < 99 && (l = W_CheckNumForName(va("TDEMO%03u", numstaff))) != LUMPERROR)
numstaff++;
numstaff--;
if (numstaff)
{
@ -1444,54 +1443,38 @@ void F_TitleScreenTicker(boolean run)
// prevent console spam if failed
demoIdleLeft = demoIdleTime;
if ((l = W_CheckNumForName("MAP01S01")) == LUMPERROR) // gotta have ONE
mapnum = G_RandMap(TOL_RACE, -2, 2, 0, false, NULL);
if (mapnum == 0) // gotta have ONE
{
F_StartIntro();
return;
}
// Replay intro when done cycling through demos
/*
if (curDemo == numDemos) -- uuuh... we have a LOT of maps AND a big devteam... probably not gonna see a repeat unless you're super unlucky :V
{
curDemo = 0;
F_StartIntro();
return;
}
*/
mapname = G_BuildMapName(G_RandMap(TOL_RACE, -2, 0, 0, false, NULL)+1);
numstaff = 1;
while (numstaff < 99 && (l = W_CheckNumForName(va("%sS%02u",mapname,numstaff+1))) != LUMPERROR)
numstaff++;
#if 0 // turns out this isn't how we're gonna organise 'em
if (numstaff > 1)
{
if (laststaff && laststaff <= numstaff) // don't do the same staff member twice in a row, even if they're on different maps
{
numstaff = M_RandomKey(numstaff-1)+1;
if (numstaff >= laststaff)
numstaff++;
}
else
numstaff = M_RandomKey(numstaff)+1;
}
laststaff = numstaff;
#else
numstaff = M_RandomKey(numstaff)+1;
#endif
// Setup demo name
snprintf(dname, 9, "%sS%02u", mapname, numstaff);
sprintf(dname, "%s/GHOST_%u", mapheaderinfo[mapnum]->lumpname, numstaff);
/*if ((l = W_CheckNumForName(dname)) == LUMPERROR) -- we KNOW it exists now
{
CONS_Alert(CONS_ERROR, M_GetText("Demo lump \"%s\" doesn't exist\n"), dname);
F_StartIntro();
return;
}*/
// vres GHOST_%u
virtres_t *vRes;
virtlump_t *vLump;
vRes = vres_GetMap(mapheaderinfo[mapnum]->lumpnum);
vLump = vres_Find(vRes, dname);
if (vLump == NULL)
{
if (((W_CheckNumForName(va("%sS%02u", mapheaderinfo[mapnum]->lumpname, numstaff)))) != LUMPERROR)
sprintf(dname, "%sS%02u", mapheaderinfo[mapnum]->lumpname, numstaff);
else
{
vres_Free(vRes);
return;
}
}
vres_Free(vRes);
}
loadreplay:
demo.title = demo.fromtitle = true;
@ -1628,7 +1611,7 @@ void F_EndCutScene(void)
F_StartGameEvaluation();
else if (cutnum == introtoplay-1)
D_StartTitle();
else if (nextmap < 1100-1)
else if (nextmap < NEXTMAP_SPECIAL)
G_NextLevel();
else
G_EndGame();

View file

@ -41,7 +41,6 @@
#include <tchar.h>
#define SUFFIX "*"
#define SLASH "\\"
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
#ifndef INVALID_FILE_ATTRIBUTES
@ -139,7 +138,7 @@ opendir (const CHAR *szPath)
/* Allocate enough space to store DIR structure and the complete
* directory path given. */
nd = (DIR *) malloc (sizeof (DIR) + (strlen(szFullPath) + strlen (SLASH) +
strlen(SUFFIX) + 1) * sizeof (CHAR));
strlen(PATHSEP) + 1) * sizeof (CHAR));
if (!nd)
{
@ -153,10 +152,9 @@ opendir (const CHAR *szPath)
/* Add on a slash if the path does not end with one. */
if (nd->dd_name[0] != '\0' &&
nd->dd_name[strlen (nd->dd_name) - 1] != '/' &&
nd->dd_name[strlen (nd->dd_name) - 1] != '\\')
nd->dd_name[strlen (nd->dd_name) - 1] != PATHSEP[0])
{
strcat (nd->dd_name, SLASH);
strcat (nd->dd_name, PATHSEP);
}
/* Add on the search pattern */
@ -473,9 +471,9 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want
return FS_NOTFOUND;
}
if (searchpath[searchpathindex[depthleft]-2] != '/')
if (searchpath[searchpathindex[depthleft]-2] != PATHSEP[0])
{
searchpath[searchpathindex[depthleft]-1] = '/';
searchpath[searchpathindex[depthleft]-1] = PATHSEP[0];
searchpath[searchpathindex[depthleft]] = 0;
}
else
@ -517,8 +515,8 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want
depthleft++;
}
searchpath[searchpathindex[depthleft]-1]='/';
searchpath[searchpathindex[depthleft]]=0;
searchpath[searchpathindex[depthleft]-1] = PATHSEP[0];
searchpath[searchpathindex[depthleft]] = 0;
}
else if (!strcasecmp(searchname, dent->d_name))
{

View file

@ -59,12 +59,14 @@ consvar_t cv_recordmultiplayerdemos = CVAR_INIT ("netdemo_record", "Manual Save"
static CV_PossibleValue_t netdemosyncquality_cons_t[] = {{1, "MIN"}, {35, "MAX"}, {0, NULL}};
consvar_t cv_netdemosyncquality = CVAR_INIT ("netdemo_syncquality", "1", CV_SAVE, netdemosyncquality_cons_t, NULL);
consvar_t cv_netdemosize = CVAR_INIT ("netdemo_size", "6", CV_SAVE, CV_Natural, NULL);
boolean nodrawers; // for comparative timing purposes
boolean noblit; // for comparative timing purposes
tic_t demostarttime; // for comparative timing purposes
static char demoname[MAX_WADPATH];
static savebuffer_t demobuf;
static savebuffer_t demobuf = {0};
static UINT8 *demotime_p, *demoinfo_p;
static UINT8 demoflags;
boolean demosynced = true; // console warning message
@ -2000,22 +2002,13 @@ void G_RecordDemo(const char *name)
strcpy(demoname, name);
strcat(demoname, ".lmp");
//@TODO make a maxdemosize cvar
maxsize = 1024*1024*2;
maxsize = 1024 * 1024 * cv_netdemosize.value;
if (M_CheckParm("-maxdemo") && M_IsNextParm())
maxsize = atoi(M_GetNextParm()) * 1024;
// if (demobuf.buffer)
// P_SaveBufferFree(&demobuf);
demobuf.size = maxsize;
demobuf.buffer = (UINT8 *)malloc(maxsize);
P_SaveBufferAlloc(&demobuf, maxsize);
demobuf.p = NULL;
demobuf.end = demobuf.buffer + demobuf.size;
demo.recording = true;
//demo.buffer = &demobuf;
demo.buffer = &demobuf;
/* FIXME: This whole file is in a wretched state. Take a
look at G_WriteAllGhostTics and G_WriteDemoTiccmd, they
@ -2039,10 +2032,8 @@ void G_RecordMetal(void)
if (M_CheckParm("-maxdemo") && M_IsNextParm())
maxsize = atoi(M_GetNextParm()) * 1024;
demobuf.size = maxsize;
demobuf.buffer = (UINT8 *)malloc(maxsize);
P_SaveBufferAlloc(&demobuf, maxsize);
demobuf.p = NULL;
demobuf.end = demobuf.buffer + demobuf.size;
metalrecording = true;
}
@ -2088,7 +2079,7 @@ void G_BeginRecording(void)
// game data
M_Memcpy(demobuf.p, "PLAY", 4); demobuf.p += 4;
WRITEINT16(demobuf.p,gamemap);
WRITESTRINGN(demobuf.p, mapheaderinfo[gamemap-1]->lumpname, MAXMAPLUMPNAME);
M_Memcpy(demobuf.p, mapmd5, 16); demobuf.p += 16;
WRITEUINT8(demobuf.p, demoflags);
@ -2531,7 +2522,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
@ -2589,7 +2580,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
@ -2635,6 +2626,7 @@ void G_LoadDemoInfo(menudemo_t *pdemo)
UINT8 *infobuffer, *info_p, *extrainfo_p;
UINT8 version, subversion, pdemoflags;
UINT16 pdemoversion, count;
char mapname[MAXMAPLUMPNAME];
if (!FIL_ReadFile(pdemo->filepath, &infobuffer))
{
@ -2694,7 +2686,8 @@ void G_LoadDemoInfo(menudemo_t *pdemo)
return;
}
info_p += 4; // "PLAY"
pdemo->map = READINT16(info_p);
READSTRINGN(info_p, mapname, sizeof(mapname));
pdemo->map = G_MapNumber(mapname);
info_p += 16; // mapmd5
pdemoflags = READUINT8(info_p);
@ -2808,7 +2801,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];
@ -2848,7 +2841,7 @@ void G_DoPlayDemo(char *defdemoname)
if (FIL_CheckExtension(defdemoname))
{
//FIL_DefaultExtension(defdemoname, ".lmp");
if (!FIL_ReadFile(defdemoname, &demobuf.buffer))
if (P_SaveBufferFromFile(&demobuf, defdemoname) == false)
{
snprintf(msg, 1024, M_GetText("Failed to read file '%s'.\n"), defdemoname);
CONS_Alert(CONS_ERROR, "%s", msg);
@ -2856,22 +2849,72 @@ void G_DoPlayDemo(char *defdemoname)
M_StartMessage(msg, NULL, MM_NOTHING);
return;
}
demobuf.p = demobuf.buffer;
}
// load demo resource from WAD
else if ((l = W_CheckNumForName(defdemoname)) == LUMPERROR)
else
{
snprintf(msg, 1024, M_GetText("Failed to read lump '%s'.\n"), defdemoname);
CONS_Alert(CONS_ERROR, "%s", msg);
gameaction = ga_nothing;
M_StartMessage(msg, NULL, MM_NOTHING);
return;
}
else // it's an internal demo
{
demobuf.buffer = demobuf.p = W_CacheLumpNum(l, PU_STATIC);
if (n == defdemoname)
{
// Raw lump.
if ((l = W_CheckNumForName(defdemoname)) == LUMPERROR)
{
snprintf(msg, 1024, M_GetText("Failed to read lump '%s'.\n"), defdemoname);
CONS_Alert(CONS_ERROR, "%s", msg);
Z_Free(pdemoname);
gameaction = ga_nothing;
M_StartMessage(msg, NULL, MM_NOTHING);
return;
}
P_SaveBufferFromLump(&demobuf, l);
}
else
{
// vres GHOST_%u
virtres_t *vRes;
virtlump_t *vLump;
UINT16 mapnum;
size_t step = 0;
step = 0;
while (defdemoname+step < n-1)
{
mapname[step] = defdemoname[step];
step++;
}
mapname[step] = '\0';
mapnum = G_MapNumber(mapname);
if (mapnum >= nummapheaders || mapheaderinfo[mapnum]->lumpnum == LUMPERROR)
{
snprintf(msg, 1024, M_GetText("Failed to read lump '%s (couldn't find map %s)'.\n"), defdemoname, mapname);
CONS_Alert(CONS_ERROR, "%s", msg);
Z_Free(pdemoname);
gameaction = ga_nothing;
M_StartMessage(msg, NULL, MM_NOTHING);
return;
}
vRes = vres_GetMap(mapheaderinfo[mapnum]->lumpnum);
vLump = vres_Find(vRes, pdemoname);
if (vLump == NULL)
{
snprintf(msg, 1024, M_GetText("Failed to read lump '%s (couldn't find lump %s in %s)'.\n"), defdemoname, pdemoname, mapname);
CONS_Alert(CONS_ERROR, "%s", msg);
Z_Free(pdemoname);
gameaction = ga_nothing;
M_StartMessage(msg, NULL, MM_NOTHING);
return;
}
P_SaveBufferAlloc(&demobuf, vLump->size);
memcpy(demobuf.buffer, vLump->data, vLump->size);
vres_Free(vRes);
}
#if defined(SKIPERRORS) && !defined(DEVELOP)
skiperrors = true; // SRB2Kart: Don't print warnings for staff ghosts, since they'll inevitably happen when we make bugfixes/changes...
skiperrors = true; // RR: Don't print warnings for staff ghosts, since they'll inevitably happen when we make bugfixes/changes...
#endif
}
}
@ -2879,13 +2922,14 @@ void G_DoPlayDemo(char *defdemoname)
// read demo header
gameaction = ga_nothing;
demo.playback = true;
demo.buffer = &demobuf;
if (memcmp(demobuf.p, DEMOHEADER, 12))
{
snprintf(msg, 1024, M_GetText("%s is not a SRB2Kart replay file.\n"), pdemoname);
CONS_Alert(CONS_ERROR, "%s", msg);
M_StartMessage(msg, NULL, MM_NOTHING);
Z_Free(pdemoname);
Z_Free(demobuf.buffer);
P_SaveBufferFree(&demobuf);
demo.playback = false;
demo.title = false;
return;
@ -2905,7 +2949,7 @@ void G_DoPlayDemo(char *defdemoname)
CONS_Alert(CONS_ERROR, "%s", msg);
M_StartMessage(msg, NULL, MM_NOTHING);
Z_Free(pdemoname);
Z_Free(demobuf.buffer);
P_SaveBufferFree(&demobuf);
demo.playback = false;
demo.title = false;
return;
@ -2923,14 +2967,15 @@ void G_DoPlayDemo(char *defdemoname)
CONS_Alert(CONS_ERROR, "%s", msg);
M_StartMessage(msg, NULL, MM_NOTHING);
Z_Free(pdemoname);
Z_Free(demobuf.buffer);
P_SaveBufferFree(&demobuf);
demo.playback = false;
demo.title = false;
return;
}
demobuf.p += 4; // "PLAY"
gamemap = READINT16(demobuf.p);
READSTRINGN(demobuf.p, mapname, sizeof(mapname)); // gamemap
gamemap = G_MapNumber(mapname)+1;
demobuf.p += 16; // mapmd5
demoflags = READUINT8(demobuf.p);
@ -2987,7 +3032,7 @@ void G_DoPlayDemo(char *defdemoname)
if (!CON_Ready()) // In the console they'll just see the notice there! No point pulling them out.
M_StartMessage(msg, NULL, MM_NOTHING);
Z_Free(pdemoname);
Z_Free(demobuf.buffer);
P_SaveBufferFree(&demobuf);
demo.playback = false;
demo.title = false;
return;
@ -3024,13 +3069,13 @@ void G_DoPlayDemo(char *defdemoname)
demobuf.p += 4; // Extrainfo location
// ...*map* not loaded?
if (!gamemap || (gamemap > NUMMAPS) || !mapheaderinfo[gamemap-1] || !(mapheaderinfo[gamemap-1]->alreadyExists == true))
if (!gamemap || (gamemap > nummapheaders) || !mapheaderinfo[gamemap-1] || mapheaderinfo[gamemap-1]->lumpnum == LUMPERROR)
{
snprintf(msg, 1024, M_GetText("%s features a course that is not currently loaded.\n"), pdemoname);
CONS_Alert(CONS_ERROR, "%s", msg);
M_StartMessage(msg, NULL, MM_NOTHING);
Z_Free(pdemoname);
Z_Free(demobuf.buffer);
P_SaveBufferFree(&demobuf);
demo.playback = false;
demo.title = false;
return;
@ -3049,7 +3094,7 @@ void G_DoPlayDemo(char *defdemoname)
CONS_Alert(CONS_ERROR, "%s", msg);
M_StartMessage(msg, NULL, MM_NOTHING);
Z_Free(pdemoname);
Z_Free(demobuf.buffer);
P_SaveBufferFree(&demobuf);
demo.playback = false;
demo.title = false;
return;
@ -3099,7 +3144,7 @@ void G_DoPlayDemo(char *defdemoname)
CONS_Alert(CONS_ERROR, "%s", msg);
M_StartMessage(msg, NULL, MM_NOTHING);
Z_Free(pdemoname);
Z_Free(demobuf.buffer);
P_SaveBufferFree(&demobuf);
demo.playback = false;
demo.title = false;
return;
@ -3115,7 +3160,7 @@ void G_DoPlayDemo(char *defdemoname)
CONS_Alert(CONS_ERROR, "%s", msg);
M_StartMessage(msg, NULL, MM_NOTHING);
Z_Free(pdemoname);
Z_Free(demobuf.buffer);
P_SaveBufferFree(&demobuf);
demo.playback = false;
demo.title = false;
return;
@ -3225,7 +3270,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++)
{
@ -3340,7 +3385,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);
@ -3468,7 +3513,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;
@ -3572,7 +3617,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);
@ -3650,6 +3695,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"));
@ -3758,7 +3804,7 @@ ATTRNORETURN void FUNCNORETURN G_StopMetalRecording(boolean kill)
WriteDemoChecksum();
saved = FIL_WriteFile(va("%sMS.LMP", G_BuildMapName(gamemap)), demobuf.buffer, demobuf.p - demobuf.buffer); // finally output the file.
}
free(demobuf.buffer);
P_SaveBufferFree(&demobuf);
metalrecording = false;
if (saved)
I_Error("Saved to %sMS.LMP", G_BuildMapName(gamemap));
@ -3826,8 +3872,7 @@ static void G_StopTimingDemo(void)
// called from stopdemo command, map command, and g_checkdemoStatus.
void G_StopDemo(void)
{
Z_Free(demobuf.buffer);
demobuf.buffer = NULL;
P_SaveBufferFree(&demobuf);
demo.playback = false;
if (demo.title)
modeattacking = false;
@ -3893,6 +3938,8 @@ boolean G_CheckDemoStatus(void)
return true;
}
if (demo.recording)
P_SaveBufferFree(&demobuf);
demo.recording = false;
return false;
}
@ -3966,7 +4013,7 @@ void G_SaveDemo(void)
if (FIL_WriteFile(demoname, demobuf.buffer, demobuf.p - demobuf.buffer)) // finally output the file.
demo.savemode = DSM_SAVED;
free(demobuf.buffer);
P_SaveBufferFree(&demobuf);
demo.recording = false;
if (!modeattacking)

View file

@ -28,7 +28,7 @@ extern UINT8 *demo_p;
// DEMO playback/recording related stuff.
// ======================================
extern consvar_t cv_recordmultiplayerdemos, cv_netdemosyncquality;
extern consvar_t cv_recordmultiplayerdemos, cv_netdemosyncquality, cv_netdemosize;
extern tic_t demostarttime;
@ -58,6 +58,7 @@ struct demovars_s {
boolean freecam;
const savebuffer_t *buffer; // debug, valid only if recording or playback
};
extern struct demovars_s demo;

File diff suppressed because it is too large Load diff

View file

@ -27,7 +27,6 @@ extern "C" {
extern char gamedatafilename[64];
extern char timeattackfolder[64];
extern char customversionstring[32];
#define GAMEDATASIZE (4*8192)
extern char player_names[MAXPLAYERS][MAXPLAYERNAME+1];
extern INT32 player_name_changes[MAXPLAYERS];
@ -40,6 +39,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)
@ -93,8 +105,8 @@ void weaponPrefChange4(void);
#define MAXPLMOVE (50)
#define SLOWTURNTICS (cv_turnsmooth.value * 3)
// build an internal map name MAPxx from map number
const char *G_BuildMapName(INT32 map);
INT32 G_MapNumber(const char *mapname);
void G_ResetAnglePrediction(player_t *player);
void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer);
@ -136,7 +148,7 @@ extern INT32 localaiming[MAXSPLITSCREENPLAYERS]; // should be an angle_t but sig
void G_ChangePlayerReferences(mobj_t *oldmo, mobj_t *newmo);
void G_DoReborn(INT32 playernum);
void G_PlayerReborn(INT32 player, boolean betweenmaps);
void G_InitNew(UINT8 pencoremode, const char *mapname, boolean resetplayer,
void G_InitNew(UINT8 pencoremode, INT32 map, boolean resetplayer,
boolean skipprecutscene, boolean FLS);
char *G_BuildMapTitle(INT32 mapnum);
@ -173,7 +185,7 @@ void G_SpawnPlayer(INT32 playernum, boolean starpost);
// Can be called by the startup code or M_Responder.
// A normal game starts at map 1, but a warp test can start elsewhere
void G_DeferedInitNew(boolean pencoremode, const char *mapname, INT32 pickedchar,
void G_DeferedInitNew(boolean pencoremode, INT32 map, INT32 pickedchar,
UINT8 ssplayers, boolean FLS);
void G_DoLoadLevel(boolean resetplayer);
@ -205,7 +217,8 @@ boolean G_IsSpecialStage(INT32 mapnum);
boolean G_GametypeUsesLives(void);
boolean G_GametypeHasTeams(void);
boolean G_GametypeHasSpectators(void);
INT16 G_SometimesGetDifferentGametype(void);
#define VOTEMODIFIER_ENCORE 0x80
INT16 G_SometimesGetDifferentGametype(UINT8 prefgametype);
UINT8 G_GetGametypeColor(INT16 gt);
void G_BeginLevelExit(void);
void G_FinishExitLevel(void);
@ -267,6 +280,7 @@ FUNCMATH INT32 G_TicsToMilliseconds(tic_t tics);
// Don't split up TOL handling
UINT32 G_TOLFlag(INT32 pgametype);
INT16 G_GetFirstMapOfGametype(UINT8 pgametype);
INT16 G_RandMap(UINT32 tolflags, INT16 pprevmap, UINT8 ignorebuffer, UINT8 maphell, boolean callagainsoon, INT16 *extbuffer);
void G_AddMapToBuffer(INT16 map);

View file

@ -98,6 +98,9 @@ static char hu_tick;
//-------------------------------------------
patch_t *missingpat;
patch_t *blanklvl;
patch_t *randomlvl;
patch_t *nolvl;
// song credits
static patch_t *songcreditbg;
@ -186,6 +189,10 @@ void HU_LoadGraphics(void)
Font_Load();
HU_UpdatePatch(&blanklvl, "BLANKLVL");
HU_UpdatePatch(&randomlvl, "RANDOMLV");
HU_UpdatePatch(&nolvl, "M_NOLVL");
HU_UpdatePatch(&songcreditbg, "K_SONGCR");
// cache ping gfx:

View file

@ -241,7 +241,7 @@ void K_CheckBumpers(void)
winnerscoreadd -= players[i].roundscore;
}
if (bossinfo.boss)
if (K_CanChangeRules() == false)
{
if (nobumpers)
{

View file

@ -1454,7 +1454,7 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UI
else if ((drawtime/TICRATE) & 1)
V_DrawKartString(TX, TY+3, splitflags, va("99'59\"99"));
if (emblemmap && (modeattacking || (mode == 1)) && !demo.playback) // emblem time!
if ((modeattacking || (mode == 1)) && !demo.playback) // emblem time!
{
INT32 workx = TX + 96, worky = TY+18;
SINT8 curemb = 0;
@ -3300,7 +3300,6 @@ static void K_drawKartMinimapWaypoint(waypoint_t *wp, INT32 hudx, INT32 hudy, IN
static void K_drawKartMinimap(void)
{
INT32 lumpnum;
patch_t *AutomapPic, *workingPic;
INT32 i = 0;
INT32 x, y;
@ -3323,12 +3322,12 @@ static void K_drawKartMinimap(void)
if (stplyr != &players[displayplayers[0]])
return;
lumpnum = W_CheckNumForName(va("%sR", G_BuildMapName(gamemap)));
AutomapPic = mapheaderinfo[gamemap-1]->minimapPic;
if (lumpnum != -1)
AutomapPic = W_CachePatchName(va("%sR", G_BuildMapName(gamemap)), PU_HUDGFX);
else
if (!AutomapPic)
{
return; // no pic, just get outta here
}
if (r_splitscreen < 2) // 1/2P right aligned
{

View file

@ -222,6 +222,7 @@ void K_RegisterKartStuff(void)
CV_RegisterVar(&cv_kartcomeback);
CV_RegisterVar(&cv_kartencore);
CV_RegisterVar(&cv_kartvoterulechanges);
CV_RegisterVar(&cv_kartgametypepreference);
CV_RegisterVar(&cv_kartspeedometer);
CV_RegisterVar(&cv_kartvoices);
CV_RegisterVar(&cv_kartbot);

View file

@ -34,7 +34,6 @@
#include "k_hud.h"
#include "d_netcmd.h" // IsPlayerAdmin
#include "m_menu.h" // Player Setup menu color stuff
#include "m_misc.h" // M_MapNumber
#include "p_spec.h" // P_StartQuake
#include "i_system.h" // I_GetPreciseTime, I_GetPrecisePrecision
@ -390,18 +389,18 @@ static int lib_pGetColorAfter(lua_State *L)
// M_MISC
//////////////
static int lib_mMapNumber(lua_State *L)
static int lib_gMapNumber(lua_State *L)
{
const char *arg = luaL_checkstring(L, 1);
size_t len = strlen(arg);
if (len == 2 || len == 5) {
char first = arg[len-2];
char second = arg[len-1];
lua_pushinteger(L, M_MapNumber(first, second));
} else {
lua_pushinteger(L, 0);
}
return 1;
INT32 map;
map = G_MapNumber(arg);
if (map == INT32_MAX)
return 0;
return map;
}
// M_RANDOM
@ -3166,12 +3165,12 @@ static int lib_gBuildMapTitle(lua_State *L)
{
INT32 map = Lcheckmapnumber(L, 1, "G_BuildMapTitle");
char *name;
if (map < 1 || map > NUMMAPS)
if (map < 1 || map > nummapheaders)
{
return luaL_error(L,
"map number %d out of range (1 - %d)",
"map ID %d out of range (1 - %d)",
map,
NUMMAPS
nummapheaders
);
}
name = G_BuildMapTitle(map);
@ -3968,9 +3967,6 @@ static luaL_Reg lib[] = {
{"M_GetColorAfter",lib_pGetColorAfter},
{"M_GetColorBefore",lib_pGetColorBefore},
// m_misc
{"M_MapNumber",lib_mMapNumber},
// m_random
{"P_RandomFixed",lib_pRandomFixed},
{"P_RandomByte",lib_pRandomByte},
@ -4173,6 +4169,7 @@ static luaL_Reg lib[] = {
// g_game
{"G_AddGametype", lib_gAddGametype},
{"G_BuildMapName",lib_gBuildMapName},
{"G_MapNumber",lib_gMapNumber},
{"G_BuildMapTitle",lib_gBuildMapTitle},
{"G_FindMap",lib_gFindMap},
{"G_FindMapByNameOrCode",lib_gFindMapByNameOrCode},

View file

@ -22,6 +22,7 @@
#include "p_local.h" // camera_t
#include "screen.h" // screen width/height
#include "m_random.h" // m_random
#include "m_menu.h" // M_GetMapThumbnail
#include "v_video.h"
#include "w_wad.h"
#include "z_zone.h"
@ -605,7 +606,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;
@ -691,12 +691,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);
@ -1091,6 +1091,41 @@ static int libd_getStringColormap(lua_State *L)
return 0;
}
static int libd_getMapThumbnail(lua_State *L)
{
INT16 mapnum;
patch_t *patch = NULL;
HUDONLY
if (lua_type(L, 1) == LUA_TNUMBER)
mapnum = luaL_checkinteger(L, 1) - 1;
else
mapnum = G_MapNumber(luaL_checkstring(L, 1));
fixed_t scale = M_GetMapThumbnail(mapnum, &patch);
LUA_PushUserdata(L, patch, META_PATCH);
lua_pushfixed(L, scale);
return 2;
}
static int libd_getMapMinimap(lua_State *L)
{
INT16 mapnum;
patch_t *patch = NULL;
HUDONLY
if (lua_type(L, 1) == LUA_TNUMBER)
mapnum = luaL_checkinteger(L, 1) - 1;
else
mapnum = G_MapNumber(luaL_checkstring(L, 1));
if (mapnum >= 0 && mapnum < nummapheaders && mapheaderinfo[mapnum])
patch = mapheaderinfo[mapnum]->minimapPic;
if (!patch)
patch = missingpat;
LUA_PushUserdata(L, patch, META_PATCH);
return 1;
}
static int libd_width(lua_State *L)
{
HUDONLY
@ -1258,6 +1293,8 @@ static luaL_Reg lib_draw[] = {
{"getSprite2Patch", libd_getSprite2Patch},
{"getColormap", libd_getColormap},
{"getStringColormap", libd_getStringColormap},
{"getMapThumbnail", libd_getMapThumbnail},
{"getMapMinimap", libd_getMapMinimap},
// drawing
{"draw", libd_draw},
{"drawScaled", libd_drawScaled},

View file

@ -2516,8 +2516,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);
@ -2535,7 +2535,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;
}
@ -2547,7 +2547,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"))
@ -2558,10 +2557,6 @@ static int mapheaderinfo_get(lua_State *L)
lua_pushstring(L, header->actnum);
else if (fastcmp(field,"typeoflevel"))
lua_pushinteger(L, header->typeoflevel);
else if (fastcmp(field,"nextlevel"))
lua_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")) // we create a table here because it saves us from a userdata nightmare
@ -2585,22 +2580,6 @@ static int mapheaderinfo_get(lua_State *L)
lua_pushinteger(L, header->muspos);
else if (fastcmp(field,"musname_size"))
lua_pushinteger(L, header->musname_size);
else if (fastcmp(field,"musinterfadeout"))
lua_pushinteger(L, header->musinterfadeout);
else if (fastcmp(field,"musintername"))
lua_pushstring(L, header->musintername);
else if (fastcmp(field,"muspostbossname"))
lua_pushstring(L, header->muspostbossname);
else if (fastcmp(field,"muspostbosstrack"))
lua_pushinteger(L, header->muspostbosstrack);
else if (fastcmp(field,"muspostbosspos"))
lua_pushinteger(L, header->muspostbosspos);
else if (fastcmp(field,"muspostbossfadein"))
lua_pushinteger(L, header->muspostbossfadein);
else if (fastcmp(field,"musforcereset"))
lua_pushinteger(L, header->musforcereset);
else if (fastcmp(field,"forcecharacter"))
lua_pushstring(L, header->forcecharacter);
else if (fastcmp(field,"weather"))
lua_pushinteger(L, header->weather);
else if (fastcmp(field,"skytexture"))
@ -2611,12 +2590,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);
@ -2624,8 +2598,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"))
@ -2634,31 +2606,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

@ -213,35 +213,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

@ -758,6 +758,8 @@ struct debugFlagNames_s const debug_flag_names[] =
{"Lua", DBG_LUA},
{"RNG", DBG_RNG},
{"Randomizer", DBG_RNG}, // alt name
{"Demo", DBG_DEMO},
{"Replay", DBG_DEMO}, // alt name
{NULL, 0}
};

View file

@ -30,124 +30,7 @@ UINT32 unlocktriggers;
conditionset_t conditionSets[MAXCONDITIONSETS];
// Default Emblem locations
emblem_t emblemlocations[MAXEMBLEMS] =
{
// GOLD DEV MEDALS
// These values are directly lifted from the Champion ghost, through the power of hex editing!
{ET_TIME, 0, 1, 'A', SKINCOLOR_GOLD, 3021, "", 0}, // Green Hills Zone - 1'26"31
{ET_TIME, 0, 2, 'A', SKINCOLOR_GOLD, 4466, "", 0}, // Dark Race - 2'07"60
{ET_TIME, 0, 3, 'A', SKINCOLOR_GOLD, 4337, "", 0}, // Northern District Zone - 2'03"91
{ET_TIME, 0, 4, 'A', SKINCOLOR_GOLD, 3452, "", 0}, // Darkvile Garden Zone - 1'38"62
{ET_TIME, 0, 5, 'A', SKINCOLOR_GOLD, 3525, "", 0}, // Daytona Speedway Zone - 1'40"71
{ET_TIME, 0, 6, 'A', SKINCOLOR_GOLD, 4047, "", 0}, // Egg Zeppelin Zone - 1'55"62
{ET_TIME, 0, 7, 'A', SKINCOLOR_GOLD, 4041, "", 0}, // Sonic Speedway Zone - 1'55"45
{ET_TIME, 0, 8, 'A', SKINCOLOR_GOLD, 3281, "", 0}, // Hill Top Zone - 1'33"74
{ET_TIME, 0, 9, 'A', SKINCOLOR_GOLD, 4764, "", 0}, // Misty Maze Zone - 2'16"11
{ET_TIME, 0, 10, 'A', SKINCOLOR_GOLD, 4378, "", 0}, // Grand Metropolis - 2'05"08
{ET_TIME, 0, 11, 'A', SKINCOLOR_GOLD, 3678, "", 0}, // Sunbeam Paradise Zone - 1'45"08
{ET_TIME, 0, 12, 'A', SKINCOLOR_GOLD, 3928, "", 0}, // Diamond Square Zone - 1'52"22
{ET_TIME, 0, 13, 'A', SKINCOLOR_GOLD, 3846, "", 0}, // Midnight Meadow Zone - 1'49"88
{ET_TIME, 0, 14, 'A', SKINCOLOR_GOLD, 3278, "", 0}, // Twinkle Cart - 1'33"65
{ET_TIME, 0, 15, 'A', SKINCOLOR_GOLD, 3591, "", 0}, // Pleasure Castle - 1'42"60
{ET_TIME, 0, 16, 'A', SKINCOLOR_GOLD, 5187, "", 0}, // Paradise Hill Zone - 2'28"20
{ET_TIME, 0, 17, 'A', SKINCOLOR_GOLD, 4976, "", 0}, // Sub-Zero Peak Zone - 2'22"17
{ET_TIME, 0, 18, 'A', SKINCOLOR_GOLD, 3696, "", 0}, // Sapphire Coast Zone - 1'45"60
{ET_TIME, 0, 19, 'A', SKINCOLOR_GOLD, 4931, "", 0}, // Sand Valley Zone - 2'20"88
{ET_TIME, 0, 20, 'A', SKINCOLOR_GOLD, 4220, "", 0}, // Megablock Castle Zone - 2'00"57
{ET_TIME, 0, 21, 'A', SKINCOLOR_GOLD, 4053, "", 0}, // Canyon Rush Zone - 1'55"80
{ET_TIME, 0, 22, 'A', SKINCOLOR_GOLD, 3613, "", 0}, // Casino Resort Zone - 1'43"22
{ET_TIME, 0, 23, 'A', SKINCOLOR_GOLD, 4385, "", 0}, // Silvercloud Island Zone - 2'05"28
{ET_TIME, 0, 24, 'A', SKINCOLOR_GOLD, 5321, "", 0}, // Blue Mountain Zone - 2'32"02
{ET_TIME, 0, 25, 'A', SKINCOLOR_GOLD, 4476, "", 0}, // Petroleum Refinery Zone - 2'07"88
{ET_TIME, 0, 26, 'A', SKINCOLOR_GOLD, 3295, "", 0}, // Desert Palace Zone - 1'34"14
{ET_TIME, 0, 27, 'A', SKINCOLOR_GOLD, 4765, "", 0}, // Aurora Atoll Zone - 2'16"14
{ET_TIME, 0, 28, 'A', SKINCOLOR_GOLD, 4670, "", 0}, // Barren Badlands Zone - 2'13"42
{ET_TIME, 0, 29, 'A', SKINCOLOR_GOLD, 5888, "", 0}, // Red Barrage Area - 2'48"22
{ET_TIME, 0, 30, 'A', SKINCOLOR_GOLD, 4047, "", 0}, // Midnight Channel - 1'55"62
{ET_TIME, 0, 31, 'A', SKINCOLOR_GOLD, 4944, "", 0}, // Vanilla Hotel Zone - 2'21"25
{ET_TIME, 0, 32, 'A', SKINCOLOR_GOLD, 4638, "", 0}, // Toxic Palace Zone - 2'12"51
{ET_TIME, 0, 33, 'A', SKINCOLOR_GOLD, 4036, "", 0}, // Ancient Tomb Zone - 1'55"31
{ET_TIME, 0, 34, 'A', SKINCOLOR_GOLD, 3595, "", 0}, // Cloud Cradle Zone K - 1'42"71
{ET_TIME, 0, 35, 'A', SKINCOLOR_GOLD, 4705, "", 0}, // Volcanic Valley Zone - 2'14"42
{ET_TIME, 0, 36, 'A', SKINCOLOR_GOLD, 3314, "", 0}, // Kodachrome Void Zone - 1'34"68
{ET_TIME, 0, 37, 'A', SKINCOLOR_GOLD, 3501, "", 0}, // Boiling Bedrock Zone - 1'40"02
{ET_TIME, 0, 38, 'A', SKINCOLOR_GOLD, 4920, "", 0}, // Egg Quarters - 2'20"57
{ET_TIME, 0, 39, 'A', SKINCOLOR_GOLD, 4318, "", 0}, // Virtual Highway Zone - 2'03"37
{ET_TIME, 0, 40, 'A', SKINCOLOR_GOLD, 3550, "", 0}, // Eggman's Nightclub Zone - 1'41"42
{ET_TIME, 0, 41, 'A', SKINCOLOR_GOLD, 2572, "", 0}, // KKR Ganbare Dochu 2 - 1'13"48
{ET_TIME, 0, 42, 'A', SKINCOLOR_GOLD, 3091, "", 0}, // CK Chao Circuit 1 - 1'28"31
{ET_TIME, 0, 43, 'A', SKINCOLOR_GOLD, 3454, "", 0}, // CK Chao Circuit 2 - 1'38"68
{ET_TIME, 0, 44, 'A', SKINCOLOR_GOLD, 2958, "", 0}, // CK Cloud Tops 2 - 1'24"51
{ET_TIME, 0, 45, 'A', SKINCOLOR_GOLD, 3693, "", 0}, // CK Regal Raceway - 1'45"51
{ET_TIME, 0, 46, 'A', SKINCOLOR_GOLD, 3437, "", 0}, // SD2 Balloon Panic - 1'38"20
{ET_TIME, 0, 47, 'A', SKINCOLOR_GOLD, 3238, "", 0}, // SM Dimension Heist - 1'32"51
{ET_TIME, 0, 48, 'A', SKINCOLOR_GOLD, 3063, "", 0}, // MKSC Sky Garden - 1'27"51
{ET_TIME, 0, 49, 'A', SKINCOLOR_GOLD, 2980, "", 0}, // MKDS Peach Gardens - 1'25"14
{ET_TIME, 0, 50, 'A', SKINCOLOR_GOLD, 2914, "", 0}, // MKSC Rainbow Road - 1'23"25
{ET_TIME, 0, 51, 'A', SKINCOLOR_GOLD, 3003, "", 0}, // SMK Donut Plains 1 - 1'25"80
{ET_TIME, 0, 52, 'A', SKINCOLOR_GOLD, 2930, "", 0}, // SMK Mario Circuit 2 - 1'23"71
{ET_TIME, 0, 53, 'A', SKINCOLOR_GOLD, 2389, "", 0}, // SMK Ghost Valley 2 - 1'08"25
{ET_TIME, 0, 54, 'A', SKINCOLOR_GOLD, 4292, "", 0}, // SMK Bowser Castle 3 - 2'02"62
{ET_TIME, 0, 55, 'A', SKINCOLOR_GOLD, 2346, "", 0}, // SMK Vanilla Lake 2 - 1'07"02
// SILVER NORMAL MEDALS
// The general "guideline" of how good we want a player to be at a map.
{ET_TIME, 0, 1, 'B', SKINCOLOR_GREY, 110*TICRATE, "", 0}, // Green Hills Zone - 1'50"00
{ET_TIME, 0, 2, 'B', SKINCOLOR_GREY, 160*TICRATE, "", 0}, // Dark Race - 2'40"00
{ET_TIME, 0, 3, 'B', SKINCOLOR_GREY, 160*TICRATE, "", 0}, // Northern District Zone - 2'40"00
{ET_TIME, 0, 4, 'B', SKINCOLOR_GREY, 120*TICRATE, "", 0}, // Darkvile Garden Zone - 2'00"00
{ET_TIME, 0, 5, 'B', SKINCOLOR_GREY, 130*TICRATE, "", 0}, // Daytona Speedway Zone - 2'10"00
{ET_TIME, 0, 6, 'B', SKINCOLOR_GREY, 140*TICRATE, "", 0}, // Egg Zeppelin Zone - 2'20"00
{ET_TIME, 0, 7, 'B', SKINCOLOR_GREY, 140*TICRATE, "", 0}, // Sonic Speedway Zone - 2'20"00
{ET_TIME, 0, 8, 'B', SKINCOLOR_GREY, 110*TICRATE, "", 0}, // Hill Top Zone - 1'50"00
{ET_TIME, 0, 9, 'B', SKINCOLOR_GREY, 170*TICRATE, "", 0}, // Misty Maze Zone - 2'50"00
{ET_TIME, 0, 10, 'B', SKINCOLOR_GREY, 140*TICRATE, "", 0}, // Grand Metropolis - 2'20"00
{ET_TIME, 0, 11, 'B', SKINCOLOR_GREY, 120*TICRATE, "", 0}, // Sunbeam Paradise Zone - 2'00"00
{ET_TIME, 0, 12, 'B', SKINCOLOR_GREY, 130*TICRATE, "", 0}, // Diamond Square Zone - 2'10"00
{ET_TIME, 0, 13, 'B', SKINCOLOR_GREY, 135*TICRATE, "", 0}, // Midnight Meadow Zone - 2'15"00
{ET_TIME, 0, 14, 'B', SKINCOLOR_GREY, 120*TICRATE, "", 0}, // Twinkle Cart - 2'00"00
{ET_TIME, 0, 15, 'B', SKINCOLOR_GREY, 120*TICRATE, "", 0}, // Pleasure Castle - 2'00"00
{ET_TIME, 0, 16, 'B', SKINCOLOR_GREY, 160*TICRATE, "", 0}, // Paradise Hill Zone - 2'40"00
{ET_TIME, 0, 17, 'B', SKINCOLOR_GREY, 170*TICRATE, "", 0}, // Sub-Zero Peak Zone - 2'50"00
{ET_TIME, 0, 18, 'B', SKINCOLOR_GREY, 130*TICRATE, "", 0}, // Sapphire Coast Zone - 2'10"00
{ET_TIME, 0, 19, 'B', SKINCOLOR_GREY, 170*TICRATE, "", 0}, // Sand Valley Zone - 2'50"00
{ET_TIME, 0, 20, 'B', SKINCOLOR_GREY, 145*TICRATE, "", 0}, // Megablock Castle Zone - 2'25"00
{ET_TIME, 0, 21, 'B', SKINCOLOR_GREY, 140*TICRATE, "", 0}, // Canyon Rush Zone - 2'20"00
{ET_TIME, 0, 22, 'B', SKINCOLOR_GREY, 120*TICRATE, "", 0}, // Casino Resort Zone - 2'00"00
{ET_TIME, 0, 23, 'B', SKINCOLOR_GREY, 150*TICRATE, "", 0}, // Silvercloud Island Zone - 2'30"00
{ET_TIME, 0, 24, 'B', SKINCOLOR_GREY, 170*TICRATE, "", 0}, // Blue Mountain Zone - 2'50"00
{ET_TIME, 0, 25, 'B', SKINCOLOR_GREY, 150*TICRATE, "", 0}, // Petroleum Refinery Zone - 2'30"00
{ET_TIME, 0, 26, 'B', SKINCOLOR_GREY, 120*TICRATE, "", 0}, // Desert Palace Zone - 2'00"00
{ET_TIME, 0, 27, 'B', SKINCOLOR_GREY, 160*TICRATE, "", 0}, // Aurora Atoll Zone - 2'40"00
{ET_TIME, 0, 28, 'B', SKINCOLOR_GREY, 150*TICRATE, "", 0}, // Barren Badlands Zone - 2'30"00
{ET_TIME, 0, 29, 'B', SKINCOLOR_GREY, 170*TICRATE, "", 0}, // Red Barrage Area - 2'50"00
{ET_TIME, 0, 30, 'B', SKINCOLOR_GREY, 135*TICRATE, "", 0}, // Midnight Channel - 2'15"00
{ET_TIME, 0, 31, 'B', SKINCOLOR_GREY, 160*TICRATE, "", 0}, // Vanilla Hotel Zone - 2'40"00
{ET_TIME, 0, 32, 'B', SKINCOLOR_GREY, 160*TICRATE, "", 0}, // Toxic Palace Zone - 2'40"00
{ET_TIME, 0, 33, 'B', SKINCOLOR_GREY, 150*TICRATE, "", 0}, // Ancient Tomb Zone - 2'30"00
{ET_TIME, 0, 34, 'B', SKINCOLOR_GREY, 120*TICRATE, "", 0}, // Cloud Cradle Zone K - 2'00"00
{ET_TIME, 0, 35, 'B', SKINCOLOR_GREY, 165*TICRATE, "", 0}, // Volcanic Valley Zone - 2'45"00
{ET_TIME, 0, 36, 'B', SKINCOLOR_GREY, 110*TICRATE, "", 0}, // Kodachrome Void Zone - 1'50"00
{ET_TIME, 0, 37, 'B', SKINCOLOR_GREY, 130*TICRATE, "", 0}, // Boiling Bedrock Zone - 2'10"00
{ET_TIME, 0, 38, 'B', SKINCOLOR_GREY, 165*TICRATE, "", 0}, // Egg Quarters - 2'45"00
{ET_TIME, 0, 39, 'B', SKINCOLOR_GREY, 145*TICRATE, "", 0}, // Virtual Highway Zone - 2'25"00
{ET_TIME, 0, 40, 'B', SKINCOLOR_GREY, 120*TICRATE, "", 0}, // Eggman's Nightclub Zone - 2'00"00
{ET_TIME, 0, 41, 'B', SKINCOLOR_GREY, 100*TICRATE, "", 0}, // KKR Ganbare Dochu 2 - 1'40"00
{ET_TIME, 0, 42, 'B', SKINCOLOR_GREY, 110*TICRATE, "", 0}, // CK Chao Circuit 1 - 1'50"00
{ET_TIME, 0, 43, 'B', SKINCOLOR_GREY, 120*TICRATE, "", 0}, // CK Chao Circuit 2 - 2'00"00
{ET_TIME, 0, 44, 'B', SKINCOLOR_GREY, 110*TICRATE, "", 0}, // CK Cloud Tops 2 - 1'50"00
{ET_TIME, 0, 45, 'B', SKINCOLOR_GREY, 130*TICRATE, "", 0}, // CK Regal Raceway - 2'10"00
{ET_TIME, 0, 46, 'B', SKINCOLOR_GREY, 110*TICRATE, "", 0}, // SD2 Balloon Panic - 1'50"00
{ET_TIME, 0, 47, 'B', SKINCOLOR_GREY, 130*TICRATE, "", 0}, // SM Dimension Heist - 2'10"00
{ET_TIME, 0, 48, 'B', SKINCOLOR_GREY, 110*TICRATE, "", 0}, // MKSC Sky Garden - 1'50"00
{ET_TIME, 0, 49, 'B', SKINCOLOR_GREY, 105*TICRATE, "", 0}, // MKDS Peach Gardens - 1'45"00
{ET_TIME, 0, 50, 'B', SKINCOLOR_GREY, 120*TICRATE, "", 0}, // MKSC Rainbow Road - 2'00"00
{ET_TIME, 0, 51, 'B', SKINCOLOR_GREY, 100*TICRATE, "", 0}, // SMK Donut Plains 1 - 1'40"00
{ET_TIME, 0, 52, 'B', SKINCOLOR_GREY, 105*TICRATE, "", 0}, // SMK Mario Circuit 2 - 1'45"00
{ET_TIME, 0, 53, 'B', SKINCOLOR_GREY, 90*TICRATE, "", 0}, // SMK Ghost Valley 2 - 1'30"00
{ET_TIME, 0, 54, 'B', SKINCOLOR_GREY, 150*TICRATE, "", 0}, // SMK Bowser Castle 3 - 2'30"00
{ET_TIME, 0, 55, 'B', SKINCOLOR_GREY, 90*TICRATE, "", 0} // SMK Vanilla Lake 2 - 1'30"00
};
emblem_t emblemlocations[MAXEMBLEMS] = {0};
// Default Extra Emblems
extraemblem_t extraemblems[MAXEXTRAEMBLEMS] =
@ -177,7 +60,7 @@ unlockable_t unlockables[MAXUNLOCKABLES] =
};
// Number of emblems and extra emblems
INT32 numemblems = 110;
INT32 numemblems = 0;
INT32 numextraemblems = 5;
// DEFAULT CONDITION SETS FOR SRB2KART:
@ -263,7 +146,10 @@ void M_ClearSecrets(void)
{
INT32 i;
memset(mapvisited, 0, sizeof(mapvisited));
for (i = 0; i < nummapheaders; ++i)
{
mapheaderinfo[i]->mapvisited = 0;
}
for (i = 0; i < MAXEMBLEMS; ++i)
emblemlocations[i].collected = false;
@ -298,11 +184,19 @@ UINT8 M_CheckCondition(condition_t *cn)
case UC_OVERALLTIME: // Requires overall time <= x
return (M_GotLowEnoughTime(cn->requirement));
case UC_MAPVISITED: // Requires map x to be visited
return ((mapvisited[cn->requirement - 1] & MV_VISITED) == MV_VISITED);
case UC_MAPBEATEN: // Requires map x to be beaten
return ((mapvisited[cn->requirement - 1] & MV_BEATEN) == MV_BEATEN);
case UC_MAPENCORE: // Requires map x to be beaten in encore
return ((mapvisited[cn->requirement - 1] & MV_ENCORE) == MV_ENCORE);
{
UINT8 mvtype = MV_VISITED;
if (cn->type == UC_MAPBEATEN)
mvtype = MV_BEATEN;
else if (cn->type == UC_MAPENCORE)
mvtype = MV_ENCORE;
return ((cn->requirement < nummapheaders)
&& (mapheaderinfo[cn->requirement])
&& ((mapheaderinfo[cn->requirement]->mapvisited & mvtype) == mvtype));
}
case UC_MAPTIME: // Requires time on map <= x
return (G_GetBestTime(cn->extrainfo1) <= (unsigned)cn->requirement);
case UC_TRIGGER: // requires map trigger set
@ -467,10 +361,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)
@ -500,17 +401,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)
@ -622,14 +530,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;
@ -648,7 +556,7 @@ emblem_t *M_GetLevelEmblems(INT32 mapnum)
static INT32 map = -1;
static INT32 i = -1;
if (mapnum > 0)
if (mapnum >= 0)
{
map = mapnum;
i = numemblems;
@ -656,7 +564,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

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

View file

@ -424,12 +424,14 @@ static void Dummystaff_OnChange(void);
consvar_t cv_showfocuslost = CVAR_INIT ("showfocuslost", "Yes", CV_SAVE, CV_YesNo, NULL);
static CV_PossibleValue_t map_cons_t[] = {
{0,"MIN"},
{NUMMAPS, "MAX"},
{-1,"MIN"},
{NEXTMAP_SPECIAL, "MAX"}, // TODO: kill nextmap (can't do that i'm afraid!)
{0, NULL}
};
consvar_t cv_nextmap = CVAR_INIT ("nextmap", "1", CV_HIDEN|CV_CALL, map_cons_t, Nextmap_OnChange);
static INT16 lastnextmap = 1;
static CV_PossibleValue_t skins_cons_t[MAXSKINS+1] = {{1, DEFAULTSKIN}};
consvar_t cv_chooseskin = CVAR_INIT ("chooseskin", DEFAULTSKIN, CV_HIDEN|CV_CALL, skins_cons_t, Nextmap_OnChange);
@ -1783,6 +1785,23 @@ INT32 HU_GetHighlightColor(void)
return highlightflags;
}
fixed_t M_GetMapThumbnail(INT16 mapnum, patch_t **out)
{
patch_t *patch = NULL;
if (mapnum == -1)
patch = randomlvl;
else if (mapnum >= 0 && mapnum < nummapheaders && mapheaderinfo[mapnum])
patch = mapheaderinfo[mapnum]->thumbnailPic;
if (!patch)
patch = blanklvl;
*out = patch;
// check width instead of height because haha big winton
return patch->width >= 320 ? FRACUNIT : FRACUNIT*2;
}
// Sky Room
menu_t SR_PandoraDef =
{
@ -2110,26 +2129,45 @@ static INT32 M_GetFirstLevelInList(void);
void Nextmap_OnChange(void)
{
char *leveltitle;
UINT8 active;
const char *gamemode = (levellistmode == LLM_ITEMBREAKER) ? "IB" : "RA";
// welp, we're stuck with nextmap for the time being. so just make the damn thing work
if (cv_nextmap.value != lastnextmap)
{
boolean increment = cv_nextmap.value > lastnextmap;
INT16 oldvalue = cv_nextmap.value - 1;
INT16 newvalue = oldvalue;
INT32 gt = cv_newgametype.value;
while (!M_CanShowLevelInList(newvalue, gt))
{
if (increment) // Going up!
{
if (++newvalue == nummapheaders)
newvalue = -1;
}
else // Going down!
{
if (--newvalue == -2)
newvalue = nummapheaders-1;
}
if (newvalue == oldvalue)
break; // don't loop forever if there's none of a certain gametype
}
cv_nextmap.value = lastnextmap = newvalue + 1;
}
// Update the string in the consvar.
Z_Free(cv_nextmap.zstring);
leveltitle = G_BuildMapTitle(cv_nextmap.value);
cv_nextmap.string = cv_nextmap.zstring = leveltitle ? leveltitle : Z_StrDup(G_BuildMapName(cv_nextmap.value));
leveltitle = cv_nextmap.value ? G_BuildMapTitle(cv_nextmap.value) : Z_StrDup("Random");
cv_nextmap.string = cv_nextmap.zstring = leveltitle;
if (currentMenu == &SP_TimeAttackDef)
{
// see also p_setup.c's P_LoadRecordGhosts
const size_t glen = strlen(srb2home)+1+strlen("media")+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1;
char *gpath = malloc(glen);
const char *gamemode = (levellistmode == LLM_ITEMBREAKER) ? "IB" : "RA";
char *gpath = xva("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value));
INT32 i;
if (!gpath)
return;
sprintf(gpath,"%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value));
UINT8 active = 0;
CV_StealthSetValue(&cv_dummystaff, 0);
@ -2198,9 +2236,6 @@ void Nextmap_OnChange(void)
itemOn = tastart;
}
if (mapheaderinfo[cv_nextmap.value-1] && mapheaderinfo[cv_nextmap.value-1]->forcecharacter[0] != '\0')
CV_Set(&cv_chooseskin, mapheaderinfo[cv_nextmap.value-1]->forcecharacter);
free(gpath);
}
}
@ -2239,7 +2274,8 @@ static void Dummystaff_OnChange(void)
dummystaffname[0] = '\0';
if ((l = W_CheckNumForName(va("%sS01",G_BuildMapName(cv_nextmap.value)))) == LUMPERROR)
// TODO: Use map header to determine lump name
if ((l = W_CheckNumForLongName(va("%sS01",G_BuildMapName(cv_nextmap.value)))) == LUMPERROR)
{
CV_StealthSetValue(&cv_dummystaff, 0);
return;
@ -2248,7 +2284,7 @@ static void Dummystaff_OnChange(void)
{
char *temp = dummystaffname;
UINT8 numstaff = 1;
while (numstaff < 99 && (l = W_CheckNumForName(va("%sS%02u",G_BuildMapName(cv_nextmap.value),numstaff+1))) != LUMPERROR)
while (numstaff < 99 && (l = W_CheckNumForLongName(va("%sS%02u",G_BuildMapName(cv_nextmap.value),numstaff+1))) != LUMPERROR)
numstaff++;
if (cv_dummystaff.value < 1)
@ -2256,7 +2292,7 @@ static void Dummystaff_OnChange(void)
else if (cv_dummystaff.value > numstaff)
CV_StealthSetValue(&cv_dummystaff, 1);
if ((l = W_CheckNumForName(va("%sS%02u",G_BuildMapName(cv_nextmap.value), cv_dummystaff.value))) == LUMPERROR)
if ((l = W_CheckNumForLongName(va("%sS%02u",G_BuildMapName(cv_nextmap.value), cv_dummystaff.value))) == LUMPERROR)
return; // shouldn't happen but might as well check...
G_UpdateStaffGhostName(l);
@ -4458,18 +4494,24 @@ static void M_PrepareLevelSelect(void)
//
boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt)
{
UINT32 tolflag = G_TOLFlag(gt);
// Random map!
if (mapnum == -1)
return (levellistmode == LLM_CREATESERVER);
// Does the map exist?
if (!mapheaderinfo[mapnum])
if (mapnum < 0 || mapnum >= nummapheaders || !mapheaderinfo[mapnum])
return false;
// Does the map have a name?
if (!mapheaderinfo[mapnum]->lvlttl[0])
return false;
// Does the map have a LUMP?
if (mapheaderinfo[mapnum]->lumpnum == LUMPERROR)
return false;
switch (levellistmode)
{
case LLM_CREATESERVER:
@ -4480,10 +4522,11 @@ boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt)
if (M_MapLocked(mapnum+1))
return false; // not unlocked
if (gt >= 0 && gt < gametypecount && mapheaderinfo[mapnum]->typeoflevel & gametypetol[gt])
return true;
// Check for TOL
if (!(mapheaderinfo[mapnum]->typeoflevel & tolflag))
return false;
return false;
return true;
/*case LLM_LEVELSELECT:
if (mapheaderinfo[mapnum]->levelselect != maplistoption)
@ -4511,7 +4554,7 @@ boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt)
if (mapheaderinfo[mapnum]->menuflags & LF2_HIDEINMENU)
return false; // map hell
if ((mapheaderinfo[mapnum]->menuflags & LF2_VISITNEEDED) && !mapvisited[mapnum])
if ((mapheaderinfo[mapnum]->menuflags & LF2_VISITNEEDED) && !mapheaderinfo[mapnum]->mapvisited)
return false;
return true;
@ -4534,7 +4577,7 @@ static INT32 M_CountLevelsToShowInList(void)
{
INT32 mapnum, count = 0;
for (mapnum = 0; mapnum < NUMMAPS; mapnum++)
for (mapnum = 0; mapnum < nummapheaders; mapnum++)
if (M_CanShowLevelInList(mapnum, -1))
count++;
@ -4545,7 +4588,7 @@ static INT32 M_GetFirstLevelInList(void)
{
INT32 mapnum;
for (mapnum = 0; mapnum < NUMMAPS; mapnum++)
for (mapnum = 0; mapnum < nummapheaders; mapnum++)
if (M_CanShowLevelInList(mapnum, -1))
return mapnum + 1;
@ -5563,7 +5606,6 @@ static void M_HandleReplayHutList(INT32 choice)
#define SCALEDVIEWHEIGHT (vid.height/vid.dupy)
static void DrawReplayHutReplayInfo(void)
{
lumpnum_t lumpnum;
patch_t *patch;
UINT8 *colormap;
INT32 x, y, w, h;
@ -5588,21 +5630,18 @@ static void DrawReplayHutReplayInfo(void)
// Draw level stuff
x = 15; y = 15;
// A 160x100 image of the level as entry MAPxxP
//CONS_Printf("%d %s\n", demolist[dir_on[menudepthleft]].map, G_BuildMapName(demolist[dir_on[menudepthleft]].map));
lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(demolist[dir_on[menudepthleft]].map)));
if (lumpnum != LUMPERROR)
patch = W_CachePatchNum(lumpnum, PU_CACHE);
else
patch = W_CachePatchName("M_NOLVL", PU_CACHE);
fixed_t scale = M_GetMapThumbnail(demolist[dir_on[menudepthleft]].map, &patch)/4;
if (patch == blanklvl)
patch = nolvl;
if (!(demolist[dir_on[menudepthleft]].kartspeed & DF_ENCORE))
V_DrawSmallScaledPatch(x, y, V_SNAPTOTOP, patch);
V_DrawFixedPatch(x<<FRACBITS, y<<FRACBITS, scale, V_SNAPTOTOP, patch, NULL);
else
{
w = SHORT(patch->width);
h = SHORT(patch->height);
V_DrawSmallScaledPatch(x+(w>>1), y, V_SNAPTOTOP|V_FLIP, patch);
w = FixedMul(SHORT(patch->width), scale);
h = FixedMul(SHORT(patch->height), scale);
V_DrawFixedPatch((x+(w>>1))<<FRACBITS, y<<FRACBITS, scale, V_SNAPTOTOP|V_FLIP, patch, NULL);
{
static angle_t rubyfloattime = 0;
@ -5614,8 +5653,8 @@ static void DrawReplayHutReplayInfo(void)
x += 85;
if (mapheaderinfo[demolist[dir_on[menudepthleft]].map-1])
V_DrawString(x, y, V_SNAPTOTOP, G_BuildMapTitle(demolist[dir_on[menudepthleft]].map));
if (demolist[dir_on[menudepthleft]].map != NEXTMAP_INVALID)
V_DrawString(x, y, V_SNAPTOTOP, G_BuildMapTitle(demolist[dir_on[menudepthleft]].map+1));
else
V_DrawString(x, y, V_SNAPTOTOP|V_ALLOWLOWERCASE|V_TRANSLUCENT, "Level is not loaded.");
@ -6252,15 +6291,10 @@ static boolean M_ExitPandorasBox(void)
static void M_ChangeLevel(INT32 choice)
{
char mapname[6];
(void)choice;
strlcpy(mapname, G_BuildMapName(cv_nextmap.value), sizeof (mapname));
strlwr(mapname);
mapname[5] = '\0';
INT16 map = cv_nextmap.value ? cv_nextmap.value : G_RandMap(G_TOLFlag(cv_newgametype.value), gamestate == GS_LEVEL ? gamemap-1 : prevmap, 0, 0, false, NULL);
M_ClearMenus(true);
COM_BufAddText(va("map %s -gametype \"%s\"\n", mapname, cv_newgametype.string));
COM_BufAddText(va("map %d -gametype \"%s\"\n", map, cv_newgametype.string));
}
static void M_ConfirmSpectate(INT32 choice)
@ -6618,8 +6652,15 @@ static void M_DrawEmblemHints(void)
for (i = 0; i < numemblems; i++)
{
INT32 checkLevel;
emblem = &emblemlocations[i];
if (emblem->level != gamemap || emblem->type != ET_GLOBAL)
if (emblem->type != ET_GLOBAL)
continue;
checkLevel = G_MapNumber(emblem->level);
if (!mapheaderinfo[checkLevel] || gamemap != checkLevel)
continue;
if (emblem->collected)
@ -7544,7 +7585,8 @@ static void M_ChoosePlayer(INT32 choice)
static INT32 statsLocation;
static INT32 statsMax;
static INT16 statsMapList[NUMMAPS+1];
static INT16 *statsMapList = NULL;
static INT16 statsMapListLen;
static void M_Statistics(INT32 choice)
{
@ -7552,9 +7594,13 @@ static void M_Statistics(INT32 choice)
(void)choice;
memset(statsMapList, 0, sizeof(statsMapList));
if (!statsMapList || nummapheaders != statsMapListLen)
{
statsMapList = Z_Realloc(statsMapList, nummapheaders * sizeof(*statsMapList), PU_LEVEL, NULL);
statsMapListLen = nummapheaders;
}
for (i = 0; i < NUMMAPS; i++)
for (i = 0; i < nummapheaders; i++)
{
if (!mapheaderinfo[i] || mapheaderinfo[i]->lvlttl[0] == '\0')
continue;
@ -7696,18 +7742,18 @@ static void M_DrawLevelStats(void)
V_DrawRightAlignedString(BASEVIDWIDTH-16, 52, 0, va("Race: %i", vspowerlevel[PWRLV_RACE]));
V_DrawRightAlignedString(BASEVIDWIDTH-16, 60, 0, va("Battle: %i", vspowerlevel[PWRLV_BATTLE]));
for (i = 0; i < NUMMAPS; i++)
for (i = 0; i < nummapheaders; i++)
{
if (!mapheaderinfo[i] || (mapheaderinfo[i]->menuflags & LF2_NOTIMEATTACK))
continue;
if (!mainrecords[i] || mainrecords[i]->time <= 0)
if (!mapheaderinfo[i]->mainrecord || mapheaderinfo[i]->mainrecord->time <= 0)
{
mapsunfinished++;
continue;
}
besttime += mainrecords[i]->time;
besttime += mapheaderinfo[i]->mainrecord->time;
}
V_DrawString(20, 70, highlightflags, "Combined time records:");
@ -7784,6 +7830,7 @@ static void M_GrandPrixTemp(INT32 choice)
static void M_StartGrandPrix(INT32 choice)
{
cupheader_t *gpcup = kartcupheaders;
INT32 levelNum;
(void)choice;
@ -7835,9 +7882,11 @@ static void M_StartGrandPrix(INT32 choice)
grandprixinfo.initalize = true;
levelNum = G_MapNumber(grandprixinfo.cup->levellist[0]);
G_DeferedInitNew(
false,
G_BuildMapName(grandprixinfo.cup->levellist[0] + 1),
levelNum + 1,
(UINT8)(cv_chooseskin.value - 1),
(UINT8)(cv_splitplayers.value - 1),
false
@ -7943,10 +7992,10 @@ void M_DrawTimeAttackMenu(void)
{
INT32 dupadjust = (vid.width/vid.dupx);
tic_t lap = 0, time = 0;
if (mainrecords[cv_nextmap.value-1])
if (mapheaderinfo[cv_nextmap.value-1]->mainrecord)
{
lap = mainrecords[cv_nextmap.value-1]->lap;
time = mainrecords[cv_nextmap.value-1]->time;
lap = mapheaderinfo[cv_nextmap.value-1]->mainrecord->lap;
time = mapheaderinfo[cv_nextmap.value-1]->mainrecord->time;
}
V_DrawFill((BASEVIDWIDTH - dupadjust)>>1, 78, dupadjust, 36, 159);
@ -7954,11 +8003,11 @@ void M_DrawTimeAttackMenu(void)
if (levellistmode != LLM_ITEMBREAKER)
{
V_DrawRightAlignedString(149, 80, highlightflags, "BEST LAP:");
K_drawKartTimestamp(lap, 19, 86, 0, 2);
K_drawKartTimestamp(lap, 19, 86, -1, 2);
}
V_DrawRightAlignedString(292, 80, highlightflags, "BEST TIME:");
K_drawKartTimestamp(time, 162, 86, cv_nextmap.value, 1);
K_drawKartTimestamp(time, 162, 86, cv_nextmap.value-1, 1);
}
/*{
char beststr[40];
@ -8134,7 +8183,7 @@ static void M_ChooseTimeAttack(INT32 choice)
else
G_RecordDemo(nameofdemo);
G_DeferedInitNew(false, G_BuildMapName(cv_nextmap.value), (UINT8)(cv_chooseskin.value-1), 0, false);
G_DeferedInitNew(false, cv_nextmap.value, (UINT8)(cv_chooseskin.value-1), 0, false);
}
static void M_HandleStaffReplay(INT32 choice)
@ -8877,7 +8926,7 @@ static INT32 M_FindFirstMap(INT32 gtype)
if (mapheaderinfo[gamemap] && (mapheaderinfo[gamemap]->typeoflevel & gametypetol[gtype]))
return gamemap;
for (i = 0; i < NUMMAPS; i++)
for (i = 0; i < nummapheaders; i++)
{
if (!mapheaderinfo[i])
continue;
@ -8942,24 +8991,12 @@ static void M_StartServer(INT32 choice)
static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade)
{
lumpnum_t lumpnum;
patch_t *PictureOfLevel;
INT32 x, y, w, i, oldval, trans, dupadjust = ((vid.width/vid.dupx) - BASEVIDWIDTH)>>1;
fixed_t scale = M_GetMapThumbnail(cv_nextmap.value-1, &PictureOfLevel)/4;
// A 160x100 image of the level as entry MAPxxP
if (cv_nextmap.value)
{
lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(cv_nextmap.value)));
if (lumpnum != LUMPERROR)
PictureOfLevel = W_CachePatchNum(lumpnum, PU_CACHE);
else
PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE);
}
else
PictureOfLevel = W_CachePatchName("RANDOMLV", PU_CACHE);
w = SHORT(PictureOfLevel->width)/2;
i = SHORT(PictureOfLevel->height)/2;
w = FixedMul(SHORT(PictureOfLevel->width), scale);
i = FixedMul(SHORT(PictureOfLevel->height), scale);
x = BASEVIDWIDTH/2 - w/2;
y = currentMenu->y + 130 + 8 - i;
@ -8971,14 +9008,14 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade)
V_DrawFill(x-1, y-1, w+2, i+2, trans); // variable reuse...
if ((cv_kartencore.value != 1) || gamestate == GS_TIMEATTACK || cv_newgametype.value != GT_RACE)
V_DrawSmallScaledPatch(x, y, 0, PictureOfLevel);
V_DrawFixedPatch(x<<FRACBITS, y<<FRACBITS, scale, 0, PictureOfLevel, NULL);
else
{
/*UINT8 *mappingforencore = NULL;
if ((lumpnum = W_CheckNumForName(va("%sE", mapname))) != LUMPERROR)
mappingforencore = W_CachePatchNum(lumpnum, PU_CACHE);*/
V_DrawFixedPatch((x+w)<<FRACBITS, (y)<<FRACBITS, FRACUNIT/2, V_FLIP, PictureOfLevel, 0);
V_DrawFixedPatch((x+w)<<FRACBITS, y<<FRACBITS, scale, V_FLIP, PictureOfLevel, NULL);
{
static angle_t rubyfloattime = 0;
@ -9002,7 +9039,7 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade)
{
i--;
if (i == -2)
i = NUMMAPS-1;
i = nummapheaders-1;
if (i == oldval)
return;
@ -9012,21 +9049,11 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade)
} while (!M_CanShowLevelInList(i, cv_newgametype.value));
// A 160x100 image of the level as entry MAPxxP
if (i+1)
{
lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(i+1)));
if (lumpnum != LUMPERROR)
PictureOfLevel = W_CachePatchNum(lumpnum, PU_CACHE);
else
PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE);
}
else
PictureOfLevel = W_CachePatchName("RANDOMLV", PU_CACHE);
scale = M_GetMapThumbnail(i, &PictureOfLevel)/8;
x -= horizspac + w/2;
V_DrawTinyScaledPatch(x, y, trans, PictureOfLevel);
V_DrawFixedPatch(x<<FRACBITS, y<<FRACBITS, scale, trans, PictureOfLevel, NULL);
} while (x > horizspac-dupadjust);
x = (BASEVIDWIDTH + w)/2 + horizspac;
@ -9039,7 +9066,7 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade)
do
{
i++;
if (i == NUMMAPS)
if (i == nummapheaders)
i = -1;
if (i == oldval)
@ -9050,19 +9077,9 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade)
} while (!M_CanShowLevelInList(i, cv_newgametype.value));
// A 160x100 image of the level as entry MAPxxP
if (i+1)
{
lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(i+1)));
if (lumpnum != LUMPERROR)
PictureOfLevel = W_CachePatchNum(lumpnum, PU_CACHE);
else
PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE);
}
else
PictureOfLevel = W_CachePatchName("RANDOMLV", PU_CACHE);
scale = M_GetMapThumbnail(i, &PictureOfLevel)/8;
V_DrawTinyScaledPatch(x, y, trans, PictureOfLevel);
V_DrawFixedPatch(x<<FRACBITS, y<<FRACBITS, scale, trans, PictureOfLevel, NULL);
x += horizspac + w/2;
}

View file

@ -479,6 +479,8 @@ void M_RefreshPauseMenu(void);
INT32 HU_GetHighlightColor(void);
fixed_t M_GetMapThumbnail(INT16 mapnum, patch_t **out);
// Moviemode menu updating
void Moviemode_option_Onchange(void);

View file

@ -182,32 +182,6 @@ boolean takescreenshot = false; // Take a screenshot this tic
moviemode_t moviemode = MM_OFF;
/** Returns the map number for a map identified by the last two characters in
* its name.
*
* \param first The first character after MAP.
* \param second The second character after MAP.
* \return The map number, or 0 if no map corresponds to these characters.
* \sa G_BuildMapName
*/
INT32 M_MapNumber(char first, char second)
{
if (isdigit(first))
{
if (isdigit(second))
return ((INT32)first - '0') * 10 + ((INT32)second - '0');
return 0;
}
if (!isalpha(first))
return 0;
if (!isalnum(second))
return 0;
return 100 + ((INT32)tolower(first) - 'a') * 36 + (isdigit(second) ? ((INT32)second - '0') :
((INT32)tolower(second) - 'a') + 10);
}
// ==========================================================================
// FILE INPUT / OUTPUT
// ==========================================================================
@ -819,7 +793,7 @@ static void M_PNGText(png_structp png_ptr, png_infop png_info_ptr, PNG_CONST png
"Unknown";
#endif
char rendermodetxt[9];
char maptext[8];
char maptext[MAXMAPLUMPNAME];
char lvlttltext[48];
char locationtxt[40];
char ctrevision[40];
@ -840,7 +814,7 @@ static void M_PNGText(png_structp png_ptr, png_infop png_info_ptr, PNG_CONST png
}
if (gamestate == GS_LEVEL)
snprintf(maptext, 8, "%s", G_BuildMapName(gamemap));
snprintf(maptext, MAXMAPLUMPNAME, "%s", G_BuildMapName(gamemap));
else
snprintf(maptext, 8, "Unknown");
@ -1739,6 +1713,32 @@ char *va(const char *format, ...)
return string;
}
/** Allocates and returns a string made out of varargs.
*
* \param format Format string.
* \return Pointer to the resulting string.
*/
char *xva(const char *format, ...)
{
va_list argptr;
char *string;
va_start(argptr, format);
int size = vsnprintf(NULL, 0, format, argptr);
if (size < 0)
I_Error("xva: can't format string");
string = static_cast<char *>(malloc((unsigned)size+1));
if (!string)
I_Error("xva: out of memory");
va_end(argptr);
va_start(argptr, format);
vsprintf(string, format, argptr);
va_end(argptr);
return string;
}
/** Creates a string in the first argument that is the second argument followed
* by the third argument followed by the first argument.
* Useful for making filenames with full path. s1 = s2+s3+s1

View file

@ -46,8 +46,6 @@ void M_StopMovie(void);
// the file where game vars and settings are saved
#define CONFIGFILENAME "kartconfig.cfg"
INT32 M_MapNumber(char first, char second);
boolean FIL_WriteFile(char const *name, const void *source, size_t length);
size_t FIL_ReadFileTag(char const *name, UINT8 **buffer, INT32 tag);
#define FIL_ReadFile(n, b) FIL_ReadFileTag(n, b, PU_STATIC)

View file

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

@ -4852,8 +4852,8 @@ static inline void P_UnArchiveSPGame(savebuffer_t *save, INT16 mapoverride)
// gamemap changed; we assume that its map header is always valid,
// so make it so
if(!mapheaderinfo[gamemap-1])
P_AllocMapHeader(gamemap-1);
if (!gamemap || gamemap > nummapheaders || !mapheaderinfo[gamemap-1])
I_Error("P_UnArchiveSPGame: Internal map ID %d not found (nummapheaders = %d)", gamemap-1, nummapheaders);
//lastmapsaved = gamemap;
lastmaploaded = gamemap;
@ -4908,7 +4908,6 @@ static void P_NetArchiveMisc(savebuffer_t *save, boolean resending)
WRITEUINT8(save->p, mapmusrng);
WRITEUINT32(save->p, leveltime);
WRITEUINT32(save->p, ssspheres);
WRITEINT16(save->p, lastmap);
WRITEUINT16(save->p, bossdisabled);
WRITEUINT8(save->p, ringsdisabled);
@ -4935,7 +4934,6 @@ static void P_NetArchiveMisc(savebuffer_t *save, boolean resending)
}
WRITEUINT32(save->p, token);
WRITEINT32(save->p, sstimer);
WRITEUINT32(save->p, bluescore);
WRITEUINT32(save->p, redscore);
@ -4968,9 +4966,6 @@ static void P_NetArchiveMisc(savebuffer_t *save, boolean resending)
WRITEFIXED(save->p, gravity);
WRITEFIXED(save->p, mapobjectscale);
WRITEUINT32(save->p, countdowntimer);
WRITEUINT8(save->p, countdowntimeup);
// SRB2kart
WRITEINT32(save->p, numgotboxes);
WRITEUINT8(save->p, numtargets);
@ -5041,8 +5036,8 @@ FUNCINLINE static ATTRINLINE boolean P_NetUnArchiveMisc(savebuffer_t *save, bool
// gamemap changed; we assume that its map header is always valid,
// so make it so
if(!mapheaderinfo[gamemap-1])
P_AllocMapHeader(gamemap-1);
if (!gamemap || gamemap > nummapheaders || !mapheaderinfo[gamemap-1])
I_Error("P_NetUnArchiveMisc: Internal map ID %d not found (nummapheaders = %d)", gamemap-1, nummapheaders);
// tell the sound code to reset the music since we're skipping what
// normally sets this flag
@ -5078,7 +5073,6 @@ FUNCINLINE static ATTRINLINE boolean P_NetUnArchiveMisc(savebuffer_t *save, bool
// get the time
leveltime = READUINT32(save->p);
ssspheres = READUINT32(save->p);
lastmap = READINT16(save->p);
bossdisabled = READUINT16(save->p);
ringsdisabled = READUINT8(save->p);
@ -5102,7 +5096,6 @@ FUNCINLINE static ATTRINLINE boolean P_NetUnArchiveMisc(savebuffer_t *save, bool
}
token = READUINT32(save->p);
sstimer = READINT32(save->p);
bluescore = READUINT32(save->p);
redscore = READUINT32(save->p);
@ -5135,9 +5128,6 @@ FUNCINLINE static ATTRINLINE boolean P_NetUnArchiveMisc(savebuffer_t *save, bool
gravity = READFIXED(save->p);
mapobjectscale = READFIXED(save->p);
countdowntimer = (tic_t)READUINT32(save->p);
countdowntimeup = (boolean)READUINT8(save->p);
// SRB2kart
numgotboxes = READINT32(save->p);
numtargets = READUINT8(save->p);
@ -5314,7 +5304,7 @@ boolean P_LoadGame(savebuffer_t *save, INT16 mapoverride)
return false;
// Only do this after confirming savegame is ok
G_DeferedInitNew(false, G_BuildMapName(gamemap), savedata.skin, 0, true);
G_DeferedInitNew(false, gamemap, savedata.skin, 0, true);
COM_BufAddText("dummyconsvar 1\n"); // G_DeferedInitNew doesn't do this
return true;
@ -5352,3 +5342,93 @@ boolean P_LoadNetGame(savebuffer_t *save, boolean reloading)
return P_UnArchiveLuabanksAndConsistency(save);
}
boolean P_SaveBufferZAlloc(savebuffer_t *save, size_t alloc_size, INT32 tag, void *user)
{
I_Assert(save->buffer == NULL);
save->buffer = (UINT8 *)Z_Malloc(alloc_size, tag, user);
if (save->buffer == NULL)
{
return false;
}
save->size = alloc_size;
save->p = save->buffer;
save->end = save->buffer + save->size;
return true;
}
boolean P_SaveBufferFromExisting(savebuffer_t *save, UINT8 *existing_buffer, size_t existing_size)
{
I_Assert(save->buffer == NULL);
if (existing_buffer == NULL || existing_size == 0)
{
return false;
}
save->buffer = existing_buffer;
save->size = existing_size;
save->p = save->buffer;
save->end = save->buffer + save->size;
return true;
}
boolean P_SaveBufferFromLump(savebuffer_t *save, lumpnum_t lump)
{
I_Assert(save->buffer == NULL);
if (lump == LUMPERROR)
{
return false;
}
save->buffer = (UINT8 *)W_CacheLumpNum(lump, PU_STATIC);
if (save->buffer == NULL)
{
return false;
}
save->size = W_LumpLength(lump);
save->p = save->buffer;
save->end = save->buffer + save->size;
return true;
}
size_t P_SaveBufferFromFile(savebuffer_t *save, char const *name)
{
size_t len = 0;
I_Assert(save->buffer == NULL);
len = FIL_ReadFile(name, &save->buffer);
if (len != 0)
{
save->size = len;
save->p = save->buffer;
save->end = save->buffer + save->size;
}
return len;
}
static void P_SaveBufferInvalidate(savebuffer_t *save)
{
save->buffer = save->p = save->end = NULL;
save->size = 0;
}
void P_SaveBufferFree(savebuffer_t *save)
{
I_Assert(save->buffer != NULL);
Z_Free(save->buffer);
P_SaveBufferInvalidate(save);
}

View file

@ -53,6 +53,13 @@ struct savebuffer_t
size_t size;
};
boolean P_SaveBufferZAlloc(savebuffer_t *save, size_t alloc_size, INT32 tag, void *user);
#define P_SaveBufferAlloc(a,b) P_SaveBufferZAlloc(a, b, PU_STATIC, NULL)
boolean P_SaveBufferFromExisting(savebuffer_t *save, UINT8 *existing_buffer, size_t existing_size);
boolean P_SaveBufferFromLump(savebuffer_t *save, lumpnum_t lump);
size_t P_SaveBufferFromFile(savebuffer_t *save, char const *name);
void P_SaveBufferFree(savebuffer_t *save);
#ifdef __cplusplus
} // extern "C"
#endif

View file

@ -334,11 +334,19 @@ boolean P_IsDegeneratedTubeWaypointSequence(UINT8 sequence)
FUNCNORETURN static ATTRNORETURN void CorruptMapError(const char *msg)
{
// don't use va() because the calling function probably uses it
char mapnum[10];
char mapname[MAXMAPLUMPNAME];
if (gamemap > 0 && gamemap <= nummapheaders && mapheaderinfo[gamemap-1])
{
sprintf(mapname, "%s", mapheaderinfo[gamemap-1]->lumpname);
}
else
{
sprintf(mapname, "ID %d", gamemap-1);
}
sprintf(mapnum, "%hd", gamemap);
CON_LogMessage("Map ");
CON_LogMessage(mapnum);
CON_LogMessage(mapname);
CON_LogMessage(" is corrupt: ");
CON_LogMessage(msg);
CON_LogMessage("\n");
@ -387,40 +395,20 @@ static void P_ClearMapHeaderLighting(mapheader_lighting_t *lighting)
* \param i Map number to clear header for.
* \sa P_ClearMapHeaderInfo
*/
static void P_ClearSingleMapHeaderInfo(INT16 i)
static void P_ClearSingleMapHeaderInfo(INT16 num)
{
const INT16 num = (INT16)(i-1);
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] = '\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]->use_walltransfer = false;
mapheaderinfo[num]->keywords[0] = '\0';
for (i = 0; i < MAXMUSNAMES; i++)
for (int i = 0; i < MAXMUSNAMES; i++)
mapheaderinfo[num]->musname[i][0] = 0;
mapheaderinfo[num]->mustrack = 0;
mapheaderinfo[num]->muspos = 0;
mapheaderinfo[num]->musinterfadeout = 0;
mapheaderinfo[num]->musintername[0] = 0;
mapheaderinfo[num]->muspostbossname[0] = 0;
mapheaderinfo[num]->muspostbosstrack = 0;
mapheaderinfo[num]->muspostbosspos = 0;
mapheaderinfo[num]->muspostbossfadein = 0;
mapheaderinfo[num]->musforcereset = -1;
mapheaderinfo[num]->forcecharacter[0] = '\0';
mapheaderinfo[num]->musname_size = 0;
mapheaderinfo[num]->weather = PRECIP_NONE;
snprintf(mapheaderinfo[num]->skytexture, 5, "SKY1");
@ -428,19 +416,15 @@ static void P_ClearSingleMapHeaderInfo(INT16 i)
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;
@ -453,10 +437,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;
@ -468,110 +452,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);
}
//
@ -808,65 +735,6 @@ void P_ReloadRings(void)
}
}
#ifdef SCANTHINGS
void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum)
{
size_t i, n;
UINT8 *data, *datastart;
UINT16 type, maprings;
INT16 tol;
UINT32 flags;
tol = mapheaderinfo[mapnum-1]->typeoflevel;
flags = mapheaderinfo[mapnum-1]->levelflags;
n = W_LumpLengthPwad(wadnum, lumpnum) / (5 * sizeof (INT16));
//CONS_Printf("%u map things found!\n", n);
maprings = 0;
data = datastart = W_CacheLumpNumPwad(wadnum, lumpnum, PU_STATIC);
for (i = 0; i < n; i++)
{
data += 3 * sizeof (INT16); // skip x y position, angle
type = READUINT16(data) & 4095;
data += sizeof (INT16); // skip options
if (mt->type == mobjinfo[MT_RANDOMITEM].doomednum)
{
nummapboxes++;
}
else if (mt->type == mobjinfo[MT_RING].doomednum)
{
maprings++;
}
else
{
switch (type)
{
case 603: // 10 diagonal rings
maprings += 10;
break;
case 600: // 5 vertical rings
case 601: // 5 vertical rings
case 602: // 5 diagonal rings
maprings += 5;
break;
case 604: // 8 circle rings
maprings += 8;
break;
case 605: // 16 circle rings
maprings += 16;
break;
}
}
}
Z_Free(datastart);
if (maprings)
CONS_Printf("%s has %u rings\n", G_BuildMapName(mapnum), maprings);
}
#endif
static int cmp_loopends(const void *a, const void *b)
{
const mapthing_t
@ -968,20 +836,15 @@ void P_WriteThings(void)
{
size_t i, length;
mapthing_t *mt;
savebuffer_t save;
savebuffer_t save = {0};
INT16 temp;
save.size = nummapthings * sizeof (mapthing_t);
save.p = save.buffer = (UINT8 *)malloc(nummapthings * sizeof (mapthing_t));
if (!save.p)
if (P_SaveBufferAlloc(&save, nummapthings * sizeof (mapthing_t)) == false)
{
CONS_Alert(CONS_ERROR, M_GetText("No more free memory for thing writing!\n"));
return;
}
save.end = save.buffer + save.size;
mt = mapthings;
for (i = 0; i < nummapthings; i++, mt++)
{
@ -2389,7 +2252,7 @@ typedef struct
static FILE *P_OpenTextmap(const char *mode, const char *error)
{
FILE *f;
char *filepath = va(pandf, srb2home, "TEXTMAP");
char *filepath = va("%s" PATHSEP "TEXTMAP.%s.txt", srb2home, mapheaderinfo[gamemap-1]->lumpname);
f = fopen(filepath, mode);
if (!f)
@ -7879,19 +7742,9 @@ static void P_InitLevelSettings(boolean reloadinggamestate)
// emerald hunt
hunt1 = hunt2 = hunt3 = NULL;
// map time limit
if (mapheaderinfo[gamemap-1]->countdown)
{
countdowntimer = mapheaderinfo[gamemap-1]->countdown * TICRATE;
}
else
countdowntimer = 0;
countdowntimeup = false;
// circuit, race and competition stuff
circuitmap = false;
numstarposts = 0;
ssspheres = 0;
numbosswaypoints = 0;
if (!reloadinggamestate)
timeinmap = 0;
@ -8047,43 +7900,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;
@ -8112,7 +7928,7 @@ static void P_LoadRecordGhosts(void)
INT32 i;
const char *gamemode = (modeattacking & ATTACKING_ITEMBREAK) ? "IB" : "RA";
gpath = Z_StrDup(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap)));
gpath = xva("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap));
// Best Time ghost
if (cv_ghost_besttime.value)
@ -8165,14 +7981,15 @@ static void P_LoadRecordGhosts(void)
{
lumpnum_t l;
UINT8 j = 1;
while (j <= 99 && (l = W_CheckNumForName(va("%sS%02u",G_BuildMapName(gamemap),j))) != LUMPERROR)
// 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++;
}
}
Z_Free(gpath);
free(gpath);
}
static void P_SetupCamera(UINT8 pnum, camera_t *cam)
@ -8307,7 +8124,7 @@ static void P_InitGametype(void)
#else
strcpy(ver, VERSIONSTRING);
#endif
sprintf(buf, "%s"PATHSEP"media"PATHSEP"replay"PATHSEP"online"PATHSEP"%s"PATHSEP"%d-%s",
snprintf(buf, sizeof buf, "%s"PATHSEP"media"PATHSEP"replay"PATHSEP"online"PATHSEP"%s"PATHSEP"%d-%s",
srb2home, ver, (int) (time(NULL)), G_BuildMapName(gamemap));
parts = M_PathParts(buf);
@ -8329,6 +8146,8 @@ 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;
lumpnum_t oldEncore = LUMPERROR;
levelloading = true;
@ -8366,9 +8185,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;
@ -8540,15 +8356,46 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
}
// internal game map
maplumpname = G_BuildMapName(gamemap);
lastloadedmaplumpnum = W_CheckNumForMap(maplumpname);
maplumpname = mapheaderinfo[gamemap-1]->lumpname;
lastloadedmaplumpnum = mapheaderinfo[gamemap-1]->lumpnum;
if (lastloadedmaplumpnum == LUMPERROR)
I_Error("Map %s not found.\n", maplumpname);
curmapvirt = vres_GetMap(lastloadedmaplumpnum);
R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette,
W_CheckNumForName(va("%s%c", maplumpname, (encoremode ? 'E' : 'T'))));
if (mapheaderinfo[gamemap-1])
{
if (encoremode)
{
encoreLump = vres_Find(curmapvirt, "ENCORE");
if (!encoreLump)
oldEncore = W_CheckNumForName(va("%sE", maplumpname));
}
else
{
encoreLump = vres_Find(curmapvirt, "TWEAKMAP");
if (!encoreLump)
oldEncore = W_CheckNumForName(va("%sT", maplumpname));
}
}
if (encoreLump)
{
R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette, encoreLump->data, encoreLump->size, false);
}
else if (oldEncore != LUMPERROR)
{
// mildly annoying, but whatever
size_t size = W_LumpLength(oldEncore);
void *data = malloc(size);
W_ReadLump(oldEncore, data);
R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette, data, size, wadfiles[WADFILENUM(oldEncore)]->compatmode);
free(data);
}
else
{
R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette, NULL, 0, false);
}
CON_SetupBackColormap();
// SRB2 determines the sky texture to be used depending on the map header.
@ -8662,9 +8509,9 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
R_PrecacheLevel();
if (!(netgame || multiplayer || demo.playback) && !majormods)
mapvisited[gamemap-1] |= MV_VISITED;
mapheaderinfo[gamemap-1]->mapvisited |= MV_VISITED;
else if (!demo.playback)
mapvisited[gamemap-1] |= MV_MP; // you want to record that you've been there this session, but not permanently
mapheaderinfo[gamemap-1]->mapvisited |= MV_MP; // you want to record that you've been there this session, but not permanently
G_AddMapToBuffer(gamemap-1);
@ -8901,6 +8748,143 @@ static lumpinfo_t* FindFolder(const char *folName, UINT16 *start, UINT16 *end, l
return lumpinfo;
}
lumpnum_t wadnamelump = LUMPERROR;
INT16 wadnamemap = 0; // gamemap based
// Initialising map data...
UINT8 P_InitMapData(boolean existingmapheaders)
{
UINT8 ret = 0;
INT32 i;
lumpnum_t maplump;
virtres_t *virtmap;
virtlump_t *minimap, *thumbnailPic;
patch_t *oldPic;
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 (!existingmapheaders)
{
I_Error("P_InitMapData: Base map %s has a header but no level\n", name);
}
#endif
continue;
}
// Always check for cup cache reassociations.
// (The core assumption is that cups < headers.)
{
cupheader_t *cup = kartcupheaders;
INT32 j;
mapheaderinfo[i]->cup = NULL;
while (cup)
{
for (j = 0; j < CUPCACHE_MAX; j++)
{
// Already discovered?
if (cup->cachedlevels[j] != NEXTMAP_INVALID)
continue;
if (!cup->levellist[j] || strcasecmp(cup->levellist[j], name) != 0)
continue;
// Only panic about back-reference for non-bonus material.
if (j < MAXLEVELLIST)
{
if (mapheaderinfo[i]->cup)
I_Error("P_InitMapData: Map %s cannot appear in cups multiple times! (First in %s, now in %s)", name, mapheaderinfo[i]->cup->name, cup->name);
mapheaderinfo[i]->cup = cup;
}
cup->cachedlevels[j] = i;
}
cup = cup->next;
}
}
// No change?
if (mapheaderinfo[i]->lumpnum == maplump)
continue;
// Okay, it does...
{
ret |= MAPRET_ADDED;
if (existingmapheaders)
{
CONS_Printf("%s\n", name);
if (mapheaderinfo[i]->lumpnum != LUMPERROR)
{
G_SetGameModified(multiplayer, true); // oops, double-defined - no record attack privileges for you
//If you replaced the map you're on, end the level when done.
if (i == gamemap - 1)
ret |= MAPRET_CURRENTREPLACED;
}
}
mapheaderinfo[i]->lumpnum = maplump;
if (maplump == wadnamelump)
wadnamemap = i+1;
// Get map thumbnail and minimap
virtmap = vres_GetMap(mapheaderinfo[i]->lumpnum);
thumbnailPic = vres_Find(virtmap, "PICTURE");
minimap = vres_Find(virtmap, "MINIMAP");
// 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);
}
// okay... try finding them the old-fashioned way
else
{
oldPic = W_CachePatchName(va("%sP", name), PU_STATIC);
if (oldPic != missingpat)
mapheaderinfo[i]->thumbnailPic = oldPic;
}
if (minimap)
{
mapheaderinfo[i]->minimapPic = vres_GetPatch(minimap, PU_STATIC);
}
else
{
oldPic = W_CachePatchName(va("%sR", name), PU_STATIC);
if (oldPic != missingpat)
mapheaderinfo[i]->minimapPic = oldPic;
}
vres_Free(virtmap);
}
}
return ret;
}
//
// Add a wadfile to the active wad files,
// replace sounds, musics, patches, textures, sprites and maps
@ -8926,7 +8910,6 @@ UINT16 P_PartialAddWadFile(const char *wadfilename, wadcompat_t compat)
UINT16 numlumps, wadnum;
char *name;
lumpinfo_t *lumpinfo;
boolean mapsadded = false;
// Vars to help us with the position start and amount of each resource type.
// Useful for PK3s since they use folders.
@ -9082,41 +9065,6 @@ UINT16 P_PartialAddWadFile(const char *wadfilename, wadcompat_t compat)
//
R_LoadSpriteInfoLumps(wadnum, numlumps);
//
// search for maps
//
lumpinfo = wadfiles[wadnum]->lumpinfo;
for (i = 0; i < numlumps; i++, lumpinfo++)
{
name = lumpinfo->name;
if (name[0] == 'M' && name[1] == 'A' && name[2] == 'P') // Ignore the headers
{
INT16 num;
if (name[5]!='\0')
continue;
num = (INT16)M_MapNumber(name[3], name[4]);
// we want to record whether this map exists. if it doesn't have a header, we can assume it's not relephant
if (num <= NUMMAPS && mapheaderinfo[num-1])
{
if (mapheaderinfo[num - 1]->alreadyExists != false)
{
G_SetGameModified(multiplayer, true); // oops, double-defined - no record attack privileges for you
}
mapheaderinfo[num - 1]->alreadyExists = true;
}
if (num == gamemap)
partadd_replacescurrentmap = true;
CONS_Printf("%s\n", name);
mapsadded = true;
}
}
if (!mapsadded)
CONS_Printf(M_GetText("No maps added\n"));
refreshdirmenu &= ~REFRESHDIR_GAMEDATA; // Under usual circumstances we'd wait for REFRESHDIR_ flags to disappear the next frame, but this one's a bit too dangerous for that...
partadd_stage = 0;
return wadnum;
@ -9180,9 +9128,16 @@ boolean P_MultiSetupWadFiles(boolean fullsetup)
if (partadd_stage == 2)
{
if (partadd_replacescurrentmap && gamestate == GS_LEVEL && (netgame || multiplayer))
UINT8 mapsadded = P_InitMapData(true);
if (!mapsadded)
CONS_Printf(M_GetText("No maps added\n"));
if ((mapsadded & MAPRET_CURRENTREPLACED)
&& (gamestate == GS_LEVEL)
&& (netgame || multiplayer))
{
CONS_Printf(M_GetText("Current map %d replaced, ending the level to ensure consistency.\n"), gamemap);
CONS_Printf(M_GetText("Current map %s replaced by added file, ending the level to ensure consistency.\n"), mapheaderinfo[gamemap-1]->lumpname);
if (server)
SendNetXCmd(XD_EXITLEVEL, NULL, 0);
}

View file

@ -103,9 +103,6 @@ extern size_t nummapthings;
extern mapthing_t *mapthings;
void P_SetupLevelSky(const char *skytexname, boolean global);
#ifdef SCANTHINGS
void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum);
#endif
void P_RespawnThings(void);
boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate);
void P_PostLoadLevel(void);
@ -114,6 +111,13 @@ void HWR_LoadLevel(void);
#endif
boolean P_AddWadFile(const char *wadfilename, wadcompat_t compat);
#define MAPRET_ADDED (1)
#define MAPRET_CURRENTREPLACED (1<<1)
UINT8 P_InitMapData(boolean existingmapheaders);
extern lumpnum_t wadnamelump;
extern INT16 wadnamemap;
#define WADNAMECHECK(name) (!strncmp(name, "WADNAME", 7))
// WARNING: The following functions should be grouped as follows:
// any amount of PartialAdds followed by MultiSetups until returned true,
// as soon as possible.
@ -150,11 +154,6 @@ void P_DeleteFlickies(INT16 i);
// Needed for NiGHTS
void P_ReloadRings(void);
void P_DeleteGrades(INT16 i);
void P_AddGradesForMare(INT16 i, UINT8 mare, char *gtext);
UINT8 P_GetGrade(UINT32 pscore, INT16 map, UINT8 mare);
UINT8 P_HasGrades(INT16 map, UINT8 mare);
UINT32 P_GetScoreForGrade(INT16 map, UINT8 mare, UINT8 grade);
#ifdef __cplusplus
} // extern "C"

View file

@ -6714,10 +6714,6 @@ void P_InitSpecials(void)
maplighting.directional = lighting->use_light_angle;
maplighting.angle = lighting->light_angle;
// Defaults in case levels don't have them set.
sstimer = mapheaderinfo[gamemap-1]->sstimer*TICRATE + 6;
ssspheres = mapheaderinfo[gamemap-1]->ssspheres;
CheckForBustableBlocks = CheckForBouncySector = CheckForQuicksand = CheckForMarioBlocks = CheckForFloatBob = CheckForReverseGravity = false;
// Set weather
@ -6868,11 +6864,6 @@ void P_SpawnSpecials(boolean fromnetsave)
// Process Section 2
switch(GETSECSPECIAL(sector->special, 2))
{
case 10: // Time for special stage
sstimer = (sector->floorheight>>FRACBITS) * TICRATE + 6; // Time to finish
ssspheres = sector->ceilingheight>>FRACBITS; // Ring count for special stage
break;
case 11: // Custom global gravity!
if (udmf)
break;

View file

@ -303,11 +303,15 @@ boolean P_PlayerMoving(INT32 pnum)
//
UINT8 P_GetNextEmerald(void)
{
if (gamemap >= sstage_start && gamemap <= sstage_end)
return (UINT8)(gamemap - sstage_start);
if (gamemap >= smpstage_start || gamemap <= smpstage_end)
return (UINT8)(gamemap - smpstage_start);
return 0;
INT16 mapnum = gamemap-1;
if (mapnum > nummapheaders || !mapheaderinfo[mapnum])
return 0;
if (!mapheaderinfo[mapnum]->cup || mapheaderinfo[mapnum]->cup->cachedlevels[CUPCACHE_SPECIAL] != mapnum)
return 0;
return mapheaderinfo[mapnum]->cup->emeraldnum;
}
//
@ -2098,9 +2102,6 @@ void P_MovePlayer(player_t *player)
fixed_t runspd;
if (countdowntimeup)
return;
cmd = &player->cmd;
runspd = 14*player->mo->scale; //srb2kart
@ -4293,14 +4294,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

@ -287,7 +287,7 @@ void R_InitColormaps(void)
#endif
}
void R_ReInitColormaps(UINT16 num, lumpnum_t newencoremap)
void R_ReInitColormaps(UINT16 num, void *newencoremap, size_t encoremapsize, boolean compat)
{
char colormap[9] = "COLORMAP";
lumpnum_t lump;
@ -325,18 +325,17 @@ void R_ReInitColormaps(UINT16 num, lumpnum_t newencoremap)
}
// Encore mode.
if (newencoremap != LUMPERROR)
if (newencoremap)
{
lighttable_t *colormap_p, *colormap_p2;
size_t p, i;
encoremap = Z_MallocAlign(256 + 10, PU_LEVEL, NULL, 8);
W_ReadLump(newencoremap, encoremap);
M_Memcpy(encoremap, newencoremap, encoremapsize);
colormap_p = colormap_p2 = colormaps;
colormap_p += COLORMAP_REMAPOFFSET;
remap = wadfiles[WADFILENUM(newencoremap)]->compatmode;
if (remap)
if (compat)
{
UINT8 *copy = malloc(256);
memcpy(copy, encoremap, 256);

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, boolean compat);
void R_ClearColormaps(void);
extracolormap_t *R_CreateDefaultColormap(boolean lighttable);
extracolormap_t *R_GetDefaultColormap(void);

View file

@ -913,6 +913,9 @@ struct patch_t
};
extern patch_t *missingpat;
extern patch_t *blanklvl;
extern patch_t *randomlvl;
extern patch_t *nolvl;
#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

@ -198,12 +198,6 @@ boolean R_SkinUsable(INT32 playernum, INT32 skinnum)
return true;
}
if (Playing() && (R_SkinAvailable(mapheaderinfo[gamemap-1]->forcecharacter) == skinnum))
{
// Being forced to play as this character by the level
return true;
}
if (netgame && (cv_forceskin.value == skinnum))
{
// Being forced to play as this character by the server

View file

@ -442,6 +442,31 @@ static void ST_drawRenderDebug(INT32 *height)
ST_pushDebugString(height, va("Skybox Portals: %4s", sizeu1(i->skybox_portals)));
}
static void ST_drawDemoDebug(INT32 *height)
{
if (!demo.recording && !demo.playback)
return;
size_t needle = demo.buffer->p - demo.buffer->buffer;
size_t size = demo.buffer->size;
double percent = (double)needle / size * 100.0;
double avg = (double)needle / leveltime;
ST_pushDebugString(height, va("%s/%s bytes", sizeu1(needle), sizeu2(size)));
ST_pushDebugString(height, va(
"%.2f/%.2f MB %5.2f%%",
needle / (1024.0 * 1024.0),
size / (1024.0 * 1024.0),
percent
));
ST_pushDebugString(height, va(
"%.2f KB/s (ETA %.2f minutes)",
avg * TICRATE / 1024.0,
(size - needle) / (avg * TICRATE * 60.0)
));
ST_pushDebugString(height, va("Demo (%s)", demo.recording ? "recording" : "playback"));
}
static void ST_drawDebugInfo(void)
{
INT32 height = 192;
@ -512,6 +537,11 @@ static void ST_drawDebugInfo(void)
ST_drawRenderDebug(&height);
}
if (cht_debug & DBG_DEMO)
{
ST_drawDemoDebug(&height);
}
if (cht_debug & DBG_MEMORY)
V_DrawRightAlignedString(320, height, V_MONOSPACE, va("Heap used: %7sKB", sizeu1(Z_TagsUsage(0, INT32_MAX)>>10)));
}

View file

@ -64,11 +64,7 @@
#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 "g_game.h" // G_MapNumber
#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];
UINT32 lumphash;
lumpnum_t lumpnum;
} lumpnum_cache_t;
@ -307,22 +305,6 @@ static inline void W_LoadDehackedLumps(UINT16 wadnum, boolean mainfile)
DEH_LoadDehackedLumpPwad(wadnum, lump, mainfile);
}
}
#ifdef SCANTHINGS
// Scan maps for emblems 'n shit
{
lumpinfo_t *lump_p = wadfiles[wadnum]->lumpinfo;
for (lump = 0; lump < wadfiles[wadnum]->numlumps; lump++, lump_p++)
{
const char *name = lump_p->name;
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
}
static inline boolean CheckCompatFilename(const char *filename)
@ -545,19 +527,76 @@ static lumpinfo_t* ResGetLumpsWad (FILE* handle, UINT16* nlmp, const char* filen
}
else
lump_p->compression = CM_NOCOMPRESSION;
memset(lump_p->name, 0x00, 9);
strncpy(lump_p->name, fileinfo->name, 8);
lump_p->hash = quickncasehash(lump_p->name, 8);
// Allocate the lump's long name.
lump_p->longname = Z_Malloc(9 * sizeof(char), PU_STATIC, NULL);
strncpy(lump_p->longname, fileinfo->name, 8);
lump_p->longname[8] = '\0';
if (WADNAMECHECK(fileinfo->name))
{
size_t namelen;
const char *trimname, *dotpos;
// Allocate the lump's full name.
lump_p->fullname = Z_Malloc(9 * sizeof(char), PU_STATIC, NULL);
strncpy(lump_p->fullname, fileinfo->name, 8);
lump_p->fullname[8] = '\0';
trimname = strrchr(filename, PATHSEP[0]);
#if defined (_WIN32)
// For Zone Builder support, work around temporary filenames.
// They're annoyingly randomised, BUT they follow \Temp\8\8.3...
// AND they're always guaranteed to follow the map file, which
// should already have a WADNAME in it for us to piggyback off.
// EXAMPLE: // \Temp\gj3l7w7n\4f926789.wad
if (trimname != 0
&& wadnamelump != LUMPERROR
&& strlen(trimname+1) == 8+1+3)
{
const char *temp = trimname-1;
while (temp >= filename+5 && *temp != PATHSEP[0])
temp--;
if (((trimname-1) - temp) == 8
&& temp >= filename+5
&& !strncmp(temp-5, PATHSEP"Temp", 5))
{
filename = wadfiles[
((wadnamelump & ~UINT16_MAX) >> 16)
]->filename;
trimname = strrchr(filename, PATHSEP[0]);
}
}
#endif
// Strip away file address
if (trimname != 0)
trimname++;
else
trimname = filename; // Care taken for root files.
// First stop, not last, to permit RR_GREENHILLS.beta3.wad
if ((dotpos = strchr(trimname, '.')) != 0)
namelen = (dotpos + 1 - trimname);
else
namelen = strlen(trimname);
// Allocate the lump's long and full name (save on memory).
lump_p->longname = lump_p->fullname = Z_Calloc(namelen * sizeof(char), PU_STATIC, NULL);
strncpy(lump_p->longname, trimname, namelen);
lump_p->longname[namelen-1] = '\0';
CONS_Debug(DBG_SETUP, "WADNAME handling:\n -- path %s\n -- interpreted lumpname %s\n", filename, lump_p->longname);
// Grab the hash from the first part
lump_p->hash = quickncasehash(lump_p->longname, 8);
wadnamelump = i | (numwadfiles << 16);
}
else
{
// Set up true hash
lump_p->hash = quickncasehash(lump_p->name, 8);
// Allocate the lump's long and full name (save on memory).
lump_p->longname = lump_p->fullname = Z_Malloc(9 * sizeof(char), PU_STATIC, NULL);
strncpy(lump_p->longname, fileinfo->name, 8);
lump_p->longname[8] = '\0';
}
}
free(fileinfov);
*nlmp = numlumps;
@ -1094,6 +1133,63 @@ UINT16 W_FindNextEmptyInPwad(UINT16 wad, UINT16 startlump)
return INT16_MAX;
}
// Get a map marker for WADs, and a standalone WAD file lump inside PK3s.
UINT16 W_CheckNumForMapPwad(const char *name, UINT32 hash, UINT16 wad, UINT16 startlump)
{
UINT16 i, end;
if (wadfiles[wad]->type == RET_WAD)
{
for (i = startlump; i < wadfiles[wad]->numlumps; i++)
{
// Not the hash?
if ((wadfiles[wad]->lumpinfo + i)->hash != hash)
continue;
// Not the name? (always use longname, even in wads, to accomodate WADNAME)
if (strcasecmp(name, (wadfiles[wad]->lumpinfo + i)->longname))
continue;
// Not a header?
if (W_LumpLength(i | (wad << 16)) > 0)
continue;
return i;
}
}
else if (wadfiles[wad]->type == RET_PK3)
{
i = W_CheckNumForFolderStartPK3("maps/", wad, startlump);
if (i != INT16_MAX)
{
end = W_CheckNumForFolderEndPK3("maps/", wad, i);
// Now look for the specified map.
for (; i < end; i++)
{
// Not the hash?
if ((wadfiles[wad]->lumpinfo + i)->hash != hash)
continue;
// Not the name?
if (strcasecmp(name, (wadfiles[wad]->lumpinfo + i)->longname))
continue;
#if 0
// Not a .wad?
if (!W_IsLumpWad(i | (wad << 16)))
continue;
#endif
return i;
}
}
}
return INT16_MAX;
}
//
// Same as the original, but checks in one pwad only.
// wadid is a wad number
@ -1141,12 +1237,14 @@ UINT16 W_CheckNumForLongNamePwad(const char *name, UINT16 wad, UINT16 startlump)
{
UINT16 i;
static char uname[256 + 1];
UINT32 hash;
if (!TestValidLump(wad,0))
return INT16_MAX;
strlcpy(uname, name, sizeof uname);
strupr(uname);
hash = quickncasehash(uname, 8); // Not a mistake, legacy system for short lumpnames
//
// scan forward
@ -1157,8 +1255,14 @@ UINT16 W_CheckNumForLongNamePwad(const char *name, UINT16 wad, UINT16 startlump)
{
lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo + startlump;
for (i = startlump; i < wadfiles[wad]->numlumps; i++, lump_p++)
if (!strcmp(lump_p->longname, uname))
return i;
{
if (lump_p->hash != hash)
continue;
if (strcmp(lump_p->longname, uname))
continue;
return i;
}
}
// not found.
@ -1234,6 +1338,7 @@ UINT16 W_CheckNumForFullNamePK3(const char *name, UINT16 wad, UINT16 startlump)
lumpnum_t W_CheckNumForName(const char *name)
{
INT32 i;
UINT32 hash = name ? quickncasehash(name, 8) : 0;
lumpnum_t check = INT16_MAX;
if (name == NULL)
@ -1247,6 +1352,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);
@ -1284,6 +1390,7 @@ lumpnum_t W_CheckNumForName(const char *name)
lumpnum_t W_CheckNumForLongName(const char *name)
{
INT32 i;
UINT32 hash = name ? quickncasehash(name, 8) : 0;
lumpnum_t check = INT16_MAX;
if (name == NULL)
@ -1321,6 +1428,7 @@ lumpnum_t W_CheckNumForLongName(const char *name)
memset(lumpnumcache[lumpnumcacheindex].lumpname, '\0', 32);
strlcpy(lumpnumcache[lumpnumcacheindex].lumpname, name, 32);
lumpnumcache[lumpnumcacheindex].lumpnum = (i << 16) + check;
lumpnumcache[lumpnumcacheindex].lumphash = hash;
}
return (i << 16) + check;
@ -1329,45 +1437,52 @@ lumpnum_t W_CheckNumForLongName(const char *name)
// Look for valid map data through all added files in descendant order.
// Get a map marker for WADs, and a standalone WAD file lump inside PK3s.
// TODO: Make it search through cache first, maybe...?
lumpnum_t W_CheckNumForMap(const char *name)
{
UINT32 hash = quickncasehash(name, 8);
UINT16 lumpNum, end;
UINT32 i;
lumpinfo_t *p;
for (i = numwadfiles - 1; i < numwadfiles; i--)
lumpnum_t check = INT16_MAX;
UINT32 uhash, hash = quickncasehash(name, LUMPNUMCACHENAME);
INT32 i;
// Check the lumpnumcache first. Loop backwards so that we check
// most recent entries first
for (i = lumpnumcacheindex + LUMPNUMCACHESIZE; i > lumpnumcacheindex; i--)
{
if (wadfiles[i]->type == RET_WAD)
if (lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumphash == hash
&& strcasecmp(lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumpname, name) == 0)
{
for (lumpNum = 0; lumpNum < wadfiles[i]->numlumps; lumpNum++)
{
p = wadfiles[i]->lumpinfo + lumpNum;
if (p->hash == hash && !strncmp(name, p->name, 8))
return (i<<16) + lumpNum;
}
}
else if (wadfiles[i]->type == RET_PK3)
{
lumpNum = W_CheckNumForFolderStartPK3("maps/", i, 0);
if (lumpNum != INT16_MAX)
end = W_CheckNumForFolderEndPK3("maps/", i, lumpNum);
else
continue;
// Now look for the specified map.
for (; lumpNum < end; lumpNum++)
{
p = wadfiles[i]->lumpinfo + lumpNum;
if (p->hash == hash && !strnicmp(name, p->name, 8))
{
const char *extension = strrchr(p->fullname, '.');
if (!(extension && stricmp(extension, ".wad")))
return (i<<16) + lumpNum;
}
}
lumpnumcacheindex = i & (LUMPNUMCACHESIZE - 1);
return lumpnumcache[lumpnumcacheindex].lumpnum;
}
}
return LUMPERROR;
uhash = quickncasehash(name, 8); // Not a mistake, legacy system for short lumpnames
for (i = numwadfiles - 1; i >= 0; i--)
{
check = W_CheckNumForMapPwad(name, uhash, (UINT16)i, 0);
if (check != INT16_MAX)
break; // found it
}
if (check == INT16_MAX)
{
return LUMPERROR;
}
else
{
if (strlen(name) < LUMPNUMCACHENAME)
{
// Update the cache.
lumpnumcacheindex = (lumpnumcacheindex + 1) & (LUMPNUMCACHESIZE - 1);
memset(lumpnumcache[lumpnumcacheindex].lumpname, '\0', LUMPNUMCACHENAME);
strlcpy(lumpnumcache[lumpnumcacheindex].lumpname, name, LUMPNUMCACHENAME);
lumpnumcache[lumpnumcacheindex].lumpnum = (i << 16) + check;
lumpnumcache[lumpnumcacheindex].lumphash = hash;
}
return (i << 16) + check;
}
}
//
@ -1893,6 +2008,28 @@ void *W_CacheLumpName(const char *name, INT32 tag)
// Cache a patch into heap memory, convert the patch format as necessary
//
static void *MakePatch(void *lumpdata, size_t size, INT32 tag, void *cache, boolean remap)
{
void *ptr, *dest;
size_t len = size;
ptr = lumpdata;
#ifndef NO_PNG_LUMPS
if (Picture_IsLumpPNG((UINT8 *)lumpdata, len))
ptr = Picture_PNGConvert((UINT8 *)lumpdata, PICFMT_DOOMPATCH, NULL, NULL, NULL, NULL, len, &len, 0);
#endif
if (remap)
R_DoPaletteRemapPatch(ptr, len);
dest = Z_Calloc(sizeof(patch_t), tag, cache);
Patch_Create(ptr, len, dest);
return dest;
}
void *W_CacheSoftwarePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag)
{
lumpcache_t *lumpcache = NULL;
@ -1905,25 +2042,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
// we already know this is a patch, do palette remapping here
if (wadfiles[wad]->compatmode)
R_DoPaletteRemapPatch(ptr, len);
dest = Z_Calloc(sizeof(patch_t), tag, &lumpcache[lump]);
Patch_Create(ptr, len, dest);
Z_Free(ptr);
MakePatch(lumpdata, len, tag, &lumpcache[lump], wadfiles[wad]->compatmode);
Z_Free(lumpdata);
}
else
Z_ChangeTag(lumpcache[lump], tag);
@ -2395,28 +2520,48 @@ 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;
lumpnum_t lastlump = wadfiles[WADFILENUM(lumpnum)]->numlumps;
// or the end of directory, for PK3 files
@ -2430,8 +2575,12 @@ virtres_t* vres_GetMap(lumpnum_t lumpnum)
free(dirname);
}
for (i = LUMPNUM(lumppos); i < lastlump; i++, lumppos++, numlumps++)
if (memcmp(W_CheckNameForNum(lumppos), "MAP", 3) == 0)
break;
{
if (W_LumpLength(lumppos) > 0)
continue;
break;
}
numlumps++;
vlumps = Z_Malloc(sizeof(virtlump_t)*numlumps, PU_LEVEL, NULL);
@ -2463,7 +2612,12 @@ void vres_Free(virtres_t* vres)
}
while (vres->numlumps--)
Z_Free(vres->vlumps[vres->numlumps].data);
{
if (vres->vlumps[vres->numlumps].data)
{
Z_Free(vres->vlumps[vres->numlumps].data);
}
}
Z_Free(vres->vlumps);
Z_Free(vres);
}
@ -2494,3 +2648,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, false);
#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 @@ struct virtres_t {
virtres_t* vres_GetMap(lumpnum_t);
void vres_Free(virtres_t*);
virtlump_t* vres_Find(const virtres_t*, const char*);
void* vres_GetPatch(virtlump_t *vlump, INT32);
// =========================================================================
// DYNAMIC WAD LOADING
@ -163,6 +164,7 @@ const char *W_CheckNameForNum(lumpnum_t lumpnum);
UINT16 W_FindNextEmptyInPwad(UINT16 wad, UINT16 startlump); // checks only in one pwad
UINT16 W_CheckNumForMapPwad(const char *name, UINT32 hash, UINT16 wad, UINT16 startlump);
UINT16 W_CheckNumForNamePwad(const char *name, UINT16 wad, UINT16 startlump); // checks only in one pwad
UINT16 W_CheckNumForLongNamePwad(const char *name, UINT16 wad, UINT16 startlump);

View file

@ -142,7 +142,6 @@ typedef struct
char str[62];
UINT8 gtc;
const char *gts;
patch_t *pic;
boolean encore;
} y_votelvlinfo;
@ -175,7 +174,6 @@ static patch_t *cursor1 = NULL;
static patch_t *cursor2 = NULL;
static patch_t *cursor3 = NULL;
static patch_t *cursor4 = NULL;
static patch_t *randomlvl = NULL;
static patch_t *rubyicon = NULL;
static void Y_UnloadVoteData(void);
@ -1036,8 +1034,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)
{
@ -1189,6 +1187,9 @@ void Y_VoteDrawer(void)
INT32 i, x, y = 0, height = 0;
UINT8 selected[4];
fixed_t rubyheight = 0;
fixed_t scale;
patch_t *pic;
INT16 mapnum;
if (rendermode == render_none)
return;
@ -1257,19 +1258,19 @@ void Y_VoteDrawer(void)
for (i = 0; i < 4; i++)
{
const char *str;
patch_t *pic;
UINT8 j, color;
if (i == 3)
{
str = "RANDOM";
pic = randomlvl;
mapnum = -1;
}
else
{
str = levelinfo[i].str;
pic = levelinfo[i].pic;
mapnum = votelevels[i][0];
}
scale = M_GetMapThumbnail(mapnum, &pic)/4;
if (selected[i])
{
@ -1333,10 +1334,10 @@ void Y_VoteDrawer(void)
}
if (!levelinfo[i].encore)
V_DrawSmallScaledPatch(BASEVIDWIDTH-100, y, V_SNAPTORIGHT, pic);
V_DrawFixedPatch((BASEVIDWIDTH-100)<<FRACBITS, y<<FRACBITS, scale, V_SNAPTORIGHT, pic, NULL);
else
{
V_DrawFixedPatch((BASEVIDWIDTH-20)<<FRACBITS, (y)<<FRACBITS, FRACUNIT/2, V_FLIP|V_SNAPTORIGHT, pic, 0);
V_DrawFixedPatch((BASEVIDWIDTH-20)<<FRACBITS, y<<FRACBITS, scale, V_FLIP|V_SNAPTORIGHT, pic, NULL);
V_DrawFixedPatch((BASEVIDWIDTH-60)<<FRACBITS, ((y+25)<<FRACBITS) - (rubyheight<<1), FRACUNIT, V_SNAPTORIGHT, rubyicon, NULL);
}
@ -1356,11 +1357,12 @@ void Y_VoteDrawer(void)
}
else
{
scale /= 2;
if (!levelinfo[i].encore)
V_DrawTinyScaledPatch(BASEVIDWIDTH-60, y, V_SNAPTORIGHT, pic);
V_DrawFixedPatch((BASEVIDWIDTH-60)<<FRACBITS, y<<FRACBITS, scale, V_SNAPTORIGHT, pic, NULL);
else
{
V_DrawFixedPatch((BASEVIDWIDTH-20)<<FRACBITS, y<<FRACBITS, FRACUNIT/4, V_FLIP|V_SNAPTORIGHT, pic, 0);
V_DrawFixedPatch((BASEVIDWIDTH-20)<<FRACBITS, y<<FRACBITS, scale, V_FLIP|V_SNAPTORIGHT, pic, NULL);
V_DrawFixedPatch((BASEVIDWIDTH-40)<<FRACBITS, (y<<FRACBITS) + (25<<(FRACBITS-1)) - rubyheight, FRACUNIT/2, V_SNAPTORIGHT, rubyicon, NULL);
}
@ -1385,12 +1387,12 @@ void Y_VoteDrawer(void)
if ((playeringame[i] && !players[i].spectator) && votes[i] != -1)
{
patch_t *pic;
if (votes[i] >= 3 && (i != pickedvote || voteendtic == -1))
pic = randomlvl;
mapnum = -1; // randomlvl
else
pic = levelinfo[votes[i]].pic;
mapnum = votelevels[votes[i]][0];
scale = M_GetMapThumbnail(mapnum, &pic)/8;
if (!timer && i == voteclient.ranim)
{
@ -1402,10 +1404,10 @@ void Y_VoteDrawer(void)
}
if (!levelinfo[votes[i]].encore)
V_DrawTinyScaledPatch(x, y, V_SNAPTOLEFT, pic);
V_DrawFixedPatch(x<<FRACBITS, y<<FRACBITS, scale, V_SNAPTOLEFT, pic, NULL);
else
{
V_DrawFixedPatch((x+40)<<FRACBITS, (y)<<FRACBITS, FRACUNIT/4, V_SNAPTOLEFT|V_FLIP, pic, 0);
V_DrawFixedPatch((x+FixedMul(pic->width, scale))<<FRACBITS, y<<FRACBITS, scale, V_SNAPTOLEFT|V_FLIP, pic, NULL);
V_DrawFixedPatch((x+20)<<FRACBITS, (y<<FRACBITS) + (25<<(FRACBITS-1)) - rubyheight, FRACUNIT/2, V_SNAPTOLEFT, rubyicon, NULL);
}
@ -1719,6 +1721,7 @@ void Y_VoteTicker(void)
void Y_StartVote(void)
{
INT32 i = 0;
boolean battlemode = ((votelevels[0][1] & ~VOTEMODIFIER_ENCORE) == GT_BATTLE); // todo gametyperules
votetic = -1;
@ -1729,14 +1732,13 @@ void Y_StartVote(void)
Y_AnimatedVoteScreenCheck();
widebgpatch = W_CachePatchName(((gametype == GT_BATTLE) ? "BATTLSCW" : "INTERSCW"), PU_STATIC);
bgpatch = W_CachePatchName(((gametype == GT_BATTLE) ? "BATTLSCR" : "INTERSCR"), PU_STATIC);
widebgpatch = W_CachePatchName((battlemode ? "BATTLSCW" : "INTERSCW"), PU_STATIC);
bgpatch = W_CachePatchName((battlemode ? "BATTLSCR" : "INTERSCR"), PU_STATIC);
cursor = W_CachePatchName("M_CURSOR", PU_STATIC);
cursor1 = W_CachePatchName("P1CURSOR", PU_STATIC);
cursor2 = W_CachePatchName("P2CURSOR", PU_STATIC);
cursor3 = W_CachePatchName("P3CURSOR", PU_STATIC);
cursor4 = W_CachePatchName("P4CURSOR", PU_STATIC);
randomlvl = W_CachePatchName("RANDOMLV", PU_STATIC);
rubyicon = W_CachePatchName("RUBYICON", PU_STATIC);
timer = cv_votetime.value*TICRATE;
@ -1761,11 +1763,9 @@ void Y_StartVote(void)
for (i = 0; i < 4; i++)
{
lumpnum_t lumpnum;
// set up the encore
levelinfo[i].encore = (votelevels[i][1] & 0x80);
votelevels[i][1] &= ~0x80;
levelinfo[i].encore = (votelevels[i][1] & VOTEMODIFIER_ENCORE);
votelevels[i][1] &= ~VOTEMODIFIER_ENCORE;
// set up the levelstring
if (mapheaderinfo[votelevels[i][0]]->levelflags & LF_NOZONE || !mapheaderinfo[votelevels[i][0]]->zonttl[0])
@ -1803,13 +1803,6 @@ void Y_StartVote(void)
levelinfo[i].gts = gametype_cons_t[votelevels[i][1]].strvalue;
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;
@ -1833,8 +1826,6 @@ void Y_EndVote(void)
//
static void Y_UnloadVoteData(void)
{
UINT8 i;
voteclient.loaded = false;
if (rendermode != render_soft)
@ -1847,30 +1838,7 @@ static void Y_UnloadVoteData(void)
UNLOAD(cursor2);
UNLOAD(cursor3);
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
}
}
//

View file

@ -47,7 +47,6 @@
#ifdef HAVE_VALGRIND
#include "valgrind.h"
static boolean Z_calloc = false;
#include "memcheck.h"
#endif
#define ZONEID 0xa441d13d
@ -151,7 +150,7 @@ void Z_Free2(void *ptr, const char *file, INT32 line)
if (block->user != NULL)
*block->user = NULL;
#ifdef VALGRIND_DESTROY_MEMPOOL
#ifdef HAVE_VALGRIND
VALGRIND_DESTROY_MEMPOOL(block);
#endif
block->prev->next = block->next;
@ -217,10 +216,6 @@ void *Z_Malloc2(size_t size, INT32 tag, void *user, INT32 alignbits,
ptr = MEMORY(block);
I_Assert((intptr_t)ptr % alignof (max_align_t) == 0);
#ifdef HAVE_VALGRIND
Z_calloc = false;
#endif
block->next = head.next;
block->prev = &head;
head.next = block;
@ -233,8 +228,9 @@ void *Z_Malloc2(size_t size, INT32 tag, void *user, INT32 alignbits,
block->size = sizeof (memblock_t) + size;
block->realsize = size;
#ifdef VALGRIND_CREATE_MEMPOOL
#ifdef HAVE_VALGRIND
VALGRIND_CREATE_MEMPOOL(block, size, Z_calloc);
Z_calloc = false;
#endif
block->id = ZONEID;
@ -266,7 +262,7 @@ void *Z_Malloc2(size_t size, INT32 tag, void *user, INT32 alignbits,
*/
void *Z_Calloc2(size_t size, INT32 tag, void *user, INT32 alignbits, const char *file, INT32 line)
{
#ifdef VALGRIND_MEMPOOL_ALLOC
#ifdef HAVE_VALGRIND
Z_calloc = true;
#endif
return memset(Z_Malloc2 (size, tag, user, alignbits, file, line), 0, size);
@ -435,13 +431,12 @@ void Z_CheckHeap(INT32 i)
CONS_Debug(DBG_MEMORY, "block %u owned by %s:%d\n",
blocknumon, block->ownerfile, block->ownerline);
#endif
#ifdef VALGRIND_MEMPOOL_EXISTS
if (!VALGRIND_MEMPOOL_EXISTS(block))
#ifdef HAVE_VALGRIND
if (RUNNING_ON_VALGRIND && !VALGRIND_MEMPOOL_EXISTS(block))
{
I_Error("Z_CheckHeap %d: block %u"
"(owned by %s:%d)"
" should not exist", i, blocknumon,
" should not exist", i, blocknumon,
block->ownerfile, block->ownerline
);
}
@ -470,9 +465,6 @@ void Z_CheckHeap(INT32 i)
block->ownerfile, block->ownerline
);
}
#ifdef VALGRIND_MAKE_MEM_DEFINED
VALGRIND_MAKE_MEM_DEFINED(hdr, sizeof *hdr);
#endif
if (block->id != ZONEID)
{
I_Error("Z_CheckHeap %d: block %u"