diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index c2df866c..195eac38 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -134,12 +134,12 @@ WorldMapTravelMarkers=0 WorldMapTerrainInfo=0 ;Set to 1 to enable tall trade/barter window with 4 item slots per table instead of 3 -;Requires the high-res patch mode and new barter_239.frm and trade_238.frm files in art\intrface\ (included in sfall.dat) -;The resolution of the hi-res patch must be set to at least 640x528 +;Requires the high-res mode with resolution of at least 640x528 +;Requires new frm files in art\intrface\: barter_e.frm (640x239), trade_e.frm (640x238) (included in sfall.dat) ExpandedBarter=0 ;Set to 1 to enable tall inventory/loot/item select windows with 8 vertical slots instead of 6 -;Requires new frms: invbox_473.frm, loot_472.frm and use_472.frm files in art\intrface\ (included in sfall.dat) to display correctly +;Requires new frm files in art\intrface\: invbox_e.frm (499x467), loot_e.frm (537x464) and use_e.frm (292x464) files (included in sfall.dat) ExpandedInventory=0 ;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX diff --git a/artifacts/sfall_dat/dat_en/art/intrface/barter_e.frm b/artifacts/sfall_dat/dat_en/art/intrface/barter_e.frm new file mode 100644 index 00000000..c793d823 Binary files /dev/null and b/artifacts/sfall_dat/dat_en/art/intrface/barter_e.frm differ diff --git a/artifacts/sfall_dat/dat_en/art/intrface/invbox_e.frm b/artifacts/sfall_dat/dat_en/art/intrface/invbox_e.frm new file mode 100644 index 00000000..fa201709 Binary files /dev/null and b/artifacts/sfall_dat/dat_en/art/intrface/invbox_e.frm differ diff --git a/artifacts/sfall_dat/dat_en/art/intrface/loot_e.frm b/artifacts/sfall_dat/dat_en/art/intrface/loot_e.frm new file mode 100644 index 00000000..18393795 Binary files /dev/null and b/artifacts/sfall_dat/dat_en/art/intrface/loot_e.frm differ diff --git a/artifacts/sfall_dat/dat_en/art/intrface/trade_e.frm b/artifacts/sfall_dat/dat_en/art/intrface/trade_e.frm new file mode 100644 index 00000000..33df9feb Binary files /dev/null and b/artifacts/sfall_dat/dat_en/art/intrface/trade_e.frm differ diff --git a/artifacts/sfall_dat/dat_en/art/intrface/use_e.frm b/artifacts/sfall_dat/dat_en/art/intrface/use_e.frm new file mode 100644 index 00000000..cf4b2b35 Binary files /dev/null and b/artifacts/sfall_dat/dat_en/art/intrface/use_e.frm differ diff --git a/sfall/Modules/ExtraArt.cpp b/sfall/Modules/ExtraArt.cpp index 88ef13be..41a5df13 100644 --- a/sfall/Modules/ExtraArt.cpp +++ b/sfall/Modules/ExtraArt.cpp @@ -63,22 +63,40 @@ PcxFile LoadPcxFileCached(const char* file) { return pcxFileCache.emplace(file, LoadPcxFile(file)).first->second; } +static void GetUnlistedFrmPath(const char* frmName, unsigned int folderRef, bool useLanguage, char* buf, size_t bufSize) { + + const char* artfolder = fo::var::art[folderRef].path; // address of art type name + if (useLanguage) { + sprintf_s(buf, MAX_PATH, "art\\%s\\%s\\%s", (const char*)fo::var::language, artfolder, frmName); + } else { + sprintf_s(buf, MAX_PATH, "art\\%s\\%s", artfolder, frmName); + } +} + +bool UnlistedFrmExists(const char* frmName, unsigned int folderRef) { + if (folderRef > fo::OBJ_TYPE_SKILLDEX) return nullptr; + + char frmPath[MAX_PATH]; + GetUnlistedFrmPath(frmName, folderRef, fo::var::use_language != 0, frmPath, MAX_PATH); + + bool exists = fo::func::db_access(frmPath); + if (!exists && fo::var::use_language) { + GetUnlistedFrmPath(frmName, folderRef, false, frmPath, MAX_PATH); + exists = fo::func::db_access(frmPath); + } + return exists; +} + fo::FrmFile* LoadUnlistedFrmCached(const char* frmName, unsigned int folderRef) { if (folderRef > fo::OBJ_TYPE_SKILLDEX) return nullptr; - const char* artfolder = fo::var::art[folderRef].path; // address of art type name char frmPath[MAX_PATH]; - if (fo::var::use_language) { - sprintf_s(frmPath, MAX_PATH, "art\\%s\\%s\\%s", (const char*)fo::var::language, artfolder, frmName); - } - else { - sprintf_s(frmPath, MAX_PATH, "art\\%s\\%s", artfolder, frmName); - } + GetUnlistedFrmPath(frmName, folderRef, fo::var::use_language != 0, frmPath, MAX_PATH); fo::FrmFile* frm = LoadFrmFileCached(frmPath); if (frm == nullptr && fo::var::use_language) { - sprintf_s(frmPath, MAX_PATH, "art\\%s\\%s", artfolder, frmName); + GetUnlistedFrmPath(frmName, folderRef, false, frmPath, MAX_PATH); frm = LoadFrmFileCached(frmPath); } return frm; diff --git a/sfall/Modules/ExtraArt.h b/sfall/Modules/ExtraArt.h index 50186975..6f6a68c7 100644 --- a/sfall/Modules/ExtraArt.h +++ b/sfall/Modules/ExtraArt.h @@ -45,6 +45,7 @@ public: fo::FrmFile* LoadFrmFileCached(const char* file); PcxFile LoadPcxFileCached(const char* file); +bool UnlistedFrmExists(const char* frmName, unsigned int folderRef); fo::FrmFile* LoadUnlistedFrmCached(const char* file, unsigned int folderRef); } diff --git a/sfall/Modules/Interface.cpp b/sfall/Modules/Interface.cpp index be578991..accb88cd 100644 --- a/sfall/Modules/Interface.cpp +++ b/sfall/Modules/Interface.cpp @@ -97,21 +97,34 @@ fo::Window* Interface::GetWindow(long winType) { return (winID > 0) ? fo::func::GNW_find(winID) : nullptr; } -static BYTE* LoadInterfaceFrmData(fo::FrmFile** frm, const char* frmName) { - if (*frm == nullptr) { - *frm = LoadUnlistedFrmCached(frmName, fo::ArtType::OBJ_TYPE_INTRFACE); - if (*frm == nullptr) { - return nullptr; - } +struct InterfaceCustomFrm { + fo::FrmFile* frm; + const char* frmName; + bool isLoaded; + + InterfaceCustomFrm(const char* _frmName) : frm(nullptr), frmName(_frmName), isLoaded(false) {} + InterfaceCustomFrm(InterfaceCustomFrm &other) = delete; + + bool ArtExists() const { + return UnlistedFrmExists(frmName, fo::ArtType::OBJ_TYPE_INTRFACE); } - return (*frm)->frameData[0].data; -} + + BYTE* LoadFrmData() { + if (!isLoaded) { + frm = LoadUnlistedFrmCached(frmName, fo::ArtType::OBJ_TYPE_INTRFACE); + isLoaded = true; + } + return frm != nullptr + ? frm->frameData[0].data + : nullptr; + } +}; static BYTE movePointBackground[16 * 9 * 5]; -static fo::FrmFile* ifaceFrm = nullptr; +static InterfaceCustomFrm ifaceFrm{ "IFACE_E.frm" }; static void* LoadIfaceFrm() { - return LoadInterfaceFrmData(&ifaceFrm, "IFACE_E.frm"); + return ifaceFrm.LoadFrmData(); } static void __declspec(naked) intface_init_hook_lock() { @@ -1113,15 +1126,14 @@ static void UIAnimationSpeedPatch() { SimplePatch(&addrs[4], 2, "Misc", "PipboyTimeAnimDelay", 50, 0, 127); } -static fo::FrmFile* barterTallFrm = nullptr; -static fo::FrmFile* tradeTallFrm = nullptr; -constexpr long numTallFrms = fo::INVENTORY_WINDOW_TYPE_TRADE; -static fo::FrmFile* inventoryTallFrms[numTallFrms] = { nullptr, nullptr, nullptr }; -static const char* inventoryTallFrmNames[numTallFrms] = { "invbox_473.frm", "use_472.frm", "loot_472.frm"}; +static InterfaceCustomFrm barterTallFrm { "barter_e.frm" }; +static InterfaceCustomFrm tradeTallFrm { "trade_e.frm" }; + +static std::array inventoryTallFrms { "invbox_e.frm", "use_e.frm", "loot_e.frm"}; static DWORD findInventoryWindowTypeByFid(DWORD fid) { fid &= 0xFFF; - for (int i = 0; i < numTallFrms; ++i) { + for (int i = 0; i < fo::INVENTORY_WINDOW_TYPE_TRADE; ++i) { if (fid == fo::var::iscr_data[i].artIndex) return i; } @@ -1132,25 +1144,21 @@ static BYTE* __fastcall inventory_get_art_data(DWORD fid) { DWORD windowType = findInventoryWindowTypeByFid(fid); if (windowType > fo::INVENTORY_WINDOW_TYPE_LOOT) return nullptr; - return LoadInterfaceFrmData(&inventoryTallFrms[windowType], inventoryTallFrmNames[windowType]); + return inventoryTallFrms[windowType].LoadFrmData(); } static BYTE* __fastcall gdialog_barter_get_art_data() { - if (fo::var::dialog_target_is_party) { - return LoadInterfaceFrmData(&tradeTallFrm, "trade_238.frm"); - } - return LoadInterfaceFrmData(&barterTallFrm, "barter_239.frm"); + return (fo::var::dialog_target_is_party ? tradeTallFrm : barterTallFrm).LoadFrmData(); } static DWORD __fastcall gdialog_barter_get_art_height() { - fo::FrmFile** frm = fo::var::dialog_target_is_party - ? &tradeTallFrm - : &barterTallFrm; + fo::FrmFile* frm = fo::var::dialog_target_is_party + ? tradeTallFrm.frm + : barterTallFrm.frm; - if (*frm == nullptr) { - return 0; - } - return (*frm)->frameData[0].height; + return frm != nullptr + ? frm->frameData[0].height + : 0; } // replace art data for dialog barter window @@ -1257,7 +1265,16 @@ static void ExpandedBarterPatch() { if (IniReader::GetConfigInt("Interface", "ExpandedBarter", 0) == 0) return; const int dialogWindowHeight = 480 + extraBarterHeight; - if (Graphics::GetGameHeightRes() < dialogWindowHeight) return; + if (Graphics::GetGameHeightRes() < dialogWindowHeight) { + dlog_f("Skipping expanded barter screen patch. Screen height = %d < %d\n", DL_INIT, Graphics::GetGameHeightRes(), dialogWindowHeight); + return; + } + + if (!barterTallFrm.ArtExists() || !tradeTallFrm.ArtExists()) { + dlog_f("Skipping expanded barter screen patch. Missing required FRM files: %s, %s.\n", DL_INIT, + barterTallFrm.frmName, tradeTallFrm.frmName); + return; + } dlogr("Applying expanded barter screen patch.", DL_INIT); SafeWrite32(0x46EDA4, 3 + numExtraBarterSlots); // Trade window slot count 3 -> 4 @@ -1285,13 +1302,26 @@ static void ExpandedBarterPatch() { static void ExpandedInventoryPatch() { if (IniReader::GetConfigInt("Interface", "ExpandedInventory", 0) == 0) return; - dlogr("Applying expanded inventory patch.", DL_INIT); + for (size_t i = 0; i < inventoryTallFrms.size(); i++) { + if (!inventoryTallFrms[i].ArtExists()) { + dlog_f("Skipping expanded inventory screen patch. Missing required FRM file: %s.\n", DL_INIT, inventoryTallFrms[i].frmName); + return; + } + } + + dlogr("Applying expanded inventory screen patch.", DL_INIT); const int numExtraSlots = 2; const int slotHeight = 48; + const int extraHeight = slotHeight * numExtraSlots - 8; // shorten by a few pixels to reduce empty space below the last item slot SafeWrite32(0x46EC9E, 6 + numExtraSlots); // All other inventory windows slot count 6 -> 8 - fo::var::iscr_data[fo::INVENTORY_WINDOW_TYPE_NORMAL].height = 377 + slotHeight * numExtraSlots; // 377 + 96 (two slots) = 473 - fo::var::iscr_data[fo::INVENTORY_WINDOW_TYPE_USE_ITEM_ON].height = 376 + slotHeight * numExtraSlots; // 377 + 96 (two slots) = 473 - fo::var::iscr_data[fo::INVENTORY_WINDOW_TYPE_LOOT].height = 376 + slotHeight * numExtraSlots; // 377 + 96 (two slots) = 473 + fo::var::iscr_data[fo::INVENTORY_WINDOW_TYPE_NORMAL].height = 377 + extraHeight; + fo::var::iscr_data[fo::INVENTORY_WINDOW_TYPE_USE_ITEM_ON].height = 376 + extraHeight; + fo::var::iscr_data[fo::INVENTORY_WINDOW_TYPE_LOOT].height = 376 + extraHeight; + + // Shift Done buttons down: + SafeWrite32(0x46F26C, 329 + extraHeight); // Normal + SafeWrite32(0x46F29C, 328 + extraHeight); // Use Item On + SafeWrite32(0x46F2CC, 331 + extraHeight); // Loot // Transparent inventory windows create issues: // - Subtle flickering when dragging items @@ -1364,10 +1394,10 @@ void Interface::init() { } } LoadGameHook::OnGameInit() += []() { - // Needs to be invoked in OnGameInit when screen height is already known. + // Needs to be invoked in OnGameInit when screen height is already known and db is initialized. ExpandedBarterPatch(); + ExpandedInventoryPatch(); }; - ExpandedInventoryPatch(); } void Interface::exit() { diff --git a/sfall/ddraw.vcxproj b/sfall/ddraw.vcxproj index 2a8f76df..8b480592 100644 --- a/sfall/ddraw.vcxproj +++ b/sfall/ddraw.vcxproj @@ -401,6 +401,7 @@ + @@ -542,6 +543,7 @@ + diff --git a/sfall/ddraw.vcxproj.filters b/sfall/ddraw.vcxproj.filters index e46e2bf0..fbfea8af 100644 --- a/sfall/ddraw.vcxproj.filters +++ b/sfall/ddraw.vcxproj.filters @@ -457,6 +457,7 @@ Modules\Scripting\Handlers + @@ -834,6 +835,7 @@ Modules\Scripting\Handlers +