From aca06e898afdd89eff2f2cda540b192e90157cdf Mon Sep 17 00:00:00 2001 From: Eric Robinson <68359262+kphoenix137@users.noreply.github.com> Date: Sat, 15 Mar 2025 16:53:36 -0400 Subject: [PATCH] Menu text revision (#3902) --- CMake/Assets.cmake | 1 + Source/control.cpp | 58 ++++++++++++++++++++++++++++++ Source/control.h | 1 + Source/diablo.cpp | 14 +++++++- Source/engine/render/scrollrt.cpp | 7 ++-- Source/gamemenu.cpp | 39 ++++++++++---------- Source/gamemenu.h | 1 + Source/player.cpp | 4 +-- assets/fonts/30-e0.clx | Bin 0 -> 30339 bytes 9 files changed, 98 insertions(+), 27 deletions(-) create mode 100644 assets/fonts/30-e0.clx diff --git a/CMake/Assets.cmake b/CMake/Assets.cmake index 7e41fc39f..d2e1b0e72 100644 --- a/CMake/Assets.cmake +++ b/CMake/Assets.cmake @@ -99,6 +99,7 @@ set(devilutionx_assets fonts/30-03.clx fonts/30-04.clx fonts/30-20.clx + fonts/30-e0.clx fonts/42-00.clx fonts/42-01.clx fonts/42-02.clx diff --git a/Source/control.cpp b/Source/control.cpp index 5e120f674..cb046f8ee 100644 --- a/Source/control.cpp +++ b/Source/control.cpp @@ -44,6 +44,7 @@ #include "panels/spell_book.hpp" #include "panels/spell_icons.hpp" #include "panels/spell_list.hpp" +#include "pfile.h" #include "playerdat.hpp" #include "qol/stash.h" #include "qol/xpbar.h" @@ -1180,6 +1181,19 @@ void CheckMainPanelButtonUp() DoAutoMap(); break; case PanelButtonMainmenu: + if (MyPlayerIsDead) { + if (!gbIsMultiplayer) { + if (gbValidSaveFile) + gamemenu_load_game(false); + else + gamemenu_exit_game(false); + } else { + NetSendCmd(true, CMD_RETOWN); + } + break; + } else if (MyPlayer->_pHitPoints == 0) { + break; + } qtextflag = false; gamemenu_handle_previous(); gamemenuOff = false; @@ -1414,6 +1428,50 @@ void RedBack(const Surface &out) } } +void DrawDeathText(const Surface &out) +{ + const TextRenderOptions largeTextOptions { + .flags = UiFlags::FontSize42 | UiFlags::ColorGold | UiFlags::AlignCenter | UiFlags::VerticalCenter, + .spacing = 2 + }; + const TextRenderOptions smallTextOptions { + .flags = UiFlags::FontSize30 | UiFlags::ColorGold | UiFlags::AlignCenter | UiFlags::VerticalCenter, + .spacing = 2 + }; + std::string text; + int verticalPadding = 42; + Point linePosition { 0, gnScreenHeight / 2 - (verticalPadding * 2) }; + + text = _("You have died"); + DrawString(out, text, linePosition, largeTextOptions); + linePosition.y += verticalPadding; + + std::string buttonText; + + switch (ControlMode) { + case ControlTypes::KeyboardAndMouse: + buttonText = _("ESC"); + break; + case ControlTypes::Gamepad: + buttonText = ToString(GamepadType, ControllerButton_BUTTON_START); + break; + case ControlTypes::VirtualGamepad: + buttonText = _("Menu Button"); + break; + } + + if (!gbIsMultiplayer) { + if (gbValidSaveFile) + text = fmt::format(fmt::runtime(_("Press {} to load last save.")), buttonText); + else + text = fmt::format(fmt::runtime(_("Press {} to return to Main Menu.")), buttonText); + + } else { + text = fmt::format(fmt::runtime(_("Press {} to restart in town.")), buttonText); + } + DrawString(out, text, linePosition, smallTextOptions); +} + void DrawGoldSplit(const Surface &out) { const int dialogX = 30; diff --git a/Source/control.h b/Source/control.h index d4e29a4f3..ffb66300d 100644 --- a/Source/control.h +++ b/Source/control.h @@ -175,6 +175,7 @@ void CheckChrBtns(); void ReleaseChrBtns(bool addAllStatPoints); void DrawDurIcon(const Surface &out); void RedBack(const Surface &out); +void DrawDeathText(const Surface &out); void DrawSpellBook(const Surface &out); void DrawGoldSplit(const Surface &out); void control_drop_gold(SDL_Keycode vkey); diff --git a/Source/diablo.cpp b/Source/diablo.cpp index 6664a2199..9f0284db3 100644 --- a/Source/diablo.cpp +++ b/Source/diablo.cpp @@ -490,6 +490,17 @@ void PressKey(SDL_Keycode vkey, uint16_t modState) } if (MyPlayerIsDead) { + if (vkey == SDLK_ESCAPE) { + if (!gbIsMultiplayer) { + if (gbValidSaveFile) + gamemenu_load_game(false); + else + gamemenu_exit_game(false); + } else { + NetSendCmd(true, CMD_RETOWN); + } + return; + } if (sgnTimeoutCurs != CURSOR_NONE) { return; } @@ -506,7 +517,8 @@ void PressKey(SDL_Keycode vkey, uint16_t modState) return; } } - if (vkey == SDLK_ESCAPE) { + // Disallow player from accessing escape menu during the frames before the death message appears + if (vkey == SDLK_ESCAPE && MyPlayer->_pHitPoints > 0) { if (!PressEscKey()) { LastMouseButtonAction = MouseActionType::None; gamemenu_on(); diff --git a/Source/engine/render/scrollrt.cpp b/Source/engine/render/scrollrt.cpp index 797f17f20..1a573d7d4 100644 --- a/Source/engine/render/scrollrt.cpp +++ b/Source/engine/render/scrollrt.cpp @@ -1286,14 +1286,15 @@ void DrawView(const Surface &out, Point startPosition) if (ChatLogFlag) { DrawChatLog(out); } - if (IsDiabloMsgAvailable()) { - DrawDiabloMsg(out.subregionY(0, out.h() - GetMainPanel().size.height)); - } if (MyPlayerIsDead) { RedBack(out); + DrawDeathText(out); } else if (PauseMode != 0) { gmenu_draw_pause(out); } + if (IsDiabloMsgAvailable()) { + DrawDiabloMsg(out.subregionY(0, out.h() - GetMainPanel().size.height)); + } DrawControllerModifierHints(out); DrawPlrMsg(out); diff --git a/Source/gamemenu.cpp b/Source/gamemenu.cpp index 2cce3d8d6..ecb744591 100644 --- a/Source/gamemenu.cpp +++ b/Source/gamemenu.cpp @@ -44,24 +44,23 @@ void GamemenuSpeed(bool bActivate); /** Contains the game menu items of the single player menu. */ TMenuItem sgSingleMenu[] = { // clang-format off - // dwFlags, pszStr, fnMenu - { GMENU_ENABLED, N_("Save Game"), &gamemenu_save_game }, - { GMENU_ENABLED, N_("Options"), &GamemenuOptions }, - { GMENU_ENABLED, N_("New Game"), &GamemenuNewGame }, - { GMENU_ENABLED, N_("Load Game"), &gamemenu_load_game }, - { GMENU_ENABLED, N_("Quit Game"), &gamemenu_quit_game }, - { GMENU_ENABLED, nullptr, nullptr } + // dwFlags, pszStr, fnMenu + { GMENU_ENABLED, N_("Options"), &GamemenuOptions }, + { GMENU_ENABLED, N_("Save Game"), &gamemenu_save_game }, + { GMENU_ENABLED, N_("Load Game"), &gamemenu_load_game }, + { GMENU_ENABLED, N_("Exit to Main Menu"), &GamemenuNewGame }, + { GMENU_ENABLED, N_("Quit Game"), &gamemenu_quit_game }, + { GMENU_ENABLED, nullptr, nullptr }, // clang-format on }; /** Contains the game menu items of the multi player menu. */ TMenuItem sgMultiMenu[] = { // clang-format off - // dwFlags, pszStr, fnMenu - { GMENU_ENABLED, N_("Options"), &GamemenuOptions }, - { GMENU_ENABLED, N_("New Game"), &GamemenuNewGame }, - { GMENU_ENABLED, N_("Restart In Town"), &GamemenuRestartTown }, - { GMENU_ENABLED, N_("Quit Game"), &gamemenu_quit_game }, - { GMENU_ENABLED, nullptr, nullptr }, + // dwFlags, pszStr, fnMenu + { GMENU_ENABLED, N_("Options"), &GamemenuOptions }, + { GMENU_ENABLED, N_("Exit to Main Menu"), &GamemenuNewGame }, + { GMENU_ENABLED, N_("Quit Game"), &gamemenu_quit_game }, + { GMENU_ENABLED, nullptr, nullptr }, // clang-format on }; TMenuItem sgOptionsMenu[] = { @@ -88,18 +87,13 @@ const char *const SoundToggleNames[] = { void GamemenuUpdateSingle() { - sgSingleMenu[3].setEnabled(gbValidSaveFile); + sgSingleMenu[2].setEnabled(gbValidSaveFile); bool enable = MyPlayer->_pmode != PM_DEATH && !MyPlayerIsDead; sgSingleMenu[0].setEnabled(enable); } -void GamemenuUpdateMulti() -{ - sgMultiMenu[2].setEnabled(MyPlayerIsDead); -} - void GamemenuPrevious(bool /*bActivate*/) { gamemenu_on(); @@ -286,6 +280,11 @@ void GamemenuSpeed(bool bActivate) } // namespace +void gamemenu_exit_game(bool bActivate) +{ + GamemenuNewGame(bActivate); +} + void gamemenu_quit_game(bool bActivate) { GamemenuNewGame(bActivate); @@ -368,7 +367,7 @@ void gamemenu_on() if (!gbIsMultiplayer) { gmenu_set_items(sgSingleMenu, GamemenuUpdateSingle); } else { - gmenu_set_items(sgMultiMenu, GamemenuUpdateMulti); + gmenu_set_items(sgMultiMenu, nullptr); } PressEscKey(); } diff --git a/Source/gamemenu.h b/Source/gamemenu.h index 070ebafea..1b6abd731 100644 --- a/Source/gamemenu.h +++ b/Source/gamemenu.h @@ -10,6 +10,7 @@ namespace devilution { void gamemenu_on(); void gamemenu_off(); void gamemenu_handle_previous(); +void gamemenu_exit_game(bool bActivate); void gamemenu_quit_game(bool bActivate); void gamemenu_load_game(bool bActivate); void gamemenu_save_game(bool bActivate); diff --git a/Source/player.cpp b/Source/player.cpp index f12ce69cd..953cd1fad 100644 --- a/Source/player.cpp +++ b/Source/player.cpp @@ -1037,9 +1037,6 @@ bool DoDeath(Player &player) dFlags[player.position.tile.x][player.position.tile.y] |= DungeonFlag::DeadPlayer; } else if (&player == MyPlayer && player.AnimInfo.tickCounterOfCurrentFrame == 30) { MyPlayerIsDead = true; - if (!gbIsMultiplayer) { - gamemenu_on(); - } } } @@ -2619,6 +2616,7 @@ StartPlayerKill(Player &player, DeathReason deathReason) if (&player == MyPlayer) { NetSendCmdParam1(true, CMD_PLRDEAD, static_cast(deathReason)); + gamemenu_off(); } const bool dropGold = !gbIsMultiplayer || !(player.isOnLevel(16) || player.isOnArenaLevel()); diff --git a/assets/fonts/30-e0.clx b/assets/fonts/30-e0.clx new file mode 100644 index 0000000000000000000000000000000000000000..59b611b4dc02aaa144273bdb3dac383124013639 GIT binary patch literal 30339 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