diff --git a/Source/DiabloUI/diabloui.cpp b/Source/DiabloUI/diabloui.cpp index b9d754f26..f5d0873bc 100644 --- a/Source/DiabloUI/diabloui.cpp +++ b/Source/DiabloUI/diabloui.cpp @@ -23,6 +23,7 @@ #include "engine/render/clx_render.hpp" #include "engine/ticks.hpp" #include "hwcursor.hpp" +#include "init.h" #include "utils/algorithm/container.hpp" #include "utils/display.h" #include "utils/is_of.hpp" diff --git a/Source/DiabloUI/dialogs.cpp b/Source/DiabloUI/dialogs.cpp index 4b60e8a27..1f3a6162c 100644 --- a/Source/DiabloUI/dialogs.cpp +++ b/Source/DiabloUI/dialogs.cpp @@ -14,7 +14,9 @@ #include "engine/load_clx.hpp" #include "engine/load_pcx.hpp" #include "engine/palette.h" +#include "headless_mode.hpp" #include "hwcursor.hpp" +#include "init.h" #include "utils/display.h" #include "utils/is_of.hpp" #include "utils/language.h" diff --git a/Source/DiabloUI/hero/selhero.cpp b/Source/DiabloUI/hero/selhero.cpp index 109e7d631..350626546 100644 --- a/Source/DiabloUI/hero/selhero.cpp +++ b/Source/DiabloUI/hero/selhero.cpp @@ -15,6 +15,7 @@ #include "DiabloUI/selyesno.h" #include "control.h" #include "controls/plrctrls.h" +#include "engine/assets.hpp" #include "game_mode.hpp" #include "menu.h" #include "options.h" @@ -161,10 +162,10 @@ void SelheroListSelect(size_t value) vecSelHeroDlgItems.push_back(std::make_unique(_("Sorcerer"), static_cast(HeroClass::Sorcerer))); if (gbIsHellfire) { vecSelHeroDlgItems.push_back(std::make_unique(_("Monk"), static_cast(HeroClass::Monk))); - if (gbBard || *sgOptions.Gameplay.testBard) { + if (HaveBardAssets() || *sgOptions.Gameplay.testBard) { vecSelHeroDlgItems.push_back(std::make_unique(_("Bard"), static_cast(HeroClass::Bard))); } - if (gbBarbarian || *sgOptions.Gameplay.testBarbarian) { + if (HaveBarbarianAssets() || *sgOptions.Gameplay.testBarbarian) { vecSelHeroDlgItems.push_back(std::make_unique(_("Barbarian"), static_cast(HeroClass::Barbarian))); } } @@ -263,7 +264,7 @@ void AddSelHeroBackground() void SelheroClassSelectorSelect(size_t value) { auto hClass = static_cast(vecSelHeroDlgItems[value]->m_value); - if (gbIsSpawn && (hClass == HeroClass::Rogue || hClass == HeroClass::Sorcerer || (hClass == HeroClass::Bard && !gbBard))) { + if (gbIsSpawn && (hClass == HeroClass::Rogue || hClass == HeroClass::Sorcerer || (hClass == HeroClass::Bard && !HaveBardAssets()))) { RemoveSelHeroBackground(); UiSelOkDialog(nullptr, _("The Rogue and Sorcerer are only available in the full retail version of Diablo. Visit https://www.gog.com/game/diablo to purchase.").data(), false); AddSelHeroBackground(); diff --git a/Source/DiabloUI/mainmenu.cpp b/Source/DiabloUI/mainmenu.cpp index d36ff3b2e..0e8e6a13a 100644 --- a/Source/DiabloUI/mainmenu.cpp +++ b/Source/DiabloUI/mainmenu.cpp @@ -3,6 +3,7 @@ #include "DiabloUI/diabloui.h" #include "DiabloUI/selok.h" #include "control.h" +#include "engine/assets.hpp" #include "engine/load_clx.hpp" #include "game_mode.hpp" #include "utils/language.h" diff --git a/Source/DiabloUI/settingsmenu.cpp b/Source/DiabloUI/settingsmenu.cpp index 37ae41426..81f008749 100644 --- a/Source/DiabloUI/settingsmenu.cpp +++ b/Source/DiabloUI/settingsmenu.cpp @@ -2,6 +2,7 @@ #include #include +#include #include @@ -11,6 +12,7 @@ #include "controls/controller_motion.h" #include "controls/plrctrls.h" #include "controls/remap_keyboard.h" +#include "engine/assets.hpp" #include "engine/render/text_render.hpp" #include "hwcursor.hpp" #include "options.h" diff --git a/Source/appfat.cpp b/Source/appfat.cpp index 938f35902..637d341c0 100644 --- a/Source/appfat.cpp +++ b/Source/appfat.cpp @@ -49,15 +49,15 @@ void FreeDlg() SNetDestroy(); } -[[noreturn]] void DisplayFatalErrorAndExit(std::string_view title, std::string_view body) +} // namespace + +void DisplayFatalErrorAndExit(std::string_view title, std::string_view body) { FreeDlg(); UiErrorOkDialog(title, body); diablo_quit(1); } -} // namespace - void app_fatal(std::string_view str) { DisplayFatalErrorAndExit(_("Error"), str); diff --git a/Source/appfat.h b/Source/appfat.h index 285c368ed..2eb29c8e2 100644 --- a/Source/appfat.h +++ b/Source/appfat.h @@ -21,6 +21,13 @@ namespace devilution { #define assert(exp) (void)((exp) || (assert_fail(__LINE__, __FILE__, #exp), 0)) #endif +/** + * @brief Terminates the game and displays an error message box. + * @param str Message box title. + * @param str Error message. + */ +[[noreturn]] void DisplayFatalErrorAndExit(std::string_view title, std::string_view body); + /** * @brief Terminates the game and displays an error message box. * @param str Error message. diff --git a/Source/capture.cpp b/Source/capture.cpp index 856263d76..2cc286a6e 100644 --- a/Source/capture.cpp +++ b/Source/capture.cpp @@ -46,7 +46,7 @@ SDL_RWops *CaptureFile(std::string *dstPath) const std::tm *tm = std::localtime(&tt); const std::string filename = tm != nullptr ? fmt::format("Screenshot from {:04}-{:02}-{:02} {:02}-{:02}-{:02}", - tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec) + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec) : "Screenshot"; *dstPath = StrCat(paths::PrefPath(), filename, ext); int i = 0; diff --git a/Source/control.cpp b/Source/control.cpp index 3d1f126bc..261ce0387 100644 --- a/Source/control.cpp +++ b/Source/control.cpp @@ -29,7 +29,6 @@ #include "engine/trn.hpp" #include "gamemenu.h" #include "headless_mode.hpp" -#include "init.h" #include "inv.h" #include "inv_iterators.hpp" #include "levels/setmaps.h" diff --git a/Source/diablo.cpp b/Source/diablo.cpp index 968bef574..94c34600e 100644 --- a/Source/diablo.cpp +++ b/Source/diablo.cpp @@ -12,6 +12,7 @@ #include #include "DiabloUI/selstart.h" +#include "appfat.h" #include "automap.h" #include "capture.h" #include "control.h" @@ -124,8 +125,6 @@ bool gbProcessPlayers; bool gbLoadGame; bool cineflag; int PauseMode; -bool gbBard; -bool gbBarbarian; clicktype sgbMouseDown; uint16_t gnTickDelay = 50; char gszProductName[64] = "DevilutionX vUnknown"; diff --git a/Source/diablo.h b/Source/diablo.h index e742e2561..3ea16a521 100644 --- a/Source/diablo.h +++ b/Source/diablo.h @@ -7,6 +7,12 @@ #include +#include + +#ifdef USE_SDL1 +#include "utils/sdl2_to_1_2_backports.h" +#endif + #ifdef _DEBUG #include "monstdat.h" #endif @@ -69,8 +75,6 @@ extern bool cineflag; /* These are defined in fonts.h */ extern void FontsCleanup(); extern DVL_API_FOR_TEST int PauseMode; -extern bool gbBard; -extern bool gbBarbarian; extern clicktype sgbMouseDown; extern uint16_t gnTickDelay; extern char gszProductName[64]; diff --git a/Source/discord/discord.cpp b/Source/discord/discord.cpp index 6353facb6..160d735d1 100644 --- a/Source/discord/discord.cpp +++ b/Source/discord/discord.cpp @@ -17,7 +17,7 @@ #include #include "config.h" -#include "init.h" +#include "game_mode.hpp" #include "levels/gendung.h" #include "levels/setmaps.h" #include "multi.h" diff --git a/Source/dvlnet/packet.h b/Source/dvlnet/packet.h index e407d62d9..a8e675d27 100644 --- a/Source/dvlnet/packet.h +++ b/Source/dvlnet/packet.h @@ -16,6 +16,7 @@ #include "appfat.h" #include "dvlnet/abstract_net.h" #include "utils/attributes.h" +#include "utils/endian_read.hpp" #include "utils/endian_write.hpp" #include "utils/str_cat.hpp" #include "utils/stubs.h" diff --git a/Source/effects.cpp b/Source/effects.cpp index 24cadcd75..838eb74c5 100644 --- a/Source/effects.cpp +++ b/Source/effects.cpp @@ -17,7 +17,7 @@ #include "engine/sound.h" #include "engine/sound_defs.hpp" #include "engine/sound_position.hpp" -#include "init.h" +#include "game_mode.hpp" #include "player.h" #include "utils/is_of.hpp" diff --git a/Source/engine/assets.cpp b/Source/engine/assets.cpp index f5caa393e..560d15ef0 100644 --- a/Source/engine/assets.cpp +++ b/Source/engine/assets.cpp @@ -5,11 +5,17 @@ #include #include +#include "appfat.h" #include "game_mode.hpp" #include "utils/file_util.h" #include "utils/log.hpp" #include "utils/paths.h" #include "utils/str_cat.hpp" +#include "utils/str_split.hpp" + +#if defined(_WIN32) && !defined(__UWP__) && !defined(DEVILUTIONX_WINDOWS_NO_WCHAR) +#include +#endif #ifndef UNPACKED_MPQS #include "mpq/mpq_sdl_rwops.hpp" @@ -258,4 +264,207 @@ std::string FailedToOpenFileErrorMessage(std::string_view path, std::string_view return fmt::format(fmt::runtime(_("Failed to open file:\n{:s}\n\n{:s}\n\nThe MPQ file(s) might be damaged. Please check the file integrity.")), path, error); } +namespace { +#ifdef UNPACKED_MPQS +std::optional FindUnpackedMpqData(const std::vector &paths, std::string_view mpqName) +{ + std::string targetPath; + for (const std::string &path : paths) { + targetPath.clear(); + targetPath.reserve(path.size() + mpqName.size() + 1); + targetPath.append(path).append(mpqName) += DirectorySeparator; + if (FileExists(targetPath)) { + LogVerbose(" Found unpacked MPQ directory: {}", targetPath); + return targetPath; + } + } + return std::nullopt; +} +#else +std::optional LoadMPQ(const std::vector &paths, std::string_view mpqName) +{ + std::optional archive; + std::string mpqAbsPath; + std::int32_t error = 0; + for (const auto &path : paths) { + mpqAbsPath = path + mpqName.data(); + if ((archive = MpqArchive::Open(mpqAbsPath.c_str(), error))) { + LogVerbose(" Found: {} in {}", mpqName, path); + return archive; + } + if (error != 0) { + LogError("Error {}: {}", MpqArchive::ErrorMessage(error), mpqAbsPath); + } + } + if (error == 0) { + LogVerbose("Missing: {}", mpqName); + } + + return std::nullopt; +} +#endif + +std::vector GetMPQSearchPaths() +{ + std::vector paths; + paths.push_back(paths::BasePath()); + paths.push_back(paths::PrefPath()); + if (paths[0] == paths[1]) + paths.pop_back(); + paths.push_back(paths::ConfigPath()); + if (paths[0] == paths[1] || (paths.size() == 3 && (paths[0] == paths[2] || paths[1] == paths[2]))) + paths.pop_back(); + +#if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__) + // `XDG_DATA_HOME` is usually the root path of `paths::PrefPath()`, so we only + // add `XDG_DATA_DIRS`. + const char *xdgDataDirs = std::getenv("XDG_DATA_DIRS"); + if (xdgDataDirs != nullptr) { + for (const std::string_view path : SplitByChar(xdgDataDirs, ':')) { + std::string fullPath(path); + if (!path.empty() && path.back() != '/') + fullPath += '/'; + fullPath.append("diasurgical/devilutionx/"); + paths.push_back(std::move(fullPath)); + } + } else { + paths.emplace_back("/usr/local/share/diasurgical/devilutionx/"); + paths.emplace_back("/usr/share/diasurgical/devilutionx/"); + } +#elif defined(NXDK) + paths.emplace_back("D:\\"); +#elif defined(_WIN32) && !defined(__UWP__) && !defined(DEVILUTIONX_WINDOWS_NO_WCHAR) + char gogpath[_FSG_PATH_MAX]; + fsg_get_gog_game_path(gogpath, "1412601690"); + if (strlen(gogpath) > 0) { + paths.emplace_back(std::string(gogpath) + "/"); + paths.emplace_back(std::string(gogpath) + "/hellfire/"); + } +#endif + + if (paths.empty() || !paths.back().empty()) { + paths.emplace_back(); // PWD + } + + if (SDL_LOG_PRIORITY_VERBOSE >= SDL_LogGetPriority(SDL_LOG_CATEGORY_APPLICATION)) { + LogVerbose("Paths:\n base: {}\n pref: {}\n config: {}\n assets: {}", + paths::BasePath(), paths::PrefPath(), paths::ConfigPath(), paths::AssetsPath()); + + std::string message; + for (std::size_t i = 0; i < paths.size(); ++i) { + message.append(fmt::format("\n{:6d}. '{}'", i + 1, paths[i])); + } + LogVerbose("MPQ search paths:{}", message); + } + + return paths; +} + +} // namespace + +void LoadCoreArchives() +{ + auto paths = GetMPQSearchPaths(); + +#ifdef UNPACKED_MPQS + font_data_path = FindUnpackedMpqData(paths, "fonts"); +#else // !UNPACKED_MPQS +#if !defined(__ANDROID__) && !defined(__APPLE__) && !defined(__3DS__) && !defined(__SWITCH__) + // Load devilutionx.mpq first to get the font file for error messages + devilutionx_mpq = LoadMPQ(paths, "devilutionx.mpq"); +#endif + font_mpq = LoadMPQ(paths, "fonts.mpq"); // Extra fonts +#endif +} + +void LoadLanguageArchive() +{ +#ifdef UNPACKED_MPQS + lang_data_path = std::nullopt; +#else + lang_mpq = std::nullopt; +#endif + + std::string_view code = GetLanguageCode(); + if (code != "en") { + std::string langMpqName { code }; +#ifdef UNPACKED_MPQS + lang_data_path = FindUnpackedMpqData(GetMPQSearchPaths(), langMpqName); +#else + langMpqName.append(".mpq"); + lang_mpq = LoadMPQ(GetMPQSearchPaths(), langMpqName); +#endif + } +} + +void LoadGameArchives() +{ + auto paths = GetMPQSearchPaths(); +#ifdef UNPACKED_MPQS + diabdat_data_path = FindUnpackedMpqData(paths, "diabdat"); + if (!diabdat_data_path) { + spawn_data_path = FindUnpackedMpqData(paths, "spawn"); + if (spawn_data_path) + gbIsSpawn = true; + } + if (!HeadlessMode) { + AssetRef ref = FindAsset("ui_art\\title.clx"); + if (!ref.ok()) { + LogError("{}", SDL_GetError()); + InsertCDDlg(_("diabdat.mpq or spawn.mpq")); + } + } + hellfire_data_path = FindUnpackedMpqData(paths, "hellfire"); + if (hellfire_data_path) + gbIsHellfire = true; + if (forceHellfire && !hellfire_data_path) + InsertCDDlg("hellfire"); + + const bool hasMonk = FileExists(*hellfire_data_path + "plrgfx/monk/mha/mhaas.clx"); + const bool hasMusic = FileExists(*hellfire_data_path + "music/dlvlf.wav") + || FileExists(*hellfire_data_path + "music/dlvlf.mp3"); + const bool hasVoice = FileExists(*hellfire_data_path + "sfx/hellfire/cowsut1.wav") + || FileExists(*hellfire_data_path + "sfx/hellfire/cowsut1.mp3"); + + if (gbIsHellfire && (!hasMonk || !hasMusic || !hasVoice)) { + DisplayFatalErrorAndExit(_("Some Hellfire MPQs are missing"), _("Not all Hellfire MPQs were found.\nPlease copy all the hf*.mpq files.")); + } +#else // !UNPACKED_MPQS + diabdat_mpq = LoadMPQ(paths, "DIABDAT.MPQ"); + if (!diabdat_mpq) { + // DIABDAT.MPQ is uppercase on the original CD and the GOG version. + diabdat_mpq = LoadMPQ(paths, "diabdat.mpq"); + } + + if (!diabdat_mpq) { + spawn_mpq = LoadMPQ(paths, "spawn.mpq"); + if (spawn_mpq) + gbIsSpawn = true; + } + if (!HeadlessMode) { + AssetRef ref = FindAsset("ui_art\\title.pcx"); + if (!ref.ok()) { + LogError("{}", SDL_GetError()); + InsertCDDlg(_("diabdat.mpq or spawn.mpq")); + } + } + + hellfire_mpq = LoadMPQ(paths, "hellfire.mpq"); + if (hellfire_mpq) + gbIsHellfire = true; + if (forceHellfire && !hellfire_mpq) + InsertCDDlg("hellfire.mpq"); + + hfmonk_mpq = LoadMPQ(paths, "hfmonk.mpq"); + hfbard_mpq = LoadMPQ(paths, "hfbard.mpq"); + hfbarb_mpq = LoadMPQ(paths, "hfbarb.mpq"); + hfmusic_mpq = LoadMPQ(paths, "hfmusic.mpq"); + hfvoice_mpq = LoadMPQ(paths, "hfvoice.mpq"); + + if (gbIsHellfire && (!hfmonk_mpq || !hfmusic_mpq || !hfvoice_mpq)) { + DisplayFatalErrorAndExit(_("Some Hellfire MPQs are missing"), _("Not all Hellfire MPQs were found.\nPlease copy all the hf*.mpq files.")); + } +#endif +} + } // namespace devilution diff --git a/Source/engine/assets.hpp b/Source/engine/assets.hpp index 0d964cf59..aae897ead 100644 --- a/Source/engine/assets.hpp +++ b/Source/engine/assets.hpp @@ -300,4 +300,26 @@ extern std::optional lang_mpq; extern std::optional devilutionx_mpq; #endif +void LoadCoreArchives(); +void LoadLanguageArchive(); +void LoadGameArchives(); + +#ifdef UNPACKED_MPQS +[[nodiscard]] inline bool HaveSpawn() { return spawn_data_path.has_value(); } +[[nodiscard]] inline bool HaveDiabdat() { return diabdat_data_path.has_value(); } +[[nodiscard]] inline bool HaveHellfire() { return hellfire_data_path.has_value(); } +[[nodiscard]] inline bool HaveExtraFonts() { return font_data_path.has_value(); } + +// Bard and barbarian are not currently supported in unpacked mode. +[[nodiscard]] inline bool HaveBardAssets() { return false; } +[[nodiscard]] inline bool HaveBarbarianAssets() { return false; } +#else +[[nodiscard]] inline bool HaveSpawn() { return spawn_mpq.has_value(); } +[[nodiscard]] inline bool HaveDiabdat() { return diabdat_mpq.has_value(); } +[[nodiscard]] inline bool HaveHellfire() { return hellfire_mpq.has_value(); } +[[nodiscard]] inline bool HaveExtraFonts() { return font_mpq.has_value(); } +[[nodiscard]] inline bool HaveBardAssets() { return hfbard_mpq.has_value(); } +[[nodiscard]] inline bool HaveBarbarianAssets() { return hfbarb_mpq.has_value(); } +#endif + } // namespace devilution diff --git a/Source/engine/dx.cpp b/Source/engine/dx.cpp index c2a3b05c2..ff5dc0c50 100644 --- a/Source/engine/dx.cpp +++ b/Source/engine/dx.cpp @@ -11,6 +11,7 @@ #include "controls/plrctrls.h" #include "engine/render/primitive_render.hpp" #include "headless_mode.hpp" +#include "init.h" #include "options.h" #include "utils/display.h" #include "utils/log.hpp" diff --git a/Source/engine/palette.h b/Source/engine/palette.h index a9cc0959a..d84aab9e5 100644 --- a/Source/engine/palette.h +++ b/Source/engine/palette.h @@ -8,6 +8,8 @@ #include #include +#include + #include "levels/gendung.h" namespace devilution { diff --git a/Source/engine/path.cpp b/Source/engine/path.cpp index 9891c6d23..8930ba67b 100644 --- a/Source/engine/path.cpp +++ b/Source/engine/path.cpp @@ -5,14 +5,15 @@ */ #include "engine/path.h" -#include #include +#include #include +#include "appfat.h" #include "crawl.hpp" +#include "engine/direction.hpp" #include "levels/gendung.h" -#include "lighting.h" #include "objects.h" namespace devilution { diff --git a/Source/engine/path.h b/Source/engine/path.h index 931c545c4..58fb73dfa 100644 --- a/Source/engine/path.h +++ b/Source/engine/path.h @@ -6,14 +6,12 @@ #pragma once #include -#include #include -#include #include -#include "engine/direction.hpp" #include "engine/point.hpp" +#include "utils/attributes.h" namespace devilution { diff --git a/Source/engine/render/clx_render.cpp b/Source/engine/render/clx_render.cpp index 05ca136cd..475a5c556 100644 --- a/Source/engine/render/clx_render.cpp +++ b/Source/engine/render/clx_render.cpp @@ -6,9 +6,11 @@ #include "clx_render.hpp" #include +#include #include "engine/point.hpp" #include "engine/render/blit_impl.hpp" +#include "engine/surface.hpp" #include "utils/attributes.h" #include "utils/clx_decode.hpp" #include "utils/static_vector.hpp" diff --git a/Source/engine/sound.cpp b/Source/engine/sound.cpp index 235f1d61c..65f4946e6 100644 --- a/Source/engine/sound.cpp +++ b/Source/engine/sound.cpp @@ -13,11 +13,11 @@ #include #include +#include #include #include #include "engine/assets.hpp" -#include "init.h" #include "options.h" #include "utils/log.hpp" #include "utils/math.h" diff --git a/Source/gamemenu.cpp b/Source/gamemenu.cpp index 9fc19a3fe..f7fcba318 100644 --- a/Source/gamemenu.cpp +++ b/Source/gamemenu.cpp @@ -13,8 +13,8 @@ #include "engine/sound_defs.hpp" #include "gmenu.h" #include "headless_mode.hpp" -#include "init.h" #include "loadsave.h" +#include "multi.h" #include "options.h" #include "pfile.h" #include "qol/floatingnumbers.h" diff --git a/Source/help.cpp b/Source/help.cpp index b9ecaf318..b6c83e49f 100644 --- a/Source/help.cpp +++ b/Source/help.cpp @@ -10,7 +10,7 @@ #include "DiabloUI/ui_flags.hpp" #include "engine/render/clx_render.hpp" #include "engine/render/text_render.hpp" -#include "init.h" +#include "game_mode.hpp" #include "minitext.h" #include "qol/chatlog.h" #include "stores.h" diff --git a/Source/init.cpp b/Source/init.cpp index 745c0fedb..515ae2968 100644 --- a/Source/init.cpp +++ b/Source/init.cpp @@ -12,10 +12,6 @@ #include #include -#if defined(_WIN32) && !defined(__UWP__) && !defined(DEVILUTIONX_WINDOWS_NO_WCHAR) -#include -#endif - #include "DiabloUI/diabloui.h" #include "engine/assets.hpp" #include "engine/backbuffer_state.hpp" @@ -46,7 +42,6 @@ int _newlib_heap_size_user = 100 * 1024 * 1024; namespace devilution { -/** True if the game is the current active window */ bool gbActive; namespace { @@ -54,101 +49,6 @@ namespace { constexpr char DevilutionXMpqVersion[] = "1\n"; constexpr char ExtraFontsVersion[] = "1\n"; -#ifdef UNPACKED_MPQS -std::optional FindUnpackedMpqData(const std::vector &paths, std::string_view mpqName) -{ - std::string targetPath; - for (const std::string &path : paths) { - targetPath.clear(); - targetPath.reserve(path.size() + mpqName.size() + 1); - targetPath.append(path).append(mpqName) += DirectorySeparator; - if (FileExists(targetPath)) { - LogVerbose(" Found unpacked MPQ directory: {}", targetPath); - return targetPath; - } - } - return std::nullopt; -} -#else -std::optional LoadMPQ(const std::vector &paths, std::string_view mpqName) -{ - std::optional archive; - std::string mpqAbsPath; - std::int32_t error = 0; - for (const auto &path : paths) { - mpqAbsPath = path + mpqName.data(); - if ((archive = MpqArchive::Open(mpqAbsPath.c_str(), error))) { - LogVerbose(" Found: {} in {}", mpqName, path); - return archive; - } - if (error != 0) { - LogError("Error {}: {}", MpqArchive::ErrorMessage(error), mpqAbsPath); - } - } - if (error == 0) { - LogVerbose("Missing: {}", mpqName); - } - - return std::nullopt; -} -#endif - -std::vector GetMPQSearchPaths() -{ - std::vector paths; - paths.push_back(paths::BasePath()); - paths.push_back(paths::PrefPath()); - if (paths[0] == paths[1]) - paths.pop_back(); - paths.push_back(paths::ConfigPath()); - if (paths[0] == paths[1] || (paths.size() == 3 && (paths[0] == paths[2] || paths[1] == paths[2]))) - paths.pop_back(); - -#if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__) - // `XDG_DATA_HOME` is usually the root path of `paths::PrefPath()`, so we only - // add `XDG_DATA_DIRS`. - const char *xdgDataDirs = std::getenv("XDG_DATA_DIRS"); - if (xdgDataDirs != nullptr) { - for (const std::string_view path : SplitByChar(xdgDataDirs, ':')) { - std::string fullPath(path); - if (!path.empty() && path.back() != '/') - fullPath += '/'; - fullPath.append("diasurgical/devilutionx/"); - paths.push_back(std::move(fullPath)); - } - } else { - paths.emplace_back("/usr/local/share/diasurgical/devilutionx/"); - paths.emplace_back("/usr/share/diasurgical/devilutionx/"); - } -#elif defined(NXDK) - paths.emplace_back("D:\\"); -#elif defined(_WIN32) && !defined(__UWP__) && !defined(DEVILUTIONX_WINDOWS_NO_WCHAR) - char gogpath[_FSG_PATH_MAX]; - fsg_get_gog_game_path(gogpath, "1412601690"); - if (strlen(gogpath) > 0) { - paths.emplace_back(std::string(gogpath) + "/"); - paths.emplace_back(std::string(gogpath) + "/hellfire/"); - } -#endif - - if (paths.empty() || !paths.back().empty()) { - paths.emplace_back(); // PWD - } - - if (SDL_LOG_PRIORITY_VERBOSE >= SDL_LogGetPriority(SDL_LOG_CATEGORY_APPLICATION)) { - LogVerbose("Paths:\n base: {}\n pref: {}\n config: {}\n assets: {}", - paths::BasePath(), paths::PrefPath(), paths::ConfigPath(), paths::AssetsPath()); - - std::string message; - for (std::size_t i = 0; i < paths.size(); ++i) { - message.append(fmt::format("\n{:6d}. '{}'", i + 1, paths[i])); - } - LogVerbose("MPQ search paths:{}", message); - } - - return paths; -} - bool AssetContentsEq(AssetRef &&ref, std::string_view expected) { const size_t size = ref.size(); @@ -243,122 +143,6 @@ void init_cleanup() NetClose(); } -void LoadCoreArchives() -{ - auto paths = GetMPQSearchPaths(); - -#ifdef UNPACKED_MPQS - font_data_path = FindUnpackedMpqData(paths, "fonts"); -#else // !UNPACKED_MPQS -#if !defined(__ANDROID__) && !defined(__APPLE__) && !defined(__3DS__) && !defined(__SWITCH__) - // Load devilutionx.mpq first to get the font file for error messages - devilutionx_mpq = LoadMPQ(paths, "devilutionx.mpq"); -#endif - font_mpq = LoadMPQ(paths, "fonts.mpq"); // Extra fonts -#endif -} - -void LoadLanguageArchive() -{ -#ifdef UNPACKED_MPQS - lang_data_path = std::nullopt; -#else - lang_mpq = std::nullopt; -#endif - - std::string_view code = GetLanguageCode(); - if (code != "en") { - std::string langMpqName { code }; -#ifdef UNPACKED_MPQS - lang_data_path = FindUnpackedMpqData(GetMPQSearchPaths(), langMpqName); -#else - langMpqName.append(".mpq"); - lang_mpq = LoadMPQ(GetMPQSearchPaths(), langMpqName); -#endif - } -} - -void LoadGameArchives() -{ - auto paths = GetMPQSearchPaths(); -#ifdef UNPACKED_MPQS - diabdat_data_path = FindUnpackedMpqData(paths, "diabdat"); - if (!diabdat_data_path) { - spawn_data_path = FindUnpackedMpqData(paths, "spawn"); - if (spawn_data_path) - gbIsSpawn = true; - } - if (!HeadlessMode) { - AssetRef ref = FindAsset("ui_art\\title.clx"); - if (!ref.ok()) { - LogError("{}", SDL_GetError()); - InsertCDDlg(_("diabdat.mpq or spawn.mpq")); - } - } - hellfire_data_path = FindUnpackedMpqData(paths, "hellfire"); - if (hellfire_data_path) - gbIsHellfire = true; - if (forceHellfire && !hellfire_data_path) - InsertCDDlg("hellfire"); - - const bool hasMonk = FileExists(*hellfire_data_path + "plrgfx/monk/mha/mhaas.clx"); - const bool hasMusic = FileExists(*hellfire_data_path + "music/dlvlf.wav") - || FileExists(*hellfire_data_path + "music/dlvlf.mp3"); - const bool hasVoice = FileExists(*hellfire_data_path + "sfx/hellfire/cowsut1.wav") - || FileExists(*hellfire_data_path + "sfx/hellfire/cowsut1.mp3"); - - // Bard and barbarian are not currently supported in unpacked mode - // because they use the same paths as rogue and warrior. - gbBard = false; - gbBarbarian = false; - - if (gbIsHellfire && (!hasMonk || !hasMusic || !hasVoice)) { - UiErrorOkDialog(_("Some Hellfire MPQs are missing"), _("Not all Hellfire MPQs were found.\nPlease copy all the hf*.mpq files.")); - diablo_quit(1); - } -#else // !UNPACKED_MPQS - diabdat_mpq = LoadMPQ(paths, "DIABDAT.MPQ"); - if (!diabdat_mpq) { - // DIABDAT.MPQ is uppercase on the original CD and the GOG version. - diabdat_mpq = LoadMPQ(paths, "diabdat.mpq"); - } - - if (!diabdat_mpq) { - spawn_mpq = LoadMPQ(paths, "spawn.mpq"); - if (spawn_mpq) - gbIsSpawn = true; - } - if (!HeadlessMode) { - AssetRef ref = FindAsset("ui_art\\title.pcx"); - if (!ref.ok()) { - LogError("{}", SDL_GetError()); - InsertCDDlg(_("diabdat.mpq or spawn.mpq")); - } - } - - hellfire_mpq = LoadMPQ(paths, "hellfire.mpq"); - if (hellfire_mpq) - gbIsHellfire = true; - if (forceHellfire && !hellfire_mpq) - InsertCDDlg("hellfire.mpq"); - - hfmonk_mpq = LoadMPQ(paths, "hfmonk.mpq"); - hfbard_mpq = LoadMPQ(paths, "hfbard.mpq"); - if (hfbard_mpq) - gbBard = true; - hfbarb_mpq = LoadMPQ(paths, "hfbarb.mpq"); - if (hfbarb_mpq) - gbBarbarian = true; - hfmusic_mpq = LoadMPQ(paths, "hfmusic.mpq"); - hfvoice_mpq = LoadMPQ(paths, "hfvoice.mpq"); - - if (gbIsHellfire && (!hfmonk_mpq || !hfmusic_mpq || !hfvoice_mpq)) { - UiErrorOkDialog(_("Some Hellfire MPQs are missing"), _("Not all Hellfire MPQs were found.\nPlease copy all the hf*.mpq files.")); - diablo_quit(1); - } -#endif -} - void init_create_window() { if (!SpawnWindow(PROJECT_NAME)) diff --git a/Source/init.h b/Source/init.h index 8429fd5a1..eab3ae3d6 100644 --- a/Source/init.h +++ b/Source/init.h @@ -21,42 +21,6 @@ namespace devilution { /** True if the game is the current active window */ extern bool gbActive; -inline bool HaveSpawn() -{ -#ifdef UNPACKED_MPQS - return bool(spawn_data_path); -#else - return bool(spawn_mpq); -#endif -} - -inline bool HaveDiabdat() -{ -#ifdef UNPACKED_MPQS - return bool(diabdat_data_path); -#else - return bool(diabdat_mpq); -#endif -} - -inline bool HaveHellfire() -{ -#ifdef UNPACKED_MPQS - return bool(hellfire_data_path); -#else - return bool(hellfire_mpq); -#endif -} - -inline bool HaveExtraFonts() -{ -#ifdef UNPACKED_MPQS - return bool(font_data_path); -#else - return bool(font_mpq); -#endif -} - #ifdef UNPACKED_MPQS bool AreExtraFontsOutOfDate(const std::string &path); #else @@ -86,9 +50,6 @@ inline bool IsDevilutionXMpqOutOfDate() } void init_cleanup(); -void LoadCoreArchives(); -void LoadLanguageArchive(); -void LoadGameArchives(); void init_create_window(); void MainWndProc(const SDL_Event &event); diff --git a/Source/interfac.cpp b/Source/interfac.cpp index 78c3c24f5..009475858 100644 --- a/Source/interfac.cpp +++ b/Source/interfac.cpp @@ -20,10 +20,11 @@ #include "engine/palette.h" #include "engine/render/clx_render.hpp" #include "engine/render/primitive_render.hpp" +#include "game_mode.hpp" #include "headless_mode.hpp" #include "hwcursor.hpp" -#include "init.h" #include "loadsave.h" +#include "multi.h" #include "pfile.h" #include "plrmsg.h" #include "utils/log.hpp" diff --git a/Source/items.cpp b/Source/items.cpp index 7577df4ab..5bd770b1e 100644 --- a/Source/items.cpp +++ b/Source/items.cpp @@ -27,8 +27,8 @@ #include "engine/render/clx_render.hpp" #include "engine/render/primitive_render.hpp" #include "engine/render/text_render.hpp" +#include "game_mode.hpp" #include "headless_mode.hpp" -#include "init.h" #include "inv_iterators.hpp" #include "levels/town.h" #include "lighting.h" diff --git a/Source/levels/gendung.cpp b/Source/levels/gendung.cpp index 03d8e3310..f53bed99a 100644 --- a/Source/levels/gendung.cpp +++ b/Source/levels/gendung.cpp @@ -15,7 +15,8 @@ #include "engine/load_file.hpp" #include "engine/random.hpp" #include "engine/world_tile.hpp" -#include "init.h" +#include "game_mode.hpp" +#include "items.h" #include "levels/drlg_l1.h" #include "levels/drlg_l2.h" #include "levels/drlg_l3.h" @@ -23,7 +24,9 @@ #include "levels/reencode_dun_cels.hpp" #include "levels/town.h" #include "lighting.h" -#include "options.h" +#include "monster.h" +#include "objects.h" +#include "utils/algorithm/container.hpp" #include "utils/bitset2d.hpp" #include "utils/is_of.hpp" #include "utils/log.hpp" diff --git a/Source/levels/gendung.h b/Source/levels/gendung.h index f6f8ede9c..7c318d7c8 100644 --- a/Source/levels/gendung.h +++ b/Source/levels/gendung.h @@ -11,6 +11,7 @@ #include #include +#include #include #include "engine/clx_sprite.hpp" diff --git a/Source/levels/town.cpp b/Source/levels/town.cpp index 66681fd6c..d1f927a1e 100644 --- a/Source/levels/town.cpp +++ b/Source/levels/town.cpp @@ -4,9 +4,11 @@ #include "engine/load_file.hpp" #include "engine/random.hpp" -#include "init.h" +#include "engine/world_tile.hpp" +#include "game_mode.hpp" #include "levels/drlg_l1.h" #include "levels/trigs.h" +#include "multi.h" #include "player.h" #include "quests.h" diff --git a/Source/levels/trigs.cpp b/Source/levels/trigs.cpp index c52549463..c51edec19 100644 --- a/Source/levels/trigs.cpp +++ b/Source/levels/trigs.cpp @@ -15,7 +15,7 @@ #include "cursor.h" #include "diablo_msg.hpp" #include "game_mode.hpp" -#include "init.h" +#include "multi.h" #include "utils/algorithm/container.hpp" #include "utils/is_of.hpp" #include "utils/language.h" diff --git a/Source/lighting.h b/Source/lighting.h index aae599763..2a0de57ad 100644 --- a/Source/lighting.h +++ b/Source/lighting.h @@ -7,12 +7,8 @@ #include #include -#include -#include -#include #include -#include #include "automap.h" #include "engine/displacement.hpp" diff --git a/Source/loadsave.cpp b/Source/loadsave.cpp index 55303eae8..b485e2468 100644 --- a/Source/loadsave.cpp +++ b/Source/loadsave.cpp @@ -24,7 +24,7 @@ #include "doom.h" #include "engine/point.hpp" #include "engine/random.hpp" -#include "init.h" +#include "game_mode.hpp" #include "inv.h" #include "levels/dun_tile.hpp" #include "lighting.h" diff --git a/Source/missiles.cpp b/Source/missiles.cpp index 3f1838615..d693e7363 100644 --- a/Source/missiles.cpp +++ b/Source/missiles.cpp @@ -22,8 +22,8 @@ #include "engine/points_in_rectangle_range.hpp" #include "engine/random.hpp" #include "engine/render/primitive_render.hpp" +#include "game_mode.hpp" #include "headless_mode.hpp" -#include "init.h" #include "inv.h" #include "levels/dun_tile.hpp" #include "levels/trigs.h" diff --git a/Source/monster.cpp b/Source/monster.cpp index 572d0fa46..91e1620db 100644 --- a/Source/monster.cpp +++ b/Source/monster.cpp @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -32,7 +33,6 @@ #include "engine/world_tile.hpp" #include "game_mode.hpp" #include "headless_mode.hpp" -#include "init.h" #include "levels/crypt.h" #include "levels/drlg_l4.h" #include "levels/themes.h" @@ -55,7 +55,6 @@ #include "utils/static_vector.hpp" #include "utils/status_macros.hpp" #include "utils/str_cat.hpp" -#include "utils/utf8.hpp" #ifdef _DEBUG #include "debug.h" diff --git a/Source/monster.h b/Source/monster.h index 006e8736b..93221b1a6 100644 --- a/Source/monster.h +++ b/Source/monster.h @@ -22,7 +22,6 @@ #include "engine/sound.h" #include "engine/world_tile.hpp" #include "game_mode.hpp" -#include "init.h" #include "levels/dun_tile.hpp" #include "misdat.h" #include "monstdat.h" diff --git a/Source/mpq/mpq_writer.cpp b/Source/mpq/mpq_writer.cpp index c4e4de1d5..9d5a3b2b1 100644 --- a/Source/mpq/mpq_writer.cpp +++ b/Source/mpq/mpq_writer.cpp @@ -6,11 +6,11 @@ #include #include +#include #include #include "appfat.h" #include "encrypt.h" -#include "utils/endian_read.hpp" #include "utils/file_util.h" #include "utils/language.h" #include "utils/log.hpp" diff --git a/Source/objects.cpp b/Source/objects.cpp index 60431d218..185b9d0f3 100644 --- a/Source/objects.cpp +++ b/Source/objects.cpp @@ -27,7 +27,6 @@ #include "engine/points_in_rectangle_range.hpp" #include "engine/random.hpp" #include "headless_mode.hpp" -#include "init.h" #include "inv.h" #include "inv_iterators.hpp" #include "levels/crypt.h" @@ -49,7 +48,6 @@ #include "utils/language.h" #include "utils/log.hpp" #include "utils/str_cat.hpp" -#include "utils/utf8.hpp" namespace devilution { diff --git a/Source/options.cpp b/Source/options.cpp index 8311457fd..7192df1eb 100644 --- a/Source/options.cpp +++ b/Source/options.cpp @@ -19,6 +19,7 @@ #include "controls/game_controls.h" #include "controls/plrctrls.h" #include "discord/discord.h" +#include "engine/assets.hpp" #include "engine/demomode.h" #include "engine/sound_defs.hpp" #include "game_mode.hpp" @@ -717,10 +718,10 @@ void OptionEntryResolution::SetActiveListIndex(size_t index) OptionEntryResampler::OptionEntryResampler() : OptionEntryListBase("Resampler", OptionEntryFlags::CantChangeInGame - // When there are exactly 2 options there is no submenu, so we need to recreate the UI - // to reflect the change in the "Resampling quality" setting visibility. - | (NumResamplers == 2 ? OptionEntryFlags::RecreateUI : OptionEntryFlags::None), - N_("Resampler"), N_("Audio resampler")) + // When there are exactly 2 options there is no submenu, so we need to recreate the UI + // to reflect the change in the "Resampling quality" setting visibility. + | (NumResamplers == 2 ? OptionEntryFlags::RecreateUI : OptionEntryFlags::None), + N_("Resampler"), N_("Audio resampler")) { } void OptionEntryResampler::LoadFromIni(std::string_view category) diff --git a/Source/pack.cpp b/Source/pack.cpp index c8b029bc1..0f917c056 100644 --- a/Source/pack.cpp +++ b/Source/pack.cpp @@ -9,7 +9,6 @@ #include "engine/random.hpp" #include "game_mode.hpp" -#include "init.h" #include "items/validation.h" #include "loadsave.h" #include "playerdat.hpp" diff --git a/Source/panels/spell_book.cpp b/Source/panels/spell_book.cpp index 23ead32ef..a640bd651 100644 --- a/Source/panels/spell_book.cpp +++ b/Source/panels/spell_book.cpp @@ -15,7 +15,7 @@ #include "engine/rectangle.hpp" #include "engine/render/clx_render.hpp" #include "engine/render/text_render.hpp" -#include "init.h" +#include "game_mode.hpp" #include "missiles.h" #include "panels/spell_icons.hpp" #include "panels/ui_panels.hpp" diff --git a/Source/panels/spell_icons.cpp b/Source/panels/spell_icons.cpp index 9d0230abb..ad07ecaa4 100644 --- a/Source/panels/spell_icons.cpp +++ b/Source/panels/spell_icons.cpp @@ -9,7 +9,6 @@ #include "engine/render/clx_render.hpp" #include "engine/render/primitive_render.hpp" #include "game_mode.hpp" -#include "init.h" namespace devilution { diff --git a/Source/pfile.cpp b/Source/pfile.cpp index 3e660b956..4f98a2af7 100644 --- a/Source/pfile.cpp +++ b/Source/pfile.cpp @@ -17,7 +17,6 @@ #include "engine/load_file.hpp" #include "engine/render/primitive_render.hpp" #include "game_mode.hpp" -#include "init.h" #include "loadsave.h" #include "menu.h" #include "mpq/mpq_common.hpp" diff --git a/Source/player.cpp b/Source/player.cpp index cba3a5ea3..18b6816b0 100644 --- a/Source/player.cpp +++ b/Source/player.cpp @@ -28,7 +28,6 @@ #include "gamemenu.h" #include "headless_mode.hpp" #include "help.h" -#include "init.h" #include "inv_iterators.hpp" #include "levels/trigs.h" #include "lighting.h" @@ -1463,9 +1462,9 @@ void ValidatePlayer() HeroClass GetPlayerSpriteClass(HeroClass cls) { - if (cls == HeroClass::Bard && !gbBard) + if (cls == HeroClass::Bard && !HaveBardAssets()) return HeroClass::Rogue; - if (cls == HeroClass::Barbarian && !gbBarbarian) + if (cls == HeroClass::Barbarian && !HaveBarbarianAssets()) return HeroClass::Warrior; return cls; } diff --git a/Source/qol/chatlog.cpp b/Source/qol/chatlog.cpp index 4fde2956a..5704cdd5d 100644 --- a/Source/qol/chatlog.cpp +++ b/Source/qol/chatlog.cpp @@ -20,7 +20,6 @@ #include "engine/render/text_render.hpp" #include "gamemenu.h" #include "help.h" -#include "init.h" #include "inv.h" #include "minitext.h" #include "stores.h" diff --git a/Source/quests.cpp b/Source/quests.cpp index f7e69a3b4..c96a922a6 100644 --- a/Source/quests.cpp +++ b/Source/quests.cpp @@ -18,7 +18,6 @@ #include "engine/render/text_render.hpp" #include "engine/world_tile.hpp" #include "game_mode.hpp" -#include "init.h" #include "levels/gendung.h" #include "levels/town.h" #include "levels/trigs.h" diff --git a/Source/stores.cpp b/Source/stores.cpp index e5afd5175..bd22465e6 100644 --- a/Source/stores.cpp +++ b/Source/stores.cpp @@ -14,14 +14,14 @@ #include "controls/plrctrls.h" #include "cursor.h" #include "engine/backbuffer_state.hpp" -#include "engine/load_cel.hpp" #include "engine/random.hpp" #include "engine/render/clx_render.hpp" #include "engine/render/primitive_render.hpp" #include "engine/render/text_render.hpp" #include "engine/trn.hpp" -#include "init.h" +#include "game_mode.hpp" #include "minitext.h" +#include "multi.h" #include "options.h" #include "panels/info_box.hpp" #include "qol/stash.h" diff --git a/Source/utils/log.hpp b/Source/utils/log.hpp index 26c429527..387658155 100644 --- a/Source/utils/log.hpp +++ b/Source/utils/log.hpp @@ -4,6 +4,7 @@ #include #include +#include #include #include "utils/str_cat.hpp" diff --git a/Source/utils/soundsample.cpp b/Source/utils/soundsample.cpp index ac34d5369..40ce0ba47 100644 --- a/Source/utils/soundsample.cpp +++ b/Source/utils/soundsample.cpp @@ -7,6 +7,8 @@ #include #include +#include + #include #ifdef USE_SDL1 #include "utils/sdl2_to_1_2_backports.h" @@ -91,6 +93,26 @@ float VolumeLogToLinear(int logVolume, int logMin, int logMax) ///// SoundSample ///// +void SoundSample::SetFinishCallback(Aulib::Stream::Callback &&callback) +{ + stream_->setFinishCallback(std::forward(callback)); +} + +void SoundSample::Stop() +{ + stream_->stop(); +} + +void SoundSample::Mute() +{ + stream_->mute(); +} + +void SoundSample::Unmute() +{ + stream_->unmute(); +} + void SoundSample::Release() { stream_ = nullptr; diff --git a/Source/utils/soundsample.h b/Source/utils/soundsample.h index 5673d6479..6f2223a23 100644 --- a/Source/utils/soundsample.h +++ b/Source/utils/soundsample.h @@ -2,13 +2,19 @@ #include #include +#include #include - -#include +#include #include "engine/sound_defs.hpp" #include "utils/stdcompat/shared_ptr_array.hpp" +// Forward-declares Aulib::Stream to avoid adding dependencies +// on SDL_audiolib to every user of this header. +namespace Aulib { +class Stream; +} // namespace Aulib + namespace devilution { class SoundSample final { @@ -28,10 +34,7 @@ public: // Returns 0 on success. int SetChunkStream(std::string filePath, bool isMp3, bool logErrors = true); - void SetFinishCallback(Aulib::Stream::Callback &&callback) - { - stream_->setFinishCallback(std::forward(callback)); - } + void SetFinishCallback(std::function &&callback); /** * @brief Sets the sample's WAV, FLAC, or Ogg/Vorbis data. @@ -72,23 +75,13 @@ public: /** * @brief Stop playing the sound */ - void Stop() - { - stream_->stop(); - } + void Stop(); void SetVolume(int logVolume, int logMin, int logMax); void SetStereoPosition(int logPan); - void Mute() - { - stream_->mute(); - } - - void Unmute() - { - stream_->unmute(); - } + void Mute(); + void Unmute(); /** * @return Audio duration in ms diff --git a/test/app_fatal_for_testing.cpp b/test/app_fatal_for_testing.cpp index fd888865a..348a73e2e 100644 --- a/test/app_fatal_for_testing.cpp +++ b/test/app_fatal_for_testing.cpp @@ -3,10 +3,32 @@ namespace devilution { +[[noreturn]] void DisplayFatalErrorAndExit(std::string_view title, std::string_view body) +{ + std::cerr << "fatal error: " << title << "\n" + << body << std::endl; + std::abort(); +} + [[noreturn]] void app_fatal(std::string_view str) { std::cerr << "app_fatal: " << str << std::endl; std::abort(); } +[[noreturn]] void ErrDlg(const char *title, std::string_view error, std::string_view logFilePath, int logLineNr) +{ + std::cerr << "ErrDlg: " << title << "\n" + << error << "\n" + << logFilePath << ":" << logLineNr << std::endl; + std::abort(); +} + +[[noreturn]] void assert_fail(int nLineNo, const char *pszFile, const char *pszFail) +{ + std::cerr << "assert_fail: " << pszFile << ":" << nLineNo << "\n" + << pszFail << std::endl; + std::abort(); +} + } // namespace devilution diff --git a/test/dun_render_benchmark.cpp b/test/dun_render_benchmark.cpp index d5b4a0b99..ece593093 100644 --- a/test/dun_render_benchmark.cpp +++ b/test/dun_render_benchmark.cpp @@ -5,12 +5,12 @@ #include #include "diablo.h" +#include "engine/assets.hpp" #include "engine/clx_sprite.hpp" #include "engine/displacement.hpp" #include "engine/load_file.hpp" #include "engine/render/dun_render.hpp" #include "engine/surface.hpp" -#include "init.h" #include "levels/dun_tile.hpp" #include "levels/gendung.h" #include "lighting.h" diff --git a/test/inv_test.cpp b/test/inv_test.cpp index 29d25e8f2..999b12f8c 100644 --- a/test/inv_test.cpp +++ b/test/inv_test.cpp @@ -1,6 +1,7 @@ #include #include "cursor.h" +#include "engine/assets.hpp" #include "inv.h" #include "player.h" #include "storm/storm_net.hpp" diff --git a/test/language_for_testing.cpp b/test/language_for_testing.cpp index 08667758e..292d04ce6 100644 --- a/test/language_for_testing.cpp +++ b/test/language_for_testing.cpp @@ -1,5 +1,6 @@ #include #include +#include std::string_view GetLanguageCode() { return "en"; } bool HasTranslation(const std::string &locale) { return true; } @@ -7,3 +8,4 @@ void LanguageInitialize() { } std::string_view LanguageTranslate(const char *key) { return key; } std::string_view LanguagePluralTranslate(const char *singular, std::string_view plural, int count) { return count == 1 ? singular : plural; } std::string_view LanguageParticularTranslate(std::string_view context, std::string_view message) { return message; } +std::vector GetLocales() { return {}; } diff --git a/test/pack_test.cpp b/test/pack_test.cpp index 862427c5e..36df4e024 100644 --- a/test/pack_test.cpp +++ b/test/pack_test.cpp @@ -3,6 +3,7 @@ #include #include "cursor.h" +#include "engine/assets.hpp" #include "game_mode.hpp" #include "monstdat.h" #include "pack.h" diff --git a/test/timedemo_test.cpp b/test/timedemo_test.cpp index b67498bbb..d8c19de51 100644 --- a/test/timedemo_test.cpp +++ b/test/timedemo_test.cpp @@ -2,10 +2,11 @@ #include #include -#include "diablo.h" +#include "engine/assets.hpp" #include "engine/demomode.h" #include "game_mode.hpp" #include "headless_mode.hpp" +#include "init.h" #include "lua/lua.hpp" #include "monstdat.h" #include "options.h"