Skip to content

Commit

Permalink
Merge pull request #532 from sfall-team/feature/apbarpatch-small-frm
Browse files Browse the repository at this point in the history
ActionPointsBar: language agnostic FRM
  • Loading branch information
NovaRain authored May 12, 2024
2 parents 08efe38 + 44e7a67 commit 2d7c49a
Show file tree
Hide file tree
Showing 15 changed files with 91 additions and 47 deletions.
2 changes: 1 addition & 1 deletion artifacts/ddraw.ini
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Binary file not shown.
Binary file removed artifacts/sfall_dat/dat_en/art/intrface/IFACE_E.frm
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file removed artifacts/sfall_dat/dat_ru/art/intrface/IFACE_E.frm
Binary file not shown.
Binary file not shown.
Binary file removed artifacts/sfall_dat/dat_zh/art/intrface/IFACE_E.frm
Binary file not shown.
1 change: 1 addition & 0 deletions sfall/FalloutEngine/VariableOffsets.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions sfall/FalloutEngine/Variables_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
9 changes: 2 additions & 7 deletions sfall/HRP/InterfaceBar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand All @@ -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
Expand Down Expand Up @@ -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));
}
Expand Down
2 changes: 0 additions & 2 deletions sfall/HRP/InterfaceBar.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ class IFaceBar {
static long display_width;
static char* display_string_buf;

static void SetExpandAPBar();

static void Hide();
static void Show();
};
Expand Down
66 changes: 49 additions & 17 deletions sfall/Modules/ExtraArt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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() {
Expand All @@ -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();
Expand Down
17 changes: 17 additions & 0 deletions sfall/Modules/ExtraArt.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

}
40 changes: 20 additions & 20 deletions sfall/Modules/Interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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_;
}
}

Expand Down Expand Up @@ -175,28 +179,25 @@ 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;
}
LoadGameHook::OnAfterGameInit() += APBarRectPatch;
} 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);
Expand Down Expand Up @@ -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) {
Expand Down

0 comments on commit 2d7c49a

Please sign in to comment.