From 64a112e358299a45879e53e5eec6bf63d4a1eac2 Mon Sep 17 00:00:00 2001 From: James R <justsomejames2@gmail.com> Date: Fri, 25 Aug 2023 17:13:13 -0700 Subject: [PATCH] Pause menu: add cheats menu Automatically populated with every cheat cvar. --- src/command.c | 2 +- src/command.h | 2 + src/k_menu.h | 1 + src/menus/transient/CMakeLists.txt | 1 + src/menus/transient/pause-cheats.cpp | 161 +++++++++++++++++++++++++++ src/menus/transient/pause-game.c | 9 ++ 6 files changed, 175 insertions(+), 1 deletion(-) create mode 100644 src/menus/transient/pause-cheats.cpp diff --git a/src/command.c b/src/command.c index daf0865b99..fd5044e8b7 100644 --- a/src/command.c +++ b/src/command.c @@ -66,7 +66,7 @@ static boolean CV_Command(void); consvar_t *CV_FindVar(const char *name); static const char *CV_StringValue(const char *var_name); -static consvar_t *consvar_vars; // list of registered console variables +consvar_t *consvar_vars; // list of registered console variables static UINT16 consvar_number_of_netids = 0; static char com_token[1024]; diff --git a/src/command.h b/src/command.h index 9c3e8277e1..953af40b1d 100644 --- a/src/command.h +++ b/src/command.h @@ -208,6 +208,8 @@ struct CVarList; { __VA_ARGS__, NULL, 0, NULL, NULL, {0, {NULL}}, 0U, (char)0, NULL } #endif +extern consvar_t *consvar_vars; // list of registered console variables + extern CV_PossibleValue_t CV_OnOff[]; extern CV_PossibleValue_t CV_YesNo[]; extern CV_PossibleValue_t CV_Unsigned[]; diff --git a/src/k_menu.h b/src/k_menu.h index 3c39dd8769..875da6535f 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -462,6 +462,7 @@ typedef enum mpause_canceljoin, mpause_spectatemenu, mpause_psetup, + mpause_cheats, mpause_options, mpause_title, diff --git a/src/menus/transient/CMakeLists.txt b/src/menus/transient/CMakeLists.txt index aa13975951..ea38b85056 100644 --- a/src/menus/transient/CMakeLists.txt +++ b/src/menus/transient/CMakeLists.txt @@ -11,4 +11,5 @@ target_sources(SRB2SDL2 PRIVATE pause-kick.c pause-replay.c virtual-keyboard.c + pause-cheats.cpp ) diff --git a/src/menus/transient/pause-cheats.cpp b/src/menus/transient/pause-cheats.cpp new file mode 100644 index 0000000000..92d9a1a1bb --- /dev/null +++ b/src/menus/transient/pause-cheats.cpp @@ -0,0 +1,161 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) 2023 by James Robert Roman +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file menus/transient/pause-cheats.c +/// \brief Cheats directory, for developers + +#include <algorithm> +#include <cstddef> +#include <cstring> +#include <vector> + +#include "../../v_draw.hpp" +#include "../../v_video.h" + +#include "../../command.h" +#include "../../doomtype.h" +#include "../../k_menu.h" +#include "../../screen.h" + +using srb2::Draw; + +namespace +{ + +std::vector<menuitem_t> g_menu; +std::vector<INT32> g_menu_offsets; + +void sort_menu() +{ + std::sort(g_menu.begin(), g_menu.end(), + [](menuitem_t& a, menuitem_t& b) { return std::strcmp(a.text, b.text) < 0; }); + + int old_key = '\0'; + + // Can't use range-for because iterators are invalidated + // by std::vector::insert. + for (std::size_t i = 0; i < g_menu.size(); ++i) + { + int new_key = g_menu[i].text[0]; + + if (new_key == old_key) + { + // Group cvars starting with the same letter + // together. + continue; + } + + old_key = new_key; + + if (i == 0) + { + continue; + } + + constexpr int spacer = 8; + + g_menu.insert( + g_menu.begin() + i, + menuitem_t {IT_SPACE | IT_DYLITLSPACE, nullptr, nullptr, nullptr, {}, spacer, spacer} + ); + + i++; // skip the inserted element + } +} + +void menu_open() +{ + g_menu = {}; + g_menu_offsets = {}; + + for (consvar_t* var = consvar_vars; var; var = var->next) + { + if (!(var->flags & CV_CHEAT)) + { + continue; + } + + UINT16 status = IT_STRING | IT_CVAR; + INT32 height = 8; + + if (!var->PossibleValue && !(var->flags & CV_FLOAT)) + { + status |= IT_CV_STRING; + height += 16; + } + + g_menu.push_back(menuitem_t {status, var->name, nullptr, nullptr, {.cvar = var}, 0, height}); + } + + sort_menu(); + + INT32 y = 0; + + for (menuitem_t& item : g_menu) + { + g_menu_offsets.push_back(y); + y += item.mvar2; + } + + PAUSE_CheatsDef.menuitems = g_menu.data(); + PAUSE_CheatsDef.numitems = g_menu.size(); +} + +boolean menu_close() +{ + PAUSE_CheatsDef.menuitems = nullptr; + PAUSE_CheatsDef.numitems = 0; + + g_menu = {}; + g_menu_offsets = {}; + + return true; +} + +void draw_menu() +{ + auto tooltip = Draw(0, 0); + + tooltip.patch("MENUHINT"); + + const menuitem_t& item = currentMenu->menuitems[itemOn]; + + if (const consvar_t* cvar = item.itemaction.cvar; cvar && cvar->description) + { + tooltip.xy(BASEVIDWIDTH/2, 12).font(Draw::Font::kThin).align(Draw::Align::kCenter).text(cvar->description); + } + + constexpr int kTooltipHeight = 27; + constexpr int kPad = 4; + int y = tooltip.y() + kTooltipHeight + kPad; + + currentMenu->y = std::min(y, (BASEVIDHEIGHT/2) - g_menu_offsets[itemOn]); + + V_SetClipRect(0, y * FRACUNIT, BASEVIDWIDTH * FRACUNIT, (BASEVIDHEIGHT - y - kPad) * FRACUNIT, 0); + M_DrawGenericMenu(); + V_ClearClipRect(); +} + +}; // namespace + +menu_t PAUSE_CheatsDef = { + 0, + &PAUSE_MainDef, + 0, + nullptr, + 48, 0, + 0, 0, + MBF_SOUNDLESS, + nullptr, + 0, 0, + draw_menu, + nullptr, + menu_open, + menu_close, + nullptr, +}; diff --git a/src/menus/transient/pause-game.c b/src/menus/transient/pause-game.c index 7cc349a051..3f69e46556 100644 --- a/src/menus/transient/pause-game.c +++ b/src/menus/transient/pause-game.c @@ -64,6 +64,9 @@ menuitem_t PAUSE_Main[] = {IT_STRING | IT_CALL, "PLAYER SETUP", "M_ICOCHR", NULL, {.routine = M_CharacterSelect}, 0, 0}, + {IT_STRING | IT_SUBMENU, "CHEATS", "M_ICOCHT", + NULL, {.submenu = &PAUSE_CheatsDef}, 0, 0}, + {IT_STRING | IT_CALL, "OPTIONS", "M_ICOOPT", NULL, {.routine = M_InitOptions}, 0, 0}, @@ -135,6 +138,7 @@ void M_OpenPauseMenu(void) PAUSE_Main[mpause_canceljoin].status = IT_DISABLED; PAUSE_Main[mpause_spectatemenu].status = IT_DISABLED; PAUSE_Main[mpause_psetup].status = IT_DISABLED; + PAUSE_Main[mpause_cheats].status = IT_DISABLED; Dummymenuplayer_OnChange(); // Make sure the consvar is within bounds of the amount of splitscreen players we have. @@ -217,6 +221,11 @@ void M_OpenPauseMenu(void) } } + if (CV_CheatsEnabled()) + { + PAUSE_Main[mpause_cheats].status = IT_STRING | IT_SUBMENU; + } + G_ResetAllDeviceRumbles(); } -- GitLab