List demos by title in the replay hut

This commit is contained in:
fickleheart 2019-03-31 01:22:41 -05:00
parent 1602b0e3d9
commit 48dcfab7f6
4 changed files with 243 additions and 14 deletions

View file

@ -896,6 +896,8 @@ boolean preparefilemenu(boolean samedepth, boolean replayhut)
strcpy(temp+len, PATHSEP); strcpy(temp+len, PATHSEP);
coredirmenu[folderpos++] = temp; coredirmenu[folderpos++] = temp;
} }
else if (replayhut) // Reverse-alphabetical on just the files; acts as a fake "most recent first" with the current filename format
coredirmenu[sizecoredirmenu - 1 - pos++] = temp;
else else
coredirmenu[numfolders + pos++] = temp; coredirmenu[numfolders + pos++] = temp;
} }

View file

@ -6564,6 +6564,128 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
return c; return c;
} }
void G_LoadDemoInfo(menudemo_t *pdemo)
{
UINT8 *infobuffer, *info_p;
UINT8 version, subversion, pdemoflags;
UINT16 pdemoversion, cvarcount;
if (!FIL_ReadFile(pdemo->filepath, &infobuffer))
{
CONS_Alert(CONS_ERROR, M_GetText("Failed to read file '%s'.\n"), pdemo->filepath);
pdemo->type = MD_INVALID;
sprintf(pdemo->title, "INVALID REPLAY");
return;
}
info_p = infobuffer;
if (memcmp(info_p, DEMOHEADER, 12))
{
CONS_Alert(CONS_ERROR, M_GetText("%s is not a SRB2Kart replay file.\n"), pdemo->filepath);
pdemo->type = MD_INVALID;
sprintf(pdemo->title, "INVALID REPLAY");
Z_Free(infobuffer);
return;
}
pdemo->type = MD_LOADED;
info_p += 12; // DEMOHEADER
version = READUINT8(info_p);
subversion = READUINT8(info_p);
pdemoversion = READUINT16(info_p);
switch(pdemoversion)
{
case DEMOVERSION: // latest always supported
// demo title
M_Memcpy(pdemo->title, info_p, 64);
info_p += 64;
break;
#ifdef DEMO_COMPAT_100
case 0x0001:
pdemo->type = MD_OUTDATED;
sprintf(pdemo->title, "Legacy Replay");
break;
#endif
// too old, cannot support.
default:
CONS_Alert(CONS_ERROR, M_GetText("%s is an incompatible replay format and cannot be played.\n"), pdemo->filepath);
pdemo->type = MD_INVALID;
sprintf(pdemo->title, "INVALID REPLAY");
Z_Free(infobuffer);
return;
}
if (version != VERSION || subversion != SUBVERSION)
pdemo->type = MD_OUTDATED;
info_p += 16; // demo checksum
if (memcmp(info_p, "PLAY", 4))
{
CONS_Alert(CONS_ERROR, M_GetText("%s is the wrong type of recording and cannot be played.\n"), pdemo->filepath);
pdemo->type = MD_INVALID;
sprintf(pdemo->title, "INVALID REPLAY");
Z_Free(infobuffer);
return;
}
demo_p += 4; // "PLAY"
pdemo->map = READINT16(info_p);
demo_p += 16; // mapmd5
pdemoflags = READUINT8(info_p);
// temp?
if (!(pdemoflags & DF_MULTIPLAYER))
{
CONS_Alert(CONS_ERROR, M_GetText("%s is not a multiplayer replay and can't be listed on this menu fully yet.\n"), pdemo->filepath);
Z_Free(infobuffer);
return;
}
pdemo->gametype = READUINT8(info_p);
G_SkipDemoExtraFiles(&info_p); //@TODO see if this information is useful for display?
demo_p += 4; // RNG seed
// Pared down version of CV_LoadNetVars to find the kart speed
cvarcount = READUINT16(info_p);
while (cvarcount--)
{
UINT16 netid;
char *svalue;
netid = READUINT16(info_p);
svalue = (char *)info_p;
SKIPSTRING(info_p);
info_p++; // stealth
if (netid == cv_kartspeed.netid)
{
for (cvarcount = 0; kartspeed_cons_t[cvarcount].value; cvarcount++)
{
if (!strcasecmp(kartspeed_cons_t[cvarcount].strvalue, svalue))
{
pdemo->kartspeed = kartspeed_cons_t[cvarcount].value;
break;
}
}
break;
}
}
if (pdemoflags & DF_ENCORE)
pdemo->kartspeed |= DF_ENCORE;
// I think that's everything we need?
free(infobuffer);
}
// //
// G_PlayDemo // G_PlayDemo
// //

