From a43186df7aebce98bb8f1c3761bf1cf1825a4ab5 Mon Sep 17 00:00:00 2001 From: phobos2077 Date: Sat, 4 May 2024 02:06:40 +0200 Subject: [PATCH] Barter extra slots: Make optional by using LoadUnlistedFrm to replace default FRM --- artifacts/ddraw.ini | 4 ++ sfall/FalloutEngine/EngineUtils.cpp | 2 +- sfall/FalloutEngine/EngineUtils.h | 2 +- sfall/Modules/Interface.cpp | 100 +++++++++++++++++++++++++--- 4 files changed, 95 insertions(+), 13 deletions(-) diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index 2c0b0a5e..35ee691e 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -133,6 +133,10 @@ WorldMapTravelMarkers=0 ;Set to 1 to display terrain types when hovering the cursor over the player's marker on the world map WorldMapTerrainInfo=0 +;Set to 1 to enable tall trade window with 4 item slots per table instead of 3 +;Requires new barter_239.frm and trade_238.frm files in art\intrface\ (included in sfall.dat) to display correctly +InventoryExtraSlots=0 + ;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX [Sound] ;Sets the number of allowed simultaneous sound effects diff --git a/sfall/FalloutEngine/EngineUtils.cpp b/sfall/FalloutEngine/EngineUtils.cpp index 9f03b808..4ddc24d4 100644 --- a/sfall/FalloutEngine/EngineUtils.cpp +++ b/sfall/FalloutEngine/EngineUtils.cpp @@ -712,7 +712,7 @@ static bool LoadFrmFrame(fo::UnlistedFrm::Frame *frame, fo::DbFile* frmStream) { return true; } -fo::UnlistedFrm *LoadUnlistedFrm(char *frmName, unsigned int folderRef) { +fo::UnlistedFrm *LoadUnlistedFrm(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 diff --git a/sfall/FalloutEngine/EngineUtils.h b/sfall/FalloutEngine/EngineUtils.h index 579e084f..54198a79 100644 --- a/sfall/FalloutEngine/EngineUtils.h +++ b/sfall/FalloutEngine/EngineUtils.h @@ -191,7 +191,7 @@ void RedrawObject(fo::GameObject* obj); // Redraws all windows void RefreshGNW(bool skipOwner = false); -fo::UnlistedFrm *LoadUnlistedFrm(char *frmName, unsigned int folderRef); +fo::UnlistedFrm *LoadUnlistedFrm(const char *frmName, unsigned int folderRef); } } diff --git a/sfall/Modules/Interface.cpp b/sfall/Modules/Interface.cpp index 27a5d182..5155c933 100644 --- a/sfall/Modules/Interface.cpp +++ b/sfall/Modules/Interface.cpp @@ -1104,6 +1104,94 @@ static void UIAnimationSpeedPatch() { SimplePatch(&addrs[4], 2, "Misc", "PipboyTimeAnimDelay", 50, 0, 127); } + +static fo::UnlistedFrm* barterTallFrm = nullptr; +static fo::UnlistedFrm* tradeTallFrm = nullptr; + +static BYTE* __fastcall gdialog_barter_create_win__get_art_data() { + fo::UnlistedFrm** frm; + const char* frmName; + if (fo::var::dialog_target_is_party) { + frm = &tradeTallFrm; + frmName = "trade_238.frm"; + } + else { + frm = &barterTallFrm; + frmName = "barter_239.frm"; + } + if (*frm == nullptr) { + *frm = fo::util::LoadUnlistedFrm(frmName, fo::ArtType::OBJ_TYPE_INTRFACE); + if (*frm == nullptr) { + return nullptr; + } + } + return (*frm)->frames[0].indexBuff; +} + +static DWORD __fastcall gdialog_barter_create_win__get_art_height() { + fo::UnlistedFrm** frm = fo::var::dialog_target_is_party + ? &tradeTallFrm + : &barterTallFrm; + + if (*frm == nullptr) { + return 0; + } + return (*frm)->frames[0].height; +} + +static void __declspec(naked) gdialog_barter_create_win__art_frame_data_hook() { + __asm { + pushadc; + call gdialog_barter_create_win__get_art_data; + test eax, eax; + jz skipCall; + pop ecx; + pop edx; + add esp, 4; + retn; +skipCall: + popadc; + jmp fo::funcoffs::art_frame_data_; + } +} + +static long frmHeight; +static void __declspec(naked) gdialog_barter_create_win__art_frame_length_hook() { + __asm { + pushadc; + call gdialog_barter_create_win__get_art_height; + test eax, eax; + jz skipCall; + pop ecx; + pop edx; + add esp, 4; + retn; +skipCall: + popadc; + jmp fo::funcoffs::art_frame_length_; + } +} + + +static void InventoryExtraSlotsPatch() { + if (IniReader::GetConfigInt("Interface", "InventoryExtraSlots", 0) == 0) return; + + dlogr("Applying extra inventory slots patch.", DL_INIT); + SafeWrite32(0x46EDA4, 4); // Trade window slot count 3 -> 4 + SafeWriteBatch(228, { 0x46EDAB, 0x46EE13 }); // Trade window height 180 + 48 (one slot) = 228 + SafeWrite32(0x46EDD4, 518); // Trade window max Y = Y pos + height = 290 + 228 = 518 (was 470) + SafeWriteBatch(528, { // Game dialog BG window height = 480 + 48 = 528 + 0x44831E, // gdialog_barter_create_win_ + //0x44879F, // gdControlCreateWin_ + //0x449740, // gdCustomCreateWin_ + //0x44A6CF, // gdialog_window_create_ + 0x44AAE9, // talk_to_create_background_window + }); + + HookCall(0x4482EA, gdialog_barter_create_win__art_frame_data_hook); + HookCall(0x4482FF, gdialog_barter_create_win__art_frame_length_hook); +} + void Interface::init() { InterfaceWindowPatch(); InventoryCharacterRotationSpeedPatch(); @@ -1139,17 +1227,7 @@ void Interface::init() { ammoBarXPos -= 2; } } - - SafeWrite32(0x46EDA4, 4); // Trade window slot count 3 -> 4 - SafeWriteBatch(228, { 0x46EDAB, 0x46EE13 }); // Trade window height 180 + 48 (one slot) = 228 - SafeWrite32(0x46EDD4, 518); // Trade window max Y = Y pos + height = 290 + 228 = 518 (was 470) - SafeWriteBatch(528, { // Game dialog BG window height = 480 + 48 = 528 - 0x44831E, // gdialog_barter_create_win_ - //0x44879F, // gdControlCreateWin_ - //0x449740, // gdCustomCreateWin_ - //0x44A6CF, // gdialog_window_create_ - 0x44AAE9, // talk_to_create_background_window - }); + InventoryExtraSlotsPatch(); } void Interface::exit() {