From fd7eb9e06d7f500b888d20d7159cf8477022b198 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Tue, 25 Mar 2025 21:08:56 +0100 Subject: [PATCH] Refined message box code, consistent DrawPatchFill M_StartMessage now takes a function pointer instead of an object pointer. No more FUNCPTRCAST --- src/d_clisrv.c | 6 +- src/m_menu.c | 213 ++++++++++++++++++------------------------------- src/m_menu.h | 4 +- 3 files changed, 80 insertions(+), 143 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index c5039f9e0..966d1d364 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1588,7 +1588,7 @@ static boolean CL_FinishedFileList(void) "You may load server addons (if any), and wait for a slot.\n" "\n" "Press ACCEL to continue or BRAKE to cancel.\n\n" - ), FUNCPTRCAST (M_ConfirmConnect), MM_EVENTHANDLER); + ), M_ConfirmConnect, MM_EVENTHANDLER); cl_mode = CL_CONFIRMCONNECT; } else @@ -1649,13 +1649,13 @@ static boolean CL_FinishedFileList(void) "You may download, load server addons, and wait for a slot.\n" "\n" "Press ACCEL to continue or BRAKE to cancel.\n\n" - ), downloadsize), FUNCPTRCAST(M_ConfirmConnect), MM_EVENTHANDLER); + ), downloadsize), M_ConfirmConnect, MM_EVENTHANDLER); else M_StartMessage(va(M_GetText( "Download of %s additional content is required to join.\n" "\n" "Press ACCEL to continue or BRAKE to cancel.\n\n" - ), downloadsize), FUNCPTRCAST(M_ConfirmConnect), MM_EVENTHANDLER); + ), downloadsize), M_ConfirmConnect, MM_EVENTHANDLER); Z_Free(downloadsize); cl_mode = CL_CONFIRMCONNECT; diff --git a/src/m_menu.c b/src/m_menu.c index cc1c31bb3..d0be0c719 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -173,6 +173,16 @@ static INT16 itemOn = 1; // menu item skull is on, Hack by Tails 09-18-2002 static INT16 skullAnimCounter = 10; // skull animation counter static tic_t followertimer = 0; // Used for smooth follower floating +static struct { + boolean active; + const char *text; + void (*routine)(); + menumessagetype_t messagetype; + INT16 x, y; + INT16 numlines; + INT16 maxlength; +} messagebox; + static UINT8 setupcontrolplayer; static INT32 (*setupcontrols)[MAXINPUTMAPPING]; // pointer to the gamecontrols of the player being edited @@ -183,12 +193,6 @@ static INT32 vidm_selected = 0; static INT32 vidm_nummodes; static INT32 vidm_column_size; -// -// PROTOTYPES -// - -static void M_StopMessage(INT32 choice); - // Prototyping is fun, innit? // ========================================================================== // NEEDED FUNCTION PROTOTYPES GO HERE @@ -197,9 +201,6 @@ static void M_StopMessage(INT32 choice); void M_SetWaitingMode(int mode); int M_GetWaitingMode(void); -// the haxor message menu -menu_t MessageDef; - #define lsheadingheight 16 // Sky Room @@ -216,7 +217,7 @@ static patch_t *addonsp[NUM_EXT+5]; static UINT8 playback_enterheld = 0; // horrid hack to prevent holding the button from being extremely fucked // Drawing functions -static void M_DrawGenericBackgroundMenu(void); +static void M_DrawMessageMenu(void); static void M_DrawLevelSelectOnly(boolean leftfade, boolean rightfade); // uhhhhhh hack? @@ -1049,6 +1050,27 @@ boolean M_Responder(event_t *ev) if (ch == -1) return false; + if (messagebox.active) + { + if (messagebox.messagetype != MM_EVENTHANDLER) + { + if (ch == ' ' || ch == 'n' || ch == 'y' || ch == KEY_ESCAPE || ch == KEY_ENTER) + { + if (messagebox.routine) + messagebox.routine(ch); + messagebox.active = false; + noFurtherInput = true; + } + } + else + { + // dirty hack: for customising controls, I want only buttons/keys/axes, not mouse + if (messagebox.routine && !(ev->type == ev_mouse || (ev->type == ev_joystick && messagebox.routine != M_ChangecontrolResponse))) + messagebox.routine(ev); + } + return true; + } + // F-Keys if (!menustack[0]) { @@ -1135,36 +1157,6 @@ boolean M_Responder(event_t *ev) return true; } - if (currentMenu->menuitems[itemOn].status == IT_MSGHANDLER) - { - if (currentMenu->menuitems[itemOn].alphaKey != MM_EVENTHANDLER) - { - if (ch == ' ' || ch == 'n' || ch == 'y' || ch == KEY_ESCAPE || ch == KEY_ENTER) - { - if (routine) - routine(ch); - M_StopMessage(0); - noFurtherInput = true; - return true; - } - return true; - } - else - { - // dirty hack: for customising controls, I want only buttons/keys/axes, not mouse - if (ev->type == ev_mouse || (ev->type == ev_joystick && currentMenu->menuitems[itemOn].itemaction.eventhandler != M_ChangecontrolResponse)) - { - return true; - } - - if (routine) - { - currentMenu->menuitems[itemOn].itemaction.eventhandler(ev); - } - return true; - } - } - // BP: one of the more big hack i have never made if (routine && (currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_CVAR) { @@ -1461,17 +1453,23 @@ boolean M_DemoResponder(event_t *ev) // void M_Drawer(void) { - if (menustack[0]) + if (menustack[0] || messagebox.active) { // now that's more readable with a faded background (yeah like Quake...) - if (!WipeInAction && menustack[0] != MN_PLAYBACK) // Replay playback has its own background + if (gamestate == GS_TIMEATTACK) + V_DrawPatchFill(W_CachePatchName("SRB2BACK", PU_CACHE)); + else if (!WipeInAction && menustack[0] != MN_PLAYBACK) // Replay playback has its own background V_DrawFadeScreen(0xFF00, 16); + } - if (currentMenu->drawroutine) - { - M_GetGametypeColor(); - currentMenu->drawroutine(); // call current menu Draw routine - } + if (messagebox.active) + { + M_DrawMessageMenu(); + } + else if (currentMenu && currentMenu->drawroutine) + { + M_GetGametypeColor(); + currentMenu->drawroutine(); // call current menu Draw routine } // focus lost notification goes on top of everything, even the former everything @@ -2227,12 +2225,6 @@ void M_DrawGenericMenu(void) } } -static void M_DrawGenericBackgroundMenu(void) -{ - V_DrawPatchFill(W_CachePatchName("SRB2BACK", PU_CACHE)); - M_DrawGenericMenu(); -} - void M_DrawPauseMenu(void) { #ifdef HAVE_DISCORDRPC @@ -2630,24 +2622,7 @@ static INT32 M_GetFirstLevelInList(void) // ================================================== // MESSAGE BOX (aka: a hacked, cobbled together menu) // ================================================== -static void M_DrawMessageMenu(void); - -// Because this is just a hack-ish 'menu', I'm not putting this with the others -static menuitem_t MessageMenu[] = {0}; - -menu_t MessageDef = -{ - NULL, // title - 1, // # of menu items - MessageMenu, // menuitem_t -> - M_DrawMessageMenu, // drawing routine -> - 0, 0, // x, y (TO HACK) - 0, // lastOn, flags (TO HACK) - NULL -}; - - -void M_StartMessage(const char *string, void *routine, +void M_StartMessage(const char *string, void (*routine)(), menumessagetype_t itemtype) { size_t max = 0, start = 0, i, strlines; @@ -2691,24 +2666,10 @@ void M_StartMessage(const char *string, void *routine, M_StartControlPanel(); // can't put menuactive to true - MessageDef.menuitems[0].text = message; - MessageDef.menuitems[0].alphaKey = (UINT8)itemtype; - if (!routine && itemtype != MM_NOTHING) itemtype = MM_NOTHING; - switch (itemtype) - { - case MM_NOTHING: - MessageDef.menuitems[0].status = IT_MSGHANDLER; - MessageDef.menuitems[0].itemaction.routine = M_StopMessage; - break; - case MM_YESNO: - MessageDef.menuitems[0].status = IT_MSGHANDLER; - *(void**)&MessageDef.menuitems[0].itemaction.routine = routine; - break; - case MM_EVENTHANDLER: - MessageDef.menuitems[0].status = IT_MSGHANDLER; - *(void**)&MessageDef.menuitems[0].itemaction.eventhandler = routine; - break; - } + messagebox.text = message; + messagebox.messagetype = itemtype; + messagebox.routine = routine; + //added : 06-02-98: now draw a textbox around the message // compute lenght max and the numbers of lines for (strlines = 0; *(message+start); strlines++) @@ -2730,34 +2691,25 @@ void M_StartMessage(const char *string, void *routine, start += i; } - MessageDef.x = (INT16)((BASEVIDWIDTH - 8*max-16)/2); - MessageDef.y = (INT16)((BASEVIDHEIGHT - M_StringHeight(message))/2); + messagebox.x = (BASEVIDWIDTH - 8*max-16)/2; + messagebox.y = (BASEVIDHEIGHT - M_StringHeight(message))/2; - MessageDef.lastOn = (INT16)((strlines<<8)+max); + messagebox.numlines = strlines; + messagebox.maxlength = max; - currentMenu = &MessageDef; - itemOn = 0; + messagebox.active = true; } #define MAXMSGLINELEN 256 static void M_DrawMessageMenu(void) { - INT32 y = currentMenu->y; + INT32 y = messagebox.y; size_t i, start = 0; - INT16 max; char string[MAXMSGLINELEN]; - INT32 mlines; - const char *msg = currentMenu->menuitems[0].text; + const char *msg = messagebox.text; - mlines = currentMenu->lastOn>>8; - max = (INT16)((UINT8)(currentMenu->lastOn & 0xFF)*8); - - // hack: draw RA background in RA menus - if (gamestate == GS_TIMEATTACK) - V_DrawPatchFill(W_CachePatchName("SRB2BACK", PU_CACHE)); - - M_DrawTextBox(currentMenu->x, y - 8, (max+7)>>3, mlines); + M_DrawTextBox(messagebox.x, y - 8, messagebox.maxlength, messagebox.numlines); while (*(msg+start)) { @@ -2804,16 +2756,6 @@ static void M_DrawMessageMenu(void) } } -// default message handler -static void M_StopMessage(INT32 choice) -{ - (void)choice; - if (menustack[0]) - M_SetupNextMenu(menustack[0], true); - else - M_ClearMenus(true); -} - // ========= // IMAGEDEFS // ========= @@ -3037,11 +2979,12 @@ static boolean prevmajormods = false; static void M_AddonsClearName(INT32 choice) { + (void)choice; if (!majormods || prevmajormods) { CLEARNAME; } - M_StopMessage(choice); + messagebox.active = false; } // returns whether to do message draw @@ -3090,7 +3033,7 @@ static boolean M_AddonsRefresh(void) if (message) { - M_StartMessage(message, FUNCPTRCAST(M_AddonsClearName), MM_EVENTHANDLER); + M_StartMessage(message, M_AddonsClearName, MM_EVENTHANDLER); return true; } @@ -3387,7 +3330,7 @@ void M_HandleAddons(INT32 choice) } break; case EXT_TXT: - M_StartMessage(va("%c%s\x80\nThis file may not be a console script.\nAttempt to run anyways? \n\n(Press 'Y' to confirm)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), dirmenu[dir_on[menudepthleft]]+DIR_STRING), FUNCPTRCAST(M_AddonExec) ,MM_YESNO); + M_StartMessage(va("%c%s\x80\nThis file may not be a console script.\nAttempt to run anyways? \n\n(Press 'Y' to confirm)\n", ('\x80' + (highlightflags>>V_CHARCOLORSHIFT)), dirmenu[dir_on[menudepthleft]]+DIR_STRING), M_AddonExec ,MM_YESNO); break; case EXT_CFG: M_AddonExec(KEY_ENTER); @@ -3745,8 +3688,6 @@ void M_DrawReplayHut(void) static UINT16 replayhutmenuy = 0; - V_DrawPatchFill(W_CachePatchName("SRB2BACK", PU_CACHE)); - if (cv_vhseffect.value) V_DrawVhsEffect(false); @@ -3887,7 +3828,7 @@ void M_DrawReplayStartMenu(void) const char *warning; UINT8 i; - M_DrawGenericBackgroundMenu(); + M_DrawGenericMenu(); #define STARTY 62-(replayScrollTitle>>1) // Draw rankings beyond first @@ -4463,7 +4404,7 @@ static void M_RetryResponse(INT32 ch) void M_Retry(INT32 choice) { (void)choice; - M_StartMessage(va("Start this %s over?\n\n(Press 'Y' to confirm)\n", (gametyperules & GTR_CIRCUIT) ? "race" : "battle"),FUNCPTRCAST(M_RetryResponse),MM_YESNO); + M_StartMessage(va("Start this %s over?\n\n(Press 'Y' to confirm)\n", (gametyperules & GTR_CIRCUIT) ? "race" : "battle"),M_RetryResponse,MM_YESNO); } void M_SelectableClearMenus(INT32 choice) @@ -4521,7 +4462,7 @@ void M_DestroyRobots(INT32 choice) { (void)choice; - M_StartMessage(M_GetText("Do you want to destroy all\nrobots in the current level?\n\n(Press 'Y' to confirm)\n"), FUNCPTRCAST(M_DestroyRobotsResponse), MM_YESNO); + M_StartMessage(M_GetText("Do you want to destroy all\nrobots in the current level?\n\n(Press 'Y' to confirm)\n"), M_DestroyRobotsResponse, MM_YESNO); } // ======== @@ -5562,8 +5503,6 @@ void M_DrawTimeAttackMenu(void) //S_ChangeMusicInternal("racent", true); // Eww, but needed for when user hits escape during demo playback - V_DrawPatchFill(W_CachePatchName("SRB2BACK", PU_CACHE)); - M_DrawMenuTitle(); if (menustack[0] == MN_SP_TIMEATTACK) M_DrawLevelSelectOnly(true, false); @@ -5898,7 +5837,7 @@ static void M_OverwriteGuest(const char *which) return; } if (FIL_FileExists(rguest)) { - M_StopMessage(0); + messagebox.active = false; remove(rguest); } FIL_WriteFile(rguest, buf, len); @@ -5943,11 +5882,11 @@ void M_SetGuestReplay(INT32 choice) break; case 3: // guest default: - M_StartMessage(M_GetText("Are you sure you want to\ndelete the guest replay data?\n\n(Press 'Y' to confirm)\n"), FUNCPTRCAST(M_EraseGuest), MM_YESNO); + M_StartMessage(M_GetText("Are you sure you want to\ndelete the guest replay data?\n\n(Press 'Y' to confirm)\n"), M_EraseGuest, MM_YESNO); return; } if (FIL_FileExists(va("%s"PATHSEP"media"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value)))) - M_StartMessage(M_GetText("Are you sure you want to\noverwrite the guest replay data?\n\n(Press 'Y' to confirm)\n"), FUNCPTRCAST(which), MM_YESNO); + M_StartMessage(M_GetText("Are you sure you want to\noverwrite the guest replay data?\n\n(Press 'Y' to confirm)\n"), which, MM_YESNO); else which(0); } @@ -6002,7 +5941,7 @@ void M_EndGame(INT32 choice) if (!Playing()) return; - M_StartMessage(M_GetText("Are you sure you want to end the game?\n\n(Press 'Y' to confirm)\n"), FUNCPTRCAST(M_ExitGameResponse), MM_YESNO); + M_StartMessage(M_GetText("Are you sure you want to end the game?\n\n(Press 'Y' to confirm)\n"), M_ExitGameResponse, MM_YESNO); } //=========================================================================== @@ -6456,7 +6395,7 @@ void M_ConnectMenuModChecks(INT32 choice) if (modifiedgame) { - M_StartMessage(M_GetText("You have addons loaded.\nYou won't be able to join netgames!\n\nTo play online, restart the game\nand don't load any addons.\nSRB2Kart will automatically add\neverything you need when you join.\n\n(Press a key)\n"), FUNCPTRCAST(M_ConnectMenu), MM_EVENTHANDLER); + M_StartMessage(M_GetText("You have addons loaded.\nYou won't be able to join netgames!\n\nTo play online, restart the game\nand don't load any addons.\nSRB2Kart will automatically add\neverything you need when you join.\n\n(Press a key)\n"), M_ConnectMenu, MM_EVENTHANDLER); return; } @@ -7860,7 +7799,7 @@ void M_EraseData(INT32 choice) else eschoice = M_GetText("ALL game data"); - M_StartMessage(va(esstr, eschoice), FUNCPTRCAST(M_EraseDataResponse), MM_YESNO); + M_StartMessage(va(esstr, eschoice), M_EraseDataResponse, MM_YESNO); } void M_ScreenshotOptions(INT32 choice) @@ -8350,7 +8289,7 @@ static void M_ChangecontrolResponse(event_t *ev) sprintf(tmp, M_GetText("The \x82Pause Key \x80is enabled, but \nit is not configurable. \n\nHit another key for\n%s\nESC for Cancel"), controltochangetext); - M_StartMessage(tmp, FUNCPTRCAST(M_ChangecontrolResponse), MM_EVENTHANDLER); + M_StartMessage(tmp, M_ChangecontrolResponse, MM_EVENTHANDLER); S_StartSound(NULL, sfx_s3k42); return; @@ -8358,7 +8297,7 @@ static void M_ChangecontrolResponse(event_t *ev) else S_StartSound(NULL, sfx_s224); - M_StopMessage(0); + messagebox.active = false; } void M_ChangeControl(INT32 choice) @@ -8372,7 +8311,7 @@ void M_ChangeControl(INT32 choice) currentMenu->menuitems[choice].text); strlcpy(controltochangetext, currentMenu->menuitems[choice].text, 33); - M_StartMessage(tmp, FUNCPTRCAST(M_ChangecontrolResponse), MM_EVENTHANDLER); + M_StartMessage(tmp, M_ChangecontrolResponse, MM_EVENTHANDLER); } static void M_ResetControlsResponse(INT32 ch) @@ -8401,7 +8340,7 @@ static void M_ResetControlsResponse(INT32 ch) void M_ResetControls(INT32 choice) { (void)choice; - M_StartMessage(va(M_GetText("Reset Player %d's controls to defaults?\n\n(Press 'Y' to confirm)\n"), setupcontrolplayer), FUNCPTRCAST(M_ResetControlsResponse), MM_YESNO); + M_StartMessage(va(M_GetText("Reset Player %d's controls to defaults?\n\n(Press 'Y' to confirm)\n"), setupcontrolplayer), M_ResetControlsResponse, MM_YESNO); } // =============== @@ -9014,7 +8953,7 @@ void M_QuitSRB2(INT32 choice) // We pick index 0 which is language sensitive, or one at random, // between 1 and maximum number. (void)choice; - M_StartMessage(quitmsg[M_RandomKey(NUM_QUITMESSAGES)], FUNCPTRCAST(M_QuitResponse), MM_YESNO); + M_StartMessage(quitmsg[M_RandomKey(NUM_QUITMESSAGES)], M_QuitResponse, MM_YESNO); } #ifdef HAVE_DISCORDRPC diff --git a/src/m_menu.h b/src/m_menu.h index 997d718e3..592dea54d 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -139,7 +139,7 @@ typedef enum MM_EVENTHANDLER // the same of above but without 'y' or 'n' restriction // and routine is void routine(event_t *) (ex: set control) } menumessagetype_t; -void M_StartMessage(const char *string, void *routine, menumessagetype_t itemtype); +void M_StartMessage(const char *string, void (*routine)(), menumessagetype_t itemtype); typedef enum { @@ -168,7 +168,6 @@ boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt); #define IT_SUBMENU 6 // go to sub menu #define IT_CVAR 8 // handle as a cvar #define IT_PAIR 11 // no handling, define both sides of text -#define IT_MSGHANDLER 12 // same as key but with event and sometime can handle y/n key (special for message) #define IT_DISPLAY (48+64+128) // 16+32+64+128 #define IT_NOTHING 0 // space @@ -225,7 +224,6 @@ typedef union menutype_t submenu; // IT_SUBMENU consvar_t *cvar; // IT_CVAR void (*routine)(INT32 choice); // IT_CALL, IT_KEYHANDLER, IT_ARROWS - void (*eventhandler)(event_t *ev); // MM_EVENTHANDLER } itemaction_t; //