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 000000000..59b611b4d Binary files /dev/null and b/assets/fonts/30-e0.clx differ