diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index ed0523119..f53393e20 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -6479,6 +6479,7 @@ void HWR_AddCommands(void) CV_RegisterVar(&cv_glshearing); CV_RegisterVar(&cv_glshaders); CV_RegisterVar(&cv_glallowshaders); + CV_RegisterVar(&cv_glanisotropicmode); CV_RegisterVar(&cv_glfiltermode); CV_RegisterVar(&cv_glsolvetjoin); @@ -6494,7 +6495,7 @@ void HWR_AddSessionCommands(void) { if (gl_sessioncommandsadded) return; - CV_RegisterVar(&cv_glanisotropicmode); + // Kept in case we ever need this again. gl_sessioncommandsadded = true; } diff --git a/src/k_menu.h b/src/k_menu.h index 713b37837..2aa4fb540 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -196,6 +196,22 @@ extern menu_t PLAY_MP_RoomSelectDef; extern menuitem_t PLAY_BattleGamemodesMenu[]; extern menu_t PLAY_BattleGamemodesDef; +// OPTIONS +extern menuitem_t OPTIONS_Main[]; +extern menu_t OPTIONS_MainDef; + +extern menuitem_t OPTIONS_Video[]; +extern menu_t OPTIONS_VideoDef; + +extern menuitem_t OPTIONS_VideoModes[]; +extern menu_t OPTIONS_VideoModesDef; + +#ifdef HWRENDER +extern menuitem_t OPTIONS_VideoOGL[]; +extern menu_t OPTIONS_VideoOGLDef; +#endif + +// PAUSE extern menuitem_t PAUSE_Main[]; extern menu_t PAUSE_MainDef; @@ -431,6 +447,55 @@ void M_MPRoomSelect(INT32 choice); void M_MPRoomSelectTick(void); void M_MPRoomSelectInit(INT32 choice); +// Options menu: + +// mode descriptions for video mode menu +typedef struct +{ + INT32 modenum; // video mode number in the vidmodes list + const char *desc; // XXXxYYY + UINT8 goodratio; // aspect correct if 1 +} modedesc_t; + + +#define MAXCOLUMNMODES 12 //max modes displayed in one column +#define MAXMODEDESCS (MAXCOLUMNMODES*3) +// Keep track of some options properties +extern struct optionsmenu_s { + + tic_t ticker; // How long the menu's been open for + INT16 offset; // To make the icons move smoothly when we transition! + + tic_t buttflash; // Button flashing before transitionning to the new submenu. + + // For moving the button when we get into a submenu. it's smooth and cool! (normal x/y and target x/y.) + // this is only used during menu transitions. + INT16 optx; + INT16 opty; + INT16 toptx; + INT16 topty; + + // for video mode testing: + INT32 vidm_testingmode; + INT32 vidm_previousmode; + INT32 vidm_selected; + INT32 vidm_nummodes; + INT32 vidm_column_size; + + modedesc_t modedescs[MAXMODEDESCS]; +} optionsmenu; + +void M_InitOptions(INT32 choice); // necessary for multiplayer since there's some options we won't want to access +void M_OptionsTick(void); +boolean M_OptionsInputs(INT32 ch); + +boolean M_OptionsQuit(void); // resets buttons when you quit the options. + +// video modes menu (resolution) + +void M_VideoModeMenu(INT32 choice); +void M_HandleVideoModes(INT32 ch); + // Pause menu: // Keep track of some pause menu data for visual goodness. @@ -516,6 +581,12 @@ void M_DrawPause(void); // Replay Playback void M_DrawPlaybackMenu(void); +// Options menus: +void M_DrawOptionsMovingButton(void); // for sick transitions... +void M_DrawOptions(void); +void M_DrawGenericOptions(void); +void M_DrawVideoModes(void); + // Misc menus: #define LOCATIONSTRING1 "Visit \x83SRB2.ORG/MODS\x80 to get & make addons!" #define LOCATIONSTRING2 "Visit \x88SRB2.ORG/MODS\x80 to get & make addons!" diff --git a/src/k_menudef.c b/src/k_menudef.c index f4f6fe7c3..860f64a0e 100644 --- a/src/k_menudef.c +++ b/src/k_menudef.c @@ -3,6 +3,9 @@ #include "k_menu.h" #include "screen.h" // BASEVIDWIDTH +#include "r_main.h" // cv_skybox +#include "v_video.h" // cv_globalgamma +#include "hardware/hw_main.h" // gl consvars // ========================================================================== // ORGANIZATION START. @@ -26,9 +29,9 @@ menuitem_t MainMenu[] = "Check out some bonus features.", "MENUI001", NULL, 0, 0}, - {IT_STRING, "Option", + {IT_STRING, "Options", "Configure your controls, settings, and preferences.", NULL, - NULL, 0, 0}, + M_InitOptions, 0, 0}, {IT_STRING | IT_CALL, "Quit", "Exit \"Dr. Robotnik's Ring Racers\".", NULL, @@ -291,6 +294,185 @@ menu_t PLAY_MP_RoomSelectDef = { NULL }; +// options menu +menuitem_t OPTIONS_Main[] = +{ + + {IT_STRING | IT_SUBMENU, "Control Setup", "Remap keys & buttons to your likings.", + NULL, NULL, 0, 0}, + + {IT_STRING | IT_SUBMENU, "Video Options", "Change video settings such as the resolution.", + NULL, &OPTIONS_VideoDef, 0, 0}, + + {IT_STRING | IT_SUBMENU, "Sound Options", "Adjust various sound settings such as the volume.", + NULL, NULL, 0, 0}, + + {IT_STRING | IT_SUBMENU, "HUD Options", "Options related to the Heads-Up Display.", + NULL, NULL, 0, 0}, + + {IT_STRING | IT_SUBMENU, "Gameplay Options", "Change various game related options", + NULL, NULL, 0, 0}, + + {IT_STRING | IT_SUBMENU, "Server Options", "Change various specific options for your game server.", + NULL, NULL, 0, 0}, + + {IT_STRING | IT_SUBMENU, "Data Options", "Miscellaneous data options such as the screenshot format.", + NULL, NULL, 0, 0}, + + {IT_STRING | IT_SUBMENU, "Tricks & Secrets", "Those who bother reading a game manual always get the edge over those who don't!", + NULL, NULL, 0, 0}, +}; + +menu_t OPTIONS_MainDef = { + sizeof (OPTIONS_Main) / sizeof (menuitem_t), + &MainDef, + 0, + OPTIONS_Main, + 0, 0, + 2, 10, + M_DrawOptions, + M_OptionsTick, + NULL, + M_OptionsInputs +}; + +// video options menu... +// options menu +menuitem_t OPTIONS_Video[] = +{ + + {IT_STRING | IT_CALL, "Set Resolution...", "Change the screen resolution for the game.", + NULL, M_VideoModeMenu, 0, 0}, + +// A check to see if you're not running on a fucking antique potato powered stone i guess??????? + +#if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL) + {IT_STRING | IT_CVAR, "Fullscreen", "Set whether you want to use fullscreen or windowed mode.", + NULL, &cv_fullscreen, 0, 0}, +#endif + + {IT_NOTHING|IT_SPACE, NULL, "Kanade best waifu! I promise!", + NULL, NULL, 0, 0}, + + // Everytime I see a screenshot at max gamma I die inside + {IT_STRING | IT_CVAR | IT_CV_SLIDER, "Gamma", "Adjusts the overall brightness of the game.", + NULL, &cv_globalgamma, 0, 0}, + + {IT_STRING | IT_CVAR, "Vertical Sync", "Locks the framerate to your monitor's refresh rate.", + NULL, &cv_vidwait, 0, 0}, + + {IT_STRING | IT_CVAR, "Enable Skyboxes", "Turning this off will improve performance at the detriment of visuals for many maps.", + NULL, &cv_skybox, 0, 0}, + + {IT_STRING | IT_CVAR, "Draw Distance", "How far objects can be drawn. Lower values may improve performance at the cost of visibility.", + NULL, &cv_drawdist, 0, 0}, + + {IT_STRING | IT_CVAR, "Weather Draw Distance", "Affects how far weather visuals can be drawn. Lower values improve performance.", + NULL, &cv_drawdist_precip, 0, 0}, + + {IT_STRING | IT_CVAR, "Show FPS", "Displays the game framerate at the lower right corner of the screen.", + NULL, &cv_ticrate, 0, 0}, + + {IT_NOTHING|IT_SPACE, NULL, "Kanade best waifu! I promise!", + NULL, NULL, 0, 0}, + +#ifdef HWRENDER + {IT_STRING | IT_SUBMENU, "Hardware Options...", "For usage and configuration of the OpenGL renderer.", + NULL, &OPTIONS_VideoOGLDef, 0, 0}, +#endif + +}; + +menu_t OPTIONS_VideoDef = { + sizeof (OPTIONS_Video) / sizeof (menuitem_t), + &OPTIONS_MainDef, + 0, + OPTIONS_Video, + 32, 80, + 2, 10, + M_DrawGenericOptions, + M_OptionsTick, + NULL, + NULL, +}; + +menuitem_t OPTIONS_VideoModes[] = { + + {IT_KEYHANDLER | IT_NOTHING, NULL, "Select a resolution.", + NULL, M_HandleVideoModes, 0, 0}, // dummy menuitem for the control func + +}; + +menu_t OPTIONS_VideoModesDef = { + sizeof (OPTIONS_VideoModes) / sizeof (menuitem_t), + &OPTIONS_VideoDef, + 0, + OPTIONS_VideoModes, + 48, 80, + 2, 10, + M_DrawVideoModes, + M_OptionsTick, + NULL, + NULL, +}; + +#ifdef HWRENDER +menuitem_t OPTIONS_VideoOGL[] = +{ + + {IT_STRING | IT_CVAR, "Renderer", "Change renderers between Software and OpenGL", + NULL, &cv_renderer, 0, 0}, + + {IT_SPACE | IT_NOTHING, NULL, NULL, + NULL, NULL, 0, 0}, + + {IT_SPACE | IT_NOTHING | IT_STRING, "OPTIONS BELOW ARE OPENGL ONLY!", "Watch people get confused anyway!!", + NULL, NULL, 0, 0}, + + {IT_STRING | IT_CVAR, "3D Models", "Use 3D models instead of sprites when applicable.", + NULL, &cv_glmodels, 0, 0}, + + {IT_STRING | IT_CVAR, "Shaders", "Use GLSL Shaders. Turning them off increases performance at the expanse of visual quality.", + NULL, &cv_glshaders, 0, 0}, + + {IT_SPACE | IT_NOTHING, NULL, NULL, + NULL, NULL, 0, 0}, + + {IT_STRING | IT_CVAR, "Texture Quality", "Texture depth. Higher values are recommended.", + NULL, &cv_scr_depth, 0, 0}, + + {IT_STRING | IT_CVAR, "Texture Filter", "Texture Filter. Nearest is recommended.", + NULL, &cv_glfiltermode, 0, 0}, + + {IT_STRING | IT_CVAR, "Anisotropic", "Lower values will improve performance at a minor quality loss.", + NULL, &cv_glanisotropicmode, 0, 0}, + + {IT_SPACE | IT_NOTHING, NULL, NULL, + NULL, NULL, 0, 0}, + + {IT_STRING | IT_CVAR, "Wall Contrast Style", "Allows faking or not Software wall colour contrast.", + NULL, &cv_glfakecontrast, 0, 0}, + + {IT_STRING | IT_CVAR, "Sprite Billboarding", "Adjusts sprites when viewed from above or below to not make them appear flat.", + NULL, &cv_glspritebillboarding, 0, 0}, + + {IT_STRING | IT_CVAR, "Software Perspective", "Emulates Software shearing when looking up or down. Not recommended.", + NULL, &cv_glshearing, 0, 0}, +}; + +menu_t OPTIONS_VideoOGLDef = { + sizeof (OPTIONS_VideoOGL) / sizeof (menuitem_t), + &OPTIONS_VideoDef, + 0, + OPTIONS_VideoOGL, + 32, 80, + 2, 10, + M_DrawGenericOptions, + M_OptionsTick, + NULL, + NULL, +}; +#endif // ------------------- // In-game/pause menus @@ -332,7 +514,7 @@ menuitem_t PAUSE_Main[] = NULL, M_CharacterSelectInit, 0, 0}, {IT_STRING | IT_CALL, "OPTIONS", "M_ICOOPT", - NULL, NULL, 0, 0}, + NULL, M_InitOptions, 0, 0}, {IT_STRING | IT_CALL, "EXIT GAME", "M_ICOEXT", NULL, M_EndGame, 0, 0}, diff --git a/src/k_menudraw.c b/src/k_menudraw.c index ec6d9af64..ce26c9189 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -80,6 +80,74 @@ int snprintf(char *str, size_t n, const char *fmt, ...); #define SLIDER_WIDTH (8*SLIDER_RANGE+6) #define SERVERS_PER_PAGE 11 + +// horizontally centered text +static void M_CentreText(INT32 xoffs, INT32 y, const char *string) +{ + INT32 x; + //added : 02-02-98 : centre on 320, because V_DrawString centers on vid.width... + x = ((BASEVIDWIDTH - V_StringWidth(string, V_OLDSPACING))>>1) + xoffs; + V_DrawString(x,y,V_OLDSPACING,string); +} + + +// A smaller 'Thermo', with range given as percents (0-100) +static void M_DrawSlider(INT32 x, INT32 y, const consvar_t *cv, boolean ontop) +{ + INT32 i; + INT32 range; + patch_t *p; + + for (i = 0; cv->PossibleValue[i+1].strvalue; i++); + + x = BASEVIDWIDTH - x - SLIDER_WIDTH; + + if (ontop) + { + V_DrawCharacter(x - 16 - (skullAnimCounter/5), y, + '\x1C' | highlightflags, false); // left arrow + V_DrawCharacter(x+(SLIDER_RANGE*8) + 8 + (skullAnimCounter/5), y, + '\x1D' | highlightflags, false); // right arrow + } + + if ((range = atoi(cv->defaultvalue)) != cv->value) + { + range = ((range - cv->PossibleValue[0].value) * 100 / + (cv->PossibleValue[1].value - cv->PossibleValue[0].value)); + + if (range < 0) + range = 0; + if (range > 100) + range = 100; + + // draw the default + p = W_CachePatchName("M_SLIDEC", PU_CACHE); + V_DrawScaledPatch(x - 4 + (((SLIDER_RANGE)*8 + 4)*range)/100, y, 0, p); + } + + V_DrawScaledPatch(x - 8, y, 0, W_CachePatchName("M_SLIDEL", PU_CACHE)); + + p = W_CachePatchName("M_SLIDEM", PU_CACHE); + for (i = 0; i < SLIDER_RANGE; i++) + V_DrawScaledPatch (x+i*8, y, 0,p); + + p = W_CachePatchName("M_SLIDER", PU_CACHE); + V_DrawScaledPatch(x+SLIDER_RANGE*8, y, 0, p); + + range = ((cv->value - cv->PossibleValue[0].value) * 100 / + (cv->PossibleValue[1].value - cv->PossibleValue[0].value)); + + if (range < 0) + range = 0; + if (range > 100) + range = 100; + + // draw the slider cursor + p = W_CachePatchName("M_SLIDEC", PU_CACHE); + V_DrawScaledPatch(x - 4 + (((SLIDER_RANGE)*8 + 4)*range)/100, y, 0, p); +} + + static patch_t *addonsp[NUM_EXT+5]; static UINT32 bgTextScroll = 0; @@ -1582,6 +1650,275 @@ void M_DrawMPRoomSelect(void) V_DrawFixedPatch(160<numitems; i++) + { + INT32 py = y - (itemOn*48); + INT32 px = x - menutransition.tics*64; + + if (i == itemOn) + c = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_PLAGUE, GTC_CACHE); + else + c = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_BLACK, GTC_CACHE); + + if (!(menutransition.tics && i == itemOn)) + { + V_DrawFixedPatch(px*FRACUNIT, py*FRACUNIT, FRACUNIT, 0, buttback, c); + V_DrawCenteredGamemodeString(px-3, py - 16, V_ALLOWLOWERCASE, (i == itemOn ? c : NULL), currentMenu->menuitems[i].text); + } + + y += 48; + x += 48; + } + + M_DrawMenuTooltips(); + + if (menutransition.tics) + M_DrawOptionsMovingButton(); + +} + +void M_DrawGenericOptions(void) +{ + INT32 x = currentMenu->x - menutransition.tics*48, y = currentMenu->y, w, i, cursory = 0; + + M_DrawOptionsCogs(); + M_DrawMenuTooltips(); + M_DrawOptionsMovingButton(); + + for (i = 0; i < currentMenu->numitems; i++) + { + if (i == itemOn) + cursory = y; + switch (currentMenu->menuitems[i].status & IT_DISPLAY) + { + case IT_PATCH: + if (currentMenu->menuitems[i].patch && currentMenu->menuitems[i].patch[0]) + { + if (currentMenu->menuitems[i].status & IT_CENTER) + { + patch_t *p; + p = W_CachePatchName(currentMenu->menuitems[i].patch, PU_CACHE); + V_DrawScaledPatch((BASEVIDWIDTH - SHORT(p->width))/2, y, 0, p); + } + else + { + V_DrawScaledPatch(x, y, 0, + W_CachePatchName(currentMenu->menuitems[i].patch, PU_CACHE)); + } + } + /* FALLTHRU */ + case IT_NOTHING: + case IT_DYBIGSPACE: + y += SMALLLINEHEIGHT; + break; +#if 0 + case IT_BIGSLIDER: + M_DrawThermo(x, y, (consvar_t *)currentMenu->menuitems[i].itemaction); + y += LINEHEIGHT; + break; +#endif + case IT_STRING: + case IT_WHITESTRING: + if (i == itemOn) + cursory = y; + + if ((currentMenu->menuitems[i].status & IT_DISPLAY)==IT_STRING) + V_DrawString(x, y, 0, currentMenu->menuitems[i].text); + else + V_DrawString(x, y, highlightflags, currentMenu->menuitems[i].text); + + // Cvar specific handling + switch (currentMenu->menuitems[i].status & IT_TYPE) + case IT_CVAR: + { + consvar_t *cv = (consvar_t *)currentMenu->menuitems[i].itemaction; + switch (currentMenu->menuitems[i].status & IT_CVARTYPE) + { + case IT_CV_SLIDER: + M_DrawSlider(x, y, cv, (i == itemOn)); + case IT_CV_NOPRINT: // color use this + case IT_CV_INVISSLIDER: // monitor toggles use this + break; + case IT_CV_STRING: + M_DrawTextBox(x, y + 4, MAXSTRINGLENGTH, 1); + V_DrawString(x + 8, y + 12, V_ALLOWLOWERCASE, cv->string); + if (skullAnimCounter < 4 && i == itemOn) + V_DrawCharacter(x + 8 + V_StringWidth(cv->string, 0), y + 12, + '_' | 0x80, false); + y += 16; + break; + default: + w = V_StringWidth(cv->string, 0); + V_DrawString(BASEVIDWIDTH - x - w, y, + ((cv->flags & CV_CHEAT) && !CV_IsSetToDefault(cv) ? warningflags : highlightflags), cv->string); + if (i == itemOn) + { + V_DrawCharacter(BASEVIDWIDTH - x - 10 - w - (skullAnimCounter/5), y, + '\x1C' | highlightflags, false); // left arrow + V_DrawCharacter(BASEVIDWIDTH - x + 2 + (skullAnimCounter/5), y, + '\x1D' | highlightflags, false); // right arrow + } + break; + } + break; + } + y += STRINGHEIGHT; + break; + case IT_STRING2: + V_DrawString(x, y, 0, currentMenu->menuitems[i].text); + /* FALLTHRU */ + case IT_DYLITLSPACE: + case IT_SPACE: + y += SMALLLINEHEIGHT; + break; + case IT_GRAYPATCH: + if (currentMenu->menuitems[i].patch && currentMenu->menuitems[i].patch[0]) + V_DrawMappedPatch(x, y, 0, + W_CachePatchName(currentMenu->menuitems[i].patch,PU_CACHE), graymap); + y += LINEHEIGHT; + break; + case IT_TRANSTEXT: + if (currentMenu->menuitems[i].mvar1) + y = currentMenu->y+currentMenu->menuitems[i].mvar1; + /* FALLTHRU */ + case IT_TRANSTEXT2: + V_DrawString(x, y, V_TRANSLUCENT, currentMenu->menuitems[i].text); + y += SMALLLINEHEIGHT; + break; + case IT_QUESTIONMARKS: + if (currentMenu->menuitems[i].mvar1) + y = currentMenu->y+currentMenu->menuitems[i].mvar1; + + V_DrawString(x, y, V_TRANSLUCENT|V_OLDSPACING, M_CreateSecretMenuOption(currentMenu->menuitems[i].text)); + y += SMALLLINEHEIGHT; + break; + case IT_HEADERTEXT: // draws 16 pixels to the left, in yellow text + if (currentMenu->menuitems[i].mvar1) + y = currentMenu->y+currentMenu->menuitems[i].mvar1; + + V_DrawString(x-16, y, highlightflags, currentMenu->menuitems[i].text); + y += SMALLLINEHEIGHT; + break; + } + } + + // DRAW THE SKULL CURSOR + if (((currentMenu->menuitems[itemOn].status & IT_DISPLAY) == IT_PATCH) + || ((currentMenu->menuitems[itemOn].status & IT_DISPLAY) == IT_NOTHING)) + { + V_DrawScaledPatch(x + SKULLXOFF, cursory - 5, 0, + W_CachePatchName("M_CURSOR", PU_CACHE)); + } + else + { + V_DrawScaledPatch(x - 24, cursory, 0, + W_CachePatchName("M_CURSOR", PU_CACHE)); + V_DrawString(x, cursory, highlightflags, currentMenu->menuitems[itemOn].text); + } +} + +// Draw the video modes list, a-la-Quake +void M_DrawVideoModes(void) +{ + INT32 i, j, row, col; + + M_DrawOptionsCogs(); + M_DrawMenuTooltips(); + M_DrawOptionsMovingButton(); + + V_DrawCenteredString(BASEVIDWIDTH/2 + menutransition.tics*64, currentMenu->y, + highlightflags, "Choose mode, reselect to change default"); + + row = 41 + menutransition.tics*64; + col = currentMenu->y + 14; + for (i = 0; i < optionsmenu.vidm_nummodes; i++) + { + if (i == optionsmenu.vidm_selected) + V_DrawString(row, col, highlightflags, optionsmenu.modedescs[i].desc); + // Show multiples of 320x200 as green. + else + V_DrawString(row, col, (optionsmenu.modedescs[i].goodratio) ? recommendedflags : 0, optionsmenu.modedescs[i].desc); + + col += 8; + if ((i % optionsmenu.vidm_column_size) == (optionsmenu.vidm_column_size-1)) + { + row += 7*13; + col = currentMenu->y + 14; + } + } + + if (optionsmenu.vidm_testingmode > 0) + { + INT32 testtime = (optionsmenu.vidm_testingmode/TICRATE) + 1; + + M_CentreText(menutransition.tics*64, currentMenu->y + 75, + va("Previewing mode %c%dx%d", + (SCR_IsAspectCorrect(vid.width, vid.height)) ? 0x83 : 0x80, + vid.width, vid.height)); + M_CentreText(menutransition.tics*64, currentMenu->y + 75+8, + "Press ENTER again to keep this mode"); + M_CentreText(menutransition.tics*64, currentMenu->y + 75+16, + va("Wait %d second%s", testtime, (testtime > 1) ? "s" : "")); + M_CentreText(menutransition.tics*64, currentMenu->y + 75+24, + "or press ESC to return"); + + } + else + { + M_CentreText(menutransition.tics*64, currentMenu->y + 75, + va("Current mode is %c%dx%d", + (SCR_IsAspectCorrect(vid.width, vid.height)) ? 0x83 : 0x80, + vid.width, vid.height)); + M_CentreText(menutransition.tics*64, currentMenu->y + 75+8, + va("Default mode is %c%dx%d", + (SCR_IsAspectCorrect(cv_scr_width.value, cv_scr_height.value)) ? 0x83 : 0x80, + cv_scr_width.value, cv_scr_height.value)); + + V_DrawCenteredString(BASEVIDWIDTH/2 + menutransition.tics*64, currentMenu->y + 75+16, + recommendedflags, "Marked modes are recommended."); + V_DrawCenteredString(BASEVIDWIDTH/2 + menutransition.tics*64, currentMenu->y + 75+24, + highlightflags, "Other modes may have visual errors."); + V_DrawCenteredString(BASEVIDWIDTH/2 + menutransition.tics*64, currentMenu->y + 75+32, + highlightflags, "Larger modes may have performance issues."); + } + + // Draw the cursor for the VidMode menu + i = 41 - 10 + ((optionsmenu.vidm_selected / optionsmenu.vidm_column_size)*7*13) + menutransition.tics*64; + j = currentMenu->y + 14 + ((optionsmenu.vidm_selected % optionsmenu.vidm_column_size)*8); + + V_DrawScaledPatch(i - 8, j, 0, + W_CachePatchName("M_CURSOR", PU_CACHE)); +} + + // // INGAME / PAUSE MENUS // diff --git a/src/k_menufunc.c b/src/k_menufunc.c index fe4807e0d..6e043bbaf 100644 --- a/src/k_menufunc.c +++ b/src/k_menufunc.c @@ -2943,6 +2943,257 @@ void M_MPRoomSelectInit(INT32 choice) M_SetupNextMenu(&PLAY_MP_RoomSelectDef, false); } +// Options menu: +struct optionsmenu_s optionsmenu; + +void M_InitOptions(INT32 choice) +{ + (void)choice; + + // @TODO: Change options when you do them from a netgame. + + optionsmenu.ticker = 0; + optionsmenu.offset = 0; + + optionsmenu.optx = 0; + optionsmenu.opty = 0; + optionsmenu.toptx = 0; + optionsmenu.topty = 0; + + OPTIONS_MainDef.prevMenu = currentMenu; + + M_SetupNextMenu(&OPTIONS_MainDef, false); +} + +boolean M_OptionsQuit(void) +{ + optionsmenu.toptx = 140-1; + optionsmenu.topty = 70+1; + + return true; // Always allow quitting, duh. +} + +void M_OptionsTick(void) +{ + optionsmenu.offset /= 2; + optionsmenu.ticker++; + + optionsmenu.optx += (optionsmenu.toptx - optionsmenu.optx)/2; + optionsmenu.opty += (optionsmenu.topty - optionsmenu.opty)/2; + + if (abs(optionsmenu.optx - optionsmenu.opty) < 2) + { + optionsmenu.optx = optionsmenu.toptx; + optionsmenu.opty = optionsmenu.topty; // Avoid awkward 1 px errors. + } + + // Garbage: + if (currentMenu == &OPTIONS_MainDef) + { + M_OptionsQuit(); // ...So now this is used here. + } + else + { + optionsmenu.toptx = 160; + optionsmenu.topty = 50; + } + +} + +boolean M_OptionsInputs(INT32 ch) +{ + + switch (ch) + { + case KEY_DOWNARROW: + { + optionsmenu.offset += 48; + M_NextOpt(); + + if (itemOn == 0) + optionsmenu.offset -= currentMenu->numitems*48; + + return true; + } + case KEY_UPARROW: + { + optionsmenu.offset -= 48; + M_PrevOpt(); + + if (itemOn == currentMenu->numitems-1) + optionsmenu.offset += currentMenu->numitems*48; + + return true; + } + case KEY_ENTER: + { + optionsmenu.optx = 140; + optionsmenu.opty = 70; // Default position for the currently selected option. + + return false; // Don't eat. + } + + } + + return false; +} + +// setup video mode menu +void M_VideoModeMenu(INT32 choice) +{ + INT32 i, j, vdup, nummodes, width, height; + const char *desc; + + (void)choice; + + memset(optionsmenu.modedescs, 0, sizeof(optionsmenu.modedescs)); + +#if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL) + VID_PrepareModeList(); // FIXME: hack +#endif + optionsmenu.vidm_nummodes = 0; + optionsmenu.vidm_selected = 0; + nummodes = VID_NumModes(); + +#ifdef _WINDOWS + // clean that later: skip windowed mode 0, video modes menu only shows FULL SCREEN modes + if (nummodes <= NUMSPECIALMODES) + i = 0; // unless we have nothing + else + i = NUMSPECIALMODES; +#else + // DOS does not skip mode 0, because mode 0 is ALWAYS present + i = 0; +#endif + for (; i < nummodes && optionsmenu.vidm_nummodes < MAXMODEDESCS; i++) + { + desc = VID_GetModeName(i); + if (desc) + { + vdup = 0; + + // when a resolution exists both under VGA and VESA, keep the + // VESA mode, which is always a higher modenum + for (j = 0; j < optionsmenu.vidm_nummodes; j++) + { + if (!strcmp(optionsmenu.modedescs[j].desc, desc)) + { + // mode(0): 320x200 is always standard VGA, not vesa + if (optionsmenu.modedescs[j].modenum) + { + optionsmenu.modedescs[j].modenum = i; + vdup = 1; + + if (i == vid.modenum) + optionsmenu.vidm_selected = j; + } + else + vdup = 1; + + break; + } + } + + if (!vdup) + { + optionsmenu.modedescs[optionsmenu.vidm_nummodes].modenum = i; + optionsmenu.modedescs[optionsmenu.vidm_nummodes].desc = desc; + + if (i == vid.modenum) + optionsmenu.vidm_selected = optionsmenu.vidm_nummodes; + + // Pull out the width and height + sscanf(desc, "%u%*c%u", &width, &height); + + // Show multiples of 320x200 as green. + if (SCR_IsAspectCorrect(width, height)) + optionsmenu.modedescs[optionsmenu.vidm_nummodes].goodratio = 1; + + optionsmenu.vidm_nummodes++; + } + } + } + + optionsmenu.vidm_column_size = (optionsmenu.vidm_nummodes+2) / 3; + + M_SetupNextMenu(&OPTIONS_VideoModesDef, false); +} + + +// special menuitem key handler for video mode list +void M_HandleVideoModes(INT32 ch) +{ + if (optionsmenu.vidm_testingmode > 0) switch (ch) + { + // change back to the previous mode quickly + case KEY_ESCAPE: + setmodeneeded = optionsmenu.vidm_previousmode + 1; + optionsmenu.vidm_testingmode = 0; + break; + + case KEY_ENTER: + S_StartSound(NULL, sfx_menu1); + optionsmenu.vidm_testingmode = 0; // stop testing + } + + else switch (ch) + { + case KEY_DOWNARROW: + S_StartSound(NULL, sfx_menu1); + if (++optionsmenu.vidm_selected >= optionsmenu.vidm_nummodes) + optionsmenu.vidm_selected = 0; + break; + + case KEY_UPARROW: + S_StartSound(NULL, sfx_menu1); + if (--optionsmenu.vidm_selected < 0) + optionsmenu.vidm_selected = optionsmenu.vidm_nummodes - 1; + break; + + case KEY_LEFTARROW: + S_StartSound(NULL, sfx_menu1); + optionsmenu.vidm_selected -= optionsmenu.vidm_column_size; + if (optionsmenu.vidm_selected < 0) + optionsmenu.vidm_selected = (optionsmenu.vidm_column_size*3) + optionsmenu.vidm_selected; + if (optionsmenu.vidm_selected >= optionsmenu.vidm_nummodes) + optionsmenu.vidm_selected = optionsmenu.vidm_nummodes - 1; + break; + + case KEY_RIGHTARROW: + S_StartSound(NULL, sfx_menu1); + optionsmenu.vidm_selected += optionsmenu.vidm_column_size; + if (optionsmenu.vidm_selected >= (optionsmenu.vidm_column_size*3)) + optionsmenu.vidm_selected %= optionsmenu.vidm_column_size; + if (optionsmenu.vidm_selected >= optionsmenu.vidm_nummodes) + optionsmenu.vidm_selected = optionsmenu.vidm_nummodes - 1; + break; + + case KEY_ENTER: + S_StartSound(NULL, sfx_menu1); + if (vid.modenum == optionsmenu.modedescs[optionsmenu.vidm_selected].modenum) + SCR_SetDefaultMode(); + else + { + optionsmenu.vidm_testingmode = 15*TICRATE; + optionsmenu.vidm_previousmode = vid.modenum; + if (!setmodeneeded) // in case the previous setmode was not finished + setmodeneeded = optionsmenu.modedescs[optionsmenu.vidm_selected].modenum + 1; + } + break; + + case KEY_ESCAPE: // this one same as M_Responder + if (currentMenu->prevMenu) + M_SetupNextMenu(currentMenu->prevMenu, false); + else + M_ClearMenus(true); + break; + + default: + break; + } +} + + // ===================== // PAUSE / IN-GAME MENUS // =====================