diff --git a/src/k_menu.h b/src/k_menu.h index 3d0cc3272..7eca2ca0d 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -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!" diff --git a/src/k_menudef.c b/src/k_menudef.c index 594d4475d..6a9487828 100644 --- a/src/k_menudef.c +++ b/src/k_menudef.c @@ -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 // ------------------- diff --git a/src/k_menudraw.c b/src/k_menudraw.c index a865fcb97..c9fc729c3 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -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))<>2))<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) diff --git a/src/k_menufunc.c b/src/k_menufunc.c index 15cbf7316..5ced69765 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -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