mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
Merge pull request #532 from sfall-team/feature/apbarpatch-small-frm
ActionPointsBar: language agnostic FRM
This commit is contained in:
+1
-1
@@ -110,7 +110,7 @@ FadeMultiplier=100
|
||||
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
[Interface]
|
||||
;Set to 1 to expand the number of action points displayed on the interface bar
|
||||
;Requires new IFACE_E.frm and HR_IFACE_<res>E.frm files in art\intrface\ (included in sfall.dat) to display correctly
|
||||
;Requires new iface_apbar_e.frm in art\intrface\ (included in sfall.dat) to display correctly
|
||||
;The minimum supported version of the hi-res patch is v4.1.8
|
||||
ActionPointsBar=0
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -165,6 +165,7 @@
|
||||
#define FO_VAR_idle_func 0x51E234
|
||||
#define FO_VAR_In_WorldMap 0x672E1C
|
||||
#define FO_VAR_info_line 0x5707D0
|
||||
#define FO_VAR_interfaceBuffer 0x59D3F4
|
||||
#define FO_VAR_interfaceWindow 0x519024
|
||||
#define FO_VAR_intface_full_width 0x56FB4C
|
||||
#define FO_VAR_intfaceEnabled 0x518F10
|
||||
|
||||
@@ -102,6 +102,7 @@ VAR_(i_worn, fo::GameObject*)
|
||||
VAR_(idle_func, void*)
|
||||
VAR_(In_WorldMap, DWORD) // moving on WorldMap
|
||||
VAR_(info_line, DWORD)
|
||||
VAR_(interfaceBuffer, BYTE*)
|
||||
VARC(interfaceWindow, DWORD)
|
||||
VAR_(intfaceEnabled, DWORD)
|
||||
VAR_(intotal, DWORD)
|
||||
|
||||
@@ -36,7 +36,6 @@ static long yPosition;
|
||||
static long xOffset;
|
||||
static long xyOffsetCBtn;
|
||||
static long xyOffsetAP;
|
||||
static bool expandAPBar = false;
|
||||
|
||||
long IFaceBar::display_width = 0; // width of the area for text output
|
||||
char* IFaceBar::display_string_buf = (char*)FO_VAR_display_string_buf;
|
||||
@@ -202,7 +201,7 @@ static long __cdecl InterfaceArt(BYTE* scr, long w, long h, long srcWidth, BYTE*
|
||||
fo::var::itemButtonRect.offx += xOffset;
|
||||
|
||||
char file[33];
|
||||
std::sprintf(file, "HR_IFACE_%i%s.frm", IFaceBar::IFACE_BAR_WIDTH, ((expandAPBar) ? "E" : ""));
|
||||
std::sprintf(file, "HR_IFACE_%i.frm", IFaceBar::IFACE_BAR_WIDTH);
|
||||
|
||||
fo::FrmFile* frm = sf::LoadUnlistedFrmCached(file, fo::ArtType::OBJ_TYPE_INTRFACE);
|
||||
if (frm != nullptr && frm->frameData[0].width == IFaceBar::IFACE_BAR_WIDTH) {
|
||||
@@ -214,7 +213,7 @@ static long __cdecl InterfaceArt(BYTE* scr, long w, long h, long srcWidth, BYTE*
|
||||
}
|
||||
|
||||
// no required file, use the default one provided by HRP
|
||||
if (frm == nullptr) frm = sf::LoadUnlistedFrmCached(((expandAPBar) ? "HR_IFACE_800E.frm" : "HR_IFACE_800.frm"), fo::ArtType::OBJ_TYPE_INTRFACE);
|
||||
if (frm == nullptr) frm = sf::LoadUnlistedFrmCached("HR_IFACE_800.frm", fo::ArtType::OBJ_TYPE_INTRFACE);
|
||||
|
||||
if (frm != nullptr) {
|
||||
// scale the 800px wide interface to the width of IFACE_BAR_WIDTH
|
||||
@@ -466,10 +465,6 @@ static void __declspec(naked) intface_update_ammo_lights_hook() {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void IFaceBar::SetExpandAPBar() {
|
||||
expandAPBar = true;
|
||||
}
|
||||
|
||||
void IFaceBar::Hide() {
|
||||
InterfaceHide(fo::var::getInt(FO_VAR_interfaceWindow));
|
||||
}
|
||||
|
||||
@@ -25,8 +25,6 @@ public:
|
||||
static long display_width;
|
||||
static char* display_string_buf;
|
||||
|
||||
static void SetExpandAPBar();
|
||||
|
||||
static void Hide();
|
||||
static void Show();
|
||||
};
|
||||
|
||||
+49
-17
@@ -41,15 +41,25 @@ static PcxFile LoadPcxFile(const char* file) {
|
||||
return pcx;
|
||||
}
|
||||
|
||||
static fo::FrmFile* LoadFrmFile(const char* file) {
|
||||
fo::FrmFile* frmPtr = nullptr;
|
||||
if (fo::func::load_frame(file, &frmPtr)) {
|
||||
frmPtr = nullptr;
|
||||
}
|
||||
return frmPtr;
|
||||
}
|
||||
|
||||
void UnloadFrmFile(fo::FrmFile* frm) {
|
||||
fo::func::mem_free(frm);
|
||||
}
|
||||
|
||||
fo::FrmFile* LoadFrmFileCached(const char* file) {
|
||||
fo::FrmFile* frmPtr = nullptr;
|
||||
auto cacheHit = frmFileCache.find(file);
|
||||
if (cacheHit != frmFileCache.end()) {
|
||||
frmPtr = cacheHit->second;
|
||||
} else {
|
||||
if (fo::func::load_frame(file, &frmPtr)) {
|
||||
frmPtr = nullptr;
|
||||
}
|
||||
frmPtr = LoadFrmFile(file);
|
||||
frmFileCache.emplace(file, frmPtr);
|
||||
}
|
||||
return frmPtr;
|
||||
@@ -64,7 +74,6 @@ PcxFile LoadPcxFileCached(const char* file) {
|
||||
}
|
||||
|
||||
static void GetUnlistedFrmPath(const char* frmName, unsigned int folderRef, bool useLanguage, char* pathBuf) {
|
||||
|
||||
const char* artfolder = fo::var::art[folderRef].path; // address of art type name
|
||||
if (useLanguage) {
|
||||
sprintf_s(pathBuf, MAX_PATH, "art\\%s\\%s\\%s", (const char*)fo::var::language, artfolder, frmName);
|
||||
@@ -73,10 +82,9 @@ static void GetUnlistedFrmPath(const char* frmName, unsigned int folderRef, bool
|
||||
}
|
||||
}
|
||||
|
||||
bool UnlistedFrmExists(const char* frmName, unsigned int folderRef) {
|
||||
static bool CheckUnlistedFrm(const char* frmName, unsigned int folderRef, char* frmPath) {
|
||||
if (folderRef > fo::OBJ_TYPE_SKILLDEX) return nullptr;
|
||||
|
||||
char frmPath[MAX_PATH];
|
||||
GetUnlistedFrmPath(frmName, folderRef, fo::var::use_language != 0, frmPath);
|
||||
|
||||
bool exists = fo::func::db_access(frmPath);
|
||||
@@ -87,19 +95,21 @@ bool UnlistedFrmExists(const char* frmName, unsigned int folderRef) {
|
||||
return exists;
|
||||
}
|
||||
|
||||
fo::FrmFile* LoadUnlistedFrmCached(const char* frmName, unsigned int folderRef) {
|
||||
if (folderRef > fo::OBJ_TYPE_SKILLDEX) return nullptr;
|
||||
|
||||
bool UnlistedFrmExists(const char* frmName, unsigned int folderRef) {
|
||||
char frmPath[MAX_PATH];
|
||||
return CheckUnlistedFrm(frmName, folderRef, frmPath);
|
||||
}
|
||||
|
||||
GetUnlistedFrmPath(frmName, folderRef, fo::var::use_language != 0, frmPath);
|
||||
fo::FrmFile* LoadUnlistedFrm(const char* frmName, unsigned int folderRef) {
|
||||
char frmPath[MAX_PATH];
|
||||
if (!CheckUnlistedFrm(frmName, folderRef, frmPath)) return nullptr;
|
||||
return LoadFrmFile(frmPath);
|
||||
}
|
||||
|
||||
fo::FrmFile* frm = LoadFrmFileCached(frmPath);
|
||||
if (frm == nullptr && fo::var::use_language) {
|
||||
GetUnlistedFrmPath(frmName, folderRef, false, frmPath);
|
||||
frm = LoadFrmFileCached(frmPath);
|
||||
}
|
||||
return frm;
|
||||
fo::FrmFile* LoadUnlistedFrmCached(const char* frmName, unsigned int folderRef) {
|
||||
char frmPath[MAX_PATH];
|
||||
if (!CheckUnlistedFrm(frmName, folderRef, frmPath)) return nullptr;
|
||||
return LoadFrmFileCached(frmPath);
|
||||
}
|
||||
|
||||
static void ClearInterfaceArtCache() {
|
||||
@@ -109,11 +119,33 @@ static void ClearInterfaceArtCache() {
|
||||
pcxFileCache.clear();
|
||||
|
||||
for (auto &pair : frmFileCache) {
|
||||
fo::func::mem_free(pair.second);
|
||||
UnloadFrmFile(pair.second);
|
||||
}
|
||||
frmFileCache.clear();
|
||||
}
|
||||
|
||||
TempFrmHandle::TempFrmHandle(fo::FrmFile* frm) : _frm(frm) {
|
||||
}
|
||||
|
||||
TempFrmHandle::TempFrmHandle(TempFrmHandle&& other) : _frm(other._frm) {
|
||||
other._frm = nullptr;
|
||||
}
|
||||
|
||||
TempFrmHandle::~TempFrmHandle() {
|
||||
if (_frm == nullptr) return;
|
||||
UnloadFrmFile(_frm);
|
||||
_frm = nullptr;
|
||||
}
|
||||
|
||||
bool TempFrmHandle::IsValid() {
|
||||
return _frm != nullptr;
|
||||
}
|
||||
|
||||
const fo::FrmFile& TempFrmHandle::Frm() const {
|
||||
assert(_frm != nullptr);
|
||||
return *_frm;
|
||||
}
|
||||
|
||||
void ExtraArt::init() {
|
||||
LoadGameHook::OnGameReset() += []() {
|
||||
ClearInterfaceArtCache();
|
||||
|
||||
@@ -36,16 +36,33 @@ struct PcxFile {
|
||||
PcxFile() : pixelData(nullptr), width(0), height(0) {}
|
||||
};
|
||||
|
||||
class TempFrmHandle {
|
||||
public:
|
||||
TempFrmHandle(fo::FrmFile* frm);
|
||||
TempFrmHandle(const TempFrmHandle&) = delete;
|
||||
TempFrmHandle(TempFrmHandle&&);
|
||||
TempFrmHandle& operator=(TempFrmHandle) = delete;
|
||||
~TempFrmHandle();
|
||||
|
||||
bool IsValid();
|
||||
const fo::FrmFile& Frm() const;
|
||||
private:
|
||||
fo::FrmFile* _frm;
|
||||
};
|
||||
|
||||
class ExtraArt : public Module {
|
||||
public:
|
||||
const char* name() { return "ExtraArt"; }
|
||||
void init();
|
||||
};
|
||||
|
||||
// TODO: more robust caching, similar to how art_ptr_lock works.
|
||||
fo::FrmFile* LoadFrmFileCached(const char* file);
|
||||
PcxFile LoadPcxFileCached(const char* file);
|
||||
|
||||
bool UnlistedFrmExists(const char* frmName, unsigned int folderRef);
|
||||
fo::FrmFile* LoadUnlistedFrm(const char* frmName, unsigned int folderRef);
|
||||
fo::FrmFile* LoadUnlistedFrmCached(const char* file, unsigned int folderRef);
|
||||
void UnloadFrmFile(fo::FrmFile* frm);
|
||||
|
||||
}
|
||||
|
||||
+20
-20
@@ -126,25 +126,29 @@ struct InterfaceCustomFrm {
|
||||
};
|
||||
|
||||
static BYTE movePointBackground[16 * 9 * 5];
|
||||
static InterfaceCustomFrm ifaceFrm{ "IFACE_E.frm" };
|
||||
|
||||
static void* LoadIfaceFrm() {
|
||||
return ifaceFrm.LoadFrmData();
|
||||
static void DrawExtendedApBar() {
|
||||
const char* const ifaceApBarFrm = "iface_apbar_e.frm"; // 183x13 at 266,10 (x = width - 374)
|
||||
TempFrmHandle frmHandle{ LoadUnlistedFrm(ifaceApBarFrm, fo::ArtType::OBJ_TYPE_INTRFACE) };
|
||||
if (!frmHandle.IsValid()) return;
|
||||
|
||||
DWORD ifaceWin = fo::var::interfaceWindow;
|
||||
fo::Window* win = fo::func::GNW_find(ifaceWin);
|
||||
if (win == nullptr) return;
|
||||
|
||||
constexpr int destOffsetRight = 374;
|
||||
constexpr int destOffsetTop = 10;
|
||||
const fo::FrmFrameData& srcFrame = frmHandle.Frm().frameData[0];
|
||||
BYTE* dest = fo::var::interfaceBuffer + (win->width * (destOffsetTop + 1)) - destOffsetRight;
|
||||
fo::func::buf_to_buf((BYTE*)srcFrame.data, srcFrame.width, srcFrame.height, srcFrame.width, dest, win->width);
|
||||
}
|
||||
|
||||
static void __declspec(naked) intface_init_hook_lock() {
|
||||
static void __declspec(naked) intface_init_hook_unlock_iface_frm() {
|
||||
__asm {
|
||||
pushadc;
|
||||
call LoadIfaceFrm;
|
||||
test eax, eax;
|
||||
jz skip;
|
||||
pop ecx;
|
||||
add esp, 8;
|
||||
mov dword ptr [ecx], 0;
|
||||
retn;
|
||||
skip:
|
||||
call DrawExtendedApBar;
|
||||
popadc;
|
||||
jmp fo::funcoffs::art_ptr_lock_data_;
|
||||
jmp fo::funcoffs::art_ptr_unlock_;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,14 +179,10 @@ static void APBarRectPatch() {
|
||||
}
|
||||
|
||||
static void ActionPointsBarPatch() {
|
||||
HRP::IFaceBar::SetExpandAPBar();
|
||||
|
||||
dlog("Applying expanded action points bar patch.", DL_INIT);
|
||||
if (HRP::Setting::ExternalEnabled()) {
|
||||
// check valid data
|
||||
if (HRP::Setting::VersionIsValid && !_stricmp((const char*)HRP::Setting::GetAddress(HRP_VAR_HR_IFACE_FRM_STR), "HR_IFACE_%i.frm")) {
|
||||
SafeWriteStr(HRP::Setting::GetAddress(HRP_VAR_HR_IFACE_FRM_STR + 11), "E.frm"); // patching HRP
|
||||
} else {
|
||||
if (!HRP::Setting::VersionIsValid) {
|
||||
dlogr(" Incorrect HRP version!", DL_INIT);
|
||||
return;
|
||||
}
|
||||
@@ -190,13 +190,14 @@ static void ActionPointsBarPatch() {
|
||||
} else {
|
||||
APBarRectPatch();
|
||||
}
|
||||
|
||||
// intface_init_
|
||||
SafeWriteBatch<DWORD>((DWORD)&movePointBackground, {0x45E343, 0x45EE3F});
|
||||
// intface_update_move_points_
|
||||
SafeWriteBatch<BYTE>(16, {0x45EE55, 0x45EE7B, 0x45EE82, 0x45EE9C, 0x45EEA0});
|
||||
SafeWriteBatch<DWORD>(9276 - (54 / 2), {0x45EE33, 0x45EEC8, 0x45EF16});
|
||||
|
||||
HookCall(0x45D918, intface_init_hook_lock);
|
||||
HookCall(0x45D962, intface_init_hook_unlock_iface_frm);
|
||||
MakeCall(0x45E356, intface_init_hack);
|
||||
MakeJump(0x45EE38, intface_update_move_points_hack, 1);
|
||||
dlogr(" Done", DL_INIT);
|
||||
@@ -1412,7 +1413,6 @@ void Interface::init() {
|
||||
ExpandedInventoryPatch();
|
||||
};
|
||||
LoadGameHook::OnGameReset() += []() {
|
||||
ifaceFrm.Reset();
|
||||
barterTallFrm.Reset();
|
||||
tradeTallFrm.Reset();
|
||||
for (size_t i = 0; i < inventoryTallFrms.size(); ++i) {
|
||||
|
||||
Reference in New Issue
Block a user