extras: replay hut

This commit is contained in:
SinnamonLat 2021-12-10 20:30:09 +01:00
parent 75df86da2f
commit 9de737682d
4 changed files with 677 additions and 2 deletions

View file

@ -18,6 +18,7 @@
#include "d_event.h"
#include "command.h"
#include "doomstat.h" // MAXSPLITSCREENPLAYERS
#include "g_demo.h" //menudemo_t
// flags for items in the menu
// menu handle (what we do when key is pressed
@ -272,6 +273,12 @@ extern menu_t OPTIONS_DataEraseDef;
extern menuitem_t EXTRAS_Main[];
extern menu_t EXTRAS_MainDef;
extern menuitem_t EXTRAS_ReplayHut[];
extern menu_t EXTRAS_ReplayHutDef;
extern menuitem_t EXTRAS_ReplayStart[];
extern menu_t EXTRAS_ReplayStartDef;
// PAUSE
extern menuitem_t PAUSE_Main[];
extern menu_t PAUSE_MainDef;
@ -571,6 +578,8 @@ void M_HandleVideoModes(INT32 ch);
// Extras menu:
#define DF_ENCORE 0x40
extern struct extrasmenu_s {
tic_t ticker; // How long the menu's been open for
@ -583,6 +592,16 @@ extern struct extrasmenu_s {
INT16 textx;
INT16 texty;
// The replay vars...... oh no......
menudemo_t *demolist;
INT16 replayScrollTitle;
SINT8 replayScrollDelay;
SINT8 replayScrollDir;
} extrasmenu;
void M_InitExtras(INT32 choice); // init for the struct
@ -590,6 +609,13 @@ void M_ExtrasTick(void);
boolean M_ExtrasInputs(INT32 ch);
boolean M_ExtrasQuit(void); // resets buttons when you quit
// Extras: Replay Hut
void M_HandleReplayHutList(INT32 choice);
boolean M_QuitReplayHut(void);
void M_HutStartReplay(INT32 choice);
void M_PrepReplayList(void);
// Pause menu:
// Keep track of some pause menu data for visual goodness.
@ -688,6 +714,9 @@ void M_DrawItemToggles(void);
// Extras menu:
void M_DrawExtrasMovingButton(void);
void M_DrawExtras(void);
void M_DrawReplayHut(void);
void M_DrawReplayStartMenu(void);
void M_DrawReplayHutReplayInfo(void);
// Misc menus:
#define LOCATIONSTRING1 "Visit \x83SRB2.ORG/MODS\x80 to get & make addons!"

View file

@ -1113,7 +1113,7 @@ menuitem_t EXTRAS_Main[] =
NULL, M_Addons, 0, 0},
{IT_STRING | IT_CALL, "Replay Hut", "Play the replays you've saved throughout your many races & battles!",
NULL, NULL, 0, 0},
NULL, M_ReplayHut, 0, 0},
{IT_STRING | IT_CALL, "Statistics", "Look back on some of your greatest achievements such as your playtime and wins!",
NULL, NULL, 0, 0},
@ -1137,6 +1137,62 @@ menu_t EXTRAS_MainDef = {
M_ExtrasInputs
};
// extras menu: replay hut
menuitem_t EXTRAS_ReplayHut[] =
{
{IT_KEYHANDLER|IT_NOTHING, "", "", // Dummy menuitem for the replay list
NULL, M_HandleReplayHutList, 0, 0},
{IT_NOTHING, "", "", // Dummy for handling wrapping to the top of the menu..
NULL, NULL, 0, 0},
};
menu_t EXTRAS_ReplayHutDef =
{
sizeof (EXTRAS_ReplayHut)/sizeof (menuitem_t),
&EXTRAS_MainDef,
0,
EXTRAS_ReplayHut,
30, 80,
0, 0,
0, 0,
M_DrawReplayHut,
NULL,
M_QuitReplayHut,
NULL
};
menuitem_t EXTRAS_ReplayStart[] =
{
{IT_CALL |IT_STRING, "Load Addons and Watch", NULL,
NULL, M_HutStartReplay, 0, 0},
{IT_CALL |IT_STRING, "Load Without Addons", NULL,
NULL, M_HutStartReplay, 10, 0},
{IT_CALL |IT_STRING, "Watch Replay", NULL,
NULL, M_HutStartReplay, 10, 0},
{IT_SUBMENU |IT_STRING, "Go Back", NULL,
NULL, &EXTRAS_ReplayHutDef, 30, 0},
};
menu_t EXTRAS_ReplayStartDef =
{
sizeof (EXTRAS_ReplayStart)/sizeof (menuitem_t),
&EXTRAS_ReplayHutDef,
0,
EXTRAS_ReplayStart,
27, 80,
0, 0,
0, 0,
M_DrawReplayStartMenu,
NULL,
NULL,
NULL
};
// -------------------
// In-game/pause menus
// -------------------

View file

@ -342,7 +342,7 @@ static const char *M_CreateSecretMenuOption(const char *str)
//
void M_DrawGenericMenu(void)
{
INT32 x = 0, y = 0, w, i, cursory = 0;
INT32 x = currentMenu->x, y = currentMenu->y, w, i, cursory = 0;
M_DrawMenuTooltips();
@ -2456,6 +2456,385 @@ void M_DrawPlaybackMenu(void)
}
// replay hut...
// ...dear lord this is messy, but Ima be real I ain't fixing this.
#define SCALEDVIEWWIDTH (vid.width/vid.dupx)
#define SCALEDVIEWHEIGHT (vid.height/vid.dupy)
void M_DrawReplayHutReplayInfo(void)
{
lumpnum_t lumpnum;
patch_t *patch;
UINT8 *colormap;
INT32 x, y, w, h;
switch (extrasmenu.demolist[dir_on[menudepthleft]].type)
{
case MD_NOTLOADED:
V_DrawCenteredString(160, 40, V_SNAPTOTOP, "Loading replay information...");
break;
case MD_INVALID:
V_DrawCenteredString(160, 40, V_SNAPTOTOP|warningflags, "This replay cannot be played.");
break;
case MD_SUBDIR:
break; // Can't think of anything to draw here right now
case MD_OUTDATED:
V_DrawThinString(17, 64, V_SNAPTOTOP|V_ALLOWLOWERCASE|V_TRANSLUCENT|highlightflags, "Recorded on an outdated version.");
/* FALLTHRU */
default:
// Draw level stuff
x = 15; y = 15;
// A 160x100 image of the level as entry MAPxxP
//CONS_Printf("%d %s\n", extrasmenu.demolist[dir_on[menudepthleft]].map, G_BuildMapName(extrasmenu.demolist[dir_on[menudepthleft]].map));
lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(extrasmenu.demolist[dir_on[menudepthleft]].map)));
if (lumpnum != LUMPERROR)
patch = W_CachePatchNum(lumpnum, PU_CACHE);
else
patch = W_CachePatchName("M_NOLVL", PU_CACHE);
if (!(extrasmenu.demolist[dir_on[menudepthleft]].kartspeed & DF_ENCORE))
V_DrawSmallScaledPatch(x, y, V_SNAPTOTOP, patch);
else
{
w = SHORT(patch->width);
h = SHORT(patch->height);
V_DrawSmallScaledPatch(x+(w>>1), y, V_SNAPTOTOP|V_FLIP, patch);
{
static angle_t rubyfloattime = 0;
const fixed_t rubyheight = FINESINE(rubyfloattime>>ANGLETOFINESHIFT);
V_DrawFixedPatch((x+(w>>2))<<FRACBITS, ((y+(h>>2))<<FRACBITS) - (rubyheight<<1), FRACUNIT, V_SNAPTOTOP, W_CachePatchName("RUBYICON", PU_CACHE), NULL);
rubyfloattime += (ANGLE_MAX/NEWTICRATE);
}
}
x += 85;
if (mapheaderinfo[extrasmenu.demolist[dir_on[menudepthleft]].map-1])
V_DrawString(x, y, V_SNAPTOTOP, G_BuildMapTitle(extrasmenu.demolist[dir_on[menudepthleft]].map));
else
V_DrawString(x, y, V_SNAPTOTOP|V_ALLOWLOWERCASE|V_TRANSLUCENT, "Level is not loaded.");
if (extrasmenu.demolist[dir_on[menudepthleft]].numlaps)
V_DrawThinString(x, y+9, V_SNAPTOTOP|V_ALLOWLOWERCASE, va("(%d laps)", extrasmenu.demolist[dir_on[menudepthleft]].numlaps));
V_DrawString(x, y+20, V_SNAPTOTOP|V_ALLOWLOWERCASE, extrasmenu.demolist[dir_on[menudepthleft]].gametype == GT_RACE ?
va("Race (%s speed)", kartspeed_cons_t[(extrasmenu.demolist[dir_on[menudepthleft]].kartspeed & ~DF_ENCORE) + 1].strvalue) :
"Battle Mode");
if (!extrasmenu.demolist[dir_on[menudepthleft]].standings[0].ranking)
{
// No standings were loaded!
V_DrawString(x, y+39, V_SNAPTOTOP|V_ALLOWLOWERCASE|V_TRANSLUCENT, "No standings available.");
break;
}
V_DrawThinString(x, y+29, V_SNAPTOTOP|highlightflags, "WINNER");
V_DrawString(x+38, y+30, V_SNAPTOTOP|V_ALLOWLOWERCASE, extrasmenu.demolist[dir_on[menudepthleft]].standings[0].name);
if (extrasmenu.demolist[dir_on[menudepthleft]].gametype == GT_RACE)
{
V_DrawThinString(x, y+39, V_SNAPTOTOP|highlightflags, "TIME");
V_DrawRightAlignedString(x+84, y+40, V_SNAPTOTOP, va("%d'%02d\"%02d",
G_TicsToMinutes(extrasmenu.demolist[dir_on[menudepthleft]].standings[0].timeorscore, true),
G_TicsToSeconds(extrasmenu.demolist[dir_on[menudepthleft]].standings[0].timeorscore),
G_TicsToCentiseconds(extrasmenu.demolist[dir_on[menudepthleft]].standings[0].timeorscore)
));
}
else
{
V_DrawThinString(x, y+39, V_SNAPTOTOP|highlightflags, "SCORE");
V_DrawString(x+32, y+40, V_SNAPTOTOP, va("%d", extrasmenu.demolist[dir_on[menudepthleft]].standings[0].timeorscore));
}
// Character face!
// Lat: 08/06/2020: For some reason missing skins have their value set to 255 (don't even ask me why I didn't write this)
// and for an even STRANGER reason this passes the first check below, so we're going to make sure that the skin here ISN'T 255 before we do anything stupid.
if (extrasmenu.demolist[dir_on[menudepthleft]].standings[0].skin != 0xFF)
{
patch = faceprefix[extrasmenu.demolist[dir_on[menudepthleft]].standings[0].skin][FACE_WANTED];
colormap = R_GetTranslationColormap(
extrasmenu.demolist[dir_on[menudepthleft]].standings[0].skin,
extrasmenu.demolist[dir_on[menudepthleft]].standings[0].color,
GTC_MENUCACHE);
}
else
{
patch = W_CachePatchName("M_NOWANT", PU_CACHE);
colormap = R_GetTranslationColormap(
TC_RAINBOW,
extrasmenu.demolist[dir_on[menudepthleft]].standings[0].color,
GTC_MENUCACHE);
}
V_DrawMappedPatch(BASEVIDWIDTH-15 - SHORT(patch->width), y+20, V_SNAPTOTOP, patch, colormap);
break;
}
}
void M_DrawReplayHut(void)
{
INT32 x, y, cursory = 0;
INT16 i;
INT16 replaylistitem = currentMenu->numitems-2;
boolean processed_one_this_frame = false;
static UINT16 replayhutmenuy = 0;
M_DrawEggaChannel();
// Draw menu choices
x = currentMenu->x;
y = currentMenu->y;
if (itemOn > replaylistitem)
{
itemOn = replaylistitem;
dir_on[menudepthleft] = sizedirmenu-1;
extrasmenu.replayScrollTitle = 0; extrasmenu.replayScrollDelay = TICRATE; extrasmenu.replayScrollDir = 1;
}
else if (itemOn < replaylistitem)
{
dir_on[menudepthleft] = 0;
extrasmenu.replayScrollTitle = 0; extrasmenu.replayScrollDelay = TICRATE; extrasmenu.replayScrollDir = 1;
}
if (itemOn == replaylistitem)
{
INT32 maxy;
// Scroll menu items if needed
cursory = y + currentMenu->menuitems[replaylistitem].mvar1 + dir_on[menudepthleft]*10;
maxy = y + currentMenu->menuitems[replaylistitem].mvar1 + sizedirmenu*10;
if (cursory > maxy - 20)
cursory = maxy - 20;
if (cursory - replayhutmenuy > SCALEDVIEWHEIGHT-50)
replayhutmenuy += (cursory-SCALEDVIEWHEIGHT-replayhutmenuy + 51)/2;
else if (cursory - replayhutmenuy < 110)
replayhutmenuy += (max(0, cursory-110)-replayhutmenuy - 1)/2;
}
else
replayhutmenuy /= 2;
y -= replayhutmenuy;
// Draw static menu items
for (i = 0; i < replaylistitem; i++)
{
INT32 localy = y + currentMenu->menuitems[i].mvar1;
if (localy < 65)
continue;
if (i == itemOn)
cursory = localy;
if ((currentMenu->menuitems[i].status & IT_DISPLAY)==IT_STRING)
V_DrawString(x, localy, V_SNAPTOTOP|V_SNAPTOLEFT, currentMenu->menuitems[i].text);
else
V_DrawString(x, localy, V_SNAPTOTOP|V_SNAPTOLEFT|highlightflags, currentMenu->menuitems[i].text);
}
y += currentMenu->menuitems[replaylistitem].mvar1;
for (i = 0; i < (INT16)sizedirmenu; i++)
{
INT32 localy = y+i*10;
INT32 localx = x;
if (localy < 65)
continue;
if (localy >= SCALEDVIEWHEIGHT)
break;
if (extrasmenu.demolist[i].type == MD_NOTLOADED && !processed_one_this_frame)
{
processed_one_this_frame = true;
G_LoadDemoInfo(&extrasmenu.demolist[i]);
}
if (extrasmenu.demolist[i].type == MD_SUBDIR)
{
localx += 8;
V_DrawScaledPatch(x - 4, localy, V_SNAPTOTOP|V_SNAPTOLEFT, W_CachePatchName(dirmenu[i][DIR_TYPE] == EXT_UP ? "M_RBACK" : "M_RFLDR", PU_CACHE));
}
if (itemOn == replaylistitem && i == (INT16)dir_on[menudepthleft])
{
cursory = localy;
if (extrasmenu.replayScrollDelay)
extrasmenu.replayScrollDelay--;
else if (extrasmenu.replayScrollDir > 0)
{
if (extrasmenu.replayScrollTitle < (V_StringWidth(extrasmenu.demolist[i].title, 0) - (SCALEDVIEWWIDTH - (x<<1)))<<1)
extrasmenu.replayScrollTitle++;
else
{
extrasmenu.replayScrollDelay = TICRATE;
extrasmenu.replayScrollDir = -1;
}
}
else
{
if (extrasmenu.replayScrollTitle > 0)
extrasmenu.replayScrollTitle--;
else
{
extrasmenu.replayScrollDelay = TICRATE;
extrasmenu.replayScrollDir = 1;
}
}
V_DrawString(localx - (extrasmenu.replayScrollTitle>>1), localy, V_SNAPTOTOP|V_SNAPTOLEFT|highlightflags|V_ALLOWLOWERCASE, extrasmenu.demolist[i].title);
}
else
V_DrawString(localx, localy, V_SNAPTOTOP|V_SNAPTOLEFT|V_ALLOWLOWERCASE, extrasmenu.demolist[i].title);
}
// Draw scrollbar
y = sizedirmenu*10 + currentMenu->menuitems[replaylistitem].mvar1 + 30;
if (y > SCALEDVIEWHEIGHT-80)
{
V_DrawFill(BASEVIDWIDTH-4, 75, 4, SCALEDVIEWHEIGHT-80, V_SNAPTOTOP|V_SNAPTORIGHT|159);
V_DrawFill(BASEVIDWIDTH-3, 76 + (SCALEDVIEWHEIGHT-80) * replayhutmenuy / y, 2, (((SCALEDVIEWHEIGHT-80) * (SCALEDVIEWHEIGHT-80))-1) / y - 1, V_SNAPTOTOP|V_SNAPTORIGHT|149);
}
// Draw the cursor
V_DrawScaledPatch(currentMenu->x - 24, cursory, V_SNAPTOTOP|V_SNAPTOLEFT,
W_CachePatchName("M_CURSOR", PU_CACHE));
V_DrawString(currentMenu->x, cursory, V_SNAPTOTOP|V_SNAPTOLEFT|highlightflags, currentMenu->menuitems[itemOn].text);
// Now draw some replay info!
V_DrawFill(10, 10, 300, 60, V_SNAPTOTOP|159);
if (itemOn == replaylistitem)
{
M_DrawReplayHutReplayInfo();
}
}
void M_DrawReplayStartMenu(void)
{
const char *warning;
UINT8 i;
M_DrawEggaChannel();
M_DrawGenericMenu();
#define STARTY 62-(extrasmenu.replayScrollTitle>>1)
// Draw rankings beyond first
for (i = 1; i < MAXPLAYERS && extrasmenu.demolist[dir_on[menudepthleft]].standings[i].ranking; i++)
{
patch_t *patch;
UINT8 *colormap;
V_DrawRightAlignedString(BASEVIDWIDTH-100, STARTY + i*20, V_SNAPTOTOP|highlightflags, va("%2d", extrasmenu.demolist[dir_on[menudepthleft]].standings[i].ranking));
V_DrawThinString(BASEVIDWIDTH-96, STARTY + i*20, V_SNAPTOTOP|V_ALLOWLOWERCASE, extrasmenu.demolist[dir_on[menudepthleft]].standings[i].name);
if (extrasmenu.demolist[dir_on[menudepthleft]].standings[i].timeorscore == UINT32_MAX-1)
V_DrawThinString(BASEVIDWIDTH-92, STARTY + i*20 + 9, V_SNAPTOTOP, "NO CONTEST");
else if (extrasmenu.demolist[dir_on[menudepthleft]].gametype == GT_RACE)
V_DrawRightAlignedString(BASEVIDWIDTH-40, STARTY + i*20 + 9, V_SNAPTOTOP, va("%d'%02d\"%02d",
G_TicsToMinutes(extrasmenu.demolist[dir_on[menudepthleft]].standings[i].timeorscore, true),
G_TicsToSeconds(extrasmenu.demolist[dir_on[menudepthleft]].standings[i].timeorscore),
G_TicsToCentiseconds(extrasmenu.demolist[dir_on[menudepthleft]].standings[i].timeorscore)
));
else
V_DrawString(BASEVIDWIDTH-92, STARTY + i*20 + 9, V_SNAPTOTOP, va("%d", extrasmenu.demolist[dir_on[menudepthleft]].standings[i].timeorscore));
// Character face!
// Lat: 08/06/2020: For some reason missing skins have their value set to 255 (don't even ask me why I didn't write this)
// and for an even STRANGER reason this passes the first check below, so we're going to make sure that the skin here ISN'T 255 before we do anything stupid.
if (extrasmenu.demolist[dir_on[menudepthleft]].standings[i].skin != 0xFF)
{
patch = faceprefix[extrasmenu.demolist[dir_on[menudepthleft]].standings[i].skin][FACE_RANK];
colormap = R_GetTranslationColormap(
extrasmenu.demolist[dir_on[menudepthleft]].standings[i].skin,
extrasmenu.demolist[dir_on[menudepthleft]].standings[i].color,
GTC_MENUCACHE);
}
else
{
patch = W_CachePatchName("M_NORANK", PU_CACHE);
colormap = R_GetTranslationColormap(
TC_RAINBOW,
extrasmenu.demolist[dir_on[menudepthleft]].standings[i].color,
GTC_MENUCACHE);
}
V_DrawMappedPatch(BASEVIDWIDTH-5 - SHORT(patch->width), STARTY + i*20, V_SNAPTOTOP, patch, colormap);
}
#undef STARTY
// Handle scrolling rankings
if (extrasmenu.replayScrollDelay)
extrasmenu.replayScrollDelay--;
else if (extrasmenu.replayScrollDir > 0)
{
if (extrasmenu.replayScrollTitle < (i*20 - SCALEDVIEWHEIGHT + 100)<<1)
extrasmenu.replayScrollTitle++;
else
{
extrasmenu.replayScrollDelay = TICRATE;
extrasmenu.replayScrollDir = -1;
}
}
else
{
if (extrasmenu.replayScrollTitle > 0)
extrasmenu.replayScrollTitle--;
else
{
extrasmenu.replayScrollDelay = TICRATE;
extrasmenu.replayScrollDir = 1;
}
}
V_DrawFill(10, 10, 300, 60, V_SNAPTOTOP|159);
M_DrawReplayHutReplayInfo();
V_DrawString(10, 72, V_SNAPTOTOP|highlightflags|V_ALLOWLOWERCASE, extrasmenu.demolist[dir_on[menudepthleft]].title);
// Draw a warning prompt if needed
switch (extrasmenu.demolist[dir_on[menudepthleft]].addonstatus)
{
case DFILE_ERROR_CANNOTLOAD:
warning = "Some addons in this replay cannot be loaded.\nYou can watch anyway, but desyncs may occur.";
break;
case DFILE_ERROR_NOTLOADED:
case DFILE_ERROR_INCOMPLETEOUTOFORDER:
warning = "Loading addons will mark your game as modified, and Record Attack may be unavailable.\nYou can watch without loading addons, but desyncs may occur.";
break;
case DFILE_ERROR_EXTRAFILES:
warning = "You have addons loaded that were not present in this replay.\nYou can watch anyway, but desyncs may occur.";
break;
case DFILE_ERROR_OUTOFORDER:
warning = "You have this replay's addons loaded, but they are out of order.\nYou can watch anyway, but desyncs may occur.";
break;
default:
return;
}
V_DrawSmallString(4, BASEVIDHEIGHT-14, V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_ALLOWLOWERCASE, warning);
}
// Draw misc menus:
// Addons (this is merely copypasted, original code by toaster)

