mirror of
https://git.do.srb2.org/KartKrew/Kart-Public.git
synced 2024-12-27 12:50:44 +00:00
List demos by title in the replay hut
This commit is contained in:
parent
1602b0e3d9
commit
48dcfab7f6
4 changed files with 243 additions and 14 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
122
src/g_game.c
122
src/g_game.c
|
@ -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
|
||||||
//
|
//
|
||||||
|
|
20
src/g_game.h
20
src/g_game.h
|
@ -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.
|
||||||
|
|
113
src/m_menu.c
113
src/m_menu.c
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue