Final preparations for extended UI patches

- Reduced inventory UI height by 8 pixels and moved all Done buttons down
- Renamed all extra FRM files
- Added checks that all required FRMs exist before applying patch
- Add final FRM files (EN versions)
- Minor refactoring
This commit is contained in:
phobos2077
2024-05-08 20:48:11 +02:00
parent ed44706c9f
commit c850c2ec4f
11 changed files with 99 additions and 46 deletions
+3 -3
View File
@@ -134,12 +134,12 @@ WorldMapTravelMarkers=0
WorldMapTerrainInfo=0 WorldMapTerrainInfo=0
;Set to 1 to enable tall trade/barter window with 4 item slots per table instead of 3 ;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) ;Requires the high-res mode with resolution of at least 640x528
;The resolution of the hi-res patch must be set to at least 640x528 ;Requires new frm files in art\intrface\: barter_e.frm (640x239), trade_e.frm (640x238) (included in sfall.dat)
ExpandedBarter=0 ExpandedBarter=0
;Set to 1 to enable tall inventory/loot/item select windows with 8 vertical slots instead of 6 ;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 ExpandedInventory=0
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+26 -8
View File
@@ -63,22 +63,40 @@ PcxFile LoadPcxFileCached(const char* file) {
return pcxFileCache.emplace(file, LoadPcxFile(file)).first->second; 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) { fo::FrmFile* LoadUnlistedFrmCached(const char* frmName, unsigned int folderRef) {
if (folderRef > fo::OBJ_TYPE_SKILLDEX) return nullptr; 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]; char frmPath[MAX_PATH];
if (fo::var::use_language) { GetUnlistedFrmPath(frmName, folderRef, fo::var::use_language != 0, frmPath, MAX_PATH);
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);
}
fo::FrmFile* frm = LoadFrmFileCached(frmPath); fo::FrmFile* frm = LoadFrmFileCached(frmPath);
if (frm == nullptr && fo::var::use_language) { 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); frm = LoadFrmFileCached(frmPath);
} }
return frm; return frm;
+1
View File
@@ -45,6 +45,7 @@ public:
fo::FrmFile* LoadFrmFileCached(const char* file); fo::FrmFile* LoadFrmFileCached(const char* file);
PcxFile LoadPcxFileCached(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); fo::FrmFile* LoadUnlistedFrmCached(const char* file, unsigned int folderRef);
} }
+65 -35
View File
@@ -97,21 +97,34 @@ fo::Window* Interface::GetWindow(long winType) {
return (winID > 0) ? fo::func::GNW_find(winID) : nullptr; return (winID > 0) ? fo::func::GNW_find(winID) : nullptr;
} }
static BYTE* LoadInterfaceFrmData(fo::FrmFile** frm, const char* frmName) { struct InterfaceCustomFrm {
if (*frm == nullptr) { fo::FrmFile* frm;
*frm = LoadUnlistedFrmCached(frmName, fo::ArtType::OBJ_TYPE_INTRFACE); const char* frmName;
if (*frm == nullptr) { bool isLoaded;
return nullptr;
} 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 BYTE movePointBackground[16 * 9 * 5];
static fo::FrmFile* ifaceFrm = nullptr; static InterfaceCustomFrm ifaceFrm{ "IFACE_E.frm" };
static void* LoadIfaceFrm() { static void* LoadIfaceFrm() {
return LoadInterfaceFrmData(&ifaceFrm, "IFACE_E.frm"); return ifaceFrm.LoadFrmData();
} }
static void __declspec(naked) intface_init_hook_lock() { static void __declspec(naked) intface_init_hook_lock() {
@@ -1113,15 +1126,14 @@ static void UIAnimationSpeedPatch() {
SimplePatch<BYTE>(&addrs[4], 2, "Misc", "PipboyTimeAnimDelay", 50, 0, 127); SimplePatch<BYTE>(&addrs[4], 2, "Misc", "PipboyTimeAnimDelay", 50, 0, 127);
} }
static fo::FrmFile* barterTallFrm = nullptr; static InterfaceCustomFrm barterTallFrm { "barter_e.frm" };
static fo::FrmFile* tradeTallFrm = nullptr; static InterfaceCustomFrm tradeTallFrm { "trade_e.frm" };
constexpr long numTallFrms = fo::INVENTORY_WINDOW_TYPE_TRADE;
static fo::FrmFile* inventoryTallFrms[numTallFrms] = { nullptr, nullptr, nullptr }; static std::array<InterfaceCustomFrm, fo::INVENTORY_WINDOW_TYPE_TRADE> inventoryTallFrms { "invbox_e.frm", "use_e.frm", "loot_e.frm"};
static const char* inventoryTallFrmNames[numTallFrms] = { "invbox_473.frm", "use_472.frm", "loot_472.frm"};
static DWORD findInventoryWindowTypeByFid(DWORD fid) { static DWORD findInventoryWindowTypeByFid(DWORD fid) {
fid &= 0xFFF; 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) if (fid == fo::var::iscr_data[i].artIndex)
return i; return i;
} }
@@ -1132,25 +1144,21 @@ static BYTE* __fastcall inventory_get_art_data(DWORD fid) {
DWORD windowType = findInventoryWindowTypeByFid(fid); DWORD windowType = findInventoryWindowTypeByFid(fid);
if (windowType > fo::INVENTORY_WINDOW_TYPE_LOOT) return nullptr; 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() { static BYTE* __fastcall gdialog_barter_get_art_data() {
if (fo::var::dialog_target_is_party) { return (fo::var::dialog_target_is_party ? tradeTallFrm : barterTallFrm).LoadFrmData();
return LoadInterfaceFrmData(&tradeTallFrm, "trade_238.frm");
}
return LoadInterfaceFrmData(&barterTallFrm, "barter_239.frm");
} }
static DWORD __fastcall gdialog_barter_get_art_height() { static DWORD __fastcall gdialog_barter_get_art_height() {
fo::FrmFile** frm = fo::var::dialog_target_is_party fo::FrmFile* frm = fo::var::dialog_target_is_party
? &tradeTallFrm ? tradeTallFrm.frm
: &barterTallFrm; : barterTallFrm.frm;
if (*frm == nullptr) { return frm != nullptr
return 0; ? frm->frameData[0].height
} : 0;
return (*frm)->frameData[0].height;
} }
// replace art data for dialog barter window // replace art data for dialog barter window
@@ -1257,7 +1265,16 @@ static void ExpandedBarterPatch() {
if (IniReader::GetConfigInt("Interface", "ExpandedBarter", 0) == 0) return; if (IniReader::GetConfigInt("Interface", "ExpandedBarter", 0) == 0) return;
const int dialogWindowHeight = 480 + extraBarterHeight; 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); dlogr("Applying expanded barter screen patch.", DL_INIT);
SafeWrite32(0x46EDA4, 3 + numExtraBarterSlots); // Trade window slot count 3 -> 4 SafeWrite32(0x46EDA4, 3 + numExtraBarterSlots); // Trade window slot count 3 -> 4
@@ -1285,13 +1302,26 @@ static void ExpandedBarterPatch() {
static void ExpandedInventoryPatch() { static void ExpandedInventoryPatch() {
if (IniReader::GetConfigInt("Interface", "ExpandedInventory", 0) == 0) return; 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 numExtraSlots = 2;
const int slotHeight = 48; 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 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_NORMAL].height = 377 + extraHeight;
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_USE_ITEM_ON].height = 376 + extraHeight;
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_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: // Transparent inventory windows create issues:
// - Subtle flickering when dragging items // - Subtle flickering when dragging items
@@ -1364,10 +1394,10 @@ void Interface::init() {
} }
} }
LoadGameHook::OnGameInit() += []() { 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(); ExpandedBarterPatch();
ExpandedInventoryPatch();
}; };
ExpandedInventoryPatch();
} }
void Interface::exit() { void Interface::exit() {
+2
View File
@@ -401,6 +401,7 @@
<ClInclude Include="Modules\CritterPoison.h" /> <ClInclude Include="Modules\CritterPoison.h" />
<ClInclude Include="Modules\CritterStats.h" /> <ClInclude Include="Modules\CritterStats.h" />
<ClInclude Include="Modules\EngineTweaks.h" /> <ClInclude Include="Modules\EngineTweaks.h" />
<ClInclude Include="Modules\ExtraArt.h" />
<ClInclude Include="Modules\Interface.h" /> <ClInclude Include="Modules\Interface.h" />
<ClInclude Include="Modules\Drugs.h" /> <ClInclude Include="Modules\Drugs.h" />
<ClInclude Include="Modules\HookScripts\CombatHs.h" /> <ClInclude Include="Modules\HookScripts\CombatHs.h" />
@@ -542,6 +543,7 @@
<ClCompile Include="Modules\CritterPoison.cpp" /> <ClCompile Include="Modules\CritterPoison.cpp" />
<ClCompile Include="Modules\CritterStats.cpp" /> <ClCompile Include="Modules\CritterStats.cpp" />
<ClCompile Include="Modules\EngineTweaks.cpp" /> <ClCompile Include="Modules\EngineTweaks.cpp" />
<ClCompile Include="Modules\ExtraArt.cpp" />
<ClCompile Include="Modules\Interface.cpp" /> <ClCompile Include="Modules\Interface.cpp" />
<ClCompile Include="Modules\Drugs.cpp" /> <ClCompile Include="Modules\Drugs.cpp" />
<ClCompile Include="Modules\HookScripts\CombatHs.cpp" /> <ClCompile Include="Modules\HookScripts\CombatHs.cpp" />
+2
View File
@@ -457,6 +457,7 @@
<ClInclude Include="Modules\Scripting\Handlers\IniFiles.h"> <ClInclude Include="Modules\Scripting\Handlers\IniFiles.h">
<Filter>Modules\Scripting\Handlers</Filter> <Filter>Modules\Scripting\Handlers</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Modules\ExtraArt.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="main.cpp" /> <ClCompile Include="main.cpp" />
@@ -834,6 +835,7 @@
<ClCompile Include="Modules\Scripting\Handlers\IniFiles.cpp"> <ClCompile Include="Modules\Scripting\Handlers\IniFiles.cpp">
<Filter>Modules\Scripting\Handlers</Filter> <Filter>Modules\Scripting\Handlers</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Modules\ExtraArt.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ResourceCompile Include="version.rc" /> <ResourceCompile Include="version.rc" />