From 0e30c0c5eb55a1c2abe5f996c0a51d63e8826ac9 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Sat, 15 Mar 2025 04:03:44 +0100 Subject: [PATCH] SOC menus, part 1 --- src/deh_lua.c | 25 ++++- src/deh_soc.c | 239 ++++++++++++++++++++++++++++++++++++++++++++++- src/deh_tables.c | 14 +++ src/deh_tables.h | 2 + src/m_menu.c | 38 +++++++- src/m_menu.h | 21 ++++- 6 files changed, 332 insertions(+), 7 deletions(-) diff --git a/src/deh_lua.c b/src/deh_lua.c index 887b48338..a9ffa3a82 100644 --- a/src/deh_lua.c +++ b/src/deh_lua.c @@ -197,6 +197,21 @@ static inline int lib_freeslot(lua_State *L) CONS_Alert(CONS_WARNING, "Ran out of free PRECIP slots!\n"); } } + else if (fastcmp(type, "MN")) + { + menutype_t i; + for (i = 0; i < NUMMENUFREESLOTS; i++) + if (!FREE_MENUS[i]) { + CONS_Printf("Menu MN_%s allocated.\n",word); + FREE_MENUS[i] = Z_Malloc(strlen(word)+1, PU_STATIC, NULL); + strcpy(FREE_MENUS[i],word); + lua_pushinteger(L, MN_FIRSTFREESLOT + i); + r++; + break; + } + if (i == NUMMENUFREESLOTS) + CONS_Alert(CONS_WARNING, "Ran out of free menu slots!\n"); + } Z_Free(s); lua_remove(L, 1); continue; @@ -633,7 +648,15 @@ static int ScanConstants(lua_State *L, boolean mathlib, const char *word) } else if (fastncmp("MN_",word,3)) { p = word+3; - for (i = 0; i < NUMMENUTYPES; i++) + for (i = 0; i < NUMMENUFREESLOTS; i++) { + if (!FREE_MENUS[i]) + break; + if (fastcmp(p, FREE_MENUS[i])) { + CacheAndPushConstant(L, word, MN_FIRSTFREESLOT+i); + return 1; + } + } + for (i = 0; i < MN_FIRSTFREESLOT; i++) if (fastcmp(p, MENUTYPES_LIST[i])) { CacheAndPushConstant(L, word, i); return 1; diff --git a/src/deh_soc.c b/src/deh_soc.c index 783cc14e1..2a54dc1a2 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -534,6 +534,16 @@ void readfreeslots(MYFILE *f) } else deh_warning("Ran out of free PRECIP slots!\n"); } + else if (fastcmp(type, "MN")) + { + for (i = 0; i < NUMMENUFREESLOTS; i++) + if (!FREE_MENUS[i]) { + CONS_Printf("Menu MN_%s allocated.\n",word); + FREE_MENUS[i] = Z_Malloc(strlen(word)+1, PU_STATIC, NULL); + strcpy(FREE_MENUS[i],word); + break; + } + } else deh_warning("Freeslots: unknown enum class '%s' for '%s_%s'", type, type, word); } @@ -2135,6 +2145,150 @@ void readtextprompt(MYFILE *f, INT32 num) Z_Free(s); } +static void readmenuitem(MYFILE *f, menu_t *menudef, char *itemname) +{ + char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); + char *word = s; + char *word2; + char *tmp; + + menuitem_t *menuitem = menudef->menuitems + menudef->numitems; + (void)itemname; // menuitem->itemname = Z_StrDup(itemname); + boolean actionset = false; + boolean textset = false; + + // taking quite possibly the only opportunity i'll ever get + // to avoid three tabs of indentation... + do if (myfgets(s, MAXLINELEN, f)) + { + if (s[0] == '\n') + break; + + // First remove trailing newline, if there is one + tmp = strchr(s, '\n'); + if (tmp) + *tmp = '\0'; + + tmp = strchr(s, '#'); + if (tmp) + *tmp = '\0'; + if (s == tmp) + continue; // Skip comment lines, but don't break. + + // Get the part before the " = " + tmp = strchr(s, '='); + if (tmp) + *(tmp-1) = '\0'; + else + break; + strupr(word); + + // Now get the part after + word2 = tmp += 2; + //strupr(word2); + + if (fastcmp(word, "PATCH")) + { + menuitem->patch = Z_StrDup(word2); + } + else if (fastncmp(word, "TEXT", 4)) + { + UINT16 flags = IT_STRING; + if (fastcmp(word+4, "HEADER")) + flags = IT_HEADER; + else if (fastcmp(word+4, "SECRET")) + flags = IT_SECRET; + else if (word[4]) + { + deh_warning("MenuItem %s: unknown word '%s'", "", word); + continue; + } + + if (textset) + { + deh_warning("MenuItem %s: text already set!", ""); + continue; + } + textset = true; + menuitem->status |= flags; + menuitem->text = Z_StrDup(word2); + } + else if (fastncmp(word, "CVAR", 4)) + { + UINT16 flags = IT_CVAR; + 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; + else if (word[4]) + { + deh_warning("MenuItem %s: unknown word '%s'", "", word); + continue; + } + + if (actionset) + { + deh_warning("MenuItem %s: action already set!", ""); + continue; + } + consvar_t *cvar = CV_FindVar(word2); + if (!cvar) + { + deh_warning("MenuItem %s: unable to find cvar '%s'", "", word2); + continue; + } + actionset = true; + menuitem->status |= flags; + menuitem->itemaction.cvar = cvar; + } + else if (fastcmp(word, "SUBMENU")) + { + if (actionset) + { + deh_warning("MenuItem %s: action already set!", ""); + continue; + } + menutype_t mn = get_menutype(word2); + if (mn == MN_NONE) + { + deh_warning("MenuItem %s: unknown menu '%s'", "", word2); + continue; + } + actionset = true; + menuitem->status |= IT_SUBMENU; + menuitem->itemaction.submenu = menunum2menudef[mn]; + } + else if (fastcmp(word, "CALL") || fastcmp(word, "KEYHANDLER")) + { + if (actionset) + { + deh_warning("MenuItem %s: action already set!", ""); + continue; + } + void (*routine)(INT32 choice) = NULL; // TODO + if (!routine) + { + deh_warning("MenuItem %s: unknown call routine '%s'", "", word2); + continue; + } + actionset = true; + menuitem->status |= word[0] == 'C' ? IT_CALL : IT_KEYHANDLER; + menuitem->itemaction.routine = routine; + } + else if (fastcmp(word, "ALPHAKEY") || fastcmp(word, "Y")) + { + menuitem->alphaKey = atoi(word2); + } + else + deh_warning("MenuItem %s: unknown word '%s'", "", word); + } + while (!myfeof(f)); // finish when the line is empty + + Z_Free(s); +} + void readmenu(MYFILE *f, INT32 num) { char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); @@ -2142,6 +2296,20 @@ void readmenu(MYFILE *f, INT32 num) char *word2; char *tmp; INT32 value; + boolean space = false; + + menu_t *menudef = menunum2menudef[num]; + if (menudef == NULL) + { + deh_warning("No def for menu %d, that is certainly strange...", num); + return; + } + + //menuactive = false; + + memset(menudef, 0, sizeof(menu_t)); + menudef->menuid = num; + menudef->drawroutine = M_DrawGenericMenu; do { @@ -2161,12 +2329,21 @@ void readmenu(MYFILE *f, INT32 num) if (s == tmp) continue; // Skip comment lines, but don't break. + space = false; + // Get the part before the " = " tmp = strchr(s, '='); if (tmp) *(tmp-1) = '\0'; else - break; + { + space = true; + tmp = strchr(s, ' '); + if (tmp) + *tmp-- = '\0'; // decrement after, so word2 is correct + else + break; + } strupr(word); // Now get the part after @@ -2175,6 +2352,19 @@ void readmenu(MYFILE *f, INT32 num) value = atoi(word2); // used for numerical settings + if (space) + { + if (fastcmp(word, "MENUITEM")) + { + menudef->menuitems = Z_Realloc(menudef->menuitems, sizeof(menuitem_t)*(menudef->numitems+1), PU_STATIC, NULL); + readmenuitem(f, menudef, word2); + menudef->numitems++; + } + else + deh_warning("Menu %d: unknown word '%s'", num, word); + continue; + } + if (fastcmp(word, "BACKGROUNDNAME")) { strncpy(menupres[num].bgname, word2, 8); @@ -2315,6 +2505,45 @@ void readmenu(MYFILE *f, INT32 num) menupres[num].exitwipe = get_number(word2); titlechanged = true; } + // MENUDEF STARTS HERE + else if (fastcmp(word, "MENUTITLEPIC") || fastcmp(word, "TITLEPIC")) + { + menudef->menutitlepic = Z_StrDup(word2); + } + else if (fastcmp(word, "PREVMENU")) + { + value = get_menutype(word2); + if (value == MN_NONE) + { + deh_warning("Menu %d: unknown previous menu '%s'", num, word2); + continue; + } + menudef->prevMenu = menunum2menudef[value]; + } + else if (fastcmp(word, "DRAWROUTINE")) + { + { + deh_warning("Menu %d: unknown draw routine '%s'", num, word2); + continue; + } + } + else if (fastcmp(word, "X")) + { + menudef->x = value; + } + else if (fastcmp(word, "Y")) + { + menudef->y = value; + } + else if (fastcmp(word, "QUITROUTINE")) + { + { + deh_warning("Menu %d: unknown quit routine '%s'", num, word2); + continue; + } + } + else + deh_warning("Menu %d: unknown word '%s'", num, word); } } while (!myfeof(f)); // finish when the line is empty @@ -4061,7 +4290,13 @@ menutype_t get_menutype(const char *word) return atoi(word); if (fastncmp("MN_",word,3)) word += 3; // take off the MN_ - for (i = 0; i < NUMMENUTYPES; i++) + for (i = 0; i < NUMMENUFREESLOTS; i++) { + if (!FREE_MENUS[i]) + break; + if (fastcmp(word, FREE_MENUS[i])) + return MN_FIRSTFREESLOT+i; + } + for (i = 0; i < MN_FIRSTFREESLOT; i++) if (fastcmp(word, MENUTYPES_LIST[i])) return i; deh_warning("Couldn't find menutype named 'MN_%s'",word); diff --git a/src/deh_tables.c b/src/deh_tables.c index ddaa1fb03..dbb9098f0 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -33,6 +33,7 @@ char *FREE_STATES[NUMSTATEFREESLOTS]; char *FREE_MOBJS[NUMMOBJFREESLOTS]; char *FREE_SKINCOLORS[NUMCOLORFREESLOTS]; +char *FREE_MENUS[NUMMENUFREESLOTS]; UINT8 used_spr[(NUMSPRITEFREESLOTS / 8) + 1]; // Bitwise flag for sprite freeslot in use! I would use ceil() here if I could, but it only saves 1 byte of memory anyway. struct flickytypes_s FLICKYTYPES[] = { @@ -615,6 +616,8 @@ const char *const MENUTYPES_LIST[] = { "SP_NIGHTS_REPLAY", "SP_NIGHTS_GHOST", + "SP_MARATHON", + // Multiplayer "MP_MAIN", "MP_SPLITSCREEN", // SplitServer @@ -681,6 +684,17 @@ const char *const MENUTYPES_LIST[] = { // "MAPAUSE", // "HELP", + // SRB2Kart + "OP_HUD", + "OP_CHAT", + "OP_GAME", + "OP_BLANKARTGAME", + "OP_ADVANCEDSERVER", + "OP_CAMERA", + "OP_P3CAMERA", + "OP_P4CAMERA", + "MISC_REPLAY", + "SPECIAL" }; diff --git a/src/deh_tables.h b/src/deh_tables.h index 484cb281b..15923a6c0 100644 --- a/src/deh_tables.h +++ b/src/deh_tables.h @@ -16,6 +16,7 @@ #include "doomdef.h" // Constants #include "d_think.h" // actionf_t #include "info.h" // Mobj, state, sprite, etc constants +#include "m_menu.h" // NUMMENUFREESLOTS #include "lua_script.h" #ifdef __cplusplus @@ -27,6 +28,7 @@ extern "C" { extern char *FREE_STATES[NUMSTATEFREESLOTS]; extern char *FREE_MOBJS[NUMMOBJFREESLOTS]; extern char *FREE_SKINCOLORS[NUMCOLORFREESLOTS]; +extern char *FREE_MENUS[NUMMENUFREESLOTS]; extern UINT8 used_spr[(NUMSPRITEFREESLOTS / 8) + 1]; // Bitwise flag for sprite freeslot in use! I would use ceil() here if I could, but it only saves 1 byte of memory anyway. #define initfreeslots() {\ diff --git a/src/m_menu.c b/src/m_menu.c index 4ade3ffc4..2bd418f26 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -203,6 +203,9 @@ static void M_HandleServerPage(INT32 choice); void M_SetWaitingMode(int mode); int M_GetWaitingMode(void); +// a single freeslot menu for testing +menu_t FreeslotTest; + // the haxor message menu menu_t MessageDef; @@ -359,7 +362,6 @@ static void M_PlaybackQuit(INT32 choice); static UINT8 playback_enterheld = 0; // horrid hack to prevent holding the button from being extremely fucked // Drawing functions -static void M_DrawGenericMenu(void); static void M_DrawGenericBackgroundMenu(void); static void M_DrawCenteredMenu(void); static void M_DrawAddons(void); @@ -410,6 +412,33 @@ static void Dummymenuplayer_OnChange(void); //static void Dummymares_OnChange(void); static void Dummystaff_OnChange(void); +// temporary measure until menu_t and menupres_t are merged (hopefully) +menu_t *menunum2menudef[NUMMENUTYPES] = { + [MN_OP_CAMERA] = &OP_CamOptionsDef, + [MN_OP_P1CAMERA] = &OP_Player1CamOptionsDef, + [MN_OP_P2CAMERA] = &OP_Player2CamOptionsDef, + [MN_OP_P3CAMERA] = &OP_Player3CamOptionsDef, + [MN_OP_P4CAMERA] = &OP_Player4CamOptionsDef, + + [MN_OP_MAIN] = &OP_MainDef, + [MN_OP_CHANGECONTROLS] = &OP_ControlsDef, + [MN_OP_VIDEO] = &OP_VideoOptionsDef, + [MN_OP_OPENGL] = &OP_OpenGLOptionsDef, + [MN_OP_SOUND] = &OP_SoundOptionsDef, + [MN_OP_CHAT] = &OP_ChatOptionsDef, + [MN_OP_HUD] = &OP_HUDOptionsDef, + [MN_OP_GAME] = &OP_GameOptionsDef, + [MN_OP_BLANKARTGAME] = &OP_BlanKartGameOptionsDef, + [MN_OP_SERVER] = &OP_ServerOptionsDef, + [MN_OP_ADVANCEDSERVER] = &OP_AdvServerOptionsDef, + [MN_OP_MONITORTOGGLE] = &OP_MonitorToggleDef, + [MN_OP_DATA] = &OP_DataOptionsDef, + [MN_OP_ERASEDATA] = &OP_EraseDataDef, + [MN_MISC_REPLAY] = &MISC_ReplayOptionsDef, + + [MN_FIRSTFREESLOT] = &FreeslotTest, +}; + // ========================================================================== // CONSOLE VARIABLES AND THEIR POSSIBLE VALUES GO HERE. // ========================================================================== @@ -3003,7 +3032,10 @@ boolean M_Responder(event_t *ev) break; case IT_SUBMENU: currentMenu->lastOn = itemOn; - M_SetupNextMenu((menu_t *)currentMenu->menuitems[itemOn].itemaction.submenu); + if ((menu_t *)(currentMenu->menuitems[itemOn].itemaction.submenu)->menuitems == NULL) + CONS_Alert(CONS_WARNING, "Submenu is empty!\n"); + else + M_SetupNextMenu((menu_t *)currentMenu->menuitems[itemOn].itemaction.submenu); break; } } @@ -3919,7 +3951,7 @@ static void M_DrawMenuTitle(void) } } -static void M_DrawGenericMenu(void) +void M_DrawGenericMenu(void) { INT32 x, y, w, i, cursory = 0; diff --git a/src/m_menu.h b/src/m_menu.h index f652c5345..f9d1e8875 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -138,13 +138,30 @@ typedef enum // MN_MAPAUSE, // MN_HELP, + // SRB2Kart + MN_OP_HUD, + MN_OP_CHAT, + MN_OP_GAME, + MN_OP_BLANKARTGAME, + MN_OP_ADVANCEDSERVER, + MN_OP_CAMERA, + MN_OP_P3CAMERA, + MN_OP_P4CAMERA, + MN_MISC_REPLAY, + MN_SPECIAL, + + MN_FIRSTFREESLOT, + MN_LASTFREESLOT, NUMMENUTYPES, -} menutype_t; // up to 63; MN_SPECIAL = 53 +} menutype_t; // up to 63 +#define NUMMENUFREESLOTS (NUMMENUTYPES - MN_FIRSTFREESLOT) #define MTREE2(a,b) (a | (b<