From 944838dc7d86e07d2676daf39931e7c052c954b7 Mon Sep 17 00:00:00 2001 From: fickleheart Date: Mon, 1 Apr 2019 15:07:27 -0500 Subject: [PATCH] Read and write standings to replays --- src/g_game.c | 112 ++++++++++++++++++++++++++++++++++++++++++++------ src/g_game.h | 10 +++-- src/m_menu.c | 104 ++++++++++++++++++++++++++++++++++++++-------- src/y_inter.c | 9 ++++ 4 files changed, 203 insertions(+), 32 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index f2463832..0a20b104 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -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); diff --git a/src/g_game.h b/src/g_game.h index aa20dee4..c44691e8 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -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); diff --git a/src/m_menu.c b/src/m_menu.c index 37902310..4d334a47 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -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<>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(); diff --git a/src/y_inter.c b/src/y_inter.c index 256a8566..4fce58cc 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -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++; } }