/** * @file init.cpp * * Implementation of routines for initializing the environment, disable screen saver, load MPQ. */ #include #include #include #include #if defined(_WIN64) || defined(_WIN32) #include #endif #include "DiabloUI/diabloui.h" #include "dx.h" #include "options.h" #include "pfile.h" #include "storm/storm.h" #include "storm/storm_sdl_rw.h" #include "utils/language.h" #include "utils/log.hpp" #include "utils/paths.h" #include "utils/ui_fwd.h" #ifdef __vita__ // increase default allowed heap size on Vita int _newlib_heap_size_user = 100 * 1024 * 1024; #endif namespace devilution { /** True if the game is the current active window */ bool gbActive; /** A handle to an hellfire.mpq archive. */ HANDLE hellfire_mpq; /** The current input handler function */ WNDPROC CurrentProc; /** A handle to the spawn.mpq archive. */ HANDLE spawn_mpq; /** A handle to the diabdat.mpq archive. */ HANDLE diabdat_mpq; /** Indicate if we only have access to demo data */ bool gbIsSpawn; /** Indicate if we have loaded the Hellfire expansion data */ bool gbIsHellfire; /** Indicate if we want vanilla savefiles */ bool gbVanilla; /** Whether the Hellfire mode is required (forced). */ bool forceHellfire; HANDLE hfmonk_mpq; HANDLE hfbard_mpq; HANDLE hfbarb_mpq; HANDLE hfmusic_mpq; HANDLE hfvoice_mpq; HANDLE devilutionx_mpq; HANDLE lang_mpq; HANDLE font_mpq; namespace { HANDLE LoadMPQ(const std::vector &paths, const char *mpqName) { HANDLE archive; std::string mpqAbsPath; for (const auto &path : paths) { mpqAbsPath = path + mpqName; if (SFileOpenArchive(mpqAbsPath.c_str(), 0, MPQ_OPEN_READ_ONLY, &archive)) { LogVerbose(" Found: {} in {}", mpqName, path); paths::SetMpqDir(path); return archive; } if (SErrGetLastError() != STORM_ERROR_FILE_NOT_FOUND) { LogError("Open error {}: {}", SErrGetLastError(), mpqAbsPath); } } if (SErrGetLastError() == STORM_ERROR_FILE_NOT_FOUND) { LogVerbose("Missing: {}", mpqName); } return nullptr; } } // namespace void init_cleanup() { if (gbIsMultiplayer && gbRunGame) { pfile_write_hero(/*writeGameData=*/false, /*clearTables=*/true); } if (spawn_mpq != nullptr) { SFileCloseArchive(spawn_mpq); spawn_mpq = nullptr; } if (diabdat_mpq != nullptr) { SFileCloseArchive(diabdat_mpq); diabdat_mpq = nullptr; } if (hellfire_mpq != nullptr) { SFileCloseArchive(hellfire_mpq); hellfire_mpq = nullptr; } if (hfmonk_mpq != nullptr) { SFileCloseArchive(hfmonk_mpq); hfmonk_mpq = nullptr; } if (hfbard_mpq != nullptr) { SFileCloseArchive(hfbard_mpq); hfbard_mpq = nullptr; } if (hfbarb_mpq != nullptr) { SFileCloseArchive(hfbarb_mpq); hfbarb_mpq = nullptr; } if (hfmusic_mpq != nullptr) { SFileCloseArchive(hfmusic_mpq); hfmusic_mpq = nullptr; } if (hfvoice_mpq != nullptr) { SFileCloseArchive(hfvoice_mpq); hfvoice_mpq = nullptr; } if (lang_mpq != nullptr) { SFileCloseArchive(lang_mpq); lang_mpq = nullptr; } if (font_mpq != nullptr) { SFileCloseArchive(font_mpq); font_mpq = nullptr; } if (devilutionx_mpq != nullptr) { SFileCloseArchive(devilutionx_mpq); devilutionx_mpq = nullptr; } NetClose(); } void init_archives() { std::vector paths; paths.push_back(paths::BasePath()); paths.push_back(paths::PrefPath()); if (paths[0] == paths[1]) paths.pop_back(); #if defined(__linux__) && !defined(__ANDROID__) paths.emplace_back("/usr/share/diasurgical/devilutionx/"); paths.emplace_back("/usr/local/share/diasurgical/devilutionx/"); #elif defined(__3DS__) paths.emplace_back("romfs:/"); #elif defined(_WIN64) || defined(_WIN32) 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 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) { char prefix[32]; std::snprintf(prefix, sizeof(prefix), "\n%6u. '", static_cast(i + 1)); message.append(prefix); message.append(paths[i]); message += '\''; } LogVerbose("MPQ search paths:{}", message); } // Load devilutionx.mpq first to get the font file for error messages devilutionx_mpq = LoadMPQ(paths, "devilutionx.mpq"); font_mpq = LoadMPQ(paths, "fonts.mpq"); // Extra fonts if (strcasecmp("en", sgOptions.Language.szCode) != 0 || strlen(sgOptions.Language.szCode) != 2) { char langMpqName[9] = {}; strncpy(langMpqName, sgOptions.Language.szCode, sizeof(langMpqName) - strlen(langMpqName) - 1); strncat(langMpqName, ".mpq", sizeof(langMpqName) - strlen(langMpqName) - 1); lang_mpq = LoadMPQ(paths, langMpqName); } diabdat_mpq = LoadMPQ(paths, "DIABDAT.MPQ"); if (diabdat_mpq == nullptr) { // DIABDAT.MPQ is uppercase on the original CD and the GOG version. diabdat_mpq = LoadMPQ(paths, "diabdat.mpq"); } if (diabdat_mpq == nullptr) { spawn_mpq = LoadMPQ(paths, "spawn.mpq"); if (spawn_mpq != nullptr) gbIsSpawn = true; } SDL_RWops *handle = SFileOpenRw("ui_art\\title.pcx"); if (handle == nullptr) InsertCDDlg(_("diabdat.mpq or spawn.mpq")); SDL_RWclose(handle); hellfire_mpq = LoadMPQ(paths, "hellfire.mpq"); if (hellfire_mpq != nullptr) gbIsHellfire = true; if (forceHellfire && hellfire_mpq == nullptr) InsertCDDlg("hellfire.mpq"); hfmonk_mpq = LoadMPQ(paths, "hfmonk.mpq"); hfbard_mpq = LoadMPQ(paths, "hfbard.mpq"); if (hfbard_mpq != nullptr) gbBard = true; hfbarb_mpq = LoadMPQ(paths, "hfbarb.mpq"); if (hfbarb_mpq != nullptr) gbBarbarian = true; hfmusic_mpq = LoadMPQ(paths, "hfmusic.mpq"); hfvoice_mpq = LoadMPQ(paths, "hfvoice.mpq"); if (gbIsHellfire && (hfmonk_mpq == nullptr || hfmusic_mpq == nullptr || hfvoice_mpq == nullptr)) { UiErrorOkDialog(_("Some Hellfire MPQs are missing"), _("Not all Hellfire MPQs were found.\nPlease copy all the hf*.mpq files.")); app_fatal(nullptr); } } void init_create_window() { if (!SpawnWindow(PROJECT_NAME)) app_fatal("%s", _("Unable to create main window")); dx_init(); gbActive = true; #ifndef USE_SDL1 SDL_DisableScreenSaver(); #endif } void MainWndProc(uint32_t msg) { switch (msg) { case DVL_WM_PAINT: force_redraw = 255; break; case DVL_WM_QUERYENDSESSION: diablo_quit(0); } } WNDPROC SetWindowProc(WNDPROC newProc) { WNDPROC oldProc; oldProc = CurrentProc; CurrentProc = newProc; return oldProc; } } // namespace devilution