From 5dc95550cea37744c057e6d89a75e73fd6cda732 Mon Sep 17 00:00:00 2001 From: qndel Date: Wed, 10 Aug 2022 23:27:52 +0200 Subject: [PATCH] Add TRN debug command and support for optional class TRNs --- Source/debug.cpp | 31 ++++++++++++++++++++++++++++ Source/debug.h | 1 + Source/engine/load_file.hpp | 14 +++++++++++-- Source/engine/trn.cpp | 40 +++++++++++++++++++++++++++++++++++++ Source/engine/trn.hpp | 4 ++++ Source/player.cpp | 6 ++++++ 6 files changed, 94 insertions(+), 2 deletions(-) diff --git a/Source/debug.cpp b/Source/debug.cpp index a8a676c22..cf9d5c948 100644 --- a/Source/debug.cpp +++ b/Source/debug.cpp @@ -42,6 +42,7 @@ bool DebugVision = false; bool DebugGrid = false; std::unordered_map DebugCoordsMap; bool DebugScrollViewEnabled = false; +std::string debugTRN; namespace { @@ -954,6 +955,35 @@ std::string DebugCmdToggleFPS(const string_view parameter) return ""; } +std::string DebugCmdChangeTRN(const string_view parameter) +{ + std::stringstream paramsStream(parameter.data()); + std::string first; + std::string out; + if (std::getline(paramsStream, first, ' ')) { + std::string second; + if (std::getline(paramsStream, second, ' ')) { + std::string prefix; + if (first == "mon") { + prefix = "Monsters\\Monsters\\"; + } else if (first == "plr") { + prefix = "PlrGFX\\"; + } + debugTRN = prefix + second + ".TRN"; + } else { + debugTRN = first + ".TRN"; + } + out = fmt::format("I am a pretty butterfly. \n(Loading TRN: {:s})", debugTRN); + } else { + debugTRN = ""; + out = "I am a big brown potato."; + } + auto &player = *MyPlayer; + InitPlayerGFX(player); + StartStand(player, player._pdir); + return out; +} + std::vector DebugCmdList = { { "help", "Prints help overview or help for a specific command.", "({command})", &DebugCmdHelp }, { "give gold", "Fills the inventory with gold.", "", &DebugCmdGiveGoldCheat }, @@ -990,6 +1020,7 @@ std::vector DebugCmdList = { { "questinfo", "Shows info of quests.", "{id}", &DebugCmdQuestInfo }, { "playerinfo", "Shows info of player.", "{playerid}", &DebugCmdPlayerInfo }, { "fps", "Toggles displaying FPS", "", &DebugCmdToggleFPS }, + { "trn", "Makes player use TRN {trn} - Write 'plr' before it to look in PlrGFX\\ or 'mon' to look in Monsters\\Monsters\\ - example: trn plr infra is equal to 'PlrGFX\\Infra.TRN'", "{trn}", &DebugCmdChangeTRN }, }; } // namespace diff --git a/Source/debug.h b/Source/debug.h index 8342a028c..71442951f 100644 --- a/Source/debug.h +++ b/Source/debug.h @@ -21,6 +21,7 @@ extern bool DebugVision; extern bool DebugGrid; extern std::unordered_map DebugCoordsMap; extern bool DebugScrollViewEnabled; +extern std::string debugTRN; void FreeDebugGFX(); void LoadDebugGFX(); diff --git a/Source/engine/load_file.hpp b/Source/engine/load_file.hpp index 454049fe0..5b8dc6e05 100644 --- a/Source/engine/load_file.hpp +++ b/Source/engine/load_file.hpp @@ -18,11 +18,11 @@ namespace devilution { class SFile { public: - explicit SFile(const char *path) + explicit SFile(const char *path, bool isOptional = false) { handle_ = OpenAsset(path); if (handle_ == nullptr) { - if (!HeadlessMode) { + if (!HeadlessMode && !isOptional) { app_fatal(StrCat("Failed to open file:\n", path, "\n\n", SDL_GetError())); } } @@ -74,6 +74,16 @@ void LoadFileInMem(const char *path, T *data, std::size_t count) file.Read(reinterpret_cast(data), count * sizeof(T)); } +template +bool LoadOptionalFileInMem(const char *path, T *data, std::size_t count) +{ + SFile file { path, true }; + if (!file.Ok()) + return false; + file.Read(reinterpret_cast(data), count * sizeof(T)); + return true; +} + template void LoadFileInMem(const char *path, std::array &data) { diff --git a/Source/engine/trn.cpp b/Source/engine/trn.cpp index d33e6c069..0ed971ebb 100644 --- a/Source/engine/trn.cpp +++ b/Source/engine/trn.cpp @@ -1,6 +1,9 @@ #include #include +#ifdef _DEBUG +#include "debug.h" +#endif #include "engine/load_file.hpp" #include "engine/trn.hpp" #include "lighting.h" @@ -22,4 +25,41 @@ uint8_t *GetPauseTRN() return &LightTables[18 * 256]; } +std::optional> GetClassTRN(Player &player) +{ + std::array trn; + const char *path; + + switch (player._pClass) { + case HeroClass::Warrior: + path = "PlrGFX\\warrior.TRN"; + break; + case HeroClass::Rogue: + path = "PlrGFX\\rogue.TRN"; + break; + case HeroClass::Sorcerer: + path = "PlrGFX\\sorcerer.TRN"; + break; + case HeroClass::Monk: + path = "PlrGFX\\monk.TRN"; + break; + case HeroClass::Bard: + path = "PlrGFX\\bard.TRN"; + break; + case HeroClass::Barbarian: + path = "PlrGFX\\barbarian.TRN"; + break; + } + +#ifdef _DEBUG + if (!debugTRN.empty()) { + path = debugTRN.c_str(); + } +#endif + if (LoadOptionalFileInMem(path, &trn, 256)) { + return trn; + } + return std::nullopt; +} + } // namespace devilution diff --git a/Source/engine/trn.hpp b/Source/engine/trn.hpp index e42a388bf..6b507bcb5 100644 --- a/Source/engine/trn.hpp +++ b/Source/engine/trn.hpp @@ -5,10 +5,14 @@ */ #pragma once +#include "player.h" +#include "utils/stdcompat/optional.hpp" + namespace devilution { uint8_t *GetInfravisionTRN(); uint8_t *GetStoneTRN(); uint8_t *GetPauseTRN(); +std::optional> GetClassTRN(Player &player); } // namespace devilution diff --git a/Source/player.cpp b/Source/player.cpp index cfa1d254d..032baf97e 100644 --- a/Source/player.cpp +++ b/Source/player.cpp @@ -20,6 +20,8 @@ #include "engine/load_file.hpp" #include "engine/points_in_rectangle_range.hpp" #include "engine/random.hpp" +#include "engine/render/clx_render.hpp" +#include "engine/trn.hpp" #include "engine/world_tile.hpp" #include "gamemenu.h" #include "help.h" @@ -2234,6 +2236,10 @@ void LoadPlrGFX(Player &player, player_graphic graphic) *fmt::format_to(pszName, FMT_COMPILE(R"(PlrGFX\{0}\{1}\{1}{2}.CL2)"), path, string_view(prefix, 3), szCel) = 0; const uint16_t animationWidth = GetPlayerSpriteWidth(cls, graphic, animWeaponId); animationData.sprites = LoadCl2Sheet(pszName, animationWidth); + std::optional> trn = GetClassTRN(player); + if (trn) { + ClxApplyTrans(*animationData.sprites, trn->data()); + } } void InitPlayerGFX(Player &player)