From 56edab24809ffde0c362f148da35ff317f6c6650 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Sun, 8 Jun 2025 16:59:56 +0200 Subject: [PATCH] Remove a TON of special-case menu code You can now combine submenu/cvar/call to allow for more complex behavior, without the need for keyhandlers. All those dummy menuitems relying on keyhandlers now use cvars, like everything else does. Yes, several things are still hardcoded, but player setup no longer needs its own miniature menu system :^) --- src/command.c | 71 +---- src/deh_soc.c | 56 +--- src/deh_tables.c | 8 +- src/g_game.c | 6 +- src/m_menu.c | 760 +++++++++++++---------------------------------- src/m_menu.h | 35 +-- 6 files changed, 255 insertions(+), 681 deletions(-) diff --git a/src/command.c b/src/command.c index b21e76ba8..f607398dc 100644 --- a/src/command.c +++ b/src/command.c @@ -2108,19 +2108,28 @@ void CV_AddValue(consvar_t *var, INT32 increment) if (!increment) return; - if (var == &cv_forceskin) // Special handling. + if (var == &cv_forceskin || var == &cv_chooseskin) // Special handling. { INT32 oldvalue = var->value; + INT32 min = var == &cv_forceskin ? -1 : 0; newvalue = oldvalue; do { newvalue += increment; - if (newvalue < -1) - newvalue = (numskins - 1); + if (newvalue < min) + newvalue = numskins-1; else if (newvalue >= numskins) - newvalue = -1; - } while ((oldvalue != newvalue) - && !(R_SkinUsable(-1, newvalue))); + newvalue = min; + } while (oldvalue != newvalue && !R_SkinUsable(-1, newvalue)); + } + else if (var == &cv_playercolor[0] || var == &cv_playercolor[1] || var == &cv_playercolor[2] || var == &cv_playercolor[3] || var == &cv_dummycolor) + { + // Special case for the playercolor variable, used only directly from the menu + newvalue = var->value; + if (increment > 0) // Going up! + newvalue = M_GetColorAfter(newvalue); + else if (increment < 0) // Going down! + newvalue = M_GetColorBefore(newvalue); } else newvalue = var->value + increment; @@ -2184,56 +2193,6 @@ void CV_AddValue(consvar_t *var, INT32 increment) if (var->PossibleValue[max].value == var->value) currentindice = max; - // The following options will NOT handle netsyncing. - if (var == &cv_chooseskin) - { - // Special case for the chooseskin variable, used only directly from the menu - newvalue = var->value - 1; - do - { - if (increment > 0) // Going up! - { - newvalue++; - if (newvalue == MAXSKINS) - newvalue = 0; - } - else if (increment < 0) // Going down! - { - newvalue--; - if (newvalue == -1) - newvalue = MAXSKINS-1; - } - } while (var->PossibleValue[newvalue].strvalue == NULL); - - var->value = newvalue + 1; - var->string = var->PossibleValue[newvalue].strvalue; - var->func(); - return; - } - else if (var == &cv_playercolor[0] || var == &cv_playercolor[1] || var == &cv_playercolor[2] || var == &cv_playercolor[3]) - { - // Special case for the playercolor variable, used only directly from the menu - if (increment > 0) // Going up! - { - newvalue = var->value + 1; - if (newvalue > numskincolors-1) - newvalue = 1; - var->value = newvalue; - var->string = var->PossibleValue[var->value].strvalue; - var->func(); - return; - } - else if (increment < 0) // Going down! - { - newvalue = var->value - 1; - if (newvalue < 1) - newvalue = numskincolors-1; - var->value = newvalue; - var->string = var->PossibleValue[var->value].strvalue; - var->func(); - return; - } - } if ((var == &cv_kartspeed || var == &cv_kartbattlespeed) && !M_SecretUnlocked(SECRET_HARDSPEED)) { max = (M_SecretUnlocked(SECRET_HARDSPEED) ? 4 : 3); diff --git a/src/deh_soc.c b/src/deh_soc.c index 638757495..a337f16ff 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -1853,6 +1853,12 @@ static struct { const char *name; consvar_t *var; } HIDDENVARS[] = { { "DUMMYATTACKINGCHAINING", &cv_dummyattackingchaining }, { "DUMMYATTACKINGSLIPDASH", &cv_dummyattackingslipdash }, { "DUMMYATTACKINGPURPLEDRIFT", &cv_dummyattackingpurpledrift }, + { "DUMMYSTAFF", &cv_dummystaff }, + { "DUMMYMULTIPLAYER", &cv_dummymultiplayer }, + { "DUMMYIP", &cv_dummyip }, + { "DUMMYNAME", &cv_dummyname }, + { "DUMMYFOLLOWER", &cv_dummyfollower }, + { "DUMMYCOLOR", &cv_dummycolor }, { NULL, NULL } }; @@ -1866,8 +1872,6 @@ static void readmenuitem(MYFILE *f, menuitem_t *menuitem) char *tmp; UINT16 status = 0; - boolean actionset = false; - boolean textset = false; // taking quite possibly the only opportunity i'll ever get // to avoid three tabs of indentation... @@ -1932,12 +1936,11 @@ static void readmenuitem(MYFILE *f, menuitem_t *menuitem) continue; } - if (textset) + if (status & IT_DISPLAY) { WARN0("text already set!"); continue; } - textset = true; status |= flags; menuitem->text = Z_StrDup(word2); } @@ -1956,11 +1959,6 @@ static void readmenuitem(MYFILE *f, menuitem_t *menuitem) continue; } - if (actionset) - { - WARN0("action already set!"); - continue; - } consvar_t *cvar = CV_FindVar(word2); if (!cvar) for (size_t i = 0; HIDDENVARS[i].name; i++) @@ -1974,78 +1972,50 @@ static void readmenuitem(MYFILE *f, menuitem_t *menuitem) WARN("unable to find cvar '%s'", word2); continue; } - actionset = true; status |= flags; - menuitem->itemaction.cvar = cvar; + menuitem->cvar = cvar; } else if (fastcmp(word, "SUBMENU")) { - if (actionset) - { - WARN0("action already set!"); - continue; - } menutype_t mn = get_menutype(word2); if (mn == MAXMENUTYPES) { WARN("unknown menu '%s'", word2); continue; } - actionset = true; status |= IT_SUBMENU; - menuitem->itemaction.submenu = mn; + menuitem->submenu = mn; } - else if (fastncmp(word, "CALL", 4) || fastcmp(word, "ARROWS")) + else if (fastcmp(word, "CALL") || fastcmp(word, "ARROWS")) { UINT16 flags; if (word[0] == 'C') - { flags = IT_CALL; - if (fastcmp(word+4, "NOTMODIFIED")) - flags |= IT_CALL_NOTMODIFIED; - else if (word[4]) - { - WARN("unknown word '%s'", word); - continue; - } - } else if (word[0] == 'A') flags = IT_ARROWS; else I_Error("bruh"); // i should probably just make "CALL" the stem for all of these - if (actionset) - { - WARN0("action already set!"); - continue; - } menufunc_f *routine = get_menuroutine(word2); if (!routine) { WARN("unknown call routine '%s'", word2); continue; } - actionset = true; status |= flags; - menuitem->itemaction.routine = routine; + menuitem->routine = routine; } else if (fastcmp(word, "DUMMY")) { - if (actionset) - { - WARN0("action already set!"); - continue; - } - actionset = true; status |= IT_DUMMY; - menuitem->itemaction.routine = NULL; + menuitem->routine = NULL; } else WARN("unknown word '%s'", word); } while (!myfeof(f)); // finish when the line is empty - if (textset || actionset) + if (status) menuitem->status = status; Z_Free(s); } diff --git a/src/deh_tables.c b/src/deh_tables.c index b42ad85fe..a33552a27 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -692,9 +692,8 @@ struct menu_routine_s const MENU_ROUTINES[] = { { "SETGUESTREPLAY", &MR_SetGuestReplay }, { "REPLAYTIMEATTACK", &MR_ReplayTimeAttack }, { "TIMEATTACKPRESET", &MR_TimeAttackPreset }, - { "HANDLESTAFFREPLAY", &MR_HandleStaffReplay }, - { "HANDLEMPMAINMENU", &MR_HandleMPMainMenu }, - { "HANDLESETUPMULTIPLAYER", &MR_HandleSetupMultiPlayer }, + { "REPLAYSTAFF", &MR_ReplayStaff }, + { "CONNECTIP", &MR_ConnectIP }, { "QUITMULTIPLAYERMENU", &MR_QuitMultiPlayerMenu }, { "STARTSERVERMENU", &MR_StartServerMenu }, { "STARTSERVER", &MR_StartServer }, @@ -710,7 +709,7 @@ struct menu_routine_s const MENU_ROUTINES[] = { { "OPENGLOPTIONSMENU", &MR_OpenGLOptionsMenu }, #endif { "HANDLEVIDEOMODE", &MR_HandleVideoMode }, - { "HANDLESOUNDTEST", &MR_HandleSoundTest }, + { "PLAYSOUND", &MR_PlaySound }, { "MUSICTEST", &MR_MusicTest }, { "QUITMUSICTEST", &MR_QuitMusicTest }, { "SCREENSHOTOPTIONS", &MR_ScreenshotOptions }, @@ -765,7 +764,6 @@ struct menu_drawer_s const MENU_DRAWERS[] = { { "DRAWTIMEATTACKMENU", &M_DrawTimeAttackMenu }, { "DRAWMPMAINMENU", &M_DrawMPMainMenu }, { "DRAWSETUPMULTIPLAYERMENU", &M_DrawSetupMultiPlayerMenu }, - { "DRAWSERVERMENU", &M_DrawServerMenu }, { "DRAWVIDEOMENU", &M_DrawVideoMenu }, { "DRAWVIDEOMODE", &M_DrawVideoMode }, { "DRAWSKYROOM", &M_DrawSkyRoom }, diff --git a/src/g_game.c b/src/g_game.c index c033f6b71..547d3a1e5 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -592,14 +592,14 @@ static void G_UpdateRecordReplays(void) parts = M_PathParts(gpath); M_MkdirEachUntil(gpath, parts - 4, parts - 1, 0755); - snprintf(lastdemo, 255, "%s-%s-%s-last.lmp", gpath, cv_chooseskin.string, gamemode); + snprintf(lastdemo, 255, "%s-%s-%s-last.lmp", gpath, skins[cv_chooseskin.value].name, gamemode); if (FIL_FileExists(lastdemo)) { UINT8 *buf; size_t len = FIL_ReadFile(lastdemo, &buf); - snprintf(bestdemo, 255, "%s-%s-%s-time-best.lmp", gpath, cv_chooseskin.string, gamemode); + snprintf(bestdemo, 255, "%s-%s-%s-time-best.lmp", gpath, skins[cv_chooseskin.value].name, gamemode); if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & 1) { // Better time, save this demo. if (FIL_FileExists(bestdemo)) @@ -610,7 +610,7 @@ static void G_UpdateRecordReplays(void) if (modeattacking == ATTACKING_TIME) { - snprintf(bestdemo, 255, "%s-%s-%s-lap-best.lmp", gpath, cv_chooseskin.string, gamemode); + snprintf(bestdemo, 255, "%s-%s-%s-lap-best.lmp", gpath, skins[cv_chooseskin.value].name, gamemode); if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & (1<<1)) { // Better lap time, save this demo. if (FIL_FileExists(bestdemo)) diff --git a/src/m_menu.c b/src/m_menu.c index f8409e25a..b7976ddab 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -105,6 +105,7 @@ int snprintf(char *str, size_t n, const char *fmt, ...); #define LINEHEIGHT 8 #define SLIDER_RANGE 10 #define SLIDER_WIDTH (8*SLIDER_RANGE+6) +#define MAXIPADDRESSLEN 28 typedef enum { @@ -262,8 +263,8 @@ static INT16 M_GetMenuIndex(menutype_t type, const char *name) // an array of macros for getting/setting menuitem properties #define M_IsItemOn(t, n) (itemOn == M_GetMenuIndex(t, n)) #define M_SetItemOn(t, n) (itemOn = M_GetMenuIndex(t, n)) -#define M_SetItemRoutine(t, n, v) (M_GetMenuItem(t, n)->itemaction.routine = v) -#define M_SetItemCvar(t, n, v) (M_GetMenuItem(t, n)->itemaction.cvar = v) +#define M_SetItemRoutine(t, n, v) (M_GetMenuItem(t, n)->routine = v) +#define M_SetItemCvar(t, n, v) (M_GetMenuItem(t, n)->cvar = v) #define M_SetItemArgument(t, n, v) (M_GetMenuItem(t, n)->argument = v) #define M_SetItemX(t, n, v) (M_GetMenuItem(t, n)->x = v) #define M_SetItemY(t, n, v) (M_GetMenuItem(t, n)->y = v) @@ -310,8 +311,8 @@ consvar_t cv_nextmap = CVAR_INIT ("nextmap", "1", CV_HIDEN|CV_CALL|CV_NOINIT, ma static INT16 lastnextmap = 1; -static CV_PossibleValue_t skins_cons_t[MAXSKINS+1] = {{1, DEFAULTSKIN}}; -consvar_t cv_chooseskin = CVAR_INIT ("chooseskin", DEFAULTSKIN, CV_HIDEN|CV_CALL|CV_NOINIT, skins_cons_t, Nextmap_OnChange); +static CV_PossibleValue_t skins_cons_t[] = {{0, "MIN"}, {MAXSKINS, "MAX"}, {0, NULL}}; +consvar_t cv_chooseskin = CVAR_INIT ("chooseskin", "0", CV_HIDEN|CV_CALL|CV_NOINIT, skins_cons_t, Nextmap_OnChange); // This gametype list is integral for many different reasons. // When you add gametypes here, don't forget to update them in dehacked.c and doomstat.h! @@ -362,7 +363,7 @@ consvar_t cv_dummymenuplayer = CVAR_INIT ("dummymenuplayer", "P1", CV_HIDEN|CV_C consvar_t cv_dummyteam = CVAR_INIT ("dummyteam", "Spectator", CV_HIDEN, dummyteam_cons_t, NULL); consvar_t cv_dummyspectate = CVAR_INIT ("dummyspectate", "Spectator", CV_HIDEN, dummyspectate_cons_t, NULL); consvar_t cv_dummyscramble = CVAR_INIT ("dummyscramble", "Random", CV_HIDEN, dummyscramble_cons_t, NULL); -static consvar_t cv_dummystaff = CVAR_INIT ("dummystaff", "0", CV_HIDEN|CV_CALL, dummystaff_cons_t, Dummystaff_OnChange); +consvar_t cv_dummystaff = CVAR_INIT ("dummystaff", "0", CV_HIDEN|CV_CALL, dummystaff_cons_t, Dummystaff_OnChange); consvar_t cv_dummyattackingrings = CVAR_INIT ("dummyattackingrings", "Off", CV_HIDEN|CV_CALL|CV_NOINIT, CV_OnOff, Nextmap_OnChange); consvar_t cv_dummyattackingstacking = CVAR_INIT ("dummyattackingstacking", "Off", CV_HIDEN|CV_CALL|CV_NOINIT, CV_OnOff, Nextmap_OnChange); @@ -377,6 +378,16 @@ consvar_t cv_dummygpdifficulty = CVAR_INIT ("dummygpdifficulty", "Normal", CV_HI consvar_t cv_dummygpencore = CVAR_INIT ("dummygpencore", "Off", CV_HIDEN, CV_OnOff, NULL); consvar_t cv_dummygpcup = CVAR_INIT ("dummygpcup", "TEMP", CV_HIDEN, dummygpcup_cons_t, NULL); +static CV_PossibleValue_t dummymultiplayer_cons_t[] = {{0, "MIN"}, {3, "MAX"}, {0, NULL}}; +static CV_PossibleValue_t dummyfollower_cons_t[] = {{-1, "MIN"}, {MAXFOLLOWERS, "MAX"}, {0, NULL}}; +static CV_PossibleValue_t dummycolor_cons_t[] = {{0, "MIN"}, {MAXSKINCOLORS, "MAX"}, {0, NULL}}; + +consvar_t cv_dummymultiplayer = CVAR_INIT ("dummymultiplayer", "0", CV_HIDEN, dummymultiplayer_cons_t, NULL); +consvar_t cv_dummyip = CVAR_INIT ("dummyip", "", CV_HIDEN, NULL, NULL); +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); + consvar_t cv_menucaps = CVAR_INIT ("menucaps", "Off", CV_SAVE, CV_OnOff, NULL); static tic_t playback_last_menu_interaction_leveltime = 0; @@ -396,7 +407,8 @@ static INT32 highlightflags, recommendedflags, warningflags; inline static void M_GetGametypeColor(void) { - INT16 gt; + INT16 gt, i; + boolean usenewgametype = false; warningflags = V_REDMAP; recommendedflags = V_GREENMAP; @@ -427,7 +439,14 @@ inline static void M_GetGametypeColor(void) return; } - if (currentMenu && currentMenu->drawroutine == M_DrawServerMenu) + if (currentMenu) for (i = 0; i < currentMenu->numitems; i++) + if (currentMenu->menuitems[i].cvar == &cv_newgametype) + { + usenewgametype = true; + break; + } + + if (usenewgametype) gt = cv_newgametype.value; else if (!Playing()) { @@ -588,21 +607,21 @@ void Nextmap_OnChange(void) boolean showreplay = false, showguest = false; // best time - visible = FIL_FileExists(va("%s-%s-%s-time-best.lmp", gpath, cv_chooseskin.string, gamemode)); + visible = FIL_FileExists(va("%s-%s-%s-time-best.lmp", gpath, skins[cv_chooseskin.value].name, gamemode)); M_SetItemVisible(MN_SP_REPLAY, "REPLAYTIME", visible); M_SetItemVisible(MN_SP_GUESTREPLAY, "SAVETIME", visible); if (visible) showreplay = showguest = true; // best lap - visible = levellistmode != LLM_ITEMBREAKER && FIL_FileExists(va("%s-%s-%s-lap-best.lmp", gpath, cv_chooseskin.string, gamemode)); + visible = levellistmode != LLM_ITEMBREAKER && FIL_FileExists(va("%s-%s-%s-lap-best.lmp", gpath, skins[cv_chooseskin.value].name, gamemode)); M_SetItemVisible(MN_SP_REPLAY, "REPLAYLAP", visible); M_SetItemVisible(MN_SP_GUESTREPLAY, "SAVELAP", visible); if (visible) showreplay = showguest = true; // last - visible = FIL_FileExists(va("%s-%s-%s-last.lmp", gpath, cv_chooseskin.string, gamemode)); + visible = FIL_FileExists(va("%s-%s-%s-last.lmp", gpath, skins[cv_chooseskin.value].name, gamemode)); M_SetItemVisible(MN_SP_REPLAY, "REPLAYLAST", visible); M_SetItemVisible(MN_SP_GUESTREPLAY, "SAVELAST", visible); if (visible) @@ -778,16 +797,19 @@ void M_InitMenuPresTables(void) // BASIC MENU HANDLING // ========================================================================= +static UINT8 multi_spr2; +static void M_GetFollowerState(void); + static INT32 M_ChangeCvar(INT32 choice) { - consvar_t *cv = currentMenu->menuitems[itemOn].itemaction.cvar; + consvar_t *cv = currentMenu->menuitems[itemOn].cvar; if (choice == -1) { - if (cv == &cv_playercolor[0]) + if (cv == &cv_playercolor[0] || cv == &cv_playercolor[1] || cv == &cv_playercolor[2] || cv == &cv_playercolor[3] || cv == &cv_dummycolor) { - SINT8 skinno = R_SkinAvailable(cv_chooseskin.string); - if (skinno != -1) + 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; } @@ -816,12 +838,17 @@ static INT32 M_ChangeCvar(INT32 choice) else CV_AddValue(cv,choice); + 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 boolean M_ChangeStringCvar(INT32 choice) { - consvar_t *cv = currentMenu->menuitems[itemOn].itemaction.cvar; + consvar_t *cv = currentMenu->menuitems[itemOn].cvar; char buf[MAXSTRINGLENGTH]; size_t len; @@ -848,10 +875,22 @@ static boolean M_ChangeStringCvar(INT32 choice) } 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; + + if (choice >= KEY_KEYPAD7) + // sir, have you been golfing tonight? + choice = "789-456+1230."[choice - KEY_KEYPAD7]; + } + if (choice >= 32 && choice <= 127) { len = strlen(cv->string); - if (len < MAXSTRINGLENGTH - 1) + if (len < (cv == &cv_dummyip ? MAXIPADDRESSLEN : MAXSTRINGLENGTH) - 1) { S_StartSound(NULL,sfx_menu1); // Tails M_Memcpy(buf, cv->string, len); @@ -946,7 +985,7 @@ 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; // for some casting problem + menufunc_f *routine = NULL; // for some casting problem INT32 deviceplayer = G_GetDevicePlayer(ev->device); if (dedicated || (demo.playback && demo.title) @@ -1200,29 +1239,19 @@ boolean M_Responder(event_t *ev) // BP: one of the more big hack i have never made // G: not so hacky anymore...? - UINT16 itemtype = currentMenu->numitems ? currentMenu->menuitems[itemOn].status & IT_TYPE : 0; - switch (itemtype) + // G: nevermind we have combi menuitems now + UINT16 itemtype = 0; + if (currentMenu->numitems) { - case IT_CVAR: - if ((currentMenu->menuitems[itemOn].status & IT_ACTION) == IT_CV_STRING) - { - if (shiftdown && ch >= 32 && ch <= 127) - ch = shiftxform[ch]; - if (M_ChangeStringCvar(ch)) - return true; - else - routine = NULL; - } - else - routine = M_ChangeCvar; - break; - case IT_CALL: - case IT_ARROWS: - routine = currentMenu->menuitems[itemOn].itemaction.routine; - break; - default: - routine = NULL; - break; + 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; } if (menustack[0] == MN_PLAYBACK && !con_destlines) @@ -1270,20 +1299,20 @@ boolean M_Responder(event_t *ev) return true; case KEY_LEFTARROW: - if (itemtype == IT_ARROWS || itemtype == IT_CVAR) + if (itemtype & (IT_ARROWS|IT_CVAR) && !(itemtype & IT_CV_STRING)) { if (menustack[0] != MN_OP_SOUND || itemOn > 3) S_StartSound(NULL, sfx_menu1); - routine(0); + (itemtype & IT_ARROWS ? routine : M_ChangeCvar)(0); } return true; case KEY_RIGHTARROW: - if (itemtype == IT_ARROWS || itemtype == IT_CVAR) + if (itemtype & (IT_ARROWS|IT_CVAR) && !(itemtype & IT_CV_STRING)) { if (menustack[0] != MN_OP_SOUND || itemOn > 3) S_StartSound(NULL, sfx_menu1); - routine(1); + (itemtype & IT_ARROWS ? routine : M_ChangeCvar)(1); } return true; @@ -1299,24 +1328,24 @@ boolean M_Responder(event_t *ev) playback_enterheld = 3; } - switch (itemtype) + INT32 argument = currentMenu->menuitems[itemOn].argument; + if (currentMenu->menuitems[itemOn].cvar) + argument = currentMenu->menuitems[itemOn].cvar->value; + + if (currentMenu->menuitems[itemOn].submenu) { - case IT_CVAR: - case IT_ARROWS: S_StartSound(NULL, sfx_menu1); - routine(1); // right arrow - break; - case IT_CALL: + M_EnterMenu(currentMenu->menuitems[itemOn].submenu, true, argument); + } + else if (currentMenu->menuitems[itemOn].routine) + { S_StartSound(NULL, sfx_menu1); - routine(currentMenu->menuitems[itemOn].argument); - break; - case IT_SUBMENU: + routine(argument); + } + else if (currentMenu->menuitems[itemOn].cvar && !(itemtype & IT_CV_STRING)) + { S_StartSound(NULL, sfx_menu1); - currentMenu->lastOn = itemOn; - M_EnterMenu(currentMenu->menuitems[itemOn].itemaction.submenu, true, currentMenu->menuitems[itemOn].argument); - break; - default: - break; + M_ChangeCvar(1); // right arrow } return true; @@ -1336,19 +1365,20 @@ boolean M_Responder(event_t *ev) return true; case KEY_BACKSPACE: - if (itemtype == IT_CVAR) + if (itemtype & IT_CVAR) { - consvar_t *cv = currentMenu->menuitems[itemOn].itemaction.cvar; + consvar_t *cv = currentMenu->menuitems[itemOn].cvar; if (cv == &cv_chooseskin || cv == &cv_dummystaff || cv == &cv_nextmap - || cv == &cv_newgametype) + || cv == &cv_newgametype + || cv == &cv_dummymultiplayer) return true; if (menustack[0] != MN_OP_SOUND || itemOn > 3) S_StartSound(NULL, sfx_menu1); - routine(-1); + M_ChangeCvar(-1); return true; } @@ -1721,6 +1751,12 @@ void M_Init(void) CV_RegisterVar(&cv_dummygpencore); CV_RegisterVar(&cv_dummygpcup); + CV_RegisterVar(&cv_dummymultiplayer); + CV_RegisterVar(&cv_dummyip); + CV_RegisterVar(&cv_dummyname); + CV_RegisterVar(&cv_dummyfollower); + CV_RegisterVar(&cv_dummycolor); + 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)"); quitmsg[QUITMSG2] = M_GetText("Hey!\nWhere do ya think you're goin'?\n\n(Press 'Y' to quit)"); @@ -2076,11 +2112,9 @@ static INT16 M_DrawMenuItem(menuitem_t *item, INT16 x, INT16 y, INT32 vflags, bo (BASEVIDWIDTH-currentMenu->x, y, vflags|highlightflags, name); } - switch(item->status & IT_TYPE) + if (item->status & IT_CVAR) { - case IT_CVAR: - { - consvar_t *cv = item->itemaction.cvar; + consvar_t *cv = item->cvar; switch(item->status & IT_ACTION) { case IT_CV_SLIDER: @@ -2090,9 +2124,10 @@ static INT16 M_DrawMenuItem(menuitem_t *item, INT16 x, INT16 y, INT32 vflags, bo if (currentMenu->scrollheight && y + 12 > currentMenu->y + currentMenu->scrollheight) break; - INT32 xofs = vflags & MDF_TIMEATTACK ? 32 : 0; - INT32 yofs = vflags & MDF_TIMEATTACK ? -8 : 4; - w = vflags & MDF_TIMEATTACK ? MAXPLAYERNAME : MAXSTRINGLENGTH; + 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; M_DrawTextBox(x + xofs, y + yofs, w, 1); V_DrawString(x + xofs + 8, y + yofs + 8, vflags|V_ALLOWLOWERCASE, cv->string); @@ -2100,35 +2135,51 @@ static INT16 M_DrawMenuItem(menuitem_t *item, INT16 x, INT16 y, INT32 vflags, bo V_DrawCharacter(x + xofs + 8 + V_StringWidth(cv->string, vflags|V_ALLOWLOWERCASE), y + yofs + 8, '_' | (vflags & ~(V_FLIP|V_PARAMMASK)), false); - if (!(vflags & MDF_TIMEATTACK)) + if (!side) y += 16; break; default: { - const char *str = (cv == &cv_chooseskin ? skins[cv_chooseskin.value-1].realname : cv->string); + const char *str = cv->string; INT32 soffset = vflags & MDF_TIMEATTACK && cv != &cv_nextmap ? 40 : 0; + INT32 strvf = vflags; - w = V_StringWidth(str, vflags); + 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_dummymultiplayer) + break; + + if (menustack[0] == MN_MP_PLAYERSETUP) + strvf |= V_ALLOWLOWERCASE|highlightflags; + + w = V_StringWidth(str, strvf); V_DrawString(BASEVIDWIDTH - x - soffset - w, y, - ((cv->flags & CV_CHEAT) && !CV_IsSetToDefault(cv) ? warningflags : highlightflags)|vflags, str); + ((cv->flags & CV_CHEAT) && !CV_IsSetToDefault(cv) ? warningflags : highlightflags)|strvf, str); if (selected) { + strvf &= ~(V_FLIP|V_PARAMMASK); V_DrawCharacter(BASEVIDWIDTH - x - soffset - 10 - w - (skullAnimCounter/5), y, - '\x1C' | highlightflags | (vflags & ~(V_FLIP|V_PARAMMASK)), false); // left arrow + '\x1C' | highlightflags | strvf, false); // left arrow V_DrawCharacter(BASEVIDWIDTH - x - soffset + 2 + (skullAnimCounter/5), y, - '\x1D' | highlightflags | (vflags & ~(V_FLIP|V_PARAMMASK)), false); // right arrow + '\x1D' | highlightflags | strvf, false); // right arrow } break; } } break; } - case IT_CALL: + else if (item->status & IT_CALL) { char tmp[32*MAXINPUTMAPPING]; // should be enough :^) INT32 key; - if (item->itemaction.routine != MR_ChangeControl) + if (item->routine != MR_ChangeControl) break; tmp[0] ='\0'; @@ -2150,7 +2201,6 @@ static INT16 M_DrawMenuItem(menuitem_t *item, INT16 x, INT16 y, INT32 vflags, bo (BASEVIDWIDTH-currentMenu->x, y, vflags|highlightflags, tmp); break; } - } 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); @@ -2193,10 +2243,15 @@ static void M_DrawBaseMenu(INT32 flags) // draw title (or big pic) M_DrawMenuTitle(); - INT16 w, x = scrollx, y = scrolly, cursorx = 0, cursory = 0; + INT16 i, w, x = scrollx, y = scrolly, cursorx = 0, cursory = 0; boolean clipbot = false, cliptop = false; - for (INT16 i = 0; i < currentMenu->numitems; i++) + // levelselect no longer needs a special drawer! + for (i = 0; i < currentMenu->numitems; i++) + if (currentMenu->menuitems[i].cvar == &cv_nextmap) + M_DrawLevelSelectOnly(menustack[0] == MN_SP_TIMEATTACK, false); + + for (i = 0; i < currentMenu->numitems; i++) { INT32 vflags = flags; @@ -2315,28 +2370,15 @@ static void M_PatchSkinNameTable(void) { INT32 j; - memset(skins_cons_t, 0, sizeof (skins_cons_t)); - - for (j = 0; j < MAXSKINS; j++) - { - if (skins[j].name[0] != '\0') - { - skins_cons_t[j].strvalue = skins[j].name; - skins_cons_t[j].value = j+1; - } - else - { - skins_cons_t[j].strvalue = NULL; - skins_cons_t[j].value = 0; - break; - } - } + skins_cons_t[1].value = numskins-1; + dummyfollower_cons_t[1].value = numfollowers-1; + dummycolor_cons_t[1].value = numskincolors-1; j = R_SkinAvailable(cv_skin[0].string); if (j == -1) j = 0; - CV_SetValue(&cv_chooseskin, j+1); // This causes crash sometimes?! + CV_SetValue(&cv_chooseskin, j); // This causes crash sometimes?! return; } @@ -4409,20 +4451,10 @@ void M_DrawSkyRoom(void) } } -INT32 MR_HandleSoundTest(INT32 choice) +INT32 MR_PlaySound(INT32 arg) { - if (!M_IsItemOn(MN_OP_SOUND, "SOUNDTEST")) - return false; - - switch (choice) - { - case KEY_ENTER: - S_StopSounds(); - S_StartSound(NULL, cv_soundtest.value); - break; - default: - return false; - } + S_StopSounds(); + S_StartSound(NULL, arg); return true; } @@ -5179,7 +5211,7 @@ INT32 MR_StartGrandPrix(INT32 choice) G_DeferedInitNew( false, levelNum + 1, - (UINT8)(cv_chooseskin.value - 1), + (UINT8)(cv_chooseskin.value), (UINT8)(cv_splitplayers.value - 1), false ); @@ -5196,12 +5228,6 @@ void M_DrawTimeAttackMenu(void) INT32 i, x, y; SINT8 preset = G_RecordPresetIndex(); - //S_ChangeMusicInternal("racent", true); // Eww, but needed for when user hits escape during demo playback - - M_DrawMenuTitle(); - if (menustack[0] == MN_SP_TIMEATTACK) - M_DrawLevelSelectOnly(true, false); - // draw menu (everything else goes on top of it) // Sadly we can't just use generic mode menus because we need some extra hacks x = currentMenu->x; @@ -5209,29 +5235,8 @@ void M_DrawTimeAttackMenu(void) // Character face! { - UINT8 *colormap = R_GetTranslationColormap(cv_chooseskin.value-1, cv_playercolor[0].value, GTC_MENUCACHE); - V_DrawMappedPatch(BASEVIDWIDTH-x - SHORT(faceprefix[cv_chooseskin.value-1][FACE_WANTED]->width), y, 0, faceprefix[cv_chooseskin.value-1][FACE_WANTED], colormap); - } - - for (i = 0; i < currentMenu->numitems; ++i) - { - if (currentMenu->menuitems[i].status & IT_HIDDEN) - continue; - - y = currentMenu->y+currentMenu->menuitems[i].y; - - if (¤tMenu->menuitems[i] == M_CheckMenuItem(MN_SP_REPLAY, "REPLAYSTAFF") && cv_dummystaff.value) - { - INT32 strw = V_StringWidth(dummystaffname, V_ALLOWLOWERCASE); - V_DrawString(BASEVIDWIDTH - x - strw, y, highlightflags|V_ALLOWLOWERCASE, dummystaffname); - if (i == itemOn) - { - V_DrawCharacter(BASEVIDWIDTH - x - 10 - strw - (skullAnimCounter/5), y, - '\x1C' | highlightflags, false); // left arrow - V_DrawCharacter(BASEVIDWIDTH - x + 2 + (skullAnimCounter/5), y, - '\x1D' | highlightflags, false); // right arrow - } - } + UINT8 *colormap = R_GetTranslationColormap(cv_chooseskin.value, cv_playercolor[0].value, GTC_MENUCACHE); + 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); @@ -5299,8 +5304,6 @@ void M_DrawTimeAttackMenu(void) // Going to Time Attack menu... INT32 MR_TimeAttack(INT32 arg) { - memset(skins_cons_t, 0, sizeof (skins_cons_t)); - if (arg != -1) { levellistmode = arg ? LLM_ITEMBREAKER : LLM_TIMEATTACK; // Don't be dependent on cv_newgametype @@ -5336,7 +5339,7 @@ INT32 MR_QuitTimeAttackMenu(INT32 choice) (void)choice; // you know what? always putting these in the buffer won't hurt anything. - COM_BufAddText(va("skin \"%s\"\n", cv_chooseskin.string)); + COM_BufAddText(va("skin \"%s\"\n", skins[cv_chooseskin.value].name)); return true; } @@ -5367,37 +5370,20 @@ INT32 MR_ChooseTimeAttack(INT32 choice) else G_RecordDemo(nameofdemo); - G_DeferedInitNew(false, cv_nextmap.value, (UINT8)(cv_chooseskin.value-1), 0, false); + G_DeferedInitNew(false, cv_nextmap.value, (UINT8)(cv_chooseskin.value), 0, false); return true; } -INT32 MR_HandleStaffReplay(INT32 choice) +INT32 MR_ReplayStaff(INT32 choice) { - if (!M_IsItemOn(MN_SP_REPLAY, "REPLAYSTAFF")) + (void)choice; + lumpnum_t l = W_CheckNumForName(va("%sS%02u",G_BuildMapName(cv_nextmap.value),cv_dummystaff.value)); + if (l == LUMPERROR) return false; - lumpnum_t l = W_CheckNumForName(va("%sS%02u",G_BuildMapName(cv_nextmap.value),cv_dummystaff.value)); - - switch (choice) - { - case KEY_RIGHTARROW: - CV_AddValue(&cv_dummystaff, 1); - S_StartSound(NULL, sfx_menu1); - break; - case KEY_LEFTARROW: - CV_AddValue(&cv_dummystaff, -1); - S_StartSound(NULL, sfx_menu1); - break; - case KEY_ENTER: - if (l == LUMPERROR) - break; - M_ClearMenus(true); - demo.loadfiles = false; demo.ignorefiles = true; // Just assume that record attack replays have the files needed - G_DoPlayDemo(va("%sS%02u",G_BuildMapName(cv_nextmap.value),cv_dummystaff.value)); - break; - default: - return false; - } + M_ClearMenus(true); + demo.loadfiles = false; demo.ignorefiles = true; // Just assume that record attack replays have the files needed + G_DoPlayDemo(va("%sS%02u",G_BuildMapName(cv_nextmap.value),cv_dummystaff.value)); return true; } @@ -5450,7 +5436,7 @@ INT32 MR_ReplayTimeAttack(INT32 arg) return true; } // srb2/replay/main/map01-sonic-time-best.lmp - G_DoPlayDemo(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), cv_chooseskin.string, gamemode, which)); + G_DoPlayDemo(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), skins[cv_chooseskin.value].name, gamemode, which)); Z_Free(gamemode); return true; } @@ -5475,7 +5461,7 @@ static void M_OverwriteGuest(const char *which) char *rguest = Z_StrDup(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), gamemode)); UINT8 *buf; size_t len; - len = FIL_ReadFile(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), cv_chooseskin.string, gamemode,which), &buf); + len = FIL_ReadFile(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-%s-%s-%s.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value), skins[cv_chooseskin.value].name, gamemode,which), &buf); if (!len) { return; } @@ -6137,7 +6123,7 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) x = BASEVIDWIDTH/2 - w/2; y = currentMenu->y + 130 + 8 - i; - if (currentMenu->menuitems[itemOn].itemaction.cvar == &cv_nextmap && skullAnimCounter < 4) + if (currentMenu->menuitems[itemOn].cvar == &cv_nextmap && skullAnimCounter < 4) trans = 0; else trans = G_GetGametypeColor(cv_newgametype.value); @@ -6223,12 +6209,6 @@ static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade) #undef horizspac } -void M_DrawServerMenu(void) -{ - M_DrawLevelSelectOnly(false, false); - M_DrawGenericMenu(); -} - INT32 MR_MapChange(INT32 choice) { (void)choice; @@ -6254,9 +6234,6 @@ INT32 MR_StartServerMenu(INT32 choice) // CONNECT VIA IP // ============== -static char setupm_ip[28]; -static UINT8 setupm_pselect = 1; - // Draw the funky Connect IP menu. Tails 11-19-2002 // So much work for such a little thing! void M_DrawMPMainMenu(void) @@ -6278,18 +6255,6 @@ Update the maxplayers label... "(2-4 players)" ); - y += M_GetItemY(MN_MP_MAIN, "CONNECTIP"); - - V_DrawFill(x+5, y+4+5, /*16*8 + 6,*/ BASEVIDWIDTH - 2*(x+5), 8+6, 159); - - // draw name string - V_DrawString(x+8,y+12, V_ALLOWLOWERCASE, setupm_ip); - - // draw text cursor for name - if (M_IsItemOn(MN_MP_MAIN, "CONNECTIP") - && skullAnimCounter < 4) //blink cursor - V_DrawCharacter(x+8+V_StringWidth(setupm_ip, V_ALLOWLOWERCASE),y+12,'_',false); - // character bar, ripped off the color bar :V { #define iconwidth 32 @@ -6318,7 +6283,7 @@ Update the maxplayers label... V_DrawFixedPatch(x< 1) - { - if (--setupm_pselect < 1) - setupm_pselect = cv_splitplayers.value; - S_StartSound(NULL,sfx_menu1); // Tails - } - break; - - case KEY_RIGHTARROW: - if (cv_splitplayers.value > 1) - { - if (++setupm_pselect > cv_splitplayers.value) - setupm_pselect = 1; - S_StartSound(NULL,sfx_menu1); // Tails - } - break; - - case KEY_ENTER: - S_StartSound(NULL,sfx_menu1); // Tails - M_EnterMenu(MN_MP_PLAYERSETUP, true, setupm_pselect - 1); - break; - - default: - return false; - } - return true; + // anything to avoid a keyhandler :^) + dummymultiplayer_cons_t[1].value = cv_splitplayers.value - 1; } // Tails 11-19-2002 -static void M_ConnectIP(INT32 choice) +INT32 MR_ConnectIP(INT32 choice) { (void)choice; - if (*setupm_ip == 0) + if (*cv_dummyip.string == 0) { M_StartMessage("You must specify an IP address.\n", NULL, MM_NOTHING); - return; + return false; } M_ClearMenus(true); - COM_BufAddText(va("connect \"%s\"\n", setupm_ip)); + COM_BufAddText(va("connect \"%s\"\n", cv_dummyip.string)); // A little "please wait" message. M_DrawTextBox(56, BASEVIDHEIGHT/2-12, 24, 2); @@ -6397,70 +6332,9 @@ static void M_ConnectIP(INT32 choice) I_UpdateNoBlit(); if (rendermode == render_soft) I_FinishUpdate(); // page flip or blit buffer -} - -// Tails 11-19-2002 -static INT32 MR_HandleConnectIP(INT32 choice) -{ - size_t l; - - switch (choice) - { - case KEY_ENTER: - S_StartSound(NULL,sfx_menu1); // Tails - currentMenu->lastOn = itemOn; - M_ConnectIP(1); - break; - - case KEY_BACKSPACE: - if ((l = strlen(setupm_ip)) != 0) - { - S_StartSound(NULL,sfx_menu1); // Tails - setupm_ip[l-1] = 0; - } - break; - - case KEY_DEL: - if (setupm_ip[0]) - { - S_StartSound(NULL,sfx_menu1); // Tails - setupm_ip[0] = 0; - } - break; - - default: - l = strlen(setupm_ip); - - // 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; - - if (l >= 28-1) - break; - - if (choice >= KEY_KEYPAD7) - // sir, have you been golfing tonight? - choice = "789-456+1230."[choice - KEY_KEYPAD7]; - - S_StartSound(NULL,sfx_menu1); // Tails - setupm_ip[l] = (char)choice; - setupm_ip[l+1] = 0; - break; - } return true; } -INT32 MR_HandleMPMainMenu(INT32 choice) -{ - if (M_IsItemOn(MN_MP_MAIN, "PLAYERSETUP")) - return MR_SetupMultiHandler(choice); - else if (M_IsItemOn(MN_MP_MAIN, "CONNECTIP")) - return MR_HandleConnectIP(choice); - else - return false; -} - // ======================== // MULTIPLAYER PLAYER SETUP // ======================== @@ -6469,7 +6343,6 @@ INT32 MR_HandleMPMainMenu(INT32 choice) // used for skin display on player setup menu static fixed_t multi_tics; static state_t *multi_state; -static UINT8 multi_spr2; // used for follower display on player setup menu static fixed_t follower_tics; @@ -6478,16 +6351,7 @@ static state_t *follower_state; // this is set before entering the MultiPlayer setup menu, // for either player 1 or 2 -static char setupm_name[MAXPLAYERNAME+1]; -static player_t *setupm_player; -static consvar_t *setupm_cvskin; -static consvar_t *setupm_cvcolor; -static consvar_t *setupm_cvname; -static consvar_t *setupm_cvfollower; -static consvar_t *setupm_cvfollowercolor; -static INT32 setupm_fakeskin; -static menucolor_t *setupm_fakecolor; -static INT32 setupm_fakefollower; // -1 is for none, our followers start at 0 +static UINT8 setupplayer; void M_DrawSetupMultiPlayerMenu(void) { @@ -6504,7 +6368,6 @@ void M_DrawSetupMultiPlayerMenu(void) UINT8 weight; const UINT8 *flashcol = V_GetStringColormap(highlightflags); INT32 statx, staty; - char *fname; INT16 i; mx = menudefs[MN_MP_PLAYERSETUP].x; @@ -6516,59 +6379,6 @@ void M_DrawSetupMultiPlayerMenu(void) // use generic drawer for cursor, items and title M_DrawGenericMenu(); - // draw name string - M_DrawTextBox(mx + 32, my - 8, MAXPLAYERNAME, 1); - V_DrawString(mx + 40, my, V_ALLOWLOWERCASE, setupm_name); - - // draw text cursor for name - if (M_IsItemOn(MN_MP_PLAYERSETUP, "NAME") && skullAnimCounter < 4) // blink cursor - V_DrawCharacter(mx + 40 + V_StringWidth(setupm_name, V_ALLOWLOWERCASE), my, '_',false); - - // draw skin string - st = V_StringWidth(skins[setupm_fakeskin].realname, 0); - V_DrawString(BASEVIDWIDTH - mx - st, my + 16, - (!M_ItemSelectable(M_GetMenuItem(MN_MP_PLAYERSETUP, "SKIN")) ? V_TRANSLUCENT : 0)|highlightflags|V_ALLOWLOWERCASE, - skins[setupm_fakeskin].realname); - if (M_IsItemOn(MN_MP_PLAYERSETUP, "SKIN")) - { - V_DrawCharacter(BASEVIDWIDTH - mx - 10 - st - (skullAnimCounter/5), my + 16, - '\x1C' | highlightflags, false); // left arrow - V_DrawCharacter(BASEVIDWIDTH - mx + 2 + (skullAnimCounter/5), my + 16, - '\x1D' | highlightflags, false); // right arrow - } - - // draw follower string - fname = malloc(SKINNAMESIZE+1); - - if (setupm_fakefollower == -1) - strcpy(fname, "None"); - else - strcpy(fname, followers[setupm_fakefollower].name); - - st = V_StringWidth(fname, 0); - V_DrawString(BASEVIDWIDTH - mx - st, my + 26, - (!M_ItemSelectable(M_GetMenuItem(MN_MP_PLAYERSETUP, "FOLLOWER")) ? V_TRANSLUCENT : 0)|highlightflags|V_ALLOWLOWERCASE, - fname); - if (M_IsItemOn(MN_MP_PLAYERSETUP, "FOLLOWER")) - { - V_DrawCharacter(BASEVIDWIDTH - mx - 10 - st - (skullAnimCounter/5), my + 26, - '\x1C' | highlightflags, false); // left arrow - V_DrawCharacter(BASEVIDWIDTH - mx + 2 + (skullAnimCounter/5), my + 26, - '\x1D' | highlightflags, false); // right arrow - } - - // draw the name of the color you have chosen - // Just so people don't go thinking that "Default" is Green. - st = V_StringWidth(skincolors[setupm_fakecolor->color].name, 0); - V_DrawString(BASEVIDWIDTH - mx - st, my + 152, highlightflags|V_ALLOWLOWERCASE, skincolors[setupm_fakecolor->color].name); // SRB2kart - if (M_IsItemOn(MN_MP_PLAYERSETUP, "COLOR")) - { - V_DrawCharacter(BASEVIDWIDTH - mx - 10 - st - (skullAnimCounter/5), my + 152, - '\x1C' | highlightflags, false); // left arrow - V_DrawCharacter(BASEVIDWIDTH - mx + 2 + (skullAnimCounter/5), my + 152, - '\x1D' | highlightflags, false); // right arrow - } - // SRB2Kart: draw the stat backer // labels V_DrawThinString(statx+16, staty, MENUCAPS|V_6WIDTHSPACE|highlightflags, "Acceleration"); @@ -6583,7 +6393,7 @@ void M_DrawSetupMultiPlayerMenu(void) for (i = 0; i < numskins; i++) // draw the stat dots { - if (i != setupm_fakeskin && R_SkinAvailable(skins[i].name) != -1) + if (i != cv_chooseskin.value && R_SkinAvailable(skins[i].name) != -1) { speed = skins[i].kartspeed; weight = skins[i].kartweight; @@ -6591,8 +6401,8 @@ void M_DrawSetupMultiPlayerMenu(void) } } - speed = skins[setupm_fakeskin].kartspeed; - weight = skins[setupm_fakeskin].kartweight; + speed = skins[cv_chooseskin.value].kartspeed; + weight = skins[cv_chooseskin.value].kartweight; statdot = W_CachePatchName("K_SDOT1", PU_CACHE); if (skullAnimCounter < 4) // SRB2Kart: we draw this dot later so that it's not covered if there's multiple skins with the same stats @@ -6601,8 +6411,7 @@ void M_DrawSetupMultiPlayerMenu(void) V_DrawFixedPatch(((BASEVIDWIDTH - mx - 80) + ((speed-1)*8))<color) - V_DrawFixedPatch(((BASEVIDWIDTH - mx - 80) + ((speed-1)*8))<color, GTC_MENUCACHE)); + V_DrawFixedPatch(((BASEVIDWIDTH - mx - 80) + ((speed-1)*8))<prev; // Last accessed color + menucolor_t *mc, *choosecolor = menucolorhead; // Last accessed color UINT8 h; + while (choosecolor->color != cv_dummycolor.value && choosecolor != menucolortail) + choosecolor = choosecolor->next; + // Draw color in the middle x += numcolors*w; for (h = 0; h < 16; h++) - V_DrawFill(x, my+162+h, charw, 1, skincolors[setupm_fakecolor->color].ramp[h]); + V_DrawFill(x, my+162+h, charw, 1, skincolors[cv_dummycolor.value].ramp[h]); //Draw colors from middle to left + mc = choosecolor->prev; for (i=0; inext; + mc = choosecolor->next; x += numcolors*w + charw; for (i=0; icolor) // inverse should never happen #define iconwidth 32 { const INT32 icons = 4; INT32 k = -icons; - INT16 col = (setupm_fakeskin - icons) % numskins; + INT16 col = (cv_chooseskin.value - icons) % numskins; INT32 x = BASEVIDWIDTH/2 - ((icons+1)*24) - 4; fixed_t scale = FRACUNIT/2; INT32 offx = 8, offy = 8; @@ -6683,7 +6495,7 @@ void M_DrawSetupMultiPlayerMenu(void) offx = 8; offy = 8; } - colmap = R_GetTranslationColormap(col, setupm_fakecolor->color, GTC_MENUCACHE); + colmap = R_GetTranslationColormap(col, cv_dummycolor.value, GTC_MENUCACHE); if (face) V_DrawFixedPatch((x+offx)<numframes) // No frames ?? return; // Can't render! @@ -6728,23 +6540,14 @@ void M_DrawSetupMultiPlayerMenu(void) V_DrawFill(mx + 43 - (charw/2), my+65, charw, 84, 159); // draw player sprite - if (setupm_fakecolor->color) // inverse should never happen - { - UINT8 *colormap = R_GetTranslationColormap(setupm_fakeskin, setupm_fakecolor->color, GTC_MENUCACHE); - - if (skins[setupm_fakeskin].highresscale != FRACUNIT) - { - V_DrawFixedPatch((mx+43)< -1 && setupm_fakefollower < numfollowers) + if (cv_dummyfollower.value > -1) { // animate the follower @@ -6782,10 +6585,9 @@ void M_DrawSetupMultiPlayerMenu(void) flags |= V_FLIP; // This sprite is left/right flipped! // draw follower sprite - if (setupm_fakecolor->color) // inverse should never happen { // Fake the follower's in game appearance by now also applying some of its variables! coolio, eh? - follower_t fl = followers[setupm_fakefollower]; // shortcut for our sanity + follower_t fl = followers[cv_dummyfollower.value]; // shortcut for our sanity tic_t bobspeed = fl.bobspeed; if (fl.mode == FOLLOWERMODE_GROUND) @@ -6794,8 +6596,8 @@ void M_DrawSetupMultiPlayerMenu(void) // smooth floating, totally not stolen from rocket sneakers. fixed_t sine = FixedMul(fl.bobamp, FINESINE(((FixedMul(4 * M_TAU_FIXED, bobspeed) * followertimer)>>ANGLETOFINESHIFT) & FINEMASK)); - UINT16 color = K_GetEffectiveFollowerColor(setupm_cvfollowercolor->value, &fl, setupm_fakecolor->color, &skins[setupm_fakeskin]); - UINT8 *colormap = R_GetTranslationColormap(TC_DEFAULT, color, 0); // why does GTC_MENUCACHE not work here...? + UINT16 color = K_GetEffectiveFollowerColor(cv_followercolor[setupplayer].value, &fl, cv_dummycolor.value, &skins[cv_chooseskin.value]); + colormap = R_GetTranslationColormap(TC_DEFAULT, color, 0); // why does GTC_MENUCACHE not work here...? INT32 x = (mx+65)*FRACUNIT; INT32 y = ((my+100)*FRACUNIT); @@ -6815,15 +6617,14 @@ void M_DrawSetupMultiPlayerMenu(void) // follower state update. This is its own function so that it's at least somewhat clean static void M_GetFollowerState(void) { - - if (setupm_fakefollower <= -1 || setupm_fakefollower >= numfollowers) // yikes, there's none! + if (cv_dummyfollower.value <= -1) // yikes, there's none! return; // ^ we don't actually need to set anything since it won't be displayed anyway. //followertimer = 0; // reset timer. not like it'll overflow anytime soon but whatever. // set follower state - follower_state = &states[followers[setupm_fakefollower].followstate]; + follower_state = &states[followers[cv_dummyfollower.value].followstate]; if (follower_state->frame & FF_ANIMATE) follower_tics = follower_state->var2*FRACUNIT; // support for FF_ANIMATE @@ -6833,162 +6634,27 @@ static void M_GetFollowerState(void) follower_frame = follower_state->frame & FF_FRAMEMASK; } -// Handle 1P/2P MP Setup -INT32 MR_HandleSetupMultiPlayer(INT32 choice) -{ - size_t l; - INT32 prev_setupm_fakeskin; - - switch (choice) - { - case KEY_LEFTARROW: - if (M_IsItemOn(MN_MP_PLAYERSETUP, "SKIN")) //player skin - { - S_StartSound(NULL,sfx_menu1); // Tails - prev_setupm_fakeskin = setupm_fakeskin; - do - { - setupm_fakeskin--; - if (setupm_fakeskin < 0) - setupm_fakeskin = numskins-1; - } - while ((prev_setupm_fakeskin != setupm_fakeskin) && !(R_SkinUsable(-1, setupm_fakeskin))); - multi_spr2 = P_GetSkinSprite2(&skins[setupm_fakeskin], SPR2_FSTN, NULL); - } - else if (M_IsItemOn(MN_MP_PLAYERSETUP, "FOLLOWER")) // follower - { - S_StartSound(NULL,sfx_menu1); - if (--setupm_fakefollower < -1) - setupm_fakefollower = numfollowers - 1; - M_GetFollowerState(); // update follower state - } - else if (M_IsItemOn(MN_MP_PLAYERSETUP, "COLOR")) // player color - { - S_StartSound(NULL,sfx_menu1); // Tails - do - setupm_fakecolor = setupm_fakecolor->prev; - while (!skincolors[setupm_fakecolor->color].accessible); - } - break; - - case KEY_RIGHTARROW: - if (M_IsItemOn(MN_MP_PLAYERSETUP, "SKIN")) //player skin - { - S_StartSound(NULL,sfx_menu1); // Tails - prev_setupm_fakeskin = setupm_fakeskin; - do - { - setupm_fakeskin++; - if (setupm_fakeskin > numskins-1) - setupm_fakeskin = 0; - } - while ((prev_setupm_fakeskin != setupm_fakeskin) && !(R_SkinUsable(-1, setupm_fakeskin))); - multi_spr2 = P_GetSkinSprite2(&skins[setupm_fakeskin], SPR2_FSTN, NULL); - } - else if (M_IsItemOn(MN_MP_PLAYERSETUP, "FOLLOWER")) // follower - { - S_StartSound(NULL,sfx_menu1); - if (++setupm_fakefollower >= numfollowers) - setupm_fakefollower = -1; - M_GetFollowerState(); // update follower state - } - else if (M_IsItemOn(MN_MP_PLAYERSETUP, "COLOR")) // player color - { - S_StartSound(NULL,sfx_menu1); // Tails - do - setupm_fakecolor = setupm_fakecolor->next; - while (!skincolors[setupm_fakecolor->color].accessible); - } - break; - - case KEY_BACKSPACE: - if (M_IsItemOn(MN_MP_PLAYERSETUP, "NAME")) - { - if ((l = strlen(setupm_name))!=0) - { - S_StartSound(NULL,sfx_menu1); // Tails - setupm_name[l-1] =0; - } - } - else if (M_IsItemOn(MN_MP_PLAYERSETUP, "FOLLOWER")) // follower - { - S_StartSound(NULL,sfx_menu1); - setupm_fakefollower = -1; - } - else if (M_IsItemOn(MN_MP_PLAYERSETUP, "COLOR")) - { - UINT16 col = skins[setupm_fakeskin].prefcolor; - if ((setupm_fakecolor->color != col) && skincolors[col].accessible) - { - S_StartSound(NULL,sfx_menu1); // Tails - for (setupm_fakecolor=menucolorhead;;setupm_fakecolor=setupm_fakecolor->next) - if (setupm_fakecolor->color == col || setupm_fakecolor == menucolortail) - break; - } - } - break; - - case KEY_DEL: - if (M_IsItemOn(MN_MP_PLAYERSETUP, "NAME") && (l = strlen(setupm_name))!=0) - { - S_StartSound(NULL,sfx_menu1); // Tails - setupm_name[0] = 0; - } - break; - - default: - if (choice < 32 || choice > 127 || !M_IsItemOn(MN_MP_PLAYERSETUP, "NAME")) - return false; - l = strlen(setupm_name); - if (l < MAXPLAYERNAME) - { - S_StartSound(NULL,sfx_menu1); // Tails - setupm_name[l] =(char)choice; - setupm_name[l+1] =0; - } - break; - } - - return true; -} - // start the multiplayer setup menu INT32 MR_SetupMultiPlayer(INT32 arg) { if (arg < 0 || arg >= MAXSPLITSCREENPLAYERS) return false; - INT32 pnum = arg == 0 ? consoleplayer : g_localplayers[arg]; + + setupplayer = arg; + M_PatchSkinNameTable(); multi_state = &states[mobjinfo[MT_PLAYER].seestate]; multi_tics = multi_state->tics * FRACUNIT; - strcpy(setupm_name, cv_playername[arg].string); - setupm_player = &players[pnum]; - setupm_cvskin = &cv_skin[arg]; - setupm_cvcolor = &cv_playercolor[arg]; - setupm_cvname = &cv_playername[arg]; - setupm_cvfollower = &cv_follower[arg]; - setupm_cvfollowercolor = &cv_followercolor[arg]; - - setupm_fakefollower = setupm_cvfollower->value; - - // yikes, we don't want none of that... - if (setupm_fakefollower >= numfollowers) - setupm_fakefollower = -1; + CV_Set(&cv_dummyname, cv_playername[arg].string); + CV_SetValue(&cv_dummyfollower, cv_follower[arg].value); + CV_SetValue(&cv_chooseskin, R_SkinAvailable(cv_skin[arg].string)); + CV_SetValue(&cv_dummycolor, cv_playercolor[arg].value); M_GetFollowerState(); // update follower state - // For whatever reason this doesn't work right if you just use ->value - setupm_fakeskin = R_SkinAvailable(setupm_cvskin->string); - if (setupm_fakeskin == -1) - setupm_fakeskin = 0; - - for (setupm_fakecolor=menucolorhead;;setupm_fakecolor=setupm_fakecolor->next) - if (setupm_fakecolor->color == setupm_cvcolor->value || setupm_fakecolor == menucolortail) - break; - // disable skin changes if we can't actually change skins - M_SetItemDisabled(MN_MP_PLAYERSETUP, "SKIN", splitscreen >= pnum && !CanChangeSkin(pnum)); + M_SetItemDisabled(MN_MP_PLAYERSETUP, "SKIN", splitscreen >= arg && !CanChangeSkin(arg == 0 ? consoleplayer : g_localplayers[arg])); return true; } @@ -6996,22 +6662,15 @@ INT32 MR_SetupMultiPlayer(INT32 arg) INT32 MR_QuitMultiPlayerMenu(INT32 choice) { (void)choice; - size_t l; - const char *followername = setupm_fakefollower == -1 ? - "None" : followers[setupm_fakefollower].skinname; - // send name if changed - if (strcmp(setupm_name, setupm_cvname->string)) - { - // remove trailing whitespaces - for (l= strlen(setupm_name)-1; - (signed)l >= 0 && setupm_name[l] ==' '; l--) - setupm_name[l] =0; - COM_BufAddText (va("%s \"%s\"\n",setupm_cvname->name,setupm_name)); - } - // you know what? always putting these in the buffer won't hurt anything. - COM_BufAddText (va("%s \"%s\"\n",setupm_cvskin->name,skins[setupm_fakeskin].name)); - COM_BufAddText (va("%s %d\n",setupm_cvcolor->name,setupm_fakecolor->color)); - COM_BufAddText (va("%s %s\n",setupm_cvfollower->name,followername)); + const char *followername = cv_dummyfollower.value == -1 ? + "None" : followers[cv_dummyfollower.value].skinname; + COM_BufInsertText(va( + "%s \"%s\"; %s \"%s\"; %s \"%s\"; %s \"%s\"\n", + cv_playername[setupplayer].name, cv_dummyname.string, + cv_skin[setupplayer].name, skins[cv_chooseskin.value].name, + cv_playercolor[setupplayer].name, skincolors[cv_dummycolor.value].name, + cv_follower[setupplayer].name, followername + )); return true; } @@ -7397,8 +7056,7 @@ INT32 MR_SetupControlsMenu(INT32 arg) INT32 MR_HandleControlsMenu(INT32 ch) { - if ((currentMenu->menuitems[itemOn].status & IT_TYPE) != IT_CALL - || currentMenu->menuitems[itemOn].itemaction.routine != MR_ChangeControl) + if (currentMenu->menuitems[itemOn].routine != MR_ChangeControl) return false; switch (ch) diff --git a/src/m_menu.h b/src/m_menu.h index 45753e301..0e728f780 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -157,13 +157,12 @@ 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) +#define IT_TYPE (1+2+4+8192+16384) #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 (1+2) // go to sub menu -#define IT_CVAR (1+4) // handle as a cvar -#define IT_PAIR (2+4) // no handling, define both sides of text +#define IT_SUBMENU 8192 // go to sub menu +#define IT_CVAR 16384 // handle as a cvar // display flags #define IT_DISPLAY (8+16+32) @@ -180,11 +179,6 @@ boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt); #define IT_CV_STRING 128 #define IT_CV_INTEGERSTEP 256 // if cvar is CV_FLOAT, modify it by 1 instead of 0.0625 -//call/submenu specific -// There used to be a lot more here but ... -// A lot of them became redundant with the advent of the Pause menu, so they were removed -#define IT_CALL_NOTMODIFIED 64 - // extra flags #define IT_CENTER 512 // if IT_PATCH, center it on screen #define IT_HIDDEN 1024 // invisible, unselectable @@ -201,13 +195,6 @@ boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt); typedef INT32 (menufunc_f)(INT32); typedef void (menudrawer_f)(void); -typedef union -{ - menutype_t submenu; // IT_SUBMENU - consvar_t *cvar; // IT_CVAR - menufunc_f *routine; // IT_CALL, IT_ARROWS -} itemaction_t; - // // MENU TYPEDEFS // @@ -218,12 +205,14 @@ struct menuitem_t // show IT_xxx UINT16 status; + menutype_t submenu; // IT_SUBMENU + consvar_t *cvar; // IT_CVAR + menufunc_f *routine; // IT_CALL, IT_ARROWS + const char *patch; const char *text; // used when FONTBxx lump is found const char *tooltip; - itemaction_t itemaction; - INT32 argument; INT16 x, y; }; @@ -269,9 +258,8 @@ INT32 MR_ChooseTimeAttack(INT32 choice); INT32 MR_SetGuestReplay(INT32 arg); INT32 MR_TimeAttackPreset(INT32 arg); INT32 MR_ReplayTimeAttack(INT32 arg); -INT32 MR_HandleStaffReplay(INT32 choice); -INT32 MR_HandleMPMainMenu(INT32 choice); -INT32 MR_HandleSetupMultiPlayer(INT32 choice); +INT32 MR_ReplayStaff(INT32 choice); +INT32 MR_ConnectIP(INT32 choice); INT32 MR_QuitMultiPlayerMenu(INT32 choice); INT32 MR_StartServerMenu(INT32 choice); INT32 MR_StartServer(INT32 choice); @@ -287,7 +275,7 @@ INT32 MR_VideoModeMenu(INT32 choice); INT32 MR_OpenGLOptionsMenu(INT32 choice); #endif INT32 MR_HandleVideoMode(INT32 ch); -INT32 MR_HandleSoundTest(INT32 choice); +INT32 MR_PlaySound(INT32 choice); INT32 MR_MusicTest(INT32 choice); INT32 MR_QuitMusicTest(INT32 choice); INT32 MR_ScreenshotOptions(INT32 choice); @@ -337,7 +325,6 @@ void M_DrawReplayHut(void); void M_DrawTimeAttackMenu(void); void M_DrawMPMainMenu(void); void M_DrawSetupMultiPlayerMenu(void); -void M_DrawServerMenu(void); void M_DrawConnectMenu(void); void M_DrawVideoMenu(void); void M_DrawVideoMode(void); @@ -415,6 +402,8 @@ extern consvar_t cv_dummygpdifficulty, cv_dummygpencore, cv_dummygpcup; extern consvar_t cv_dummymenuplayer, cv_dummyteam, cv_dummyspectate, cv_dummyscramble; extern consvar_t cv_dummyattackingrings, cv_dummyattackingstacking, cv_dummyattackingchaining; 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_menucaps; // allow menu text to be displayed in lowercase