View file

@ -3783,12 +3783,223 @@ void M_PlaybackQuit(INT32 choice)
D_StartTitle();
}
void M_PrepReplayList(void)
{
size_t i;
if (extrasmenu.demolist)
Z_Free(extrasmenu.demolist);
extrasmenu.demolist = Z_Calloc(sizeof(menudemo_t) * sizedirmenu, PU_STATIC, NULL);
for (i = 0; i < sizedirmenu; i++)
{
if (dirmenu[i][DIR_TYPE] == EXT_UP)
{
extrasmenu.demolist[i].type = MD_SUBDIR;
sprintf(extrasmenu.demolist[i].title, "UP");
}
else if (dirmenu[i][DIR_TYPE] == EXT_FOLDER)
{
extrasmenu.demolist[i].type = MD_SUBDIR;
strncpy(extrasmenu.demolist[i].title, dirmenu[i] + DIR_STRING, 64);
}
else
{
extrasmenu.demolist[i].type = MD_NOTLOADED;
snprintf(extrasmenu.demolist[i].filepath, 255, "%s%s", menupath, dirmenu[i] + DIR_STRING);
sprintf(extrasmenu.demolist[i].title, ".....");
}
}
}
void M_ReplayHut(INT32 choice)
{
(void)choice;
extrasmenu.replayScrollTitle = 0;
extrasmenu.replayScrollDelay = TICRATE;
extrasmenu.replayScrollDir = 1;
if (!demo.inreplayhut)
{
snprintf(menupath, 1024, "%s"PATHSEP"media"PATHSEP"replay"PATHSEP"online"PATHSEP, srb2home);
menupathindex[(menudepthleft = menudepth-1)] = strlen(menupath);
}
if (!preparefilemenu(false, true))
{
M_StartMessage("No replays found.\n\n(Press a key)\n", NULL, MM_NOTHING);
return;
}
else if (!demo.inreplayhut)
dir_on[menudepthleft] = 0;
demo.inreplayhut = true;
extrasmenu.replayScrollTitle = 0; extrasmenu.replayScrollDelay = TICRATE; extrasmenu.replayScrollDir = 1;
M_PrepReplayList();
menuactive = true;
M_SetupNextMenu(&EXTRAS_ReplayHutDef, false);
//G_SetGamestate(GS_TIMEATTACK);
//titlemapinaction = TITLEMAP_OFF; // Nope don't give us HOMs please
demo.rewinding = false;
CL_ClearRewinds();
//S_ChangeMusicInternal("replst", true);
}
// key handler
void M_HandleReplayHutList(INT32 choice)
{
switch (choice)
{
case KEY_UPARROW:
if (dir_on[menudepthleft])
dir_on[menudepthleft]--;
else
return;
//M_PrevOpt();
S_StartSound(NULL, sfx_menu1);
extrasmenu.replayScrollTitle = 0; extrasmenu.replayScrollDelay = TICRATE; extrasmenu.replayScrollDir = 1;
break;
case KEY_DOWNARROW:
if (dir_on[menudepthleft] < sizedirmenu-1)
dir_on[menudepthleft]++;
else
return;
//itemOn = 0; // Not M_NextOpt because that would take us to the extra dummy item
S_StartSound(NULL, sfx_menu1);
extrasmenu.replayScrollTitle = 0; extrasmenu.replayScrollDelay = TICRATE; extrasmenu.replayScrollDir = 1;
break;
case KEY_ESCAPE:
M_QuitReplayHut();
break;
case KEY_ENTER:
switch (dirmenu[dir_on[menudepthleft]][DIR_TYPE])
{
case EXT_FOLDER:
strcpy(&menupath[menupathindex[menudepthleft]],dirmenu[dir_on[menudepthleft]]+DIR_STRING);
if (menudepthleft)
{
menupathindex[--menudepthleft] = strlen(menupath);
menupath[menupathindex[menudepthleft]] = 0;
if (!preparefilemenu(false, true))
{
S_StartSound(NULL, sfx_s224);
M_StartMessage(va("%c%s\x80\nThis folder is empty.\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), M_AddonsHeaderPath()),NULL,MM_NOTHING);
menupath[menupathindex[++menudepthleft]] = 0;
if (!preparefilemenu(true, true))
{
M_QuitReplayHut();
return;
}
}
else
{
S_StartSound(NULL, sfx_menu1);
dir_on[menudepthleft] = 1;
M_PrepReplayList();
}
}
else
{
S_StartSound(NULL, sfx_s26d);
M_StartMessage(va("%c%s\x80\nThis folder is too deep to navigate to!\n\n(Press a key)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), M_AddonsHeaderPath()),NULL,MM_NOTHING);
menupath[menupathindex[menudepthleft]] = 0;
}
break;
case EXT_UP:
S_StartSound(NULL, sfx_menu1);
menupath[menupathindex[++menudepthleft]] = 0;
if (!preparefilemenu(false, true))
{
M_QuitReplayHut();
return;
}
M_PrepReplayList();
break;
default:
// We can't just use M_SetupNextMenu because that'll run ReplayDef's quitroutine and boot us back to the title screen!
currentMenu->lastOn = itemOn;
currentMenu = &EXTRAS_ReplayStartDef;
extrasmenu.replayScrollTitle = 0; extrasmenu.replayScrollDelay = TICRATE; extrasmenu.replayScrollDir = 1;
switch (extrasmenu.demolist[dir_on[menudepthleft]].addonstatus)
{
case DFILE_ERROR_CANNOTLOAD:
// Only show "Watch Replay Without Addons"
EXTRAS_ReplayStart[0].status = IT_DISABLED;
EXTRAS_ReplayStart[1].status = IT_CALL|IT_STRING;
//EXTRAS_ReplayStart[1].alphaKey = 0;
EXTRAS_ReplayStart[2].status = IT_DISABLED;
itemOn = 1;
break;
case DFILE_ERROR_NOTLOADED:
case DFILE_ERROR_INCOMPLETEOUTOFORDER:
// Show "Load Addons and Watch Replay" and "Watch Replay Without Addons"
EXTRAS_ReplayStart[0].status = IT_CALL|IT_STRING;
EXTRAS_ReplayStart[1].status = IT_CALL|IT_STRING;
//EXTRAS_ReplayStart[1].alphaKey = 10;
EXTRAS_ReplayStart[2].status = IT_DISABLED;
itemOn = 0;
break;
case DFILE_ERROR_EXTRAFILES:
case DFILE_ERROR_OUTOFORDER:
default:
// Show "Watch Replay"
EXTRAS_ReplayStart[0].status = IT_DISABLED;
EXTRAS_ReplayStart[1].status = IT_DISABLED;
EXTRAS_ReplayStart[2].status = IT_CALL|IT_STRING;
//EXTRAS_ReplayStart[2].alphaKey = 0;
itemOn = 2;
break;
}
}
break;
}
}
boolean M_QuitReplayHut(void)
{
// D_StartTitle does its own wipe, since GS_TIMEATTACK is now a complete gamestate.
menuactive = false;
D_StartTitle();
if (extrasmenu.demolist)
Z_Free(extrasmenu.demolist);
extrasmenu.demolist = NULL;
demo.inreplayhut = false;
return true;
}
void M_HutStartReplay(INT32 choice)
{
(void)choice;
M_ClearMenus(false);
demo.loadfiles = (itemOn == 0);
demo.ignorefiles = (itemOn != 0);
G_DoPlayDemo(extrasmenu.demolist[dir_on[menudepthleft]].filepath);
}
static void Splitplayers_OnChange(void)
{
#if 0