View file

@ -61,6 +61,25 @@ struct demovars_s {
extern struct demovars_s demo; extern struct demovars_s demo;
typedef enum {
MD_NOTLOADED,
MD_LOADED,
MD_SUBDIR,
MD_OUTDATED,
MD_INVALID
} menudemotype_e;
typedef struct menudemo_s {
char filepath[256];
menudemotype_e type;
char title[65]; // Null-terminated for string prints
UINT16 map;
UINT8 gametype;
UINT8 kartspeed; // Add OR DF_ENCORE for encore mode, idk
} menudemo_t;
extern mobj_t *metalplayback; extern mobj_t *metalplayback;
// gametic at level start // gametic at level start
@ -147,6 +166,7 @@ void G_DeferedInitNew(boolean pencoremode, const char *mapname, INT32 pickedchar
UINT8 ssplayers, boolean FLS); UINT8 ssplayers, boolean FLS);
void G_DoLoadLevel(boolean resetplayer); void G_DoLoadLevel(boolean resetplayer);
void G_LoadDemoInfo(menudemo_t *pdemo);
void G_DeferedPlayDemo(const char *demo); void G_DeferedPlayDemo(const char *demo);
// Can be called by the startup code or M_Responder, calls P_SetupLevel. // Can be called by the startup code or M_Responder, calls P_SetupLevel.

View file

