Backported ActionPointsBar from 4.x

Updated resource files.
This commit is contained in:
NovaRain
2026-04-22 21:09:32 +08:00
parent 17ffdd6791
commit 2415eb31f2
13 changed files with 136 additions and 5 deletions
+4
View File
@@ -105,6 +105,10 @@ FadeMultiplier=100
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
[Interface]
;Set to 1 to expand the number of action points displayed on the interface bar
;Requires a new IFACE_APBAR_E.frm in art\intrface\ (included in sfall.dat) to display correctly
ActionPointsBar=0
;Set to 1 to use the expanded world map interface
;Set to 2 to skip correcting the position of entrance markers on town maps
;You can use resized FRMs in 700x682 for town maps in the expanded world map interface
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2
View File
@@ -92,6 +92,7 @@ PTR_(i_worn, fo::GameObject*)
PTR_(idle_func, void*)
PTR_(In_WorldMap, DWORD) // moving on WorldMap
PTR_(info_line, DWORD)
PTR_(interfaceBuffer, BYTE*)
PTRC(interfaceWindow, DWORD)
PTR_(intfaceEnabled, DWORD)
PTR_(intotal, DWORD)
@@ -136,6 +137,7 @@ PTR_(mouse_is_hidden, DWORD)
PTR_(mouse_x_, DWORD)
PTR_(mouse_y, DWORD)
PTR_(mouse_y_, DWORD)
PTR_(movePointRect, fo::BoundRect)
PTR_(movie_list, const char*) // array of 17 char*
PTR_(Mutate_, DWORD)
PTR_(name_color, DWORD)
+2
View File
@@ -151,6 +151,7 @@
#define FO_VAR_In_WorldMap 0x672E1C
#define FO_VAR_im_value 0x59E93C
#define FO_VAR_info_line 0x5707D0
#define FO_VAR_interfaceBuffer 0x59D3F4
#define FO_VAR_interfaceWindow 0x519024
#define FO_VAR_intfaceEnabled 0x518F10
#define FO_VAR_intotal 0x43E95C
@@ -209,6 +210,7 @@
#define FO_VAR_mouse_x_ 0x6AC7A8
#define FO_VAR_mouse_y 0x664450
#define FO_VAR_mouse_y_ 0x6AC7A4
#define FO_VAR_movePointRect 0x518FD4
#define FO_VAR_movie_list 0x518DA0
#define FO_VAR_Mutate_ 0x5708B4
#define FO_VAR_name_color 0x56D744
+22
View File
@@ -123,6 +123,28 @@ static void ClearInterfaceArtCache() {
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::OnGameReset() {
ClearInterfaceArtCache();
}
+16
View File
@@ -31,6 +31,22 @@ struct PcxFile {
PcxFile() : pixelData(nullptr), width(0), height(0) {}
};
class TempFrmHandle {
public:
TempFrmHandle(fo::FrmFile* frm);
TempFrmHandle(TempFrmHandle&&);
~TempFrmHandle();
bool IsValid();
const fo::FrmFile& Frm() const;
private:
// disallow copy constructor and copy assignment
TempFrmHandle(const TempFrmHandle&);
TempFrmHandle& operator=(TempFrmHandle);
fo::FrmFile* _frm;
};
class ExtraArt : public Module {
public:
const char* name() { return "ExtraArt"; }
+6 -4
View File
@@ -586,10 +586,12 @@ static void DrawCharNote(bool style, int winRef, DWORD xPosWin, DWORD yPosWin, B
BYTE *PadSurface = new BYTE [280 * 168];
surface_draw(280, 168, widthBG, xPosBG, yPosBG, BGSurface, 280, 0, 0, PadSurface);
fo::FrmFile* frm = LoadUnlistedFrm((style) ? "AppStyle.frm" : "AppRace.frm", fo::OBJ_TYPE_SKILLDEX);
if (frm != nullptr) {
fo::util::DrawToSurface(frm->frameData[0].width, frm->frameData[0].height, 0, 0, frm->frameData[0].width, frm->frameData[0].dataPtr(), 136, 37, 280, 168, PadSurface, 0); // cover buttons pics bottom
UnloadFrmFile(frm);
{
TempFrmHandle frmHandle( LoadUnlistedFrm((style) ? "AppStyle.frm" : "AppRace.frm", fo::ArtType::OBJ_TYPE_SKILLDEX) );
if (frmHandle.IsValid()) {
const fo::FrmFile& frm = frmHandle.Frm();
fo::util::DrawToSurface(frm.frameData[0].width, frm.frameData[0].height, 0, 0, frm.frameData[0].width, frm.frameData[0].dataPtr(), 136, 37, 280, 168, PadSurface, 0); // cover buttons pics bottom
}
}
int oldFont = GetFont(); // store current font
+84 -1
View File
@@ -22,6 +22,7 @@
#include "..\FalloutEngine\Fallout2.h"
#include "..\SimplePatch.h"
#include "..\Utils.h"
#include "ExtraArt.h"
#include "Graphics.h"
#include "LoadGameHook.h"
#include "Worldmap.h"
@@ -89,6 +90,82 @@ fo::Window* Interface::GetWindow(long winType) {
return (winID > 0) ? fo::func::GNW_find(winID) : nullptr;
}
static BYTE movePointBackground[16 * 9 * 5];
static bool hrpAPBarRectSetup = false;
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::ptr::interfaceWindow;
fo::Window* win = fo::func::GNW_find(ifaceWin);
if (win == nullptr) return;
const int destOffsetRight = 374;
const int destOffsetTop = 10;
const fo::FrmFrameData& srcFrame = frmHandle.Frm().frameData[0];
BYTE* dest = *fo::ptr::interfaceBuffer + (win->width * (destOffsetTop + 1)) - destOffsetRight;
fo::func::buf_to_buf(srcFrame.dataPtr(), srcFrame.width, srcFrame.height, srcFrame.width, dest, win->width);
}
static __declspec(naked) void intface_init_hook_unlock_iface_frm() {
__asm {
pushadc;
call DrawExtendedApBar;
popadc;
jmp fo::funcoffs::art_ptr_unlock_;
}
}
static __declspec(naked) void intface_init_hack() {
__asm {
add eax, 9276 - (54 / 2); // x offset
mov edx, 144 - 90; // width
add [esp + 4], edx;
add [esp + 0x10 + 4], edx;
retn;
}
}
static __declspec(naked) void intface_update_move_points_hack() {
static const DWORD intface_update_move_points_Ret = 0x45EE3E;
__asm {
mov eax, 16 * 9
push eax;
push 5;
push eax;
jmp intface_update_move_points_Ret;
}
}
static void APBarRectPatch() {
fo::ptr::movePointRect->x -= (54 / 2); // 54 = 144(new width) - 90(old width)
fo::ptr::movePointRect->offx += (54 / 2);
}
static void ActionPointsBarPatch() {
dlogr("Applying expanded action points bar patch.", DL_INIT);
if (hrpIsEnabled) {
hrpAPBarRectSetup = true;
} else {
APBarRectPatch();
}
// intface_init_
const DWORD movePointBgAddr[] = {0x45E343, 0x45EE3F};
SafeWriteBatch<DWORD>((DWORD)&movePointBackground, movePointBgAddr);
// intface_update_move_points_
const DWORD movePointMaxAddr[] = {0x45EE55, 0x45EE7B, 0x45EE82, 0x45EE9C, 0x45EEA0};
SafeWriteBatch<BYTE>(16, movePointMaxAddr);
const DWORD ifaceBufDestAddr[] = {0x45EE33, 0x45EEC8, 0x45EF16};
SafeWriteBatch<DWORD>(9276 - (54 / 2), ifaceBufDestAddr);
HookCall(0x45D962, intface_init_hook_unlock_iface_frm);
MakeCall(0x45E356, intface_init_hack);
MakeJump(0x45EE38, intface_update_move_points_hack, 1);
}
static long costAP = -1;
static __declspec(naked) void intface_redraw_items_hack0() {
__asm {
@@ -391,7 +468,7 @@ static void WorldmapViewportPatch() {
HookCall(0x4C4B8F, wmTownMapInit_hook);
}
// up/down buttons of the location list (wmInterfaceInit_)
const DWORD wmIfaceUpDnBtnXAddr[] = {0x4C2D3C, 0x4C2D7A}; // offset by X (480)
const DWORD wmIfaceUpDnBtnXAddr[] = {0x4C2D3C, 0x4C2D7A};
SafeWriteBatch<DWORD>(WMAP_WIN_WIDTH - (640 - 480), wmIfaceUpDnBtnXAddr); // offset by X (480)
// town/world button (wmInterfaceInit_)
@@ -1089,6 +1166,9 @@ static void UIAnimationSpeedPatch() {
}
void Interface::OnAfterGameInit() {
if (hrpAPBarRectSetup) {
APBarRectPatch();
}
if (worldmapInterface) {
WorldmapViewportPatch(); // Note: must be applied after WorldMapSlots patch
}
@@ -1109,6 +1189,9 @@ void Interface::init() {
SafeWriteBatch<BYTE>(CodeType::JumpShort, windowRoundingAddr);
//}
if (IniReader::GetConfigInt("Interface", "ActionPointsBar", 0)) {
ActionPointsBarPatch();
}
DrawActionPointsNumber();
WorldMapInterfacePatch();
SpeedInterfaceCounterAnimsPatch();