diff --git a/CMakeLists.txt b/CMakeLists.txt index 8879cd3ab..e7c1d500d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -492,10 +492,10 @@ set(libdevilutionx_SRCS Source/DiabloUI/diabloui.cpp Source/DiabloUI/dialogs.cpp Source/DiabloUI/errorart.cpp - Source/DiabloUI/extrasmenu.cpp Source/DiabloUI/mainmenu.cpp Source/DiabloUI/progress.cpp Source/DiabloUI/scrollbar.cpp + Source/DiabloUI/settingsmenu.cpp Source/DiabloUI/selconn.cpp Source/DiabloUI/selgame.cpp Source/DiabloUI/selhero.cpp diff --git a/Source/DiabloUI/diabloui.h b/Source/DiabloUI/diabloui.h index 3cb5ae0b3..7f7d0430b 100644 --- a/Source/DiabloUI/diabloui.h +++ b/Source/DiabloUI/diabloui.h @@ -33,9 +33,7 @@ enum _mainmenu_selections : uint8_t { MAINMENU_MULTIPLAYER, MAINMENU_REPLAY_INTRO, MAINMENU_SHOW_SUPPORT, - MAINMENU_EXTRAS, - MAINMENU_SWITCHGAME, - MAINMENU_TOGGLESPAWN, + MAINMENU_SETTINGS, MAINMENU_SHOW_CREDITS, MAINMENU_EXIT_DIABLO, MAINMENU_ATTRACT_MODE, diff --git a/Source/DiabloUI/extrasmenu.cpp b/Source/DiabloUI/extrasmenu.cpp deleted file mode 100644 index 846d75d41..000000000 --- a/Source/DiabloUI/extrasmenu.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "selstart.h" - -#include "control.h" -#include "DiabloUI/diabloui.h" -#include "options.h" -#include "utils/language.h" - -namespace devilution { -namespace { - -bool endMenu; - -std::vector> vecDialogItems; -std::vector> vecDialog; - -Art artLogo; - -_mainmenu_selections selectionExtrasMenu; - -void ItemSelected(int value) -{ - selectionExtrasMenu = static_cast<_mainmenu_selections>(vecDialogItems[value]->m_value); - endMenu = true; -} - -void EscPressed() -{ - selectionExtrasMenu = MAINMENU_NONE; - endMenu = true; -} - -} // namespace - -_mainmenu_selections UiExtrasMenu() -{ - LoadBackgroundArt("ui_art\\black.pcx"); - UiAddBackground(&vecDialog); - UiAddLogo(&vecDialog); - - if (diabdat_mpq && hellfire_mpq) - vecDialogItems.push_back(std::make_unique(gbIsHellfire ? _("Switch to Diablo") : _("Switch to Hellfire"), MAINMENU_SWITCHGAME)); - if (diabdat_mpq) - vecDialogItems.push_back(std::make_unique(gbIsSpawn ? _("Switch to Fullgame") : _("Switch to Shareware"), MAINMENU_TOGGLESPAWN)); - vecDialogItems.push_back(std::make_unique(_("Replay Intro"), MAINMENU_REPLAY_INTRO)); - vecDialogItems.push_back(std::make_unique(_("Support"), MAINMENU_SHOW_SUPPORT)); - vecDialogItems.push_back(std::make_unique(_("Previous Menu"), MAINMENU_NONE)); - vecDialog.push_back(std::make_unique(vecDialogItems, PANEL_LEFT + 34, (UI_OFFSET_Y + 240), 570, 43, UiFlags::AlignCenter | UiFlags::FontSize42 | UiFlags::ColorUiGold, 5)); - - UiInitList(vecDialogItems.size(), nullptr, ItemSelected, EscPressed, vecDialog, true); - - endMenu = false; - while (!endMenu) { - UiClearScreen(); - UiRenderItems(vecDialog); - UiPollAndRender(); - } - - ArtBackground.Unload(); - ArtBackgroundWidescreen.Unload(); - vecDialogItems.clear(); - vecDialog.clear(); - - return selectionExtrasMenu; -} - -} // namespace devilution diff --git a/Source/DiabloUI/mainmenu.cpp b/Source/DiabloUI/mainmenu.cpp index 67ec46504..ca9398b4c 100644 --- a/Source/DiabloUI/mainmenu.cpp +++ b/Source/DiabloUI/mainmenu.cpp @@ -35,7 +35,8 @@ void MainmenuLoad(const char *name, void (*fnSound)(const char *file)) vecMenuItems.push_back(std::make_unique(_("Single Player"), MAINMENU_SINGLE_PLAYER)); vecMenuItems.push_back(std::make_unique(_("Multi Player"), MAINMENU_MULTIPLAYER)); - vecMenuItems.push_back(std::make_unique(_("Extras"), MAINMENU_EXTRAS)); + vecMenuItems.push_back(std::make_unique(_("Settings"), MAINMENU_SETTINGS)); + vecMenuItems.push_back(std::make_unique(_("Support"), MAINMENU_SHOW_SUPPORT)); vecMenuItems.push_back(std::make_unique(_("Show Credits"), MAINMENU_SHOW_CREDITS)); vecMenuItems.push_back(std::make_unique(gbIsHellfire ? _("Exit Hellfire") : _("Exit Diablo"), MAINMENU_EXIT_DIABLO)); diff --git a/Source/DiabloUI/settingsmenu.cpp b/Source/DiabloUI/settingsmenu.cpp new file mode 100644 index 000000000..06fdf9733 --- /dev/null +++ b/Source/DiabloUI/settingsmenu.cpp @@ -0,0 +1,174 @@ +#include "selstart.h" + +#include "control.h" +#include "DiabloUI/diabloui.h" +#include "DiabloUI/scrollbar.h" +#include "hwcursor.hpp" +#include "options.h" +#include "utils/language.h" + +namespace devilution { +namespace { + +bool endMenu = false; +bool recreateUI = false; + +std::vector> vecDialogItems; +std::vector> vecDialog; +std::vector vecOptions; + +char optionDescription[256]; + +Rectangle rectDescription; + +enum class SpecialMenuEntry { + None = -1, + PreviousMenu = -2, + SwitchGame = -3, + ToggleSpawn = -4, +}; + +bool IsValidEntry(OptionEntryBase *pOptionEntry) +{ + return HasNoneOf(pOptionEntry->GetFlags(), OptionEntryFlags::Invisible | (gbIsHellfire ? OptionEntryFlags::OnlyDiablo : OptionEntryFlags::OnlyHellfire)); +} + +void ItemFocused(int value) +{ + auto &vecItem = vecDialogItems[value]; + optionDescription[0] = '\0'; + if (vecItem->m_value < 0) { + return; + } + auto *pOption = vecOptions[vecItem->m_value]; + auto paragraphs = WordWrapString(pOption->GetDescription(), rectDescription.size.width, GameFont12, 1); + strncpy(optionDescription, paragraphs.c_str(), sizeof(optionDescription)); +} + +void ItemSelected(int value) +{ + auto &vecItem = vecDialogItems[value]; + if (vecItem->m_value < 0) { + auto specialMenuEntry = static_cast(vecItem->m_value); + switch (specialMenuEntry) { + case SpecialMenuEntry::PreviousMenu: + endMenu = true; + break; + case SpecialMenuEntry::SwitchGame: + gbIsHellfire = !gbIsHellfire; + endMenu = true; + recreateUI = true; + break; + case SpecialMenuEntry::ToggleSpawn: + gbIsSpawn = !gbIsSpawn; + UiSetSpawned(gbIsSpawn); + endMenu = true; + recreateUI = true; + break; + } + return; + } + + auto *pOption = vecOptions[vecItem->m_value]; + switch (pOption->GetType()) { + case OptionEntryType::Boolean: { + auto *pOptionBoolean = static_cast(pOption); + pOptionBoolean->SetValue(!**pOptionBoolean); + } break; + case OptionEntryType::List: { + auto *pOptionList = static_cast(pOption); + size_t nextIndex = pOptionList->GetActiveListIndex() + 1; + if (nextIndex >= pOptionList->GetListSize()) + nextIndex = 0; + pOptionList->SetActiveListIndex(nextIndex); + } break; + } + vecDialogItems[value + 1]->m_text = pOption->GetValueDescription().data(); +} + +void EscPressed() +{ + endMenu = true; +} + +} // namespace + +void UiSettingsMenu() +{ + endMenu = false; + + do { + LoadBackgroundArt("ui_art\\black.pcx"); + LoadScrollBar(); + UiAddBackground(&vecDialog); + UiAddLogo(&vecDialog); + + Rectangle rectList = { { PANEL_LEFT + 50, (UI_OFFSET_Y + 204) }, { 540, 208 } }; + rectDescription = { { PANEL_LEFT + 24, rectList.position.y + rectList.size.height + 20 }, { 590, 35 } }; + + optionDescription[0] = '\0'; + + const char *titleText = _("Settings"); + vecDialog.push_back(std::make_unique(titleText, MakeSdlRect(PANEL_LEFT, UI_OFFSET_Y + 161, PANEL_WIDTH, 35), UiFlags::FontSize30 | UiFlags::ColorUiSilver | UiFlags::AlignCenter, 8)); + vecDialog.push_back(std::make_unique(&ArtScrollBarBackground, &ArtScrollBarThumb, &ArtScrollBarArrow, MakeSdlRect(rectList.position.x + rectList.size.width + 5, rectList.position.y, 25, rectList.size.height))); + vecDialog.push_back(std::make_unique(optionDescription, MakeSdlRect(rectDescription), UiFlags::FontSize12 | UiFlags::ColorUiSilverDark | UiFlags::AlignCenter, 1)); + + if (diabdat_mpq && hellfire_mpq) + vecDialogItems.push_back(std::make_unique(gbIsHellfire ? _("Switch to Diablo") : _("Switch to Hellfire"), static_cast(SpecialMenuEntry::SwitchGame), UiFlags::ColorUiGold)); + if (diabdat_mpq) + vecDialogItems.push_back(std::make_unique(gbIsSpawn ? _("Switch to Fullgame") : _("Switch to Shareware"), static_cast(SpecialMenuEntry::ToggleSpawn), UiFlags::ColorUiGold)); + + bool switchOptionExists = vecDialogItems.size() > 0; + int catCount = switchOptionExists ? 1 : 0; + for (auto *pCategory : sgOptions.GetCategories()) { + bool categoryCreated = false; + for (auto *pEntry : pCategory->GetEntries()) { + if (!IsValidEntry(pEntry)) + continue; + if (!categoryCreated) { + if (catCount > 0) + vecDialogItems.push_back(std::make_unique("", -1, UiFlags::ElementDisabled)); + catCount += 1; + vecDialogItems.push_back(std::make_unique(pCategory->GetName().data(), static_cast(SpecialMenuEntry::None), UiFlags::ColorWhitegold | UiFlags::ElementDisabled)); + categoryCreated = true; + } + vecDialogItems.push_back(std::make_unique(pEntry->GetName().data(), vecOptions.size(), UiFlags::ColorUiGold | UiFlags::NeedsNextElement)); + vecDialogItems.push_back(std::make_unique(pEntry->GetValueDescription().data(), vecOptions.size(), UiFlags::ColorUiSilver | UiFlags::ElementDisabled)); + vecOptions.push_back(pEntry); + } + } + + vecDialogItems.push_back(std::make_unique("", -1, UiFlags::ElementDisabled)); + vecDialogItems.push_back(std::make_unique(_("Previous Menu"), static_cast(SpecialMenuEntry::PreviousMenu), UiFlags::ColorUiGold)); + + vecDialog.push_back(std::make_unique(vecDialogItems, rectList.position.x, rectList.position.y, rectList.size.width, 26, UiFlags::FontSize24 | UiFlags::AlignCenter)); + + UiInitList(rectList.size.height / 26, ItemFocused, ItemSelected, EscPressed, vecDialog, true, nullptr, switchOptionExists ? 0 : 1); + + while (!endMenu) { + UiClearScreen(); + UiRenderItems(vecDialog); + UiPollAndRender(); + } + + vecDialogItems.clear(); + vecDialog.clear(); + vecOptions.clear(); + + ArtBackground.Unload(); + ArtBackgroundWidescreen.Unload(); + UnloadScrollBar(); + + if (recreateUI) { + UiInitialize(); + FreeItemGFX(); + InitItemGFX(); + if (IsHardwareCursor()) + SetHardwareCursor(CursorInfo::UnknownCursor()); + recreateUI = false; + endMenu = false; + } + } while (!endMenu); +} + +} // namespace devilution diff --git a/Source/DiabloUI/extrasmenu.h b/Source/DiabloUI/settingsmenu.h similarity index 67% rename from Source/DiabloUI/extrasmenu.h rename to Source/DiabloUI/settingsmenu.h index b5bf2adc5..c48c1b9ea 100644 --- a/Source/DiabloUI/extrasmenu.h +++ b/Source/DiabloUI/settingsmenu.h @@ -1,9 +1,9 @@ -#pragma once - -#include "DiabloUI/diabloui.h" - -namespace devilution { - -_mainmenu_selections UiExtrasMenu(); - -} // namespace devilution +#pragma once + +#include "DiabloUI/diabloui.h" + +namespace devilution { + +void UiSettingsMenu(); + +} // namespace devilution diff --git a/Source/menu.cpp b/Source/menu.cpp index bf3654e3d..48435410f 100644 --- a/Source/menu.cpp +++ b/Source/menu.cpp @@ -5,10 +5,8 @@ */ #include "DiabloUI/diabloui.h" -#include "DiabloUI/extrasmenu.h" -#include "DiabloUI/selok.h" +#include "DiabloUI/settingsmenu.h" #include "engine/demomode.h" -#include "hwcursor.hpp" #include "init.h" #include "movie.h" #include "options.h" @@ -141,18 +139,16 @@ void mainmenu_wait_for_button_sound() void mainmenu_loop() { bool done; - _mainmenu_selections menu = MAINMENU_NONE; RefreshMusic(); done = false; do { - if (menu == MAINMENU_NONE) { - if (demo::IsRunning()) - menu = MAINMENU_SINGLE_PLAYER; - else if (!UiMainMenuDialog(gszProductName, &menu, effects_play_sound, 30)) - app_fatal("%s", _("Unable to display mainmenu")); - } + _mainmenu_selections menu = MAINMENU_NONE; + if (demo::IsRunning()) + menu = MAINMENU_SINGLE_PLAYER; + else if (!UiMainMenuDialog(gszProductName, &menu, effects_play_sound, 30)) + app_fatal("%s", _("Unable to display mainmenu")); switch (menu) { case MAINMENU_NONE: @@ -160,60 +156,29 @@ void mainmenu_loop() case MAINMENU_SINGLE_PLAYER: if (!InitSinglePlayerMenu()) done = true; - menu = MAINMENU_NONE; break; case MAINMENU_MULTIPLAYER: if (!InitMultiPlayerMenu()) done = true; - menu = MAINMENU_NONE; break; case MAINMENU_ATTRACT_MODE: if (gbIsSpawn && !diabdat_mpq) done = false; else if (gbActive) PlayIntro(); - menu = MAINMENU_NONE; - break; - case MAINMENU_REPLAY_INTRO: - if (gbIsSpawn && !diabdat_mpq && !hellfire_mpq) { - UiSelOkDialog(nullptr, _(/* TRANSLATORS: Error Message when a Shareware User clicks on "Replay Intro" in the Main Menu */ "The Diablo introduction cinematic is only available in the full retail version of Diablo. Visit https://www.gog.com/game/diablo to purchase."), true); - } else if (gbActive) { - mainmenu_wait_for_button_sound(); - PlayIntro(); - } - menu = MAINMENU_EXTRAS; break; case MAINMENU_SHOW_CREDITS: UiCreditsDialog(); - menu = MAINMENU_NONE; break; case MAINMENU_SHOW_SUPPORT: UiSupportDialog(); - menu = MAINMENU_EXTRAS; break; case MAINMENU_EXIT_DIABLO: mainmenu_wait_for_button_sound(); done = true; break; - case MAINMENU_EXTRAS: - menu = UiExtrasMenu(); - break; - case MAINMENU_SWITCHGAME: - gbIsHellfire = !gbIsHellfire; - sgOptions.Hellfire.startUpGameOption = gbIsHellfire ? StartUpGameOption::Hellfire : StartUpGameOption::Diablo; - UiInitialize(); - FreeItemGFX(); - InitItemGFX(); - if (IsHardwareCursor()) - SetHardwareCursor(CursorInfo::UnknownCursor()); - RefreshMusic(); - menu = MAINMENU_NONE; - break; - case MAINMENU_TOGGLESPAWN: - gbIsSpawn = !gbIsSpawn; - UiSetSpawned(gbIsSpawn); - RefreshMusic(); - menu = MAINMENU_NONE; + case MAINMENU_SETTINGS: + UiSettingsMenu(); break; } } while (!done);