@ -338,6 +338,7 @@ static patch_t *addonsp[NUM_EXT+5];
// Replay hut // Replay hut
static void M_ReplayHut(INT32 choice); static void M_ReplayHut(INT32 choice);
static void M_HandleReplayHutList(INT32 choice);
static void M_DrawReplayHut(void); static void M_DrawReplayHut(void);
// Drawing functions // Drawing functions
@ -532,9 +533,10 @@ static menuitem_t MISC_AddonsMenu[] =
static menuitem_t MISC_ReplayHutMenu[] = static menuitem_t MISC_ReplayHutMenu[] =
{ {
{IT_SUBMENU |IT_STRING, NULL, "Replay Options...", NULL, 0}, {IT_SUBMENU |IT_STRING, NULL, "Replay Options...", NULL, 0},
{IT_KEYHANDLER|IT_NOTHING, NULL, "", NULL, 20}, // Dummy menuitem for the replay list {IT_KEYHANDLER|IT_NOTHING, NULL, "", M_HandleReplayHutList, 20}, // Dummy menuitem for the replay list
{IT_NOTHING, NULL, "", NULL, 20}, // Dummy for handling wrapping to the top of the menu..
}; };
// --------------------------------- // ---------------------------------
@ -1602,7 +1604,7 @@ menu_t MISC_ReplayHutDef =
MISC_ReplayHutMenu, MISC_ReplayHutMenu,
M_DrawReplayHut, M_DrawReplayHut,
30, 80, 30, 80,
0, (sizeof (MISC_ReplayHutMenu)/sizeof (menuitem_t)) - 2, // Start on the replay list
NULL NULL
}; };
@ -5008,9 +5010,35 @@ static void M_HandleAddons(INT32 choice)
} }
// ---- REPLAY HUT ----- // ---- REPLAY HUT -----
menudemo_t *demolist;
static INT16 replayOn = 0; static INT16 replayOn = 0;
static void PrepReplayList(void)
{
size_t i;
if (demolist)
Z_Free(demolist);
demolist = Z_Calloc(sizeof(menudemo_t) * sizedirmenu, PU_STATIC, NULL);
for (i = 0; i < sizedirmenu; i++)
{
if (dirmenu[i][DIR_TYPE] == EXT_FOLDER)
{
demolist[i].type = MD_SUBDIR;
strncpy(demolist[i].title, dirmenu[i] + DIR_STRING, 64);
}
else
{
demolist[i].type = MD_NOTLOADED;
snprintf(demolist[i].filepath, 255, "%s%s", menupath, dirmenu[i] + DIR_STRING);
sprintf(demolist[i].title, ".....");
}
}
}
static void M_ReplayHut(INT32 choice) static void M_ReplayHut(INT32 choice)
{ {
(void)choice; (void)choice;
@ -5026,18 +5054,46 @@ static void M_ReplayHut(INT32 choice)
else else
dir_on[menudepthleft] = 0; dir_on[menudepthleft] = 0;
PrepReplayList();
M_SetupNextMenu(&MISC_ReplayHutDef); M_SetupNextMenu(&MISC_ReplayHutDef);
G_SetGamestate(GS_TIMEATTACK); G_SetGamestate(GS_TIMEATTACK);
S_ChangeMusicInternal("replst", true); S_ChangeMusicInternal("replst", true);
} }
static void M_HandleReplayHutList(INT32 choice)
{
switch (choice)
{
case KEY_UPARROW:
if (replayOn)
replayOn--;
else
M_PrevOpt();
S_StartSound(NULL, sfx_menu1);
break;
case KEY_DOWNARROW:
if (replayOn < (INT16)sizedirmenu-1)
replayOn++;
else
itemOn = 0; // Not M_NextOpt because that would take us to the extra dummy item
S_StartSound(NULL, sfx_menu1);
break;
}
}
static void M_DrawReplayHut(void) static void M_DrawReplayHut(void)
{ {
INT32 x, y, cursory = 0; INT32 x, y, cursory = 0;
INT16 i; INT16 i;
INT16 replaylistitem = currentMenu->numitems-2;
boolean processed_one_this_frame = false;
(void)cursory; static UINT16 replayhutmenuy = 0;
V_DrawPatchFill(W_CachePatchName("SRB2BACK", PU_CACHE)); V_DrawPatchFill(W_CachePatchName("SRB2BACK", PU_CACHE));
M_DrawMenuTitle(); M_DrawMenuTitle();
@ -5046,25 +5102,41 @@ static void M_DrawReplayHut(void)
x = currentMenu->x; x = currentMenu->x;
y = currentMenu->y; y = currentMenu->y;
if (itemOn == currentMenu->numitems-1) if (itemOn > replaylistitem)
{
itemOn = replaylistitem;
replayOn = sizedirmenu-1;
}
else if (itemOn < replaylistitem)
{
replayOn = 0;
}
if (itemOn == replaylistitem)
{ {
INT32 maxy; INT32 maxy;
// Scroll menu items if needed // Scroll menu items if needed
cursory = y + currentMenu->menuitems[currentMenu->numitems-1].alphaKey + replayOn*10; cursory = y + currentMenu->menuitems[replaylistitem].alphaKey + replayOn*10;
maxy = y + currentMenu->menuitems[currentMenu->numitems-1].alphaKey + sizedirmenu*10; maxy = y + currentMenu->menuitems[replaylistitem].alphaKey + sizedirmenu*10;
if (cursory > maxy - 70) if (cursory > maxy - 20)
cursory = maxy - 70; cursory = maxy - 20;
if (cursory > 130) if (cursory - replayhutmenuy > 150)
y -= (cursory-130); replayhutmenuy += (cursory-150-replayhutmenuy)/2;
else if (cursory - replayhutmenuy < 110)
replayhutmenuy += (max(0, cursory-110)-replayhutmenuy)/2;
} }
else
replayhutmenuy /= 2;
y -= replayhutmenuy;
// Draw static menu items // Draw static menu items
for (i = 0; i < currentMenu->numitems-1; i++) for (i = 0; i < replaylistitem; i++)
{ {
if (i == itemOn) if (i == itemOn)
cursory = y; cursory = y + currentMenu->menuitems[i].alphaKey;
if ((currentMenu->menuitems[i].status & IT_DISPLAY)==IT_STRING) if ((currentMenu->menuitems[i].status & IT_DISPLAY)==IT_STRING)
V_DrawString(x, y + currentMenu->menuitems[i].alphaKey, 0, currentMenu->menuitems[i].text); V_DrawString(x, y + currentMenu->menuitems[i].alphaKey, 0, currentMenu->menuitems[i].text);
@ -5076,7 +5148,20 @@ static void M_DrawReplayHut(void)
for (i = 0; i < (INT16)sizedirmenu; i++) for (i = 0; i < (INT16)sizedirmenu; i++)
{ {
V_DrawString(x, y+i*10, V_ALLOWLOWERCASE, dirmenu[i]+DIR_STRING); INT32 localy = y+i*10;
if (localy >= 0 && localy < 200 && demolist[i].type == MD_NOTLOADED && !processed_one_this_frame)
{
processed_one_this_frame = true;
G_LoadDemoInfo(&demolist[i]);
}
if (itemOn == replaylistitem && i == replayOn)
{
cursory = localy;
V_DrawString(x, localy, highlightflags|V_ALLOWLOWERCASE, demolist[i].title);
}
else
V_DrawString(x, localy, V_ALLOWLOWERCASE, demolist[i].title);
} }
// Draw the cursor // Draw the cursor