Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions CMake/platforms/amiga.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,10 @@ set(UBSAN OFF)
set(NONET ON)
set(USE_SDL1 ON)
set(SDL1_VIDEO_MODE_BPP 8)
# Enable exception support as they are used in dvlnet code
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions")

set(DEVILUTIONX_SYSTEM_BZIP2 OFF)
set(DEVILUTIONX_SYSTEM_ZLIB OFF)

# Do not warn about unknown attributes, such as [[nodiscard]].
# As this build uses an older compiler, there are lots of them.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-attributes")

# Lower the optimization level to O2 because there are issues with O3.
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O2")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2")
Expand Down
2 changes: 1 addition & 1 deletion Packaging/amiga/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FROM amigadev/crosstools:m68k-amigaos-gcc10

RUN apt-get install --no-install-recommends -y smpq
RUN apt-get update && apt-get install --no-install-recommends -y smpq
RUN mkdir /devilutionx-deps-build
COPY Packaging/amiga/prep.sh /devilutionx-deps-build/prep.sh
RUN cd /devilutionx-deps-build && ./prep.sh
Expand Down
1 change: 1 addition & 0 deletions Source/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@ add_devilutionx_object_library(libdevilutionx_init
target_link_dependencies(libdevilutionx_init PUBLIC
libdevilutionx_assets
libdevilutionx_config
libdevilutionx_mpq
libdevilutionx_options
)

Expand Down
2 changes: 1 addition & 1 deletion Source/DiabloUI/diabloui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
#include "engine/render/text_render.hpp"
#include "engine/ticks.hpp"
#include "hwcursor.hpp"
#include "init.h"
#include "init.hpp"
#include "utils/algorithm/container.hpp"
#include "utils/display.h"
#include "utils/is_of.hpp"
Expand Down Expand Up @@ -547,14 +547,14 @@
void LoadUiGFX()
{
if (gbIsHellfire) {
ArtLogo = LoadPcxSpriteList("ui_art\\hf_logo2", /*numFrames=*/16, /*transparentColor=*/0);

Check warning on line 550 in Source/DiabloUI/diabloui.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/DiabloUI/diabloui.cpp:550:51 [bugprone-argument-comment]

argument name 'numFrames' in comment does not match parameter name 'numFramesOrFrameHeight'
} else {
ArtLogo = LoadPcxSpriteList("ui_art\\smlogo", /*numFrames=*/15, /*transparentColor=*/250);

Check warning on line 552 in Source/DiabloUI/diabloui.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/DiabloUI/diabloui.cpp:552:49 [bugprone-argument-comment]

argument name 'numFrames' in comment does not match parameter name 'numFramesOrFrameHeight'
}
DifficultyIndicator = LoadPcx("ui_art\\r1_gry", /*transparentColor=*/0);
ArtFocus[FOCUS_SMALL] = LoadPcxSpriteList("ui_art\\focus16", /*numFrames=*/8, /*transparentColor=*/250);

Check warning on line 555 in Source/DiabloUI/diabloui.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/DiabloUI/diabloui.cpp:555:63 [bugprone-argument-comment]

argument name 'numFrames' in comment does not match parameter name 'numFramesOrFrameHeight'
ArtFocus[FOCUS_MED] = LoadPcxSpriteList("ui_art\\focus", /*numFrames=*/8, /*transparentColor=*/250);

Check warning on line 556 in Source/DiabloUI/diabloui.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/DiabloUI/diabloui.cpp:556:59 [bugprone-argument-comment]

argument name 'numFrames' in comment does not match parameter name 'numFramesOrFrameHeight'
ArtFocus[FOCUS_BIG] = LoadPcxSpriteList("ui_art\\focus42", /*numFrames=*/8, /*transparentColor=*/250);

Check warning on line 557 in Source/DiabloUI/diabloui.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/DiabloUI/diabloui.cpp:557:61 [bugprone-argument-comment]

argument name 'numFrames' in comment does not match parameter name 'numFramesOrFrameHeight'

ArtCursor = LoadPcx("ui_art\\cursor", /*transparentColor=*/0);

Expand Down Expand Up @@ -609,7 +609,7 @@
if (name.size() > PlayerNameLength)
return false;

if (name.find_first_of(",<>%&\\\"?*#/: ") != name.npos)

Check warning on line 612 in Source/DiabloUI/diabloui.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/DiabloUI/diabloui.cpp:612:47 [readability-static-accessed-through-instance]

static member accessed through instance
return false;

// Only basic latin alphabet is supported for multiplayer characters to avoid rendering issues for players who do
Expand All @@ -633,8 +633,8 @@
character++;

std::string_view tempName { buffer };
for (std::string_view bannedName : bannedNames) {

Check warning on line 636 in Source/DiabloUI/diabloui.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/DiabloUI/diabloui.cpp:636:2 [readability-use-anyofallof]

replace loop by 'std::ranges::all_of()'
if (tempName.find(bannedName) != tempName.npos)

Check warning on line 637 in Source/DiabloUI/diabloui.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/DiabloUI/diabloui.cpp:637:36 [readability-static-accessed-through-instance]

static member accessed through instance
return false;
}

Expand All @@ -644,10 +644,10 @@
Sint16 GetCenterOffset(Sint16 w, Sint16 bw)
{
if (bw == 0) {
bw = gnScreenWidth;

Check warning on line 647 in Source/DiabloUI/diabloui.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/DiabloUI/diabloui.cpp:647:8 [bugprone-narrowing-conversions]

narrowing conversion from 'Uint16' (aka 'unsigned short') to signed type 'Sint16' (aka 'short') is implementation-defined
}

return (bw - w) / 2;

Check warning on line 650 in Source/DiabloUI/diabloui.cpp

View workflow job for this annotation

GitHub Actions / tidy-check

Source/DiabloUI/diabloui.cpp:650:9 [bugprone-narrowing-conversions]

narrowing conversion from 'int' to signed type 'Sint16' (aka 'short') is implementation-defined
}

void UiLoadDefaultPalette()
Expand Down
2 changes: 1 addition & 1 deletion Source/DiabloUI/dialogs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
#include "engine/palette.h"
#include "headless_mode.hpp"
#include "hwcursor.hpp"
#include "init.h"
#include "init.hpp"
#include "utils/display.h"
#include "utils/is_of.hpp"
#include "utils/language.h"
Expand Down
2 changes: 1 addition & 1 deletion Source/controls/touch/renderers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#include "engine/events.hpp"
#include "engine/render/clx_render.hpp"
#include "engine/render/primitive_render.hpp"
#include "init.h"
#include "init.hpp"
#include "inv.h"
#include "levels/gendung.h"
#include "minitext.h"
Expand Down
2 changes: 1 addition & 1 deletion Source/diablo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
#include "headless_mode.hpp"
#include "help.h"
#include "hwcursor.hpp"
#include "init.h"
#include "init.hpp"
#include "inv.h"
#include "levels/drlg_l1.h"
#include "levels/drlg_l2.h"
Expand Down
173 changes: 82 additions & 91 deletions Source/engine/assets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,37 +24,23 @@
namespace devilution {

std::vector<std::string> OverridePaths;

#ifdef UNPACKED_MPQS
std::optional<std::string> spawn_data_path;
std::optional<std::string> diabdat_data_path;
std::optional<std::string> hellfire_data_path;
std::optional<std::string> font_data_path;
std::optional<std::string> lang_data_path;
#else
std::map<int, std::unique_ptr<MpqArchive>> MpqArchives;
std::map<int, MpqArchiveT> MpqArchives;
bool HasHellfireMpq;
#endif

namespace {

#ifdef UNPACKED_MPQS
char *FindUnpackedMpqFile(char *relativePath)
{
// Iterate over archives in reverse order to prefer files from high priority archives
char *path = nullptr;
const auto at = [&](const std::optional<std::string> &unpackedDir) -> bool {
if (!unpackedDir)
return false;
path = relativePath - unpackedDir->size();
std::memcpy(path, unpackedDir->data(), unpackedDir->size());
if (FileExists(path))
return true;
for (auto rit = MpqArchives.rbegin(); rit != MpqArchives.rend(); ++rit) {
const std::string_view unpackedDir = rit->second;
path = relativePath - unpackedDir.size();
std::memcpy(path, unpackedDir.data(), unpackedDir.size());
if (FileExists(path)) break;
path = nullptr;
return false;
};
at(font_data_path) || at(lang_data_path)
|| (gbIsHellfire && at(hellfire_data_path))
|| at(spawn_data_path) || at(diabdat_data_path);
}
return path;
}
#else
Expand All @@ -78,8 +64,8 @@ bool FindMpqFile(std::string_view filename, MpqArchive **archive, uint32_t *file

// Iterate over archives in reverse order to prefer files from high priority archives
for (auto rit = MpqArchives.rbegin(); rit != MpqArchives.rend(); ++rit) {
if (rit->second->GetFileNumber(fileHash, *fileNumber)) {
*archive = rit->second.get();
if (rit->second.GetFileNumber(fileHash, *fileNumber)) {
*archive = &rit->second;
return true;
}
}
Expand Down Expand Up @@ -262,7 +248,7 @@ std::string FailedToOpenFileErrorMessage(std::string_view path, std::string_view

namespace {
#ifdef UNPACKED_MPQS
std::optional<std::string> FindUnpackedMpqData(const std::vector<std::string> &paths, std::string_view mpqName)
std::optional<std::string> FindUnpackedMpqData(std::span<const std::string> paths, std::string_view mpqName)
{
std::string targetPath;
for (const std::string &path : paths) {
Expand All @@ -276,12 +262,28 @@ std::optional<std::string> FindUnpackedMpqData(const std::vector<std::string> &p
}
return std::nullopt;
}

bool FindMPQ(std::span<const std::string> paths, std::string_view mpqName)
{
return FindUnpackedMpqData(paths, mpqName).has_value();
}

bool LoadMPQ(std::span<const std::string> paths, std::string_view mpqName, int priority)
{
std::optional<std::string> mpqPath = FindUnpackedMpqData(paths, mpqName);
if (!mpqPath.has_value()) {
LogVerbose("Missing: {}", mpqName);
return false;
}
MpqArchives[priority] = *std::move(mpqPath);
return true;
}
#else
bool FindMPQ(const std::vector<std::string> &paths, std::string_view mpqName)
bool FindMPQ(std::span<const std::string> paths, std::string_view mpqName)
{
std::string mpqAbsPath;
for (const auto &path : paths) {
mpqAbsPath = path + mpqName.data();
mpqAbsPath = StrCat(path, mpqName, ".mpq");
if (FileExists(mpqAbsPath)) {
LogVerbose(" Found: {} in {}", mpqName, path);
return true;
Expand All @@ -290,16 +292,21 @@ bool FindMPQ(const std::vector<std::string> &paths, std::string_view mpqName)

return false;
}
bool LoadMPQ(const std::vector<std::string> &paths, std::string_view mpqName, int priority)

bool LoadMPQ(std::span<const std::string> paths, std::string_view mpqName, int priority, std::string_view ext = ".mpq")
{
std::optional<MpqArchive> 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))) {
mpqAbsPath = StrCat(path, mpqName, ext);
archive = MpqArchive::Open(mpqAbsPath.c_str(), error);
if (archive.has_value()) {
LogVerbose(" Found: {} in {}", mpqName, path);
MpqArchives[priority] = std::make_unique<MpqArchive>(std::move(*archive));
auto [it, inserted] = MpqArchives.emplace(priority, *std::move(archive));
if (!inserted) {
LogError("MPQ with priority {} is already registered, skipping {}", priority, mpqName);
}
return true;
}
if (error != 0) {
Expand Down Expand Up @@ -376,92 +383,78 @@ 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
LoadMPQ(paths, "devilutionx.mpq", DevilutionXMpqPriority);
#endif
LoadMPQ(paths, "fonts.mpq", FontMpqPriority); // Extra fonts
HasHellfireMpq = FindMPQ(paths, "hellfire.mpq");
LoadMPQ(paths, "devilutionx", DevilutionXMpqPriority);
#endif
LoadMPQ(paths, "fonts", FontMpqPriority); // Extra fonts
HasHellfireMpq = FindMPQ(paths, "hellfire");
}

void LoadLanguageArchive()
{
#ifdef UNPACKED_MPQS
lang_data_path = std::nullopt;
#endif

std::string_view code = GetLanguageCode();
const 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");
LoadMPQ(GetMPQSearchPaths(), langMpqName, LangMpqPriority);
#endif
LoadMPQ(GetMPQSearchPaths(), code, LangMpqPriority);
}
}

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"));
const std::vector<std::string> paths = GetMPQSearchPaths();
bool haveDiabdat = false;
bool haveSpawn = false;

#ifndef UNPACKED_MPQS
// DIABDAT.MPQ is uppercase on the original CD and the GOG version.
haveDiabdat = LoadMPQ(paths, "DIABDAT", MainMpqPriority, ".MPQ");
#endif

if (!haveDiabdat) {
haveDiabdat = LoadMPQ(paths, "diabdat", MainMpqPriority);
if (!haveDiabdat) {
gbIsSpawn = haveSpawn = LoadMPQ(paths, "spawn", MainMpqPriority);
}
}
hellfire_data_path = FindUnpackedMpqData(paths, "hellfire");
if (forceHellfire && !hellfire_data_path)
InsertCDDlg("hellfire");
#else // !UNPACKED_MPQS
if (!LoadMPQ(paths, "DIABDAT.MPQ", MainMpqPriority)) {
// DIABDAT.MPQ is uppercase on the original CD and the GOG version.
if (!LoadMPQ(paths, "diabdat.mpq", MainMpqPriority))
gbIsSpawn = LoadMPQ(paths, "spawn.mpq", MainMpqPriority);
}

if (!HeadlessMode) {
AssetRef ref = FindAsset("ui_art\\title.pcx");
if (!ref.ok()) {
if (!haveDiabdat && !haveSpawn) {
LogError("{}", SDL_GetError());
InsertCDDlg(_("diabdat.mpq or spawn.mpq"));
}
}

if (forceHellfire && !HasHellfireMpq)
if (forceHellfire && !HasHellfireMpq) {
#ifdef UNPACKED_MPQS
InsertCDDlg("hellfire");
#else
InsertCDDlg("hellfire.mpq");
LoadMPQ(paths, "hfbard.mpq", 8110);
LoadMPQ(paths, "hfbarb.mpq", 8120);
#endif
}

#ifndef UNPACKED_MPQS
// In unpacked mode, all the hellfire data is in the hellfire directory.
LoadMPQ(paths, "hfbard", 8110);
LoadMPQ(paths, "hfbarb", 8120);
#endif
}

void LoadHellfireArchives()
{
auto paths = GetMPQSearchPaths();
const std::vector<std::string> paths = GetMPQSearchPaths();
LoadMPQ(paths, "hellfire", 8000);

#ifdef UNPACKED_MPQS
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");
#else // !UNPACKED_MPQS
LoadMPQ(paths, "hellfire.mpq", 8000);
const bool hasMonk = LoadMPQ(paths, "hfmonk.mpq", 8100);
const bool hasMusic = LoadMPQ(paths, "hfmusic.mpq", 8200);
const bool hasVoice = LoadMPQ(paths, "hfvoice.mpq", 8500);
const std::string &hellfireDataPath = MpqArchives.at(8000);
const bool hasMonk = FileExists(hellfireDataPath + "plrgfx/monk/mha/mhaas.clx");
const bool hasMusic = FileExists(hellfireDataPath + "music/dlvlf.wav")
|| FileExists(hellfireDataPath + "music/dlvlf.mp3");
const bool hasVoice = FileExists(hellfireDataPath + "sfx/hellfire/cowsut1.wav")
|| FileExists(hellfireDataPath + "sfx/hellfire/cowsut1.mp3");
#else
const bool hasMonk = LoadMPQ(paths, "hfmonk", 8100);
const bool hasMusic = LoadMPQ(paths, "hfmusic", 8200);
const bool hasVoice = LoadMPQ(paths, "hfvoice", 8500);
#endif

if (!hasMonk || !hasMusic || !hasVoice)
Expand Down Expand Up @@ -498,14 +491,12 @@ void LoadModArchives(std::span<const std::string_view> modnames)
}
OverridePaths.emplace_back(paths::PrefPath());

#ifndef UNPACKED_MPQS
int priority = 10000;
auto paths = GetMPQSearchPaths();
for (std::string_view modname : modnames) {
LoadMPQ(paths, StrCat("mods" DIRECTORY_SEPARATOR_STR, modname, ".mpq"), priority);
LoadMPQ(paths, StrCat("mods" DIRECTORY_SEPARATOR_STR, modname), priority);
priority++;
}
#endif
}

} // namespace devilution
22 changes: 6 additions & 16 deletions Source/engine/assets.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -280,19 +280,17 @@ struct AssetData {
tl::expected<AssetData, std::string> LoadAsset(std::string_view path);

#ifdef UNPACKED_MPQS
extern DVL_API_FOR_TEST std::optional<std::string> spawn_data_path;
extern DVL_API_FOR_TEST std::optional<std::string> diabdat_data_path;
extern std::optional<std::string> hellfire_data_path;
extern std::optional<std::string> font_data_path;
extern std::optional<std::string> lang_data_path;
using MpqArchiveT = std::string;
#else
extern DVL_API_FOR_TEST std::map<int, std::unique_ptr<MpqArchive>> MpqArchives;
using MpqArchiveT = MpqArchive;
#endif

extern DVL_API_FOR_TEST std::map<int, MpqArchiveT> MpqArchives;
constexpr int MainMpqPriority = 1000;
constexpr int DevilutionXMpqPriority = 9000;
constexpr int LangMpqPriority = 9100;
constexpr int FontMpqPriority = 9200;
extern bool HasHellfireMpq;
#endif

void LoadCoreArchives();
void LoadLanguageArchive();
Expand All @@ -301,19 +299,11 @@ void LoadHellfireArchives();
void UnloadModArchives();
void LoadModArchives(std::span<const std::string_view> modnames);

#ifdef UNPACKED_MPQS
#ifdef BUILD_TESTING
[[nodiscard]] inline bool HaveMainData() { return diabdat_data_path.has_value() || spawn_data_path.has_value(); }
#endif
[[nodiscard]] inline bool HaveHellfire() { return hellfire_data_path.has_value(); }
[[nodiscard]] inline bool HaveExtraFonts() { return font_data_path.has_value(); }
#else
#ifdef BUILD_TESTING
[[nodiscard]] inline bool HaveMainData() { return MpqArchives.find(MainMpqPriority) != MpqArchives.end(); }
#endif
[[nodiscard]] inline bool HaveHellfire() { return HasHellfireMpq; }
[[nodiscard]] inline bool HaveExtraFonts() { return MpqArchives.find(FontMpqPriority) != MpqArchives.end(); }
#endif
[[nodiscard]] inline bool HaveHellfire() { return HasHellfireMpq; }
[[nodiscard]] inline bool HaveIntro() { return FindAsset("gendata\\diablo1.smk").ok(); }
[[nodiscard]] inline bool HaveFullMusic() { return FindAsset("music\\dintro.wav").ok() || FindAsset("music\\dintro.mp3").ok(); }
[[nodiscard]] inline bool HaveBardAssets() { return FindAsset("plrgfx\\bard\\bha\\bhaas.clx").ok(); }
Expand Down
2 changes: 1 addition & 1 deletion Source/engine/dx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
#include "controls/plrctrls.h"
#include "engine/render/primitive_render.hpp"
#include "headless_mode.hpp"
#include "init.h"
#include "init.hpp"
#include "options.h"
#include "utils/display.h"
#include "utils/log.hpp"
Expand Down
Loading
Loading