From f14e5f2f56d9312c881f552230d5a2c643c07566 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Mon, 9 Jun 2025 22:42:48 +0200 Subject: [PATCH 1/6] Softcode server list page and sound options --- src/d_clisrv.c | 2 + src/deh_soc.c | 6 +- src/deh_tables.c | 2 - src/m_menu.c | 141 ++++++++++++----------------------------------- src/m_menu.h | 12 ++-- 5 files changed, 43 insertions(+), 120 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 8ae37a308..44a252392 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1412,6 +1412,7 @@ static void SL_ClearServerList(INT32 connectedserver) serverlist[i].node = 0; } serverlistcount = 0; + M_UpdateNumServerPages(); } static UINT32 SL_SearchServer(INT32 node) @@ -1452,6 +1453,7 @@ static void SL_InsertServer(serverinfo_pak* info, SINT8 node) return;/* that's a different mod */ i = serverlistcount++; + M_UpdateNumServerPages(); } serverlist[i].info = *info; diff --git a/src/deh_soc.c b/src/deh_soc.c index a337f16ff..89749da11 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -1859,6 +1859,7 @@ static struct { const char *name; consvar_t *var; } HIDDENVARS[] = { { "DUMMYNAME", &cv_dummyname }, { "DUMMYFOLLOWER", &cv_dummyfollower }, { "DUMMYCOLOR", &cv_dummycolor }, + { "DUMMYSERVERPAGE", &cv_dummyserverpage }, { NULL, NULL } }; @@ -2005,11 +2006,6 @@ static void readmenuitem(MYFILE *f, menuitem_t *menuitem) status |= flags; menuitem->routine = routine; } - else if (fastcmp(word, "DUMMY")) - { - status |= IT_DUMMY; - menuitem->routine = NULL; - } else WARN("unknown word '%s'", word); } diff --git a/src/deh_tables.c b/src/deh_tables.c index a33552a27..1eaf74e8f 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -701,7 +701,6 @@ struct menu_routine_s const MENU_ROUTINES[] = { { "CANCELCONNECT", &MR_CancelConnect }, { "SETUPCONTROLSMENU", &MR_SetupControlsMenu }, { "HANDLECONTROLSMENU", &MR_HandleControlsMenu }, - { "HANDLESERVERPAGE", &MR_HandleServerPage }, { "REFRESH", &MR_Refresh }, { "CONNECT", &MR_Connect }, { "VIDEOMODEMENU", &MR_VideoModeMenu }, @@ -766,7 +765,6 @@ struct menu_drawer_s const MENU_DRAWERS[] = { { "DRAWSETUPMULTIPLAYERMENU", &M_DrawSetupMultiPlayerMenu }, { "DRAWVIDEOMENU", &M_DrawVideoMenu }, { "DRAWVIDEOMODE", &M_DrawVideoMode }, - { "DRAWSKYROOM", &M_DrawSkyRoom }, { "DRAWHUDOPTIONS", &M_DrawHUDOptions }, { "DRAWADDONS", &M_DrawAddons }, { "DRAWREPLAYSTARTMENU", &M_DrawReplayStartMenu }, diff --git a/src/m_menu.c b/src/m_menu.c index b7976ddab..d8111121f 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -159,7 +159,6 @@ levellist_mode_t levellistmode = LLM_CREATESERVER; UINT8 maplistoption = 0; static char joystickInfo[MAXGAMEPADS][29]; -static UINT32 serverlistpage; INT16 startmap; // Mario, NiGHTS, or just a plain old normal game? @@ -388,6 +387,9 @@ consvar_t cv_dummyname = CVAR_INIT ("dummyname", "", CV_HIDEN, NULL, NULL); consvar_t cv_dummyfollower = CVAR_INIT ("dummyfollower", "-1", CV_HIDEN, dummyfollower_cons_t, NULL); consvar_t cv_dummycolor = CVAR_INIT ("dummycolor", "0", CV_HIDEN, dummycolor_cons_t, NULL); +static CV_PossibleValue_t dummyserverpage_cons_t[] = {{0, "MIN"}, {0, "MAX"}, {0, NULL}}; +consvar_t cv_dummyserverpage = CVAR_INIT ("dummyserverpage", "0", CV_HIDEN, dummyserverpage_cons_t, NULL); + consvar_t cv_menucaps = CVAR_INIT ("menucaps", "Off", CV_SAVE, CV_OnOff, NULL); static tic_t playback_last_menu_interaction_leveltime = 0; @@ -517,6 +519,11 @@ INT32 MR_OpenGLOptionsMenu(INT32 choice) } #endif +void M_UpdateNumServerPages(void) +{ + dummyserverpage_cons_t[1].value = serverlistcount ? (serverlistcount - 1)/M_ServersPerPage() : 0; +} + // ========================================================================== // CVAR ONCHANGE EVENTS GO HERE // ========================================================================== @@ -1756,6 +1763,7 @@ void M_Init(void) CV_RegisterVar(&cv_dummyname); CV_RegisterVar(&cv_dummyfollower); CV_RegisterVar(&cv_dummycolor); + CV_RegisterVar(&cv_dummyserverpage); quitmsg[QUITMSG] = M_GetText("Eggman's tied explosives\nto your girlfriend, and\nwill activate them if\nyou press the 'Y' key!\nPress 'N' to save her!\n\n(Press 'Y' to quit)"); quitmsg[QUITMSG1] = M_GetText("What would Tails say if\nhe saw you quitting the game?\n\n(Press 'Y' to quit)"); @@ -2143,6 +2151,7 @@ static INT16 M_DrawMenuItem(menuitem_t *item, INT16 x, INT16 y, INT32 vflags, bo const char *str = cv->string; INT32 soffset = vflags & MDF_TIMEATTACK && cv != &cv_nextmap ? 40 : 0; INT32 strvf = vflags; + boolean warning = (cv->flags & CV_CHEAT) && !CV_IsSetToDefault(cv); if (cv == &cv_chooseskin) str = skins[cv_chooseskin.value].realname; @@ -2152,15 +2161,28 @@ static INT16 M_DrawMenuItem(menuitem_t *item, INT16 x, INT16 y, INT32 vflags, bo str = dummystaffname; else if (cv == &cv_dummycolor) str = skincolors[cv_dummycolor.value].name; + else if (cv == &cv_dummyserverpage) + str = va("%d of %d", cv->value + 1, dummyserverpage_cons_t[1].value + 1); + else if (cv == &cv_soundtest && cv_soundtest.value) + V_DrawRightAlignedString(BASEVIDWIDTH - x - soffset, y + 8, strvf|highlightflags, S_sfx[cv_soundtest.value].name); + else if (cv == &cv_gamesounds) + { + str = sound_disabled ? "Off" : "On"; + warning = sound_disabled; + } + else if (cv == &cv_gamedigimusic) + { + str = digital_disabled ? "Off" : "On"; + warning = digital_disabled; + } else if (cv == &cv_dummymultiplayer) break; if (menustack[0] == MN_MP_PLAYERSETUP) - strvf |= V_ALLOWLOWERCASE|highlightflags; + strvf |= V_ALLOWLOWERCASE; w = V_StringWidth(str, strvf); - V_DrawString(BASEVIDWIDTH - x - soffset - w, y, - ((cv->flags & CV_CHEAT) && !CV_IsSetToDefault(cv) ? warningflags : highlightflags)|strvf, str); + V_DrawString(BASEVIDWIDTH - x - soffset - w, y, (warning ? warningflags : highlightflags)|strvf, str); if (selected) { @@ -2699,7 +2721,7 @@ void M_DrawImageDef(void) else V_DrawSmallScaledPatch(0,0,0,patch); - if (currentMenu->menuitems[itemOn].argument) + if (!currentMenu->menuitems[itemOn].argument) { V_DrawString(2,BASEVIDHEIGHT-10, MENUCAPS|V_YELLOWMAP, va("%d", (itemOn<<1)-1)); // intentionally not highlightflags, unlike below V_DrawRightAlignedString(BASEVIDWIDTH-2,BASEVIDHEIGHT-10, MENUCAPS|V_YELLOWMAP, va("%d", itemOn<<1)); // ditto @@ -2721,8 +2743,6 @@ void M_DrawImageDef(void) // uses left and right movement. INT32 MR_HandleImageDef(INT32 choice) { - boolean exitmenu = false; - switch (choice) { case KEY_RIGHTARROW: @@ -2740,15 +2760,10 @@ INT32 MR_HandleImageDef(INT32 choice) itemOn--; break; - case KEY_ESCAPE: - case KEY_ENTER: - exitmenu = true; - break; + default: + return false; } - if (exitmenu) - M_ExitMenu(); - return true; } @@ -4396,61 +4411,6 @@ void M_DrawChecklist(void) } #undef NUMCHECKLIST -void M_DrawSkyRoom(void) -{ - INT32 i, y = 0; - INT32 lengthstring = 0; - - M_DrawGenericMenu(); - - if (menustack[0] == MN_OP_SOUND) - { - V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, - currentMenu->y+M_GetItemY(MN_OP_SOUND, "SOUND"), - (sound_disabled ? warningflags : highlightflags), - (sound_disabled ? "OFF" : "ON")); - - V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, - currentMenu->y+M_GetItemY(MN_OP_SOUND, "MUSIC"), - (digital_disabled ? warningflags : highlightflags), - (digital_disabled ? "OFF" : "ON")); - - if (M_IsItemOn(MN_OP_SOUND, "SOUND")) - lengthstring = 8*(sound_disabled ? 3 : 2); - else if (M_IsItemOn(MN_OP_SOUND, "MUSIC")) - lengthstring = 8*(digital_disabled ? 3 : 2); - } - - for (i = 0; i < currentMenu->numitems; ++i) - { - if (¤tMenu->menuitems[i] == M_CheckMenuItem(MN_OP_SOUND, "SOUNDTEST")) - { - y = currentMenu->menuitems[i].y; - break; - } - } - - if (y) - { - y += currentMenu->y; - - V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, y, MENUCAPS|highlightflags, cv_soundtest.string); - if (cv_soundtest.value) - V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, y + 8, MENUCAPS|highlightflags, S_sfx[cv_soundtest.value].name); - - if (i == itemOn) - lengthstring = V_StringWidth(cv_soundtest.string, 0); - } - - if (lengthstring) - { - V_DrawCharacter(BASEVIDWIDTH - currentMenu->x - 10 - lengthstring - (skullAnimCounter/5), currentMenu->y+currentMenu->menuitems[itemOn].y, - '\x1C' | highlightflags, false); // left arrow - V_DrawCharacter(BASEVIDWIDTH - currentMenu->x + 2 + (skullAnimCounter/5), currentMenu->y+currentMenu->menuitems[itemOn].y, - '\x1D' | highlightflags, false); // right arrow - } -} - INT32 MR_PlaySound(INT32 arg) { S_StopSounds(); @@ -5694,37 +5654,12 @@ Fetch_servers_thread (int *id) #define S_LINEY(n) currentMenu->y + SERVERHEADERHEIGHT + (n * SERVERLINEHEIGHT) -INT32 MR_HandleServerPage(INT32 choice) -{ - if (!M_IsItemOn(MN_MP_CONNECT, "PAGE")) - return false; - - switch (choice) - { - case KEY_ENTER: - case KEY_RIGHTARROW: - S_StartSound(NULL, sfx_menu1); - if ((serverlistpage + 1) * M_ServersPerPage() < serverlistcount) - serverlistpage++; - break; - case KEY_LEFTARROW: - S_StartSound(NULL, sfx_menu1); - if (serverlistpage > 0) - serverlistpage--; - break; - - default: - return false; - } - return true; -} - INT32 MR_Connect(INT32 arg) { // do not call menuexitfunc M_ClearMenus(false); - COM_BufAddText(va("connect node %d\n", serverlist[arg + serverlistpage * M_ServersPerPage()].node)); + COM_BufAddText(va("connect node %d\n", serverlist[arg + cv_dummyserverpage.value * M_ServersPerPage()].node)); return true; } @@ -5742,7 +5677,7 @@ INT32 MR_Refresh(INT32 choice) I_FinishUpdate(); // page flip or blit buffer // first page of servers - serverlistpage = 0; + CV_SetValue(&cv_dummyserverpage, 0); #ifdef MASTERSERVER #ifdef HAVE_THREADS @@ -5765,29 +5700,21 @@ void M_DrawConnectMenu(void) const char *pwr = "----"; INT16 firstserverline = M_GetMenuIndex(MN_MP_CONNECT, "LINE1"); UINT32 serversperpage = M_ServersPerPage(); // server sperpage? - INT32 numPages = (serverlistcount+(serversperpage-1))/serversperpage; int waiting; menu_t *conmenu = &menudefs[MN_MP_CONNECT]; // meh, whatever for (i = firstserverline; i < firstserverline+serversperpage; i++) conmenu->menuitems[i].status |= IT_HIDDEN; - if (!numPages) - numPages = 1; - - // Page num - V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y + M_GetItemY(MN_MP_CONNECT, "PAGE"), - MENUCAPS|highlightflags, va("%u of %d", serverlistpage+1, numPages)); - // Horizontal line! V_DrawFill(1, currentMenu->y+32, 318, 1, 0); if (serverlistcount <= 0) V_DrawString(currentMenu->x,currentMenu->y+SERVERHEADERHEIGHT, MENUCAPS, "No servers found"); else - for (i = 0; i < min(serverlistcount - serverlistpage * serversperpage, serversperpage); i++) + for (i = 0; i < min(serverlistcount - cv_dummyserverpage.value * serversperpage, serversperpage); i++) { - INT32 slindex = i + serverlistpage * serversperpage; + INT32 slindex = i + cv_dummyserverpage.value * serversperpage; UINT32 globalflags = ((serverlist[slindex].info.numberofplayer >= serverlist[slindex].info.maxplayer) ? V_TRANSLUCENT : 0) |((itemOn == firstserverline+i) ? highlightflags : 0)|V_ALLOWLOWERCASE; @@ -5982,7 +5909,7 @@ static void M_ConnectMenu(INT32 choice) // we don't request a restart unless the filelist differs // first page of servers - serverlistpage = 0; + CV_SetValue(&cv_dummyserverpage, 0); M_EnterMenu(MN_MP_CONNECT, true, 0); itemOn = 0; diff --git a/src/m_menu.h b/src/m_menu.h index 0e728f780..85e1f6578 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -157,12 +157,11 @@ boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt); // flags for items in the menu // menu handle (what we do when key is pressed -#define IT_TYPE (1+2+4+8192+16384) +#define IT_TYPE (1+2+4+8192) #define IT_CALL 1 // call the function #define IT_ARROWS 2 // call function with 0 for left arrow and 1 for right arrow in param -#define IT_DUMMY 4 // selectable, but does nothing -#define IT_SUBMENU 8192 // go to sub menu -#define IT_CVAR 16384 // handle as a cvar +#define IT_SUBMENU 4 // go to sub menu +#define IT_CVAR 8192 // handle as a cvar // display flags #define IT_DISPLAY (8+16+32) @@ -267,7 +266,6 @@ INT32 MR_ConnectMenuModChecks(INT32 choice); INT32 MR_CancelConnect(INT32 choice); INT32 MR_SetupControlsMenu(INT32 arg); INT32 MR_HandleControlsMenu(INT32 ch); -INT32 MR_HandleServerPage(INT32 choice); INT32 MR_Refresh(INT32 choice); INT32 MR_Connect(INT32 arg); INT32 MR_VideoModeMenu(INT32 choice); @@ -328,7 +326,6 @@ void M_DrawSetupMultiPlayerMenu(void); void M_DrawConnectMenu(void); void M_DrawVideoMenu(void); void M_DrawVideoMode(void); -void M_DrawSkyRoom(void); void M_DrawHUDOptions(void); void M_DrawAddons(void); void M_DrawReplayStartMenu(void); @@ -404,12 +401,15 @@ extern consvar_t cv_dummyattackingrings, cv_dummyattackingstacking, cv_dummyatt extern consvar_t cv_dummyattackingslipdash, cv_dummyattackingpurpledrift; extern consvar_t cv_dummystaff; extern consvar_t cv_dummymultiplayer, cv_dummyip, cv_dummyname, cv_dummyfollower, cv_dummycolor; +extern consvar_t cv_dummyserverpage; extern consvar_t cv_menucaps; // allow menu text to be displayed in lowercase #define MENUCAPS (!cv_menucaps.value ? V_ALLOWLOWERCASE : 0) extern CV_PossibleValue_t gametype_cons_t[]; +void M_UpdateNumServerPages(void); + extern char dummystaffname[22]; extern INT16 startmap; From fd48ecd4ca350df68a82d06c1b922d9e9ab9248d Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Mon, 9 Jun 2025 23:26:56 +0200 Subject: [PATCH 2/6] Make the camera options work again --- src/deh_tables.c | 1 + src/info/menus.h | 5 +---- src/m_menu.c | 13 +++++++++++++ src/m_menu.h | 1 + 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/deh_tables.c b/src/deh_tables.c index 1eaf74e8f..665bb0453 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -747,6 +747,7 @@ struct menu_routine_s const MENU_ROUTINES[] = { { "ASSIGNJOYSTICK", &MR_AssignJoystick }, { "HANDLEMONITORTOGGLES", &MR_HandleMonitorToggles }, { "RESTARTAUDIO", &MR_RestartAudio }, + { "CAMERASETUP", &MR_CameraSetup }, #ifdef HAVE_DISCORDRPC { "HANDLEDISCORDREQUESTS", &MR_HandleDiscordRequests }, #endif diff --git a/src/info/menus.h b/src/info/menus.h index febb36a16..b71459fc2 100644 --- a/src/info/menus.h +++ b/src/info/menus.h @@ -42,10 +42,7 @@ _(OP_GAMEHUD) _(OP_OFFSET) _(OP_CAMERA) -_(OP_P1CAMERA) -_(OP_P2CAMERA) -_(OP_P3CAMERA) -_(OP_P4CAMERA) +_(OP_CAMERASETUP) _(OP_GAME) _(OP_BLANKARTGAME) diff --git a/src/m_menu.c b/src/m_menu.c index d8111121f..b24639138 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -7404,6 +7404,19 @@ INT32 MR_HandleVideoMode(INT32 ch) return true; } +INT32 MR_CameraSetup(INT32 arg) +{ + if (arg < 0 || arg >= MAXSPLITSCREENPLAYERS) + return false; + + M_SetItemCvar(MN_OP_CAMERASETUP, "FLIPCAM", &cv_flipcam[arg]); + M_SetItemCvar(MN_OP_CAMERASETUP, "CAMDISTANCE", &cv_cam_dist[arg]); + M_SetItemCvar(MN_OP_CAMERASETUP, "CAMHEIGHT", &cv_cam_height[arg]); + M_SetItemCvar(MN_OP_CAMERASETUP, "CAMSPEED", &cv_cam_speed[arg]); + M_SetItemCvar(MN_OP_CAMERASETUP, "CHASECAM", &cv_chasecam[arg]); + return true; +} + // =============== // Monitor Toggles // =============== diff --git a/src/m_menu.h b/src/m_menu.h index 85e1f6578..00592d7e9 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -310,6 +310,7 @@ INT32 MR_ChangeControl(INT32 arg); INT32 MR_AssignJoystick(INT32 arg); INT32 MR_HandleMonitorToggles(INT32 choice); INT32 MR_RestartAudio(INT32 choice); +INT32 MR_CameraSetup(INT32 arg); #ifdef HAVE_DISCORDRPC INT32 MR_HandleDiscordRequests(INT32 choice); #endif From f30ddcfad2d29073c0aa31efead47287cd7811da Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Thu, 12 Jun 2025 16:49:50 +0200 Subject: [PATCH 3/6] Three(!?) new methods for placing menu items Relative: changes the coordinates relative to the current ones Temporary relative: displaces the coordinates temporarily Overlay: draws at absolute coordinates, no clipping Along with custom cursor offsets and Item Styles(tm), this eliminates M_DrawControl --- src/deh_soc.c | 42 ++++++++++++++++-- src/deh_tables.c | 1 - src/m_menu.c | 113 ++++++++++++++++++++++++++++------------------- src/m_menu.h | 13 +++--- 4 files changed, 114 insertions(+), 55 deletions(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index 89749da11..f5425e369 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -1908,10 +1908,28 @@ static void readmenuitem(MYFILE *f, menuitem_t *menuitem) { menuitem->x = get_number(word2); } + else if (fastcmp(word, "OFSX")) + { + menuitem->x = get_number(word2); + status |= IT_OFSX; + } else if (fastcmp(word, "Y")) { menuitem->y = get_number(word2); } + else if (fastcmp(word, "OFSY")) + { + menuitem->y = get_number(word2); + status |= IT_OFSY; + } + else if (fastcmp(word, "OVERLAY")) + { + status |= IT_OVERLAY; + } + else if (fastcmp(word, "TEMPOFFSET")) + { + status |= IT_TEMPORARY; + } else if (fastcmp(word, "ARGUMENT")) { menuitem->argument = get_number(word2); @@ -1924,6 +1942,13 @@ static void readmenuitem(MYFILE *f, menuitem_t *menuitem) { menuitem->tooltip = Z_StrDup(word2); } + else if (fastcmp(word, "STYLE")) + { + if (fasticmp(word2, "CENTER")) + status |= IT_CENTER; + else + WARN("unknown style '%s'", word2); + } else if (fastncmp(word, "TEXT", 4)) { UINT16 flags = IT_STRING; @@ -1952,8 +1977,8 @@ static void readmenuitem(MYFILE *f, menuitem_t *menuitem) flags |= IT_CV_SLIDER; else if (fastcmp(word+4, "STRING")) flags |= IT_CV_STRING; - else if (fastcmp(word+4, "INTEGER")) - flags |= IT_CV_INTEGERSTEP; + //else if (fastcmp(word+4, "INTEGER")) + //flags |= IT_CV_INTEGERSTEP; else if (word[4]) { WARN("unknown word '%s'", word); @@ -1984,7 +2009,6 @@ static void readmenuitem(MYFILE *f, menuitem_t *menuitem) WARN("unknown menu '%s'", word2); continue; } - status |= IT_SUBMENU; menuitem->submenu = mn; } else if (fastcmp(word, "CALL") || fastcmp(word, "ARROWS")) @@ -2256,6 +2280,14 @@ void readmenu(MYFILE *f, INT32 num) { menudef->scrollheight = get_number(word2); } + else if (fastcmp(word, "CURSOROFFSET")) + { + menudef->cursoroffset = get_number(word2); + } + else if (fastcmp(word, "LINEHEIGHT")) + { + menudef->lineheight = get_number(word2); + } else if (fastcmp(word, "ENTERROUTINE")) { menufunc_f *routine = get_menuroutine(word2); @@ -2291,6 +2323,10 @@ void readmenu(MYFILE *f, INT32 num) } } while (!myfeof(f)); // finish when the line is empty + // default line height + if (!menudef->lineheight) + menudef->lineheight = 8; + Z_Free(s); } #undef WARN diff --git a/src/deh_tables.c b/src/deh_tables.c index 665bb0453..fc1063933 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -772,7 +772,6 @@ struct menu_drawer_s const MENU_DRAWERS[] = { { "DRAWPLAYBACKMENU", &M_DrawPlaybackMenu }, { "DRAWIMAGEDEF", &M_DrawImageDef }, { "DRAWMUSICTEST", &M_DrawMusicTest }, - { "DRAWCONTROL", &M_DrawControl }, { "DRAWJOYSTICK", &M_DrawJoystick }, { "DRAWMONITORTOGGLES", &M_DrawMonitorToggles }, { "DRAWCONNECTMENU", &M_DrawConnectMenu }, diff --git a/src/m_menu.c b/src/m_menu.c index b24639138..fdc819d93 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -102,7 +102,6 @@ int snprintf(char *str, size_t n, const char *fmt, ...); #include "qs22j.h" -#define LINEHEIGHT 8 #define SLIDER_RANGE 10 #define SLIDER_WIDTH (8*SLIDER_RANGE+6) #define MAXIPADDRESSLEN 28 @@ -283,7 +282,7 @@ static void M_ChangeItemStatus(menutype_t type, const char *name, UINT16 flag, b static boolean M_ItemSelectable(menuitem_t *item) { - return !(item->status & (IT_HIDDEN|IT_GRAYEDOUT|IT_SECRET)) && (item->status & IT_TYPE); + return !(item->status & (IT_HIDDEN|IT_GRAYEDOUT|IT_SECRET)) && (item->submenu || item->routine || item->cvar); } // bruh... @@ -832,14 +831,14 @@ static INT32 M_ChangeCvar(INT32 choice) } else if (cv->flags & CV_FLOAT) { - if (!(currentMenu->menuitems[itemOn].status & IT_CV_INTEGERSTEP)) + /*if (!(currentMenu->menuitems[itemOn].status & IT_CV_INTEGERSTEP)) { char s[20]; float n = FIXED_TO_FLOAT(cv->value)+(choice)*(1.0f/16.0f); sprintf(s,"%ld%s",(long)n,M_Ftrim(n)); CV_Set(cv,s); } - else + else*/ CV_SetValue(cv,FIXED_TO_FLOAT(cv->value)+(choice)); } else @@ -2102,7 +2101,7 @@ static INT16 M_DrawMenuItem(menuitem_t *item, INT16 x, INT16 y, INT32 vflags, bo break; case IT_STRING: case IT_WHITESTRING: - if (vflags & MDF_CENTERED) + if (vflags & MDF_CENTERED || item->status & IT_CENTER) V_DrawCenteredString(x, y, vflags|highlight, string); else V_DrawString(x, y, vflags|highlight, string); @@ -2225,7 +2224,7 @@ static INT16 M_DrawMenuItem(menuitem_t *item, INT16 x, INT16 y, INT32 vflags, bo } break; case IT_HEADERTEXT: // draws 16 pixels to the left, in yellow text - V_DrawString(x - (vflags & MDF_CONTROLS ? 7 : 16), y - (vflags & MDF_CONTROLS ? 2 : 0), vflags|highlight, string); + V_DrawString(x - 16, y, vflags|highlight, string); break; default: break; @@ -2234,12 +2233,22 @@ static INT16 M_DrawMenuItem(menuitem_t *item, INT16 x, INT16 y, INT32 vflags, bo return V_StringWidth(string, vflags); } +// gets the absolute Y coordinate where this menuitem should be drawn (in a broken way) +// TODO: merge this with the actual drawing loop somehow static INT16 getheight(INT16 index) { + // gotta skip overlay items... + INT16 i = 0; + while (index + i < currentMenu->numitems && currentMenu->menuitems[index + i].status & IT_OVERLAY) + i++; + index += i; + if (index >= currentMenu->numitems) + return 0; + INT16 y = currentMenu->menuitems[index].y; - if (!y) for (INT16 i = 0; i < index; i++) - if (!(currentMenu->menuitems[i].status & IT_HIDDEN)) - y += 8; + if (!y) while (i < index) + if (!(currentMenu->menuitems[i++].status & (IT_HIDDEN|IT_OVERLAY))) + y += currentMenu->lineheight; return y; } @@ -2249,6 +2258,8 @@ static void M_DrawBaseMenu(INT32 flags) INT16 scrollheight = currentMenu->scrollheight; if (!scrollheight) scrollheight = INT16_MAX; + if (!currentMenu->numitems) + return; INT16 topy = getheight(0); INT16 boty = getheight(currentMenu->numitems-1); @@ -2275,48 +2286,68 @@ static void M_DrawBaseMenu(INT32 flags) for (i = 0; i < currentMenu->numitems; i++) { + INT16 dx, dy; INT32 vflags = flags; + menuitem_t *item = ¤tMenu->menuitems[i]; - if (currentMenu->menuitems[i].status & IT_HIDDEN) - { - if (!(vflags & MDF_CONTROLS)) // don't leave gaps when buttons are hidden for P2/P3/P4 - y += LINEHEIGHT; + if (item->status & IT_HIDDEN) continue; + + if (item->status & IT_OVERLAY) + { + // draw at absolute coordinates; no clipping needed + dx = item->x; + dy = item->y; + } + else + { + dx = x + item->x; + if (item->x) + { + if (!(item->status & IT_OFSX)) + x = dx = item->x + scrollx; + else if (!(item->status & IT_TEMPORARY)) + x = dx; + } + + dy = y + item->y; + if (item->y) + { + if (!(item->status & IT_OFSY)) + y = dy = item->y + scrolly; + else if (!(item->status & IT_TEMPORARY)) + y = dy; + } + + if (dy < currentMenu->y) + { + cliptop = true; + goto nodraw; + } + else if (dy > currentMenu->y + scrollheight) + { + clipbot = true; + goto nodraw; + } } - if (currentMenu->menuitems[i].y) - y = currentMenu->menuitems[i].y + scrolly; - if (currentMenu->menuitems[i].x) - x = currentMenu->menuitems[i].x + scrollx; - - if (y < currentMenu->y) - { - cliptop = true; - y += LINEHEIGHT; - continue; - } - else if (y > currentMenu->y + scrollheight) - { - clipbot = true; - y += LINEHEIGHT; - continue; - } - - w = M_DrawMenuItem(¤tMenu->menuitems[i], x, y, vflags, i == itemOn); + w = M_DrawMenuItem(item, dx, dy, vflags, i == itemOn); if (i == itemOn) { cursory = y; - cursorx = x - (vflags & MDF_CENTERED ? w/2 : 0) - (vflags & MDF_CONTROLS ? 18 : 24); + cursorx = x - (vflags & MDF_CENTERED ? w/2 : 0) - 24 + currentMenu->cursoroffset; } - y += LINEHEIGHT; + nodraw: + if (!(item->status & IT_OVERLAY)) + y += currentMenu->lineheight; } // DRAW THE SKULL CURSOR V_DrawScaledPatch(cursorx, cursory, 0, W_CachePatchName("M_CURSOR", PU_CACHE)); - x = currentMenu->x - (flags & MDF_CONTROLS ? 16 : 20); + x = currentMenu->x - 20 + currentMenu->cursoroffset; if (cliptop) V_DrawCharacter(x, currentMenu->y - (skullAnimCounter/5), '\x1A' | highlightflags, false); // up arrow if (clipbot) @@ -3963,7 +3994,7 @@ void M_DrawPlaybackMenu(void) V_DrawCenteredString(BASEVIDWIDTH/2, currentMenu->y + 18, transmap|V_SNAPTOTOP|V_ALLOWLOWERCASE, currentMenu->menuitems[i].text); - if ((currentMenu->menuitems[i].status & IT_TYPE) == IT_ARROWS) + if (currentMenu->menuitems[i].status & IT_ARROWS) { char *str = NULL; @@ -6999,16 +7030,6 @@ INT32 MR_HandleControlsMenu(INT32 ch) return true; } -// Draws the Customise Controls menu -void M_DrawControl(void) -{ - M_CentreText(28, - (setupcontrolplayer > 1 ? va("\x86""Set controls for ""\x82""Player %d", setupcontrolplayer) : - "\x86""Press ""\x82""ENTER""\x86"" to change, ""\x82""BACKSPACE""\x86"" to clear")); - - M_DrawBaseMenu(MDF_CONTROLS|MENUCAPS); -} - static INT32 controltochange; static char controltochangetext[33]; diff --git a/src/m_menu.h b/src/m_menu.h index 00592d7e9..c532542e1 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -157,10 +157,9 @@ boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt); // flags for items in the menu // menu handle (what we do when key is pressed -#define IT_TYPE (1+2+4+8192) #define IT_CALL 1 // call the function #define IT_ARROWS 2 // call function with 0 for left arrow and 1 for right arrow in param -#define IT_SUBMENU 4 // go to sub menu +//#define IT_SUBMENU 4 // go to sub menu #define IT_CVAR 8192 // handle as a cvar // display flags @@ -176,18 +175,21 @@ boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt); //consvar specific #define IT_CV_SLIDER 64 #define IT_CV_STRING 128 -#define IT_CV_INTEGERSTEP 256 // if cvar is CV_FLOAT, modify it by 1 instead of 0.0625 +//#define IT_CV_INTEGERSTEP 256 // if cvar is CV_FLOAT, modify it by 1 instead of 0.0625 // extra flags #define IT_CENTER 512 // if IT_PATCH, center it on screen #define IT_HIDDEN 1024 // invisible, unselectable #define IT_GRAYEDOUT 2048 // grayed out, unselectable #define IT_SECRET 4096 // ??????? ???????????? +#define IT_OFSX 16384 // x coordinate is relative +#define IT_OFSY 32768 // ditto +#define IT_TEMPORARY 4 // offset is only applied temporarily +#define IT_OVERLAY 256 // no scrolling, draw at absolute coordinates // carefully chosen to not conflict with V_ flags #define MDF_CENTERED 0x20 #define MDF_TIMEATTACK 0x40 -#define MDF_CONTROLS 0x80 #define MAXSTRINGLENGTH 32 @@ -226,6 +228,8 @@ struct menu_t INT16 x, y; // x, y of menu INT16 scrollheight; // height of scrolling area INT16 lastOn; // last item user was on in menu + INT16 cursoroffset; // X offset of cursor + INT16 lineheight; // default Y offset to add for each item menufunc_f *enterroutine; // called before enter a menu menufunc_f *quitroutine; // called before quit a menu menufunc_f *keyhandler; // called before key press is processed @@ -333,7 +337,6 @@ void M_DrawReplayStartMenu(void); void M_DrawPlaybackMenu(void); void M_DrawImageDef(void); void M_DrawMusicTest(void); -void M_DrawControl(void); void M_DrawJoystick(void); void M_DrawMonitorToggles(void); #ifdef HAVE_DISCORDRPC From e276709d0cad9eb8f9e7363dbbcf93be5caa8490 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Thu, 12 Jun 2025 22:11:07 +0200 Subject: [PATCH 4/6] A whole lot of refactoring and updates to cvars cvar items now use their argument to specify the amount to add for each key press, replacing IT_CV_INTEGERSTEP cvar items are automatically displayed as strings if they don't have PossibleValues, replacing IT_CV_STRING --- src/d_netcmd.c | 3 +- src/deh_soc.c | 19 ++--- src/m_menu.c | 213 +++++++++++++++++++++++-------------------------- src/m_menu.h | 46 +++++------ src/p_user.c | 16 ++-- 5 files changed, 133 insertions(+), 164 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 7ad7e893f..dd2725673 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -536,7 +536,8 @@ consvar_t cv_votetime = CVAR_INIT ("votetime", "20", CV_NETVAR, votetime_cons_t, consvar_t cv_gravity = CVAR_INIT ("gravity", "0.8", CV_RESTRICT|CV_FLOAT|CV_CALL, NULL, Gravity_OnChange); // change DEFAULT_GRAVITY if you change this -consvar_t cv_soundtest = CVAR_INIT ("soundtest", "0", CV_CALL, NULL, SoundTest_OnChange); +static CV_PossibleValue_t soundtest_cons_t[] = {{0, "MIN"}, {NUMSFX, "MAX"}}; +consvar_t cv_soundtest = CVAR_INIT ("soundtest", "0", CV_CALL, soundtest_cons_t, SoundTest_OnChange); static CV_PossibleValue_t minitimelimit_cons_t[] = {{15, "MIN"}, {9999, "MAX"}, {0, NULL}}; consvar_t cv_countdowntime = CVAR_INIT ("countdowntime", "30", CV_NETVAR|CV_CHEAT, minitimelimit_cons_t, NULL); diff --git a/src/deh_soc.c b/src/deh_soc.c index f5425e369..9ecb1cd7d 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -1972,13 +1972,9 @@ static void readmenuitem(MYFILE *f, menuitem_t *menuitem) } else if (fastncmp(word, "CVAR", 4)) { - UINT16 flags = IT_CVAR; + UINT16 flags = IT_INTERACT; if (fastcmp(word+4, "SLIDER")) - flags |= IT_CV_SLIDER; - else if (fastcmp(word+4, "STRING")) - flags |= IT_CV_STRING; - //else if (fastcmp(word+4, "INTEGER")) - //flags |= IT_CV_INTEGERSTEP; + flags |= IT_SLIDER; else if (word[4]) { WARN("unknown word '%s'", word); @@ -2009,17 +2005,14 @@ static void readmenuitem(MYFILE *f, menuitem_t *menuitem) WARN("unknown menu '%s'", word2); continue; } + status |= IT_INTERACT; menuitem->submenu = mn; } else if (fastcmp(word, "CALL") || fastcmp(word, "ARROWS")) { - UINT16 flags; - if (word[0] == 'C') - flags = IT_CALL; - else if (word[0] == 'A') - flags = IT_ARROWS; - else - I_Error("bruh"); // i should probably just make "CALL" the stem for all of these + UINT16 flags = IT_INTERACT; + if (word[0] == 'A') + flags |= IT_ARROWS; menufunc_f *routine = get_menuroutine(word2); if (!routine) diff --git a/src/m_menu.c b/src/m_menu.c index fdc819d93..47a208b98 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -282,7 +282,7 @@ static void M_ChangeItemStatus(menutype_t type, const char *name, UINT16 flag, b static boolean M_ItemSelectable(menuitem_t *item) { - return !(item->status & (IT_HIDDEN|IT_GRAYEDOUT|IT_SECRET)) && (item->submenu || item->routine || item->cvar); + return (item->status & IT_INTERACT) && !(item->status & (IT_HIDDEN|IT_GRAYEDOUT|IT_SECRET)); } // bruh... @@ -806,57 +806,57 @@ void M_InitMenuPresTables(void) static UINT8 multi_spr2; static void M_GetFollowerState(void); -static INT32 M_ChangeCvar(INT32 choice) +static void M_ResetCvar(menuitem_t *item) { - consvar_t *cv = currentMenu->menuitems[itemOn].cvar; + consvar_t *cv = item->cvar; - if (choice == -1) + if (cv == &cv_playercolor[0] || cv == &cv_playercolor[1] || cv == &cv_playercolor[2] || cv == &cv_playercolor[3] || cv == &cv_dummycolor) { - if (cv == &cv_playercolor[0] || cv == &cv_playercolor[1] || cv == &cv_playercolor[2] || cv == &cv_playercolor[3] || cv == &cv_dummycolor) - { - INT32 skinno = R_SkinAvailable(skins[cv_chooseskin.value].name); - if (skinno != -1 && skincolors[skins[skinno].prefcolor].accessible) - CV_SetValue(cv,skins[skinno].prefcolor); - return true; - } - CV_Set(cv,cv->defaultvalue); - return true; - } - - choice = (choice<<1) - 1; - - if ((currentMenu->menuitems[itemOn].status & IT_ACTION) == IT_CV_SLIDER) - { - CV_SetValue(cv,cv->value+choice); - } - else if (cv->flags & CV_FLOAT) - { - /*if (!(currentMenu->menuitems[itemOn].status & IT_CV_INTEGERSTEP)) - { - char s[20]; - float n = FIXED_TO_FLOAT(cv->value)+(choice)*(1.0f/16.0f); - sprintf(s,"%ld%s",(long)n,M_Ftrim(n)); - CV_Set(cv,s); - } - else*/ - CV_SetValue(cv,FIXED_TO_FLOAT(cv->value)+(choice)); + INT32 skinno = R_SkinAvailable(skins[cv_chooseskin.value].name); + if (skinno != -1 && skincolors[skins[skinno].prefcolor].accessible) + CV_SetValue(cv, skins[skinno].prefcolor); } else - CV_AddValue(cv,choice); + CV_Set(cv, cv->defaultvalue); +} + +static void M_ChangeCvar(menuitem_t *item, SINT8 direction) +{ + consvar_t *cv = item->cvar; + INT32 amount = item->argument ? item->argument : cv->flags & CV_FLOAT ? FRACUNIT/16 : 1; + amount *= direction; + + if (cv->flags & CV_FLOAT) + { + char s[20]; + float n = FIXED_TO_FLOAT(cv->value + amount); + sprintf(s, "%ld%s", (long)n, M_Ftrim(n)); + CV_Set(cv, s); + } + else + CV_AddValue(cv, amount); if (cv == &cv_chooseskin) multi_spr2 = P_GetSkinSprite2(&skins[cv->value], SPR2_FSTN, NULL); else if (cv == &cv_dummyfollower) M_GetFollowerState(); // update follower state +} - return true; +static UINT32 M_StringCvarLength(consvar_t *cv) +{ + if (cv == &cv_dummyip) + return MAXIPADDRESSLEN; + else if (cv == &cv_dummyname || cv == &cv_playername[0] || cv == &cv_playername[1] || cv == &cv_playername[2] || cv == &cv_playername[3]) + return MAXPLAYERNAME + 1; + else + return MAXSTRINGLENGTH; } static boolean M_ChangeStringCvar(INT32 choice) { consvar_t *cv = currentMenu->menuitems[itemOn].cvar; char buf[MAXSTRINGLENGTH]; - size_t len; + size_t len = strlen(cv->string); if (shiftdown && choice >= 32 && choice <= 127) choice = shiftxform[choice]; @@ -864,7 +864,6 @@ static boolean M_ChangeStringCvar(INT32 choice) switch (choice) { case KEY_BACKSPACE: - len = strlen(cv->string); if (len > 0) { S_StartSound(NULL,sfx_menu1); // Tails @@ -880,33 +879,35 @@ static boolean M_ChangeStringCvar(INT32 choice) CV_Set(cv, ""); } return true; + case KEY_LEFTARROW: + case KEY_RIGHTARROW: + // TODO: navigation + return true; default: if (cv == &cv_dummyip) { // Rudimentary number and period enforcing - also allows letters so hostnames can be used instead if (!((choice >= '-' && choice <= ':') || (choice >= 'A' && choice <= 'Z') || (choice >= 'a' && choice <= 'z')) && !(choice >= KEY_KEYPAD7 && choice <= KEY_KPADDEL && choice != KEY_MINUSPAD && choice != KEY_PLUSPAD)) //numpad too! - return false; + break; if (choice >= KEY_KEYPAD7) // sir, have you been golfing tonight? choice = "789-456+1230."[choice - KEY_KEYPAD7]; } - if (choice >= 32 && choice <= 127) + if (choice < 32 || choice > 127) + break; + + if (len < M_StringCvarLength(cv) - 1) { - len = strlen(cv->string); - if (len < (cv == &cv_dummyip ? MAXIPADDRESSLEN : MAXSTRINGLENGTH) - 1) - { - S_StartSound(NULL,sfx_menu1); // Tails - M_Memcpy(buf, cv->string, len); - buf[len++] = (char)choice; - buf[len] = 0; - CV_Set(cv, buf); - } - return true; + S_StartSound(NULL, sfx_menu1); // Tails + M_Memcpy(buf, cv->string, len); + buf[len++] = (char)choice; + buf[len] = 0; + CV_Set(cv, buf); } - break; + return true; } return false; } @@ -991,7 +992,6 @@ boolean M_Responder(event_t *ev) static tic_t joywait = 0, mousewait = 0; static INT32 pmousex = 0, pmousey = 0; static INT32 lastx = 0, lasty = 0; - menufunc_f *routine = NULL; // for some casting problem INT32 deviceplayer = G_GetDevicePlayer(ev->device); if (dedicated || (demo.playback && demo.title) @@ -1246,19 +1246,10 @@ boolean M_Responder(event_t *ev) // BP: one of the more big hack i have never made // G: not so hacky anymore...? // G: nevermind we have combi menuitems now - UINT16 itemtype = 0; - if (currentMenu->numitems) - { - itemtype = currentMenu->menuitems[itemOn].status; - routine = currentMenu->menuitems[itemOn].routine; - } - if ((itemtype & (IT_CVAR|IT_CV_STRING)) == (IT_CVAR|IT_CV_STRING)) - { - if (shiftdown && ch >= 32 && ch <= 127) - ch = shiftxform[ch]; - if (M_ChangeStringCvar(ch)) - return true; - } + menuitem_t *item = currentMenu->numitems ? ¤tMenu->menuitems[itemOn] : NULL; + + if (item && item->cvar && !item->cvar->PossibleValue && M_ChangeStringCvar(ch)) + return true; if (menustack[0] == MN_PLAYBACK && !con_destlines) { @@ -1283,7 +1274,7 @@ boolean M_Responder(event_t *ev) switch (ch) { case KEY_DOWNARROW: - if (!currentMenu->numitems) + if (!item) return true; do if (++itemOn >= currentMenu->numitems) @@ -1294,7 +1285,7 @@ boolean M_Responder(event_t *ev) return true; case KEY_UPARROW: - if (!currentMenu->numitems) + if (!item) return true; do if (--itemOn < 0) @@ -1305,24 +1296,24 @@ boolean M_Responder(event_t *ev) return true; case KEY_LEFTARROW: - if (itemtype & (IT_ARROWS|IT_CVAR) && !(itemtype & IT_CV_STRING)) - { - if (menustack[0] != MN_OP_SOUND || itemOn > 3) - S_StartSound(NULL, sfx_menu1); - (itemtype & IT_ARROWS ? routine : M_ChangeCvar)(0); - } - return true; - case KEY_RIGHTARROW: - if (itemtype & (IT_ARROWS|IT_CVAR) && !(itemtype & IT_CV_STRING)) - { - if (menustack[0] != MN_OP_SOUND || itemOn > 3) - S_StartSound(NULL, sfx_menu1); - (itemtype & IT_ARROWS ? routine : M_ChangeCvar)(1); - } + if (!item || !(item->cvar || item->status & IT_ARROWS)) + return true; + + if (menustack[0] != MN_OP_SOUND || itemOn > 3) + S_StartSound(NULL, sfx_menu1); + + if (item->cvar) + M_ChangeCvar(item, ch == KEY_RIGHTARROW ? 1 : -1); + else + item->routine(ch == KEY_RIGHTARROW ? 1 : 0); + return true; case KEY_ENTER: + if (!item) + return true; + noFurtherInput = true; currentMenu->lastOn = itemOn; @@ -1334,24 +1325,24 @@ boolean M_Responder(event_t *ev) playback_enterheld = 3; } - INT32 argument = currentMenu->menuitems[itemOn].argument; - if (currentMenu->menuitems[itemOn].cvar) - argument = currentMenu->menuitems[itemOn].cvar->value; + INT32 argument = item->argument; + if (item->cvar) + argument = item->cvar->value; - if (currentMenu->menuitems[itemOn].submenu) + if (item->submenu) { S_StartSound(NULL, sfx_menu1); - M_EnterMenu(currentMenu->menuitems[itemOn].submenu, true, argument); + M_EnterMenu(item->submenu, true, argument); } - else if (currentMenu->menuitems[itemOn].routine) + else if (item->routine) { S_StartSound(NULL, sfx_menu1); - routine(argument); + item->routine(argument); } - else if (currentMenu->menuitems[itemOn].cvar && !(itemtype & IT_CV_STRING)) + else if (item->cvar && item->cvar->PossibleValue) // not for string cvars! { S_StartSound(NULL, sfx_menu1); - M_ChangeCvar(1); // right arrow + M_ChangeCvar(item, 1); // right arrow } return true; @@ -1371,23 +1362,17 @@ boolean M_Responder(event_t *ev) return true; case KEY_BACKSPACE: - if (itemtype & IT_CVAR) - { - consvar_t *cv = currentMenu->menuitems[itemOn].cvar; - - if (cv == &cv_chooseskin - || cv == &cv_dummystaff - || cv == &cv_nextmap - || cv == &cv_newgametype - || cv == &cv_dummymultiplayer) - return true; - - if (menustack[0] != MN_OP_SOUND || itemOn > 3) - S_StartSound(NULL, sfx_menu1); - M_ChangeCvar(-1); + if (!item || !item->cvar + || item->cvar == &cv_chooseskin + || item->cvar == &cv_dummystaff + || item->cvar == &cv_nextmap + || item->cvar == &cv_newgametype + || item->cvar == &cv_dummymultiplayer) return true; - } + if (menustack[0] != MN_OP_SOUND || itemOn > 3) + S_StartSound(NULL, sfx_menu1); + M_ResetCvar(item); return true; default: @@ -2119,22 +2104,18 @@ static INT16 M_DrawMenuItem(menuitem_t *item, INT16 x, INT16 y, INT32 vflags, bo (BASEVIDWIDTH-currentMenu->x, y, vflags|highlightflags, name); } - if (item->status & IT_CVAR) + if (item->cvar) { consvar_t *cv = item->cvar; - switch(item->status & IT_ACTION) + if (!cv->PossibleValue) // string cvar? { - case IT_CV_SLIDER: - M_DrawSlider(x, y, cv, selected); - break; - case IT_CV_STRING: if (currentMenu->scrollheight && y + 12 > currentMenu->y + currentMenu->scrollheight) break; boolean side = vflags & MDF_TIMEATTACK || cv == &cv_dummyname; INT32 xofs = side ? 32 : 0; INT32 yofs = side ? -8 : 4; - w = side ? MAXPLAYERNAME : cv == &cv_dummyip ? MAXIPADDRESSLEN : MAXSTRINGLENGTH; + w = M_StringCvarLength(cv); M_DrawTextBox(x + xofs, y + yofs, w, 1); V_DrawString(x + xofs + 8, y + yofs + 8, vflags|V_ALLOWLOWERCASE, cv->string); @@ -2144,8 +2125,12 @@ static INT16 M_DrawMenuItem(menuitem_t *item, INT16 x, INT16 y, INT32 vflags, bo if (!side) y += 16; - break; - default: + } + else if (item->status & IT_SLIDER) + { + M_DrawSlider(x, y, cv, selected); + } + else { const char *str = cv->string; INT32 soffset = vflags & MDF_TIMEATTACK && cv != &cv_nextmap ? 40 : 0; @@ -2191,12 +2176,10 @@ static INT16 M_DrawMenuItem(menuitem_t *item, INT16 x, INT16 y, INT32 vflags, bo V_DrawCharacter(BASEVIDWIDTH - x - soffset + 2 + (skullAnimCounter/5), y, '\x1D' | highlightflags | strvf, false); // right arrow } - break; - } } break; } - else if (item->status & IT_CALL) + else if (item->routine) { char tmp[32*MAXINPUTMAPPING]; // should be enough :^) INT32 key; diff --git a/src/m_menu.h b/src/m_menu.h index c532542e1..c52388cc2 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -155,37 +155,29 @@ void M_QuitResponse(INT32 ch); // Determines whether to show a level in the list (platter version does not need to be exposed) boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt); -// flags for items in the menu -// menu handle (what we do when key is pressed -#define IT_CALL 1 // call the function -#define IT_ARROWS 2 // call function with 0 for left arrow and 1 for right arrow in param -//#define IT_SUBMENU 4 // go to sub menu -#define IT_CVAR 8192 // handle as a cvar +typedef enum +{ + IT_INTERACT = 1<<0, // item can be interacted with + IT_HIDDEN = 1<<1, // item is invisible and cannot be interacted with (has priority over IT_INTERACT) + IT_GRAYEDOUT = 1<<2, // item is grayed out and non-interactible + IT_SECRET = 1<<3, // item text is displayed with question marks and non-interactible -// display flags -#define IT_DISPLAY (8+16+32) -#define IT_PATCH 8 // a patch or a string with big font -#define IT_STRING 16 // little string (spaced with 10) -#define IT_WHITESTRING 32 // little string in white -#define IT_HEADERTEXT (8+32) // Non-selectable header option, displays in yellow offset to the left a little + IT_ARROWS = 1<<4, // call-type items use arrow keys instead of enter + IT_SLIDER = 1<<5, // cvar-type items display a slider -// flags specific to each item action type -#define IT_ACTION (64+128+256) + IT_PATCH = 1<<6, // display a patch + IT_STRING = 1<<7, // display a string + IT_WHITESTRING = 1<<8, // displays a string with highlighted text + IT_HEADERTEXT = IT_PATCH|IT_WHITESTRING, + IT_DISPLAY = IT_PATCH|IT_STRING|IT_WHITESTRING, -//consvar specific -#define IT_CV_SLIDER 64 -#define IT_CV_STRING 128 -//#define IT_CV_INTEGERSTEP 256 // if cvar is CV_FLOAT, modify it by 1 instead of 0.0625 + IT_OFSX = 1<<9, // X coordinate is relative to current position + IT_OFSY = 1<<10, // ditto + IT_TEMPORARY = 1<<11, // with IT_OFS*, offset applies only to this item + IT_OVERLAY = 1<<12, // item is drawn at absolute coordinates, without scrolling -// extra flags -#define IT_CENTER 512 // if IT_PATCH, center it on screen -#define IT_HIDDEN 1024 // invisible, unselectable -#define IT_GRAYEDOUT 2048 // grayed out, unselectable -#define IT_SECRET 4096 // ??????? ???????????? -#define IT_OFSX 16384 // x coordinate is relative -#define IT_OFSY 32768 // ditto -#define IT_TEMPORARY 4 // offset is only applied temporarily -#define IT_OVERLAY 256 // no scrolling, draw at absolute coordinates + IT_CENTER = 1<<13, // centered text/patch +} menuitemflags_t; // carefully chosen to not conflict with V_ flags #define MDF_CENTERED 0x20 diff --git a/src/p_user.c b/src/p_user.c index eef6483a2..dc9b55e50 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2618,17 +2618,17 @@ static CV_PossibleValue_t CV_CamSpeed[] = {{0, "MIN"}, {1*FRACUNIT, "MAX"}, {0, static CV_PossibleValue_t CV_CamRotate[] = {{-720, "MIN"}, {720, "MAX"}, {0, NULL}}; consvar_t cv_cam_dist[MAXSPLITSCREENPLAYERS] = { - CVAR_INIT ("cam_dist", "190", CV_FLOAT|CV_SAVE, NULL, NULL), - CVAR_INIT ("cam2_dist", "190", CV_FLOAT|CV_SAVE, NULL, NULL), - CVAR_INIT ("cam3_dist", "190", CV_FLOAT|CV_SAVE, NULL, NULL), - CVAR_INIT ("cam4_dist", "190", CV_FLOAT|CV_SAVE, NULL, NULL) + CVAR_INIT ("cam_dist", "190", CV_FLOAT|CV_SAVE, CV_Signed, NULL), + CVAR_INIT ("cam2_dist", "190", CV_FLOAT|CV_SAVE, CV_Signed, NULL), + CVAR_INIT ("cam3_dist", "190", CV_FLOAT|CV_SAVE, CV_Signed, NULL), + CVAR_INIT ("cam4_dist", "190", CV_FLOAT|CV_SAVE, CV_Signed, NULL) }; consvar_t cv_cam_height[MAXSPLITSCREENPLAYERS] = { - CVAR_INIT ("cam_height", "75", CV_FLOAT|CV_SAVE, NULL, NULL), - CVAR_INIT ("cam2_height", "75", CV_FLOAT|CV_SAVE, NULL, NULL), - CVAR_INIT ("cam3_height", "75", CV_FLOAT|CV_SAVE, NULL, NULL), - CVAR_INIT ("cam4_height", "75", CV_FLOAT|CV_SAVE, NULL, NULL) + CVAR_INIT ("cam_height", "75", CV_FLOAT|CV_SAVE, CV_Signed, NULL), + CVAR_INIT ("cam2_height", "75", CV_FLOAT|CV_SAVE, CV_Signed, NULL), + CVAR_INIT ("cam3_height", "75", CV_FLOAT|CV_SAVE, CV_Signed, NULL), + CVAR_INIT ("cam4_height", "75", CV_FLOAT|CV_SAVE, CV_Signed, NULL) }; consvar_t cv_cam_still[MAXSPLITSCREENPLAYERS] = { From 8ded7ad542727f6332527e6733cd12a7423a663c Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Sun, 15 Jun 2025 17:17:00 +0200 Subject: [PATCH 5/6] More styles, more softcoding, patches actually usable now! --- src/deh_soc.c | 15 +++- src/deh_tables.c | 3 - src/m_menu.c | 222 +++++++++++++++++++++-------------------------- src/m_menu.h | 29 +++---- 4 files changed, 123 insertions(+), 146 deletions(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index 9ecb1cd7d..8a40dcbf0 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -1946,6 +1946,16 @@ static void readmenuitem(MYFILE *f, menuitem_t *menuitem) { if (fasticmp(word2, "CENTER")) status |= IT_CENTER; + else if (fasticmp(word2, "THIN")) + status |= IT_THIN; + else if (fasticmp(word2, "PATCH")) + status |= IT_PATCH; + else if (fasticmp(word2, "PATCH-CENTER")) + status |= IT_PATCH|IT_CENTER; + else if (fasticmp(word2, "PATCH-SMALL")) + status |= IT_PATCH|IT_SMALL; + else if (fasticmp(word2, "PATCH-HIGHLIGHT")) + status |= IT_PATCH|IT_HIGHLIGHT; else WARN("unknown style '%s'", word2); } @@ -1953,9 +1963,9 @@ static void readmenuitem(MYFILE *f, menuitem_t *menuitem) { UINT16 flags = IT_STRING; if (fastcmp(word+4, "HEADER")) - flags = IT_HEADERTEXT; + flags = IT_HEADERTEXT|IT_HIGHLIGHT; else if (fastcmp(word+4, "WHITE")) - flags = IT_WHITESTRING; + flags |= IT_HIGHLIGHT; else if (word[4]) { WARN("unknown word '%s'", word); @@ -2090,7 +2100,6 @@ void readmenu(MYFILE *f, INT32 num) menudef->menuitems = Z_Realloc(menudef->menuitems, sizeof(menuitem_t)*(menudef->numitems+1), PU_STATIC, NULL); item = menudef->menuitems + menudef->numitems++; DEH_Link(word2, &item->info, &menunames); - item->text = ""; } readmenuitem(f, item); } diff --git a/src/deh_tables.c b/src/deh_tables.c index fc1063933..c37f218a3 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -756,7 +756,6 @@ struct menu_routine_s const MENU_ROUTINES[] = { struct menu_drawer_s const MENU_DRAWERS[] = { { "DRAWGENERICMENU", &M_DrawGenericMenu }, - { "DRAWCENTEREDMENU", &M_DrawCenteredMenu }, { "DRAWPAUSEMENU", &M_DrawPauseMenu }, { "DRAWCHECKLIST", &M_DrawChecklist }, { "DRAWLEVELSTATS", &M_DrawLevelStats }, @@ -764,9 +763,7 @@ struct menu_drawer_s const MENU_DRAWERS[] = { { "DRAWTIMEATTACKMENU", &M_DrawTimeAttackMenu }, { "DRAWMPMAINMENU", &M_DrawMPMainMenu }, { "DRAWSETUPMULTIPLAYERMENU", &M_DrawSetupMultiPlayerMenu }, - { "DRAWVIDEOMENU", &M_DrawVideoMenu }, { "DRAWVIDEOMODE", &M_DrawVideoMode }, - { "DRAWHUDOPTIONS", &M_DrawHUDOptions }, { "DRAWADDONS", &M_DrawAddons }, { "DRAWREPLAYSTARTMENU", &M_DrawReplayStartMenu }, { "DRAWPLAYBACKMENU", &M_DrawPlaybackMenu }, diff --git a/src/m_menu.c b/src/m_menu.c index 47a208b98..fd6d21d1c 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -1688,6 +1688,12 @@ void M_Ticker(void) else playback_enterheld = 0; + // Hide some options based on the current render mode +#ifdef HWRENDER + M_SetItemVisible(MN_OP_VIDEO, "OPENGL", rendermode == render_opengl); +#endif + //M_SetItemVisible(MN_OP_VIDEO, "PARALLEL", rendermode == render_soft); + //added : 30-01-98 : test mode for five seconds if (vidm_testingmode > 0) { @@ -2054,9 +2060,11 @@ void M_DrawPauseMenu(void) static INT16 M_DrawMenuItem(menuitem_t *item, INT16 x, INT16 y, INT32 vflags, boolean selected) { INT16 w; - const char *string = item->text; - INT16 display = item->status & IT_DISPLAY; - INT32 highlight = selected || display == IT_WHITESTRING || display == IT_HEADERTEXT ? highlightflags : 0; + const char *string = item->text ? item->text : ""; + INT32 highlight = selected || item->status & IT_HIGHLIGHT ? highlightflags : 0; + fixed_t scale = item->status & IT_SMALL ? FRACUNIT/2 : FRACUNIT; + int font = HU_FONT; + INT32 (*widthfunc)(const char *string, INT32 option) = V_StringWidth; if (item->status & IT_SECRET) { @@ -2066,44 +2074,39 @@ static INT16 M_DrawMenuItem(menuitem_t *item, INT16 x, INT16 y, INT32 vflags, bo else if (item->status & IT_GRAYEDOUT) vflags |= V_TRANSLUCENT; - switch (display) + switch (item->status & IT_DISPLAY) { case IT_PATCH: - if (item->patch && item->patch[0]) - { - if (item->status & IT_CENTER) - { - patch_t *p; - p = W_CachePatchName(item->patch, PU_CACHE); - V_DrawScaledPatch((BASEVIDWIDTH - SHORT(p->width))/2, y, 0, p); - } - else - { - V_DrawScaledPatch(x, y, 0, - W_CachePatchName(item->patch, PU_CACHE)); - } - } + if (!item->patch) + break; + + patch_t *p = W_CachePatchName(item->patch, PU_CACHE); + UINT8 *cmap = NULL; + + if (item->status & IT_CENTER) + x -= SHORT(p->width)/2; + if (item->status & IT_HIGHLIGHT) + cmap = V_GetStringColormap(highlightflags); + + V_DrawFixedPatch(x<status & IT_CENTER) - V_DrawCenteredString(x, y, vflags|highlight, string); - else - V_DrawString(x, y, vflags|highlight, string); + if (item->status & IT_THIN) + { + font = TINY_FONT; + vflags |= V_6WIDTHSPACE; + widthfunc = V_ThinStringWidth; + } + + if (item->status & IT_CENTER) + x -= widthfunc(string, vflags)/2; + + V_DrawStringScaled(x<status & (IT_SECRET|IT_GRAYEDOUT)) break; - if (item == M_CheckMenuItem(MN_OP_CHANGECONTROLS, "SETJOY")) // gamepad select - { - INT32 stick = cv_usejoystick[setupcontrolplayer-1].value; - const char *name = stick == 0 ? "None" : I_GetJoyName(stick); - if (!name) name = "?"; - w = V_StringWidth(name, vflags); - (w > BASEVIDWIDTH/2 - 4 ? V_DrawRightAlignedThinString : V_DrawRightAlignedString) - (BASEVIDWIDTH-currentMenu->x, y, vflags|highlightflags, name); - } - + // draw the right-side string if (item->cvar) { consvar_t *cv = item->cvar; @@ -2112,7 +2115,7 @@ static INT16 M_DrawMenuItem(menuitem_t *item, INT16 x, INT16 y, INT32 vflags, bo if (currentMenu->scrollheight && y + 12 > currentMenu->y + currentMenu->scrollheight) break; - boolean side = vflags & MDF_TIMEATTACK || cv == &cv_dummyname; + boolean side = cv == &cv_dummyname || cv == &cv_playername[0]; INT32 xofs = side ? 32 : 0; INT32 yofs = side ? -8 : 4; w = M_StringCvarLength(cv); @@ -2133,10 +2136,21 @@ static INT16 M_DrawMenuItem(menuitem_t *item, INT16 x, INT16 y, INT32 vflags, bo else { const char *str = cv->string; - INT32 soffset = vflags & MDF_TIMEATTACK && cv != &cv_nextmap ? 40 : 0; + INT32 soffset = 0; INT32 strvf = vflags; boolean warning = (cv->flags & CV_CHEAT) && !CV_IsSetToDefault(cv); + // special cvar value offsets for time attack! + // i don't feel like adding an extra flag for this... + if (y < 78) for (w = 0; w < NUMMENULEVELS; w++) + { + if (menustack[w] == MN_SP_TIMEATTACK) + { + soffset = 40; + break; + } + } + if (cv == &cv_chooseskin) str = skins[cv_chooseskin.value].realname; else if (cv == &cv_dummyfollower) @@ -2159,6 +2173,18 @@ static INT16 M_DrawMenuItem(menuitem_t *item, INT16 x, INT16 y, INT32 vflags, bo str = digital_disabled ? "Off" : "On"; warning = digital_disabled; } + else if (cv == &cons_menuhighlight) + { + INT16 hx = x - 2; + static const char *hstr[5] = { + "(", "Good highlight", ",", " Warning highlight", ")" + }; + for (w = 0; w < 5; w++) + { + V_DrawString(hx, y + 10, (w == 1 ? recommendedflags : w == 3 ? warningflags : highlightflags)|strvf, hstr[w]); + hx += V_StringWidth(hstr[w], strvf); + } + } else if (cv == &cv_dummymultiplayer) break; @@ -2205,6 +2231,26 @@ static INT16 M_DrawMenuItem(menuitem_t *item, INT16 x, INT16 y, INT32 vflags, bo (BASEVIDWIDTH-currentMenu->x, y, vflags|highlightflags, tmp); break; } + else + { + if (item->submenu == MN_OP_VIDEOMODE) // show current resolution + { + V_DrawRightAlignedString(BASEVIDWIDTH - x, y, + (SCR_IsAspectCorrect(vid.width, vid.height) ? recommendedflags : highlightflags)|vflags, + va("%dx%d", vid.width, vid.height)); + } + else if (item->submenu == MN_OP_JOYSTICKSET) // gamepad select + { + INT32 stick = cv_usejoystick[setupcontrolplayer-1].value; + const char *name = stick == 0 ? "None" : I_GetJoyName(stick); + if (!name) name = "?"; + w = V_StringWidth(name, vflags); + (w > BASEVIDWIDTH/2 - 4 ? V_DrawRightAlignedThinString : V_DrawRightAlignedString) + (BASEVIDWIDTH - x, y, vflags|highlightflags, name); + } + else if (item->patch) + V_DrawRightAlignedString(BASEVIDWIDTH - x, y, (highlight ? highlightflags : 0)|vflags, item->patch); + } break; case IT_HEADERTEXT: // draws 16 pixels to the left, in yellow text V_DrawString(x - 16, y, vflags|highlight, string); @@ -2213,7 +2259,7 @@ static INT16 M_DrawMenuItem(menuitem_t *item, INT16 x, INT16 y, INT32 vflags, bo break; } - return V_StringWidth(string, vflags); + return widthfunc(string, vflags); } // gets the absolute Y coordinate where this menuitem should be drawn (in a broken way) @@ -2235,7 +2281,7 @@ static INT16 getheight(INT16 index) return y; } -static void M_DrawBaseMenu(INT32 flags) +void M_DrawGenericMenu(void) { INT16 scrollx = currentMenu->x, scrolly = currentMenu->y; INT16 scrollheight = currentMenu->scrollheight; @@ -2270,7 +2316,6 @@ static void M_DrawBaseMenu(INT32 flags) for (i = 0; i < currentMenu->numitems; i++) { INT16 dx, dy; - INT32 vflags = flags; menuitem_t *item = ¤tMenu->menuitems[i]; if (item->status & IT_HIDDEN) @@ -2314,12 +2359,12 @@ static void M_DrawBaseMenu(INT32 flags) } } - w = M_DrawMenuItem(item, dx, dy, vflags, i == itemOn); + w = M_DrawMenuItem(item, dx, dy, MENUCAPS, i == itemOn); if (i == itemOn) { cursory = y; - cursorx = x - (vflags & MDF_CENTERED ? w/2 : 0) - 24 + currentMenu->cursoroffset; + cursorx = x - (item->status & IT_CENTER ? w/2 : 0) - 24 + currentMenu->cursoroffset; } nodraw: @@ -2328,7 +2373,8 @@ static void M_DrawBaseMenu(INT32 flags) } // DRAW THE SKULL CURSOR - V_DrawScaledPatch(cursorx, cursory, 0, W_CachePatchName("M_CURSOR", PU_CACHE)); + if (M_ItemSelectable(¤tMenu->menuitems[itemOn])) + V_DrawScaledPatch(cursorx, cursory, 0, W_CachePatchName("M_CURSOR", PU_CACHE)); x = currentMenu->x - 20 + currentMenu->cursoroffset; if (cliptop) @@ -2367,16 +2413,6 @@ texty -= 10*vid.dupy;\ M_DrawMenuTooltips(); } -void M_DrawGenericMenu(void) -{ - M_DrawBaseMenu(MENUCAPS); -} - -void M_DrawCenteredMenu(void) -{ - M_DrawBaseMenu(MDF_CENTERED|MENUCAPS); -} - // // M_StringHeight // @@ -2729,11 +2765,15 @@ static void M_DrawMessageMenu(void) // You can even put multiple images in one menu! void M_DrawImageDef(void) { - patch_t *patch = W_CachePatchName(currentMenu->menuitems[itemOn].text,PU_CACHE); - if (patch->width <= BASEVIDWIDTH) - V_DrawScaledPatch(0,0,0,patch); - else - V_DrawSmallScaledPatch(0,0,0,patch); + for (INT16 i = 0; i < currentMenu->numitems; i++) + { + if (i == itemOn) + currentMenu->menuitems[i].status &= ~IT_HIDDEN; + else + currentMenu->menuitems[i].status |= IT_HIDDEN; + } + + M_DrawGenericMenu(); if (!currentMenu->menuitems[itemOn].argument) { @@ -5213,7 +5253,7 @@ void M_DrawTimeAttackMenu(void) V_DrawMappedPatch(BASEVIDWIDTH-x - SHORT(faceprefix[cv_chooseskin.value][FACE_WANTED]->width), y, 0, faceprefix[cv_chooseskin.value][FACE_WANTED], colormap); } - M_DrawBaseMenu((menustack[0] == MN_SP_TIMEATTACK ? MDF_TIMEATTACK : 0)|MENUCAPS); + M_DrawGenericMenu(); // Level record list if (cv_nextmap.value) @@ -5271,7 +5311,7 @@ void M_DrawTimeAttackMenu(void) x = menu->x + menu->menuitems[i].x; y = menu->y + menu->menuitems[i].y; if (y < 128) - M_DrawMenuItem(&menu->menuitems[i], x, y, V_TRANSLUCENT|MDF_TIMEATTACK|MENUCAPS, false); + M_DrawMenuItem(&menu->menuitems[i], x, y, V_TRANSLUCENT|MENUCAPS, false); } } @@ -6185,17 +6225,6 @@ void M_DrawMPMainMenu(void) // use generic drawer for cursor, items and title M_DrawGenericMenu(); -#if MAXPLAYERS != 16 -Update the maxplayers label... -#endif - V_DrawRightAlignedString(BASEVIDWIDTH-x, y+M_GetItemY(MN_MP_MAIN, "STARTSERVER"), - (M_IsItemOn(MN_MP_MAIN, "STARTSERVER") ? highlightflags : 0)|MENUCAPS, "(2-16 players)"); - - V_DrawRightAlignedString(BASEVIDWIDTH-x, y+M_GetItemY(MN_MP_MAIN, "OFFLINESERVER"), - (M_IsItemOn(MN_MP_MAIN, "OFFLINESERVER") ? highlightflags : 0)|MENUCAPS, - "(2-4 players)" - ); - // character bar, ripped off the color bar :V { #define iconwidth 32 @@ -6299,38 +6328,22 @@ void M_DrawSetupMultiPlayerMenu(void) INT32 mx, my, st, flags = 0; spritedef_t *sprdef; spriteframe_t *sprframe; - patch_t *statbg = W_CachePatchName("K_STATBG", PU_CACHE); - patch_t *statlr = W_CachePatchName("K_STATLR", PU_CACHE); - patch_t *statud = W_CachePatchName("K_STATUD", PU_CACHE); patch_t *statdot = W_CachePatchName("K_SDOT0", PU_CACHE); patch_t *patch; UINT8 frame; UINT8 speed; UINT8 weight; const UINT8 *flashcol = V_GetStringColormap(highlightflags); - INT32 statx, staty; INT16 i; mx = menudefs[MN_MP_PLAYERSETUP].x; my = menudefs[MN_MP_PLAYERSETUP].y; - statx = (BASEVIDWIDTH - mx - 118); - staty = (my+62); - // use generic drawer for cursor, items and title M_DrawGenericMenu(); // SRB2Kart: draw the stat backer - // labels - V_DrawThinString(statx+16, staty, MENUCAPS|V_6WIDTHSPACE|highlightflags, "Acceleration"); - V_DrawThinString(statx+91, staty, MENUCAPS|V_6WIDTHSPACE|highlightflags, "Max Speed"); - V_DrawThinString(statx, staty+12, MENUCAPS|V_6WIDTHSPACE|highlightflags, "Handling"); - V_DrawThinString(statx+7, staty+77, MENUCAPS|V_6WIDTHSPACE|highlightflags, "Weight"); - // label arrows - V_DrawFixedPatch((statx+64)<x, currentMenu->y + M_GetItemY(MN_OP_VIDEO, "SETMODE"), - (SCR_IsAspectCorrect(vid.width, vid.height) ? recommendedflags : highlightflags)|MENUCAPS, - va("%dx%d", vid.width, vid.height)); - - // Hide some options based on the current render mode -#ifdef HWRENDER - M_SetItemVisible(MN_OP_VIDEO, "OPENGL", rendermode == render_opengl); -#endif - //M_SetItemVisible(MN_OP_VIDEO, "PARALLEL", rendermode == render_soft); -} - -void M_DrawHUDOptions(void) -{ - const char *str0 = ")"; - const char *str1 = " Warning highlight"; - const char *str2 = ","; - const char *str3 = "Good highlight"; - INT32 x = BASEVIDWIDTH - currentMenu->x + 2, y = currentMenu->y + 90; - INT32 w0 = V_StringWidth(str0, 0), w1 = V_StringWidth(str1, 0), w2 = V_StringWidth(str2, 0), w3 = V_StringWidth(str3, 0); - - M_DrawGenericMenu(); - - x -= w0; - V_DrawString(x, y, MENUCAPS|highlightflags, str0); - x -= w1; - V_DrawString(x, y, MENUCAPS|warningflags, str1); - x -= w2; - V_DrawString(x, y, MENUCAPS|highlightflags, str2); - x -= w3; - V_DrawString(x, y, MENUCAPS|recommendedflags, str3); - V_DrawRightAlignedString(x, y, highlightflags, "("); -} - // Draw the video modes list, a-la-Quake void M_DrawVideoMode(void) { diff --git a/src/m_menu.h b/src/m_menu.h index c52388cc2..3b8a0ae38 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -165,24 +165,22 @@ typedef enum IT_ARROWS = 1<<4, // call-type items use arrow keys instead of enter IT_SLIDER = 1<<5, // cvar-type items display a slider - IT_PATCH = 1<<6, // display a patch - IT_STRING = 1<<7, // display a string - IT_WHITESTRING = 1<<8, // displays a string with highlighted text - IT_HEADERTEXT = IT_PATCH|IT_WHITESTRING, - IT_DISPLAY = IT_PATCH|IT_STRING|IT_WHITESTRING, + IT_OFSX = 1<<6, // X coordinate is relative to current position + IT_OFSY = 1<<7, // ditto + IT_TEMPORARY = 1<<8, // with IT_OFS*, offset applies only to this item + IT_OVERLAY = 1<<9, // item is drawn at absolute coordinates, without scrolling - IT_OFSX = 1<<9, // X coordinate is relative to current position - IT_OFSY = 1<<10, // ditto - IT_TEMPORARY = 1<<11, // with IT_OFS*, offset applies only to this item - IT_OVERLAY = 1<<12, // item is drawn at absolute coordinates, without scrolling + IT_CENTER = 1<<10, // center the text/patch + IT_SMALL = 1<<11, // draw at half scale + IT_THIN = 1<<12, // thin font + IT_HIGHLIGHT = 1<<13, // add highlightflags to text/patch - IT_CENTER = 1<<13, // centered text/patch + IT_PATCH = 1<<14, // display a patch + IT_STRING = 2<<14, // display a string + IT_HEADERTEXT = 3<<14, // whitestring with an offset + IT_DISPLAY = 3<<14, } menuitemflags_t; -// carefully chosen to not conflict with V_ flags -#define MDF_CENTERED 0x20 -#define MDF_TIMEATTACK 0x40 - #define MAXSTRINGLENGTH 32 typedef INT32 (menufunc_f)(INT32); @@ -312,7 +310,6 @@ INT32 MR_HandleDiscordRequests(INT32 choice); #endif void M_DrawGenericMenu(void); -void M_DrawCenteredMenu(void); void M_DrawPauseMenu(void); void M_DrawChecklist(void); void M_DrawLevelStats(void); @@ -321,9 +318,7 @@ void M_DrawTimeAttackMenu(void); void M_DrawMPMainMenu(void); void M_DrawSetupMultiPlayerMenu(void); void M_DrawConnectMenu(void); -void M_DrawVideoMenu(void); void M_DrawVideoMode(void); -void M_DrawHUDOptions(void); void M_DrawAddons(void); void M_DrawReplayStartMenu(void); void M_DrawPlaybackMenu(void); From 955da518caee07f7df2aeffd0feb0b87a296cc67 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Sun, 15 Jun 2025 18:00:15 +0200 Subject: [PATCH 6/6] Replace TextHeader and TextWhite with styles --- src/deh_soc.c | 41 +++--- src/m_menu.c | 341 +++++++++++++++++++++++++------------------------- src/m_menu.h | 16 ++- 3 files changed, 194 insertions(+), 204 deletions(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index 8a40dcbf0..3516b4edc 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -1934,6 +1934,10 @@ static void readmenuitem(MYFILE *f, menuitem_t *menuitem) { menuitem->argument = get_number(word2); } + else if (fastcmp(word, "TEXT")) + { + menuitem->text = Z_StrDup(word2); + } else if (fastcmp(word, "PATCH")) { menuitem->patch = Z_StrDup(word2); @@ -1944,10 +1948,24 @@ static void readmenuitem(MYFILE *f, menuitem_t *menuitem) } else if (fastcmp(word, "STYLE")) { - if (fasticmp(word2, "CENTER")) + if (status & IT_STYLE) + { + WARN0("style already set!"); + continue; + } + + if (fasticmp(word2, "HEADER")) + status |= IT_HEADER|IT_HIGHLIGHT; + else if (fasticmp(word2, "HIGHLIGHT")) + status |= IT_HIGHLIGHT; + else if (fasticmp(word2, "CENTER")) status |= IT_CENTER; + else if (fasticmp(word2, "CENTER-HIGHLIGHT")) + status |= IT_CENTER|IT_HIGHLIGHT; else if (fasticmp(word2, "THIN")) status |= IT_THIN; + else if (fasticmp(word2, "THIN-HIGHLIGHT")) + status |= IT_THIN|IT_HIGHLIGHT; else if (fasticmp(word2, "PATCH")) status |= IT_PATCH; else if (fasticmp(word2, "PATCH-CENTER")) @@ -1959,27 +1977,6 @@ static void readmenuitem(MYFILE *f, menuitem_t *menuitem) else WARN("unknown style '%s'", word2); } - else if (fastncmp(word, "TEXT", 4)) - { - UINT16 flags = IT_STRING; - if (fastcmp(word+4, "HEADER")) - flags = IT_HEADERTEXT|IT_HIGHLIGHT; - else if (fastcmp(word+4, "WHITE")) - flags |= IT_HIGHLIGHT; - else if (word[4]) - { - WARN("unknown word '%s'", word); - continue; - } - - if (status & IT_DISPLAY) - { - WARN0("text already set!"); - continue; - } - status |= flags; - menuitem->text = Z_StrDup(word2); - } else if (fastncmp(word, "CVAR", 4)) { UINT16 flags = IT_INTERACT; diff --git a/src/m_menu.c b/src/m_menu.c index fd6d21d1c..555c35180 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -2057,11 +2057,156 @@ void M_DrawPauseMenu(void) M_DrawGenericMenu(); } -static INT16 M_DrawMenuItem(menuitem_t *item, INT16 x, INT16 y, INT32 vflags, boolean selected) +static void M_DrawRightString(menuitem_t *item, INT16 x, INT16 y, INT32 vflags, boolean selected) { INT16 w; + if (item->cvar) + { + consvar_t *cv = item->cvar; + if (!cv->PossibleValue) // string cvar? + { + if (currentMenu->scrollheight && y + 12 > currentMenu->y + currentMenu->scrollheight) + return; + + boolean side = cv == &cv_dummyname || cv == &cv_playername[0]; + INT32 xofs = side ? 32 : 0; + INT32 yofs = side ? -8 : 4; + w = M_StringCvarLength(cv); + + M_DrawTextBox(x + xofs, y + yofs, w, 1); + V_DrawString(x + xofs + 8, y + yofs + 8, vflags|V_ALLOWLOWERCASE, cv->string); + if (selected && skullAnimCounter < 4) // blink cursor + V_DrawCharacter(x + xofs + 8 + V_StringWidth(cv->string, vflags|V_ALLOWLOWERCASE), y + yofs + 8, + '_' | (vflags & ~(V_FLIP|V_PARAMMASK)), false); + + if (!side) + y += 16; + } + else if (item->status & IT_SLIDER) + { + M_DrawSlider(x, y, cv, selected); + } + else + { + const char *str = cv->string; + INT32 soffset = 0; + INT32 strvf = vflags; + boolean warning = (cv->flags & CV_CHEAT) && !CV_IsSetToDefault(cv); + + // special cvar value offsets for time attack! + // i don't feel like adding an extra flag for this... + if (y < 78) for (w = 0; w < NUMMENULEVELS; w++) + { + if (menustack[w] == MN_SP_TIMEATTACK) + { + soffset = 40; + break; + } + } + + if (cv == &cv_chooseskin) + str = skins[cv_chooseskin.value].realname; + else if (cv == &cv_dummyfollower) + str = cv_dummyfollower.value == -1 ? "None" : followers[cv_dummyfollower.value].name; + else if (cv == &cv_dummystaff && cv_dummystaff.value) + str = dummystaffname; + else if (cv == &cv_dummycolor) + str = skincolors[cv_dummycolor.value].name; + else if (cv == &cv_dummyserverpage) + str = va("%d of %d", cv->value + 1, dummyserverpage_cons_t[1].value + 1); + else if (cv == &cv_soundtest && cv_soundtest.value) + V_DrawRightAlignedString(BASEVIDWIDTH - x - soffset, y + 8, strvf|highlightflags, S_sfx[cv_soundtest.value].name); + else if (cv == &cv_gamesounds) + { + str = sound_disabled ? "Off" : "On"; + warning = sound_disabled; + } + else if (cv == &cv_gamedigimusic) + { + str = digital_disabled ? "Off" : "On"; + warning = digital_disabled; + } + else if (cv == &cons_menuhighlight) + { + INT16 hx = x - 2; + static const char *hstr[5] = { + "(", "Good highlight", ",", " Warning highlight", ")" + }; + for (w = 0; w < 5; w++) + { + V_DrawString(hx, y + 10, (w == 1 ? recommendedflags : w == 3 ? warningflags : highlightflags)|strvf, hstr[w]); + hx += V_StringWidth(hstr[w], strvf); + } + } + else if (cv == &cv_dummymultiplayer) + return; + + if (menustack[0] == MN_MP_PLAYERSETUP) + strvf |= V_ALLOWLOWERCASE; + + w = V_StringWidth(str, strvf); + V_DrawString(BASEVIDWIDTH - x - soffset - w, y, (warning ? warningflags : highlightflags)|strvf, str); + + if (selected) + { + strvf &= ~(V_FLIP|V_PARAMMASK); + V_DrawCharacter(BASEVIDWIDTH - x - soffset - 10 - w - (skullAnimCounter/5), y, + '\x1C' | highlightflags | strvf, false); // left arrow + V_DrawCharacter(BASEVIDWIDTH - x - soffset + 2 + (skullAnimCounter/5), y, + '\x1D' | highlightflags | strvf, false); // right arrow + } + } + } + else if (item->routine) + { + char tmp[32*MAXINPUTMAPPING]; // should be enough :^) + INT32 key; + if (item->routine != MR_ChangeControl) + return; + + tmp[0] ='\0'; + for (w = 0; w < MAXINPUTMAPPING; w++) + { + key = setupcontrols[item->argument][w]; + if (key != KEY_NULL) + { + if (tmp[0] != '\0') + strcat(tmp, ", "); + strcat(tmp, G_KeynumToString(key)); + } + } + if (tmp[0] == '\0') + strcpy(tmp, "---"); + + w = V_StringWidth(tmp, vflags); + (w > BASEVIDWIDTH/2 - 4 ? V_DrawRightAlignedThinString : V_DrawRightAlignedString) + (BASEVIDWIDTH-currentMenu->x, y, vflags|highlightflags, tmp); + } + else + { + if (item->submenu == MN_OP_VIDEOMODE) // show current resolution + { + V_DrawRightAlignedString(BASEVIDWIDTH - x, y, + (SCR_IsAspectCorrect(vid.width, vid.height) ? recommendedflags : highlightflags)|vflags, + va("%dx%d", vid.width, vid.height)); + } + else if (item->submenu == MN_OP_JOYSTICKSET) // gamepad select + { + INT32 stick = cv_usejoystick[setupcontrolplayer-1].value; + const char *name = stick == 0 ? "None" : I_GetJoyName(stick); + if (!name) name = "?"; + w = V_StringWidth(name, vflags); + (w > BASEVIDWIDTH/2 - 4 ? V_DrawRightAlignedThinString : V_DrawRightAlignedString) + (BASEVIDWIDTH - x, y, vflags|highlightflags, name); + } + else if (item->patch) + V_DrawRightAlignedString(BASEVIDWIDTH - x, y, (selected || item->status & IT_HIGHLIGHT ? highlightflags : 0)|vflags, item->patch); + } +} + +static INT16 M_DrawMenuItem(menuitem_t *item, INT16 x, INT16 y, INT32 vflags, boolean selected) +{ const char *string = item->text ? item->text : ""; - INT32 highlight = selected || item->status & IT_HIGHLIGHT ? highlightflags : 0; fixed_t scale = item->status & IT_SMALL ? FRACUNIT/2 : FRACUNIT; int font = HU_FONT; INT32 (*widthfunc)(const char *string, INT32 option) = V_StringWidth; @@ -2074,11 +2219,11 @@ static INT16 M_DrawMenuItem(menuitem_t *item, INT16 x, INT16 y, INT32 vflags, bo else if (item->status & IT_GRAYEDOUT) vflags |= V_TRANSLUCENT; - switch (item->status & IT_DISPLAY) + // draw a patch instead of a string? + if (item->status & IT_PATCH) { - case IT_PATCH: if (!item->patch) - break; + return 0; patch_t *p = W_CachePatchName(item->patch, PU_CACHE); UINT8 *cmap = NULL; @@ -2089,176 +2234,26 @@ static INT16 M_DrawMenuItem(menuitem_t *item, INT16 x, INT16 y, INT32 vflags, bo cmap = V_GetStringColormap(highlightflags); V_DrawFixedPatch(x<status & IT_THIN) - { - font = TINY_FONT; - vflags |= V_6WIDTHSPACE; - widthfunc = V_ThinStringWidth; - } - - if (item->status & IT_CENTER) - x -= widthfunc(string, vflags)/2; - - V_DrawStringScaled(x<status & (IT_SECRET|IT_GRAYEDOUT)) - break; - - // draw the right-side string - if (item->cvar) - { - consvar_t *cv = item->cvar; - if (!cv->PossibleValue) // string cvar? - { - if (currentMenu->scrollheight && y + 12 > currentMenu->y + currentMenu->scrollheight) - break; - - boolean side = cv == &cv_dummyname || cv == &cv_playername[0]; - INT32 xofs = side ? 32 : 0; - INT32 yofs = side ? -8 : 4; - w = M_StringCvarLength(cv); - - M_DrawTextBox(x + xofs, y + yofs, w, 1); - V_DrawString(x + xofs + 8, y + yofs + 8, vflags|V_ALLOWLOWERCASE, cv->string); - if (selected && skullAnimCounter < 4) // blink cursor - V_DrawCharacter(x + xofs + 8 + V_StringWidth(cv->string, vflags|V_ALLOWLOWERCASE), y + yofs + 8, - '_' | (vflags & ~(V_FLIP|V_PARAMMASK)), false); - - if (!side) - y += 16; - } - else if (item->status & IT_SLIDER) - { - M_DrawSlider(x, y, cv, selected); - } - else - { - const char *str = cv->string; - INT32 soffset = 0; - INT32 strvf = vflags; - boolean warning = (cv->flags & CV_CHEAT) && !CV_IsSetToDefault(cv); - - // special cvar value offsets for time attack! - // i don't feel like adding an extra flag for this... - if (y < 78) for (w = 0; w < NUMMENULEVELS; w++) - { - if (menustack[w] == MN_SP_TIMEATTACK) - { - soffset = 40; - break; - } - } - - if (cv == &cv_chooseskin) - str = skins[cv_chooseskin.value].realname; - else if (cv == &cv_dummyfollower) - str = cv_dummyfollower.value == -1 ? "None" : followers[cv_dummyfollower.value].name; - else if (cv == &cv_dummystaff && cv_dummystaff.value) - str = dummystaffname; - else if (cv == &cv_dummycolor) - str = skincolors[cv_dummycolor.value].name; - else if (cv == &cv_dummyserverpage) - str = va("%d of %d", cv->value + 1, dummyserverpage_cons_t[1].value + 1); - else if (cv == &cv_soundtest && cv_soundtest.value) - V_DrawRightAlignedString(BASEVIDWIDTH - x - soffset, y + 8, strvf|highlightflags, S_sfx[cv_soundtest.value].name); - else if (cv == &cv_gamesounds) - { - str = sound_disabled ? "Off" : "On"; - warning = sound_disabled; - } - else if (cv == &cv_gamedigimusic) - { - str = digital_disabled ? "Off" : "On"; - warning = digital_disabled; - } - else if (cv == &cons_menuhighlight) - { - INT16 hx = x - 2; - static const char *hstr[5] = { - "(", "Good highlight", ",", " Warning highlight", ")" - }; - for (w = 0; w < 5; w++) - { - V_DrawString(hx, y + 10, (w == 1 ? recommendedflags : w == 3 ? warningflags : highlightflags)|strvf, hstr[w]); - hx += V_StringWidth(hstr[w], strvf); - } - } - else if (cv == &cv_dummymultiplayer) - break; - - if (menustack[0] == MN_MP_PLAYERSETUP) - strvf |= V_ALLOWLOWERCASE; - - w = V_StringWidth(str, strvf); - V_DrawString(BASEVIDWIDTH - x - soffset - w, y, (warning ? warningflags : highlightflags)|strvf, str); - - if (selected) - { - strvf &= ~(V_FLIP|V_PARAMMASK); - V_DrawCharacter(BASEVIDWIDTH - x - soffset - 10 - w - (skullAnimCounter/5), y, - '\x1C' | highlightflags | strvf, false); // left arrow - V_DrawCharacter(BASEVIDWIDTH - x - soffset + 2 + (skullAnimCounter/5), y, - '\x1D' | highlightflags | strvf, false); // right arrow - } - } - break; - } - else if (item->routine) - { - char tmp[32*MAXINPUTMAPPING]; // should be enough :^) - INT32 key; - if (item->routine != MR_ChangeControl) - break; - - tmp[0] ='\0'; - for (w = 0; w < MAXINPUTMAPPING; w++) - { - key = setupcontrols[item->argument][w]; - if (key != KEY_NULL) - { - if (tmp[0] != '\0') - strcat(tmp, ", "); - strcat(tmp, G_KeynumToString(key)); - } - } - if (tmp[0] == '\0') - strcpy(tmp, "---"); - - w = V_StringWidth(tmp, vflags); - (w > BASEVIDWIDTH/2 - 4 ? V_DrawRightAlignedThinString : V_DrawRightAlignedString) - (BASEVIDWIDTH-currentMenu->x, y, vflags|highlightflags, tmp); - break; - } - else - { - if (item->submenu == MN_OP_VIDEOMODE) // show current resolution - { - V_DrawRightAlignedString(BASEVIDWIDTH - x, y, - (SCR_IsAspectCorrect(vid.width, vid.height) ? recommendedflags : highlightflags)|vflags, - va("%dx%d", vid.width, vid.height)); - } - else if (item->submenu == MN_OP_JOYSTICKSET) // gamepad select - { - INT32 stick = cv_usejoystick[setupcontrolplayer-1].value; - const char *name = stick == 0 ? "None" : I_GetJoyName(stick); - if (!name) name = "?"; - w = V_StringWidth(name, vflags); - (w > BASEVIDWIDTH/2 - 4 ? V_DrawRightAlignedThinString : V_DrawRightAlignedString) - (BASEVIDWIDTH - x, y, vflags|highlightflags, name); - } - else if (item->patch) - V_DrawRightAlignedString(BASEVIDWIDTH - x, y, (highlight ? highlightflags : 0)|vflags, item->patch); - } - break; - case IT_HEADERTEXT: // draws 16 pixels to the left, in yellow text - V_DrawString(x - 16, y, vflags|highlight, string); - break; - default: - break; + return SHORT(p->width); } + if (item->status & IT_THIN) + { + font = TINY_FONT; + vflags |= V_6WIDTHSPACE; // TODO: make this a style? + widthfunc = V_ThinStringWidth; + } + + if (item->status & IT_CENTER) + x -= widthfunc(string, vflags)/2; + if (item->status & IT_HEADER) + x -= 16; + + V_DrawStringScaled(x<status & IT_HIGHLIGHT ? highlightflags : 0)|vflags, font, string); + + if (!(item->status & (IT_SECRET|IT_GRAYEDOUT))) + M_DrawRightString(item, x, y, vflags, selected); + return widthfunc(string, vflags); } diff --git a/src/m_menu.h b/src/m_menu.h index 3b8a0ae38..7c6c9922c 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -170,15 +170,13 @@ typedef enum IT_TEMPORARY = 1<<8, // with IT_OFS*, offset applies only to this item IT_OVERLAY = 1<<9, // item is drawn at absolute coordinates, without scrolling - IT_CENTER = 1<<10, // center the text/patch - IT_SMALL = 1<<11, // draw at half scale - IT_THIN = 1<<12, // thin font - IT_HIGHLIGHT = 1<<13, // add highlightflags to text/patch - - IT_PATCH = 1<<14, // display a patch - IT_STRING = 2<<14, // display a string - IT_HEADERTEXT = 3<<14, // whitestring with an offset - IT_DISPLAY = 3<<14, + IT_PATCH = 1<<10, // display a patch instead of text + IT_CENTER = 1<<11, // center the text/patch + IT_SMALL = 1<<12, // draw at half scale + IT_THIN = 1<<13, // thin font + IT_HIGHLIGHT = 1<<14, // add highlightflags to text/patch + IT_HEADER = 1<<15, // draw with an offset to the left + IT_STYLE = IT_PATCH|IT_CENTER|IT_SMALL|IT_THIN|IT_HIGHLIGHT|IT_HEADER, } menuitemflags_t; #define MAXSTRINGLENGTH 32