Read and write standings to replays

This commit is contained in:
fickleheart 2019-04-01 15:07:27 -05:00
parent 11586a1091
commit 944838dc7d
4 changed files with 203 additions and 32 deletions

View file

@ -3324,8 +3324,7 @@ void G_ExitLevel(void)
// Remove CEcho text on round end.
HU_ClearCEcho();
if (multiplayer && demo.recording && (demo.savemode == DSM_WILLSAVE || demo.savemode == DSM_WILLAUTOSAVE))
G_SaveDemo();
// Don't save demos immediately here! Let standings write first
}
}
@ -4799,6 +4798,9 @@ static ticcmd_t oldcmd[MAXPLAYERS];
#define DW_EXTRASTUFF 0xFE // Numbers below this are reserved for writing player slot data
// Below consts are only used for demo extrainfo sections
#define DW_STANDING 0x00
// For Metal Sonic and time attack ghosts
#define GZT_XYZ 0x01
#define GZT_MOMXY 0x02
@ -6259,6 +6261,41 @@ void G_BeginMetal(void)
oldmetal.angle = mo->angle;
}
void G_WriteStanding(UINT8 ranking, char *name, INT32 skinnum, UINT8 color, UINT32 val)
{
char temp[16];
if (demoinfo_p && (UINT32)(*demoinfo_p) == 0)
{
WRITEUINT8(demo_p, DEMOMARKER); // add the demo end marker
WRITEUINT32(demoinfo_p, demo_p - demobuffer);
}
WRITEUINT8(demo_p, DW_STANDING);
WRITEUINT8(demo_p, ranking);
// Name
memset(temp, 0, 16);
strncpy(temp, name, 16);
M_Memcpy(demo_p,temp,16);
demo_p += 16;
// Skin
memset(temp, 0, 16);
strncpy(temp, skins[skinnum].name, 16);
M_Memcpy(demo_p,temp,16);
demo_p += 16;
// Color
memset(temp, 0, 16);
strncpy(temp, KartColor_Names[color], 16);
M_Memcpy(demo_p,temp,16);
demo_p += 16;
// Score/time/whatever
WRITEUINT32(demo_p, val);
}
void G_SetDemoTime(UINT32 ptime, UINT32 plap)
{
if (!demo.recording || !demotime_p)
@ -6573,7 +6610,7 @@ void G_LoadDemoInfo(menudemo_t *pdemo)
{
UINT8 *infobuffer, *info_p, *extrainfo_p;
UINT8 version, subversion, pdemoflags;
UINT16 pdemoversion, cvarcount;
UINT16 pdemoversion, count;
if (!FIL_ReadFile(pdemo->filepath, &infobuffer))
{
@ -6671,8 +6708,8 @@ void G_LoadDemoInfo(menudemo_t *pdemo)
// Pared down version of CV_LoadNetVars to find the kart speed
pdemo->kartspeed = 1; // Default to normal speed
cvarcount = READUINT16(info_p);
while (cvarcount--)
count = READUINT16(info_p);
while (count--)
{
UINT16 netid;
char *svalue;
@ -6684,9 +6721,10 @@ void G_LoadDemoInfo(menudemo_t *pdemo)
if (netid == cv_kartspeed.netid)
{
for (cvarcount = 0; kartspeed_cons_t[cvarcount].strvalue; cvarcount++)
if (!stricmp(kartspeed_cons_t[cvarcount].strvalue, svalue))
pdemo->kartspeed = kartspeed_cons_t[cvarcount].value;
UINT8 j;
for (j = 0; kartspeed_cons_t[j].strvalue; j++)
if (!stricmp(kartspeed_cons_t[j].strvalue, svalue))
pdemo->kartspeed = kartspeed_cons_t[j].value;
}
else if (netid == cv_basenumlaps.netid && pdemo->gametype == GT_RACE)
pdemo->numlaps = atoi(svalue);
@ -6695,12 +6733,53 @@ void G_LoadDemoInfo(menudemo_t *pdemo)
if (pdemoflags & DF_ENCORE)
pdemo->kartspeed |= DF_ENCORE;
// Temporary info until this is actually present in replays.
/*// Temporary info until this is actually present in replays.
(void)extrainfo_p;
sprintf(pdemo->winnername, "transrights420");
pdemo->winnerskin = 1;
pdemo->winnercolor = SKINCOLOR_MOONSLAM;
pdemo->winnertime = 6666;
pdemo->winnertime = 6666;*/
// Read standings!
count = 0;
while (READUINT8(extrainfo_p) == DW_STANDING) // Assume standings are always first in the extrainfo
{
INT32 i;
char temp[16];
pdemo->standings[count].ranking = READUINT8(extrainfo_p);
// Name
M_Memcpy(pdemo->standings[count].name, extrainfo_p, 16);
extrainfo_p += 16;
// Skin
M_Memcpy(temp,extrainfo_p,16);
extrainfo_p += 16;
pdemo->standings[count].skin = UINT8_MAX;
for (i = 0; i < numskins; i++)
if (stricmp(skins[i].name, temp) == 0)
{
pdemo->standings[count].skin = i;
break;
}
// Color
M_Memcpy(temp,extrainfo_p,16);
extrainfo_p += 16;
for (i = 0; i < MAXSKINCOLORS; i++)
if (!stricmp(KartColor_Names[i],temp)) // SRB2kart
{
pdemo->standings[count].color = i;
break;
}
// Score/time/whatever
pdemo->standings[count].timeorscore = READUINT32(extrainfo_p);
count++;
}
// I think that's everything we need?
free(infobuffer);
@ -7763,7 +7842,14 @@ void G_SaveDemo(void)
UINT8 i;
#endif
WRITEUINT8(demo_p, DEMOMARKER); // add the demo end marker
// Ensure extrainfo pointer is always available, even if no info is present.
if (demoinfo_p && (UINT32)(*demoinfo_p) == 0)
{
WRITEUINT8(demo_p, DEMOMARKER); // add the demo end marker
WRITEUINT32(demoinfo_p, (UINT32)(demo_p - demobuffer));
}
WRITEUINT8(demo_p, DW_END); // Mark end of demo extra data.
M_Memcpy(p, demo.titlename, 64); // Write demo title here
p += 64;
@ -7810,9 +7896,11 @@ void G_SaveDemo(void)
for (i = 0; i < 16; i++, p++)
*p = M_RandomByte(); // This MD5 was chosen by fair dice roll and most likely < 50% correct.
#else
md5_buffer((char *)p+16, demo_p - (p+16), p); // make a checksum of everything after the checksum in the file.
// Make a checksum of everything after the checksum in the file up to the end of the standard data. Extrainfo is freely modifiable.
md5_buffer((char *)p+16, (demobuffer + (UINT32)*demoinfo_p) - (p+16), p);
#endif
if (FIL_WriteFile(va(pandf, srb2home, demoname), demobuffer, demo_p - demobuffer)) // finally output the file.
demo.savemode = DSM_SAVED;
free(demobuffer);

View file

@ -81,9 +81,12 @@ typedef struct menudemo_s {
UINT8 kartspeed; // Add OR DF_ENCORE for encore mode, idk
UINT8 numlaps;
char winnername[17];
UINT8 winnerskin, winnercolor;
UINT32 winnertime;
struct {
UINT8 ranking;
char name[17];
UINT8 skin, color;
UINT32 timeorscore;
} standings[MAXPLAYERS];
} menudemo_t;
@ -190,6 +193,7 @@ void G_BeginRecording(void);
void G_BeginMetal(void);
// Only called by shutdown code.
void G_WriteStanding(UINT8 ranking, char *name, INT32 skinnum, UINT8 color, UINT32 val);
void G_SetDemoTime(UINT32 ptime, UINT32 plap);
UINT8 G_CmpDemoTime(char *oldname, char *newname);

View file

@ -5113,6 +5113,8 @@ void M_ReplayHut(INT32 choice)
dir_on[menudepthleft] = 0;
demo.inreplayhut = true;
replayScrollTitle = 0; replayScrollDelay = TICRATE; replayScrollDir = 1;
PrepReplayList();
menuactive = true;
@ -5201,6 +5203,8 @@ static void M_HandleReplayHutList(INT32 choice)
currentMenu->lastOn = itemOn;
currentMenu = &MISC_ReplayStartDef;
replayScrollTitle = 0; replayScrollDelay = TICRATE; replayScrollDir = 1;
switch (demolist[dir_on[menudepthleft]].addonstatus)
{
case DFILE_ERROR_CANNOTLOAD:
@ -5233,10 +5237,6 @@ static void M_HandleReplayHutList(INT32 choice)
itemOn = 2;
break;
}
/*demo.loadfiles = true; demo.ignorefiles = false; //@TODO prompt
G_DoPlayDemo(demolist[dir_on[menudepthleft]].filepath);*/
}
break;
@ -5308,27 +5308,35 @@ static void DrawReplayHutReplayInfo(void)
"Battle Mode");
V_DrawThinString(x, y+29, highlightflags, "WINNER");
V_DrawString(x+38, y+30, V_ALLOWLOWERCASE, demolist[dir_on[menudepthleft]].winnername);
V_DrawString(x+38, y+30, V_ALLOWLOWERCASE, demolist[dir_on[menudepthleft]].standings[0].name);
V_DrawThinString(x, y+39, highlightflags, "TIME");
V_DrawString(x+28, y+40, 0, va("%2d'%02d\"%02d",
G_TicsToMinutes(demolist[dir_on[menudepthleft]].winnertime, true),
G_TicsToSeconds(demolist[dir_on[menudepthleft]].winnertime),
G_TicsToCentiseconds(demolist[dir_on[menudepthleft]].winnertime)
));
if (demolist[dir_on[menudepthleft]].gametype == GT_RACE)
{
V_DrawThinString(x, y+39, highlightflags, "TIME");
V_DrawRightAlignedString(x+84, y+40, 0, va("%d'%02d\"%02d",
G_TicsToMinutes(demolist[dir_on[menudepthleft]].standings[0].timeorscore, true),
G_TicsToSeconds(demolist[dir_on[menudepthleft]].standings[0].timeorscore),
G_TicsToCentiseconds(demolist[dir_on[menudepthleft]].standings[0].timeorscore)
));
}
else
{
V_DrawThinString(x, y+39, highlightflags, "SCORE");
V_DrawString(x+32, y+40, 0, va("%d", demolist[dir_on[menudepthleft]].standings[0].timeorscore));
}
// Character face!
if (W_CheckNumForName(skins[demolist[dir_on[menudepthleft]].winnerskin].facewant) != LUMPERROR)
if (W_CheckNumForName(skins[demolist[dir_on[menudepthleft]].standings[0].skin].facewant) != LUMPERROR)
{
UINT8 *colormap = R_GetTranslationColormap(
demolist[dir_on[menudepthleft]].winnerskin,
demolist[dir_on[menudepthleft]].winnercolor,
demolist[dir_on[menudepthleft]].standings[0].skin,
demolist[dir_on[menudepthleft]].standings[0].color,
GTC_MENUCACHE);
V_DrawMappedPatch(
BASEVIDWIDTH-15 - SHORT(facewantprefix[demolist[dir_on[menudepthleft]].winnerskin]->width),
BASEVIDWIDTH-15 - SHORT(facewantprefix[demolist[dir_on[menudepthleft]].standings[0].skin]->width),
y+20,
0,
facewantprefix[demolist[dir_on[menudepthleft]].winnerskin],
facewantprefix[demolist[dir_on[menudepthleft]].standings[0].skin],
colormap
);
}
@ -5422,7 +5430,7 @@ static void M_DrawReplayHut(void)
if (demolist[i].type == MD_SUBDIR)
{
localx += 8;
V_DrawFixedPatch(x<<FRACBITS, localy<<FRACBITS, FRACUNIT/4, 0, W_CachePatchName(dirmenu[i][DIR_TYPE] == EXT_UP ? "M_FBACK" : "M_FFLDR", PU_CACHE), NULL);
V_DrawFixedPatch((x - 4)<<FRACBITS, localy<<FRACBITS, FRACUNIT/4, 0, W_CachePatchName(dirmenu[i][DIR_TYPE] == EXT_UP ? "M_FBACK" : "M_FFLDR", PU_CACHE), NULL);
}
if (itemOn == replaylistitem && i == (INT16)dir_on[menudepthleft])
@ -5475,8 +5483,70 @@ static void M_DrawReplayHut(void)
static void M_DrawReplayStartMenu(void)
{
const char *warning;
UINT8 i;
M_DrawGenericBackgroundMenu();
#define STARTY 62-(replayScrollTitle>>1)
// Draw rankings beyond first
for (i = 1; i < MAXPLAYERS && demolist[dir_on[menudepthleft]].standings[i].ranking; i++)
{
V_DrawRightAlignedString(BASEVIDWIDTH-100, STARTY + i*20, highlightflags, va("%2d", demolist[dir_on[menudepthleft]].standings[i].ranking));
V_DrawThinString(BASEVIDWIDTH-96, STARTY + i*20, V_ALLOWLOWERCASE, demolist[dir_on[menudepthleft]].standings[i].name);
if (demolist[dir_on[menudepthleft]].standings[i].timeorscore == UINT32_MAX-1)
V_DrawThinString(BASEVIDWIDTH-96, STARTY + i*20 + 9, 0, "NO CONTEST");
else if (demolist[dir_on[menudepthleft]].gametype == GT_RACE)
V_DrawRightAlignedString(BASEVIDWIDTH-40, STARTY + i*20 + 9, 0, va("%d'%02d\"%02d",
G_TicsToMinutes(demolist[dir_on[menudepthleft]].standings[i].timeorscore, true),
G_TicsToSeconds(demolist[dir_on[menudepthleft]].standings[i].timeorscore),
G_TicsToCentiseconds(demolist[dir_on[menudepthleft]].standings[i].timeorscore)
));
else
V_DrawString(BASEVIDWIDTH-96, STARTY + i*20 + 9, 0, va("%d", demolist[dir_on[menudepthleft]].standings[i].timeorscore));
// Character face!
if (W_CheckNumForName(skins[demolist[dir_on[menudepthleft]].standings[i].skin].facerank) != LUMPERROR)
{
UINT8 *colormap = R_GetTranslationColormap(
demolist[dir_on[menudepthleft]].standings[i].skin,
demolist[dir_on[menudepthleft]].standings[i].color,
GTC_MENUCACHE);
V_DrawMappedPatch(
BASEVIDWIDTH-5 - SHORT(facerankprefix[demolist[dir_on[menudepthleft]].standings[i].skin]->width),
STARTY + i*20,
0,
facerankprefix[demolist[dir_on[menudepthleft]].standings[i].skin],
colormap
);
}
}
#undef STARTY
// Handle scrolling rankings
if (replayScrollDelay)
replayScrollDelay--;
else if (replayScrollDir > 0)
{
if (replayScrollTitle < (i*20 - 100)<<1)
replayScrollTitle++;
else
{
replayScrollDelay = TICRATE;
replayScrollDir = -1;
}
}
else
{
if (replayScrollTitle > 0)
replayScrollTitle--;
else
{
replayScrollDelay = TICRATE;
replayScrollDir = 1;
}
}
V_DrawFill(10, 10, 300, 60, 239);
DrawReplayHutReplayInfo();

View file

@ -304,6 +304,15 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32))
players[i].score += data.match.increase[i];
}
if (demo.recording)
G_WriteStanding(
data.match.pos[data.match.numplayers],
data.match.name[data.match.numplayers],
*data.match.character[data.match.numplayers],
*data.match.color[data.match.numplayers],
data.match.val[data.match.numplayers]
);
data.match.numplayers++;
}
}