Rework demo time/laptime handling

* `ATTACKING_` constants have been changed to be flags
    - `ATTACKING_TIME` contains time data for all gametypes
    - `ATTACKING_LAPS` contains laps data for `GTR_CIRCUIT` on maps with more than 1 lap
* `demoflags` now contains raw `ATTACKING_` flags
* Best time/best lap demo files will now be saved properly again (broken since `new-menus`)
* Ghosts will now be loaded properly again (broken since `unlockables-undefeatable`)
This commit is contained in:
toaster 2022-12-29 21:30:04 +00:00
parent d1852adf30
commit 834150585b
5 changed files with 104 additions and 121 deletions

View file

@ -131,9 +131,9 @@ extern boolean usedCheats;
extern boolean imcontinuing; // Temporary flag while continuing extern boolean imcontinuing; // Temporary flag while continuing
extern boolean metalrecording; extern boolean metalrecording;
#define ATTACKING_NONE 0 #define ATTACKING_NONE 0
#define ATTACKING_TIME 1 #define ATTACKING_TIME 1
#define ATTACKING_CAPSULES 2 #define ATTACKING_LAP (1<<1)
extern UINT8 modeattacking; extern UINT8 modeattacking;
// menu demo things // menu demo things

View file

@ -120,18 +120,14 @@ demoghost *ghosts = NULL;
#define DEMOVERSION 0x0007 #define DEMOVERSION 0x0007
#define DEMOHEADER "\xF0" "KartReplay" "\x0F" #define DEMOHEADER "\xF0" "KartReplay" "\x0F"
#define DF_GHOST 0x01 // This demo contains ghost data too! #define DF_ATTACKMASK (ATTACKING_TIME|ATTACKING_LAP) // This demo contains time/lap data
#define DF_TIMEATTACK 0x02 // This demo is from Time Attack and contains its final completion time & best lap!
#define DF_BREAKTHECAPSULES 0x04 // This demo is from Break the Capsules and contains its final completion time!
#define DF_ATTACKMASK 0x06 // This demo is from ??? attack and contains ???
// 0x08 free #define DF_GHOST 0x08 // This demo contains ghost data too!
#define DF_NONETMP 0x10 // multiplayer but not netgame #define DF_NONETMP 0x10 // multiplayer but not netgame
#define DF_LUAVARS 0x20 // this demo contains extra lua vars #define DF_LUAVARS 0x20 // this demo contains extra lua vars
#define DF_ATTACKSHIFT 1
#define DF_ENCORE 0x40 #define DF_ENCORE 0x40
#define DF_MULTIPLAYER 0x80 // This demo was recorded in multiplayer mode! #define DF_MULTIPLAYER 0x80 // This demo was recorded in multiplayer mode!
@ -2339,10 +2335,19 @@ void G_BeginRecording(void)
memset(name,0,sizeof(name)); memset(name,0,sizeof(name));
demo_p = demobuffer; demo_p = demobuffer;
demoflags = DF_GHOST|(multiplayer ? DF_MULTIPLAYER : (modeattacking<<DF_ATTACKSHIFT));
if (multiplayer && !netgame) demoflags = DF_GHOST;
demoflags |= DF_NONETMP;
if (multiplayer)
{
demoflags |= DF_MULTIPLAYER;
if (!netgame)
demoflags |= DF_NONETMP;
}
else
{
demoflags |= modeattacking;
}
if (encoremode) if (encoremode)
demoflags |= DF_ENCORE; demoflags |= DF_ENCORE;
@ -2382,21 +2387,18 @@ void G_BeginRecording(void)
// character list // character list
G_SaveDemoSkins(&demo_p); G_SaveDemoSkins(&demo_p);
switch ((demoflags & DF_ATTACKMASK)>>DF_ATTACKSHIFT) if ((demoflags & DF_ATTACKMASK))
{ {
case ATTACKING_NONE: // 0 demotime_p = demo_p;
break;
case ATTACKING_TIME: // 1 if (demoflags & ATTACKING_TIME)
demotime_p = demo_p;
WRITEUINT32(demo_p,UINT32_MAX); // time WRITEUINT32(demo_p,UINT32_MAX); // time
if (demoflags & ATTACKING_LAP)
WRITEUINT32(demo_p,UINT32_MAX); // lap WRITEUINT32(demo_p,UINT32_MAX); // lap
break; }
case ATTACKING_CAPSULES: // 2 else
demotime_p = demo_p; {
WRITEUINT32(demo_p,UINT32_MAX); // time demotime_p = NULL;
break;
default: // 3
break;
} }
for (i = 0; i < PRNUMCLASS; i++) for (i = 0; i < PRNUMCLASS; i++)
@ -2600,18 +2602,15 @@ void G_SetDemoTime(UINT32 ptime, UINT32 plap)
{ {
if (!demo.recording || !demotime_p) if (!demo.recording || !demotime_p)
return; return;
if (demoflags & DF_TIMEATTACK) if (demoflags & ATTACKING_TIME)
{ {
WRITEUINT32(demotime_p, ptime); WRITEUINT32(demotime_p, ptime);
}
if (demoflags & ATTACKING_LAP)
{
WRITEUINT32(demotime_p, plap); WRITEUINT32(demotime_p, plap);
demotime_p = NULL;
}
else if (demoflags & DF_BREAKTHECAPSULES)
{
WRITEUINT32(demotime_p, ptime);
(void)plap;
demotime_p = NULL;
} }
demotime_p = NULL;
} }
// Returns bitfield: // Returns bitfield:
@ -2622,7 +2621,8 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
{ {
UINT8 *buffer,*p; UINT8 *buffer,*p;
UINT8 flags; UINT8 flags;
UINT32 oldtime, newtime, oldlap, newlap; UINT32 oldtime = UINT32_MAX, newtime = UINT32_MAX;
UINT32 oldlap = UINT32_MAX, newlap = UINT32_MAX;
UINT16 oldversion; UINT16 oldversion;
size_t bufsize ATTRUNUSED; size_t bufsize ATTRUNUSED;
UINT8 c; UINT8 c;
@ -2658,17 +2658,16 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
G_SkipDemoSkins(&p); G_SkipDemoSkins(&p);
aflags = flags & (DF_TIMEATTACK|DF_BREAKTHECAPSULES); aflags = flags & DF_ATTACKMASK;
I_Assert(aflags); I_Assert(aflags);
if (flags & DF_TIMEATTACK) if (aflags & ATTACKING_LAP)
uselaps = true; // get around uninitalized error uselaps = true;
newtime = READUINT32(p); if (aflags & ATTACKING_TIME)
newtime = READUINT32(p);
if (uselaps) if (uselaps)
newlap = READUINT32(p); newlap = READUINT32(p);
else
newlap = UINT32_MAX;
Z_Free(buffer); Z_Free(buffer);
@ -2724,11 +2723,10 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
G_SkipDemoSkins(&p); G_SkipDemoSkins(&p);
oldtime = READUINT32(p); if (flags & ATTACKING_TIME)
oldtime = READUINT32(p);
if (uselaps) if (uselaps)
oldlap = READUINT32(p); oldlap = READUINT32(p);
else
oldlap = 0;
Z_Free(buffer); Z_Free(buffer);
@ -3136,7 +3134,7 @@ void G_DoPlayDemo(char *defdemoname)
return; return;
} }
modeattacking = (demoflags & DF_ATTACKMASK)>>DF_ATTACKSHIFT; modeattacking = (demoflags & DF_ATTACKMASK);
multiplayer = !!(demoflags & DF_MULTIPLAYER); multiplayer = !!(demoflags & DF_MULTIPLAYER);
demo.netgame = (multiplayer && !(demoflags & DF_NONETMP)); demo.netgame = (multiplayer && !(demoflags & DF_NONETMP));
CON_ToggleOff(); CON_ToggleOff();
@ -3144,21 +3142,10 @@ void G_DoPlayDemo(char *defdemoname)
hu_demotime = UINT32_MAX; hu_demotime = UINT32_MAX;
hu_demolap = UINT32_MAX; hu_demolap = UINT32_MAX;
switch (modeattacking) if (modeattacking & ATTACKING_TIME)
{ hu_demotime = READUINT32(demo_p);
case ATTACKING_NONE: // 0 if (modeattacking & ATTACKING_LAP)
break; hu_demolap = READUINT32(demo_p);
case ATTACKING_TIME: // 1
hu_demotime = READUINT32(demo_p);
hu_demolap = READUINT32(demo_p);
break;
case ATTACKING_CAPSULES: // 2
hu_demotime = READUINT32(demo_p);
break;
default: // 3
modeattacking = ATTACKING_NONE;
break;
}
// Random seed // Random seed
for (i = 0; i < PRNUMCLASS; i++) for (i = 0; i < PRNUMCLASS; i++)
@ -3545,19 +3532,10 @@ void G_AddGhost(char *defdemoname)
return; return;
} }
switch ((flags & DF_ATTACKMASK)>>DF_ATTACKSHIFT) if (flags & ATTACKING_TIME)
{ p += 4;
case ATTACKING_NONE: // 0 if (flags & ATTACKING_LAP)
break; p += 4;
case ATTACKING_TIME: // 1
p += 8; // demo time, lap
break;
case ATTACKING_CAPSULES: // 2
p += 4; // demo time
break;
default: // 3
break;
}
for (i = 0; i < PRNUMCLASS; i++) for (i = 0; i < PRNUMCLASS; i++)
{ {
@ -3587,9 +3565,10 @@ void G_AddGhost(char *defdemoname)
p++; // player number - doesn't really need to be checked, TODO maybe support adding multiple players' ghosts at once p++; // player number - doesn't really need to be checked, TODO maybe support adding multiple players' ghosts at once
// any invalidating flags? // any invalidating flags?
if ((READUINT8(p) & (DEMO_SPECTATOR|DEMO_BOT)) != 0) i = READUINT8(p);
if ((i & (DEMO_SPECTATOR|DEMO_BOT)) != 0)
{ {
CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Invalid player slot.\n"), pdemoname); CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Invalid player slot (spectator/bot)\n"), pdemoname);
Z_Free(skinlist); Z_Free(skinlist);
Z_Free(pdemoname); Z_Free(pdemoname);
Z_Free(buffer); Z_Free(buffer);
@ -3600,6 +3579,8 @@ void G_AddGhost(char *defdemoname)
M_Memcpy(name, p, 16); M_Memcpy(name, p, 16);
p += 16; p += 16;
p += MAXAVAILABILITY;
// Skin // Skin
i = READUINT8(p); i = READUINT8(p);
if (i < worknumskins) if (i < worknumskins)
@ -3620,7 +3601,7 @@ void G_AddGhost(char *defdemoname)
if (READUINT8(p) != 0xFF) if (READUINT8(p) != 0xFF)
{ {
CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Invalid player slot.\n"), pdemoname); CONS_Alert(CONS_NOTICE, M_GetText("Failed to add ghost %s: Invalid player slot (bad terminator)\n"), pdemoname);
Z_Free(skinlist); Z_Free(skinlist);
Z_Free(pdemoname); Z_Free(pdemoname);
Z_Free(buffer); Z_Free(buffer);
@ -3761,19 +3742,10 @@ void G_UpdateStaffGhostName(lumpnum_t l)
G_SkipDemoSkins(&p); G_SkipDemoSkins(&p);
switch ((flags & DF_ATTACKMASK)>>DF_ATTACKSHIFT) if (flags & ATTACKING_TIME)
{ p += 4;
case ATTACKING_NONE: // 0 if (flags & ATTACKING_LAP)
break; p += 4;
case ATTACKING_TIME: // 1
p += 8; // demo time, lap
break;
case ATTACKING_CAPSULES: // 2
p += 4; // demo time
break;
default: // 3
break;
}
for (i = 0; i < PRNUMCLASS; i++) for (i = 0; i < PRNUMCLASS; i++)
{ {

View file

@ -520,13 +520,18 @@ static void G_UpdateRecordReplays(void)
players[consoleplayer].realtime = UINT32_MAX; players[consoleplayer].realtime = UINT32_MAX;
} }
if (((mapheaderinfo[gamemap-1]->mainrecord->time == 0) || (players[consoleplayer].realtime < mapheaderinfo[gamemap-1]->mainrecord->time)) if (modeattacking & ATTACKING_TIME)
&& (players[consoleplayer].realtime < UINT32_MAX)) // DNF
{ {
mapheaderinfo[gamemap-1]->mainrecord->time = players[consoleplayer].realtime; if (((mapheaderinfo[gamemap-1]->mainrecord->time == 0) || (players[consoleplayer].realtime < mapheaderinfo[gamemap-1]->mainrecord->time))
&& (players[consoleplayer].realtime < UINT32_MAX)) // DNF
mapheaderinfo[gamemap-1]->mainrecord->time = players[consoleplayer].realtime;
}
else
{
mapheaderinfo[gamemap-1]->mainrecord->time = 0;
} }
if (modeattacking == ATTACKING_TIME) if (modeattacking & ATTACKING_LAP)
{ {
if ((mapheaderinfo[gamemap-1]->mainrecord->lap == 0) || (bestlap < mapheaderinfo[gamemap-1]->mainrecord->lap)) if ((mapheaderinfo[gamemap-1]->mainrecord->lap == 0) || (bestlap < mapheaderinfo[gamemap-1]->mainrecord->lap))
mapheaderinfo[gamemap-1]->mainrecord->lap = bestlap; mapheaderinfo[gamemap-1]->mainrecord->lap = bestlap;
@ -549,27 +554,32 @@ static void G_UpdateRecordReplays(void)
strcat(gpath, PATHSEP); strcat(gpath, PATHSEP);
strcat(gpath, G_BuildMapName(gamemap)); strcat(gpath, G_BuildMapName(gamemap));
snprintf(lastdemo, 255, "%s-%s-last.lmp", gpath, cv_chooseskin.string); snprintf(lastdemo, 255, "%s-%s-last.lmp", gpath, cv_skin[0].string);
gpath = Z_StrDup(gpath); if (modeattacking != ATTACKING_NONE && FIL_FileExists(lastdemo))
if (FIL_FileExists(lastdemo))
{ {
UINT8 *buf; UINT8 *buf;
size_t len = FIL_ReadFile(lastdemo, &buf); size_t len;
snprintf(bestdemo, 255, "%s-%s-time-best.lmp", gpath, cv_chooseskin.string); gpath = Z_StrDup(gpath);
if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & 1)
{ // Better time, save this demo. len = FIL_ReadFile(lastdemo, &buf);
if (FIL_FileExists(bestdemo))
remove(bestdemo); if (modeattacking & ATTACKING_TIME)
FIL_WriteFile(bestdemo, buf, len); {
CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW RECORD TIME!"), M_GetText("Saved replay as"), bestdemo); snprintf(bestdemo, 255, "%s-%s-time-best.lmp", gpath, cv_skin[0].string);
if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & 1)
{ // Better time, save this demo.
if (FIL_FileExists(bestdemo))
remove(bestdemo);
FIL_WriteFile(bestdemo, buf, len);
CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW RECORD TIME!"), M_GetText("Saved replay as"), bestdemo);
}
} }
if (modeattacking == ATTACKING_TIME) if (modeattacking & ATTACKING_LAP)
{ {
snprintf(bestdemo, 255, "%s-%s-lap-best.lmp", gpath, cv_chooseskin.string); snprintf(bestdemo, 255, "%s-%s-lap-best.lmp", gpath, cv_skin[0].string);
if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & (1<<1)) if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & (1<<1))
{ // Better lap time, save this demo. { // Better lap time, save this demo.
if (FIL_FileExists(bestdemo)) if (FIL_FileExists(bestdemo))
@ -582,9 +592,9 @@ static void G_UpdateRecordReplays(void)
//CONS_Printf("%s '%s'\n", M_GetText("Saved replay as"), lastdemo); //CONS_Printf("%s '%s'\n", M_GetText("Saved replay as"), lastdemo);
Z_Free(buf); Z_Free(buf);
}
Z_Free(gpath); Z_Free(gpath);
}
// Check emblems when level data is updated // Check emblems when level data is updated
if ((earnedEmblems = M_CheckLevelEmblems())) if ((earnedEmblems = M_CheckLevelEmblems()))

View file

@ -4056,14 +4056,12 @@ void M_StartTimeAttack(INT32 choice)
(void)choice; (void)choice;
switch (levellist.newgametype) modeattacking = ATTACKING_TIME;
if ((gametypes[levellist.newgametype]->rules & GTR_CIRCUIT)
&& (mapheaderinfo[levellist.choosemap]->numlaps != 1))
{ {
case GT_BATTLE: modeattacking |= ATTACKING_LAP;
modeattacking = ATTACKING_CAPSULES;
break;
default:
modeattacking = ATTACKING_TIME;
break;
} }
// Still need to reset devmode // Still need to reset devmode

View file

@ -6993,20 +6993,23 @@ static void P_LoadRecordGhosts(void)
gpath = Z_StrDup(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap))); gpath = Z_StrDup(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap)));
// Best Time ghost // Best Time ghost
if (cv_ghost_besttime.value) if (modeattacking & ATTACKING_TIME)
{ {
for (i = 0; i < numskins; ++i) if (cv_ghost_besttime.value)
{ {
if (cv_ghost_besttime.value == 1 && players[consoleplayer].skin != i) for (i = 0; i < numskins; ++i)
continue; {
if (cv_ghost_besttime.value == 1 && players[consoleplayer].skin != i)
continue;
if (FIL_FileExists(va("%s-%s-time-best.lmp", gpath, skins[i].name))) if (FIL_FileExists(va("%s-%s-time-best.lmp", gpath, skins[i].name)))
G_AddGhost(va("%s-%s-time-best.lmp", gpath, skins[i].name)); G_AddGhost(va("%s-%s-time-best.lmp", gpath, skins[i].name));
}
} }
} }
// Best Lap ghost // Best Lap ghost
if (modeattacking != ATTACKING_CAPSULES) if (modeattacking & ATTACKING_LAP)
{ {
if (cv_ghost_bestlap.value) if (cv_ghost_bestlap.value)
{ {