Added ActionPointsBar option to [Interface] in INI

Added a new Interface module.
Moved WorldMapInterface to the new [Interface] section.
Moved some code from Worldmap.cpp to Interface.cpp.
Updated sfall.dat with new IFACE_E.frm and HR_IFACE_800E.frm files.
This commit is contained in:
NovaRain
2019-06-28 21:40:57 +08:00
parent d3f7e2a79a
commit 3f96e42730
10 changed files with 526 additions and 369 deletions
+14 -7
View File
@@ -101,6 +101,20 @@ AllowDShowMovies=0
;Default is 100. Decrease/increase this value to speed up/slow down fade effects
FadeMultiplier=100
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
[Interface]
;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
;Requires High Resolution Patch v4.1.8 and a new WORLDMAP.frm file in art\intrface\ (included in sfall.dat)
;The resolution of hi-res patch must be set to at least 890x720
WorldMapInterface=0
;Set to 1 to expand the number of action points displayed on the interface bar
;Requires new IFACE_E.frm and HR_IFACE_800E.frm files in art\intrface\ (included in sfall.dat) to display correctly
;The minimum supported version of High Resolution Patch is 4.1.8
ActionPointsBar=0
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
[Input]
;Set to 1 to enable the mouse scroll wheel to scroll through the inventory, barter, and loot screens
@@ -204,13 +218,6 @@ WorldMapEncounterRate=5
;Setting this greater than 17 requires a replacement background FRM, or you'll get glitched graphics
WorldMapSlots=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
;Requires High Resolution Patch v4.1.8 and a new worldmap.frm file in art\intrface\ (included in sfall.dat)
;The resolution of hi-res patch must be set to at least 890x720
WorldMapInterface=0
;To start a new game somewhere other than artemple.map, uncomment the next line and set it to the map you want to load
;StartingMap=
Binary file not shown.
+2
View File
@@ -58,6 +58,7 @@
#define FO_VAR_Educated 0x57082C
#define FO_VAR_elevation 0x631D2C
#define FO_VAR_Experience_ 0x6681B4
#define FO_VAR_fade_steps 0x6642D0
#define FO_VAR_fallout_game_time 0x51C720
#define FO_VAR_fidgetFID 0x5186F4
#define FO_VAR_fidgetFp 0x5186FC
@@ -136,6 +137,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_Mutate_ 0x5708B4
#define FO_VAR_name_color 0x56D744
#define FO_VAR_name_font 0x56D74C
+1
View File
@@ -114,6 +114,7 @@ VAR_(mouse_is_hidden, DWORD)
VAR_(mouse_x_, DWORD)
VAR_(mouse_y, DWORD)
VAR_(mouse_y_, DWORD)
VAR_(movePointRect, BoundRect)
VAR_(Mutate_, DWORD)
VAR_(name_color, DWORD)
VAR_(name_font, DWORD)
+465
View File
@@ -0,0 +1,465 @@
/*
* sfall
* Copyright (C) 2008-2019 The sfall team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "..\main.h"
#include "..\FalloutEngine\Fallout2.h"
#include "Graphics.h"
#include "LoadGameHook.h"
#include "Interface.h"
namespace sfall
{
bool hrpIsEnabled = false;
static BYTE movePointBackground[16 * 9 * 5];
static fo::UnlistedFrm* ifaceFrm = nullptr;
static void* LoadIfaceFrm() {
ifaceFrm = fo::LoadUnlistedFrm("IFACE_E.frm", fo::OBJ_TYPE_INTRFACE);
if (!ifaceFrm) return nullptr;
return ifaceFrm->frames[0].indexBuff;
}
static void __declspec(naked) intface_init_hook_lock() {
__asm {
pushadc;
call LoadIfaceFrm;
test eax, eax;
jz skip;
pop ecx;
add esp, 8;
mov dword ptr [ecx], 0;
retn;
skip:
popadc;
jmp fo::funcoffs::art_ptr_lock_data_;
}
}
static void __declspec(naked) 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 const DWORD intface_update_move_points_ret = 0x45EE3E;
static void __declspec(naked) intface_update_move_points_hack() {
__asm {
mov eax, 16 * 9
push eax;
push 5;
push eax;
jmp intface_update_move_points_ret;
}
}
static void APBarRectPatch() {
fo::var::movePointRect.x -= (54 / 2); // 54 = 144(new width) - 90(old width)
fo::var::movePointRect.offx += (54 / 2);
}
static void ActionPointsBarPatch() {
dlog("Applying expanded action points bar patch.", DL_INIT);
if (hrpIsEnabled) {
// check valid data
if (!strcmp((const char*)0x10039358, "HR_IFACE_%i.frm")) { // patching HRP
SafeWriteStr(0x10039363, "E.frm");
SafeWriteStr(0x1003934F, "E.frm");
} else {
dlog(" Incorrect HRP version!", DL_INIT);
}
} else {
APBarRectPatch();
}
SafeWrite32(0x45E343, (DWORD)&movePointBackground);
SafeWrite32(0x45EE3F, (DWORD)&movePointBackground);
SafeWriteBatch<BYTE>(16, {0x45EE55, 0x45EE7B, 0x45EE82, 0x45EE9C, 0x45EEA0});
SafeWriteBatch<DWORD>(9276 - (54 / 2), {0x45EE33, 0x45EEC8, 0x45EF16});
HookCall(0x45D918, intface_init_hook_lock);
MakeCall(0x45E356, intface_init_hack);
MakeJump(0x45EE38, intface_update_move_points_hack, 1);
dlogr(" Done", DL_INIT);
}
////////////////////////////// WORLDMAP INTERFACE //////////////////////////////
static int mapSlotsScrollMax = 27 * (17 - 7);
static int mapSlotsScrollLimit = 0;
static __declspec(naked) void ScrollCityListFix() {
__asm {
push ebx;
mov ebx, ds:[0x672F10]; // _wmLastTabsYOffset
test eax, eax;
jl up;
cmp ebx, mapSlotsScrollMax;
pop ebx;
jl run;
retn;
up:
test ebx, ebx;
pop ebx;
jnz run;
retn;
run:
jmp fo::funcoffs::wmInterfaceScrollTabsStart_;
}
}
static void __declspec(naked) wmInterfaceInit_text_font_hook() {
__asm {
mov eax, 0x65; // normal text font
jmp fo::funcoffs::text_font_;
}
}
#define WMAP_WIN_WIDTH (890)
#define WMAP_WIN_HEIGHT (720)
#define WMAP_TOWN_BUTTONS (15)
static DWORD wmTownMapSubButtonIds[WMAP_TOWN_BUTTONS + 1]; // replace _wmTownMapSubButtonIds (index 0 - unused element)
static int worldmapInterface;
// Window width
static const DWORD wmWinWidth[] = {
// wmInterfaceInit_
0x4C239E, 0x4C247A,
// wmInterfaceRefresh_
0x4C38EA, 0x4C3978,
// wmInterfaceDrawCircleOverlay_
0x4C3FCA, 0x4C408E,
// wmRefreshInterfaceDial_
0x4C5757,
// wmInterfaceRefreshDate_
0x4C3D0A, 0x4C3D79, 0x4C3DBB, 0x4C3E87, 0x4C3E1F,
// wmRefreshTabs_
0x4C52BF, 0x4C53F5, 0x4C55A5, 0x4C557E, 0x4C54B2, 0x4C53E8,
// wmRefreshInterfaceOverlay_
0x4C50FD, 0x4C51CF, 0x4C51F8, 0x4C517F,
// wmInterfaceRefreshCarFuel_
0x4C528B, 0x4C529F, 0x4C52AA,
// wmInterfaceDrawSubTileList_
0x4C41C1, 0x4C41D2,
// wmTownMapRefresh_
0x4C4BDF,
// wmDrawCursorStopped_
0x4C42EE, 0x4C43C8, 0x4C445F,
// wmTownMapRefresh_
0x4C4BDF
};
// Right limit of the viewport (450)
static const DWORD wmViewportEndRight[] = {
// 0x4BC91F, // wmWorldMap_init_
0x4C3937, 0x4C393E, 0x4C39BB, 0x4C3B2F, 0x4C3B36, 0x4C3C4B, // wmInterfaceRefresh_
0x4C4288, 0x4C436A, 0x4C4409, // wmDrawCursorStopped_
0x4C44B4, // wmCursorIsVisible_
};
// Bottom limit of viewport (443)
static const DWORD wmViewportEndBottom[] = {
// 0x4BC947, // wmWorldMap_init_
0x4C3963, 0x4C38D7, 0x4C39DA, 0x4C3B62, 0x4C3AE7, 0x4C3C74, // wmInterfaceRefresh_
0x4C429A, 0x4C4378, 0x4C4413, // wmDrawCursorStopped_
0x4C44BE, // wmCursorIsVisible_
};
static const DWORD wmInterfaceInit_Ret = 0x4C23A7;
static void __declspec(naked) wmInterfaceInit_hack() {
__asm {
push eax;
mov eax, 640 - WMAP_WIN_WIDTH;
mov edx, 480 - WMAP_WIN_HEIGHT;
jmp wmInterfaceInit_Ret;
}
}
static void __declspec(naked) wmInterfaceDrawSubTileList_hack() {
__asm {
mov edx, [esp + 0x10 - 0x10 + 4];
imul edx, WMAP_WIN_WIDTH;
add edx, ecx;
retn;
}
}
static void __declspec(naked) wmInterfaceDrawCircleOverlay_hack() {
__asm {
mov eax, ecx;
imul eax, WMAP_WIN_WIDTH;
retn;
}
}
static void __declspec(naked) wmDrawCursorStopped_hack0() {
__asm {
mov ebx, ecx;
imul ebx, WMAP_WIN_WIDTH;
retn;
}
}
static void __declspec(naked) wmDrawCursorStopped_hack1() {
__asm {
mov ebx, eax;
imul ebx, WMAP_WIN_WIDTH;
retn;
}
}
static void __declspec(naked) wmRefreshTabs_hook() {
__asm {
mov eax, edx;
imul eax, WMAP_WIN_WIDTH;
sub ebp, eax;
retn;
}
}
static void __declspec(naked) wmTownMapRefresh_hook() {
__asm {
cmp edx, 700; //_wmTownWidth
jl scale;
cmp ebx, 682; //_wmTownHeight
jl scale;
jmp fo::funcoffs::buf_to_buf_;
scale:
push WMAP_WIN_WIDTH; // to_width
push 684; // height
push 702; // width
push eax; // to_buff
mov ecx, edx; // from_width
mov eax, esi; // from_buff
call fo::funcoffs::cscale_;
retn; // don't delete
}
}
static void __declspec(naked) wmTownMapRefresh_hook_textpos() {
__asm {
push eax;
push ebx;
mov eax, ecx; // xpos
shr ebx, 2; // text_width / 4
test ebx, ebx;
jz skipX;
sub ebx, 5; // x adjust
skipX:
sar eax, 1;
add ecx, eax; // xpos * 1.5
add ecx, ebx;
pop ebx;
mov eax, dword ptr [esp + 8]; // ypos
sar eax, 1;
test eax, eax;
jz skipY;
sub eax, 5; // y adjust
skipY:
add dword ptr [esp + 8], eax; // ypos * 1.5
pop eax;
jmp fo::funcoffs::win_print_;
}
}
static void __declspec(naked) wmTownMapInit_hook() {
__asm {
push eax;
mov eax, edx; // xpos
shr eax, 1;
add edx, eax; // xpos * 1.5
mov eax, ebx; // ypos
shr eax, 1;
add ebx, eax; // ypos * 1.5
pop eax;
jmp fo::funcoffs::win_register_button_;
}
}
static void WorldmapViewportPatch() {
if (Graphics::GetGameHeightRes() < WMAP_WIN_HEIGHT || Graphics::GetGameWidthRes() < WMAP_WIN_WIDTH) return;
if (!fo::func::db_access("art\\intrface\\worldmap.frm")) return;
dlog("Applying expanded world map interface patch.", DL_INIT);
mapSlotsScrollMax -= 216;
if (mapSlotsScrollMax < 0) mapSlotsScrollMax = 0;
fo::var::wmViewportRightScrlLimit = (350 * fo::var::wmNumHorizontalTiles) - (WMAP_WIN_WIDTH - (640 - 450));
fo::var::wmViewportBottomtScrlLimit = (300 * (fo::var::wmMaxTileNum / fo::var::wmNumHorizontalTiles)) - (WMAP_WIN_HEIGHT - (480 - 443));
SafeWriteBatch<DWORD>(135, {0x4C23BD, 0x4C2408}); // use unused worldmap.frm for new world map interface (wmInterfaceInit_)
// x/y axis offset of interface window
MakeJump(0x4C23A2, wmInterfaceInit_hack);
// size of the created window/buffer
SafeWriteBatch<DWORD>(WMAP_WIN_WIDTH, wmWinWidth); // width
SafeWrite32(0x4C238B, WMAP_WIN_HEIGHT); // height (wmInterfaceInit_)
// Mouse scrolling area (wmMouseBkProc_)
SafeWrite32(0x4C331D, WMAP_WIN_WIDTH - 1);
SafeWrite32(0x4C3337, WMAP_WIN_HEIGHT - 1);
MakeCall(0x4C41A4, wmInterfaceDrawSubTileList_hack); // 640 * 21
MakeCall(0x4C4082, wmInterfaceDrawCircleOverlay_hack); // 640 * y
MakeCall(0x4C4452, wmDrawCursorStopped_hack1);
MakeCalls(wmDrawCursorStopped_hack0, {0x4C43BB, 0x4C42E1});
MakeCall(0x4C5325, wmRefreshTabs_hook);
HookCall(0x4C4BFF, wmTownMapRefresh_hook);
if (worldmapInterface == 1) {
HookCall(0x4C4CD5, wmTownMapRefresh_hook_textpos);
HookCall(0x4C4B8F, wmTownMapInit_hook);
}
// up/down buttons of the location list (wmInterfaceInit_)
SafeWriteBatch<DWORD>(WMAP_WIN_WIDTH - (640 - 480), { // offset by X (480)
0x4C2D3C,
0x4C2D7A
});
// town/world button (wmInterfaceInit_)
SafeWrite32(0x4C2B9B, WMAP_WIN_HEIGHT - (480 - 439)); // offset by Y (439)
SafeWrite32(0x4C2BAF, WMAP_WIN_WIDTH - (640 - 519)); // offset by X (508)
// viewport size for mouse click
SafeWriteBatch<DWORD>(WMAP_WIN_HEIGHT - (480 - 465), { // height/offset by Y (465 - 21 = 444 (443))
0x4C0154, 0x4C02BA, // wmWorldMap_
0x4C3A47, // wmInterfaceRefresh_
});
SafeWriteBatch<DWORD>(WMAP_WIN_WIDTH - (640 - 472), { // width/offset by X (472 - 22 = 450)
0x4C0159, 0x4C02BF, // wmWorldMap_
0x4C3A3A, // wmInterfaceRefresh_
0x4C417C, 0x4C4184 // wmInterfaceDrawSubTileList_
});
SafeWriteBatch<DWORD>(WMAP_WIN_HEIGHT - (480 - 464), { // width/offset by X (464)
0x4C3FED, // wmInterfaceDrawCircleOverlay_
0x4C4157, 0x4C415F, // wmInterfaceDrawSubTileList_
});
// right limit of the viewport (450)
SafeWriteBatch<DWORD>(WMAP_WIN_WIDTH - (640 - 450), wmViewportEndRight); // 890 - 190 = 700 + 22 = 722
// bottom limit of the viewport (443)
SafeWriteBatch<DWORD>(WMAP_WIN_HEIGHT - (480 - 443), wmViewportEndBottom); // 720 - 37 = 683 + 21 = 704
// Night/Day frm (wmRefreshInterfaceDial_)
SafeWrite32(0x4C577F, WMAP_WIN_WIDTH - (640 - 532)); // X offset (532)
SafeWrite32(0x4C575D, (WMAP_WIN_WIDTH * 49) - ((640 * 49) - 31252)); // start offset in buffer (31252 / 640 = 49)
// Date/Time frm
SafeWrite32(0x4C3EC7, WMAP_WIN_WIDTH - (640 - 487)); // start offset by X (487)
SafeWrite32(0x4C3ED1, WMAP_WIN_WIDTH - (640 - 630)); // end offset by X (630)
SafeWrite32(0x4C3D10, (WMAP_WIN_WIDTH * 13) - ((640 * 13) - 8167)); // 8167 start offset in buffer (12327)
SafeWrite32(0x4C3DC1, WMAP_WIN_WIDTH + (666 - 640)); // 666
// WMCARMVE/WMGLOBE/WMSCREEN frms (wmRefreshInterfaceOverlay_)
SafeWrite32(0x4C51D5, (WMAP_WIN_WIDTH * 577) - ((640 * 337) - 215554)); // start offset for image WMCARMVE
SafeWrite32(0x4C5184, (WMAP_WIN_WIDTH * 571) - ((640 * 331) - 211695)); // start offset for image WMGLOBE
SafeWrite32(0x4C51FD, (WMAP_WIN_WIDTH * 571) - ((640 * 331) - 211699)); // start offset for image WMSCREEN
// Car gas indicator
SafeWrite32(0x4C527E, (WMAP_WIN_WIDTH * 580) - ((640 * 340) - 217460)); // start offset in buffer (217460 / 640 = 340 + (720 - 480) = 580 Y-axes)
// WMTABS.frm
SafeWriteBatch<DWORD>((WMAP_WIN_WIDTH * 136) - ((640 * 136) - 86901), {
0x4C52C4, 0x4C55AA // wmRefreshTabs_
});
SafeWrite32(0x4C52FF, (WMAP_WIN_WIDTH * 139) - ((640 * 139) - 88850)); // wmRefreshTabs_
SafeWriteBatch<DWORD>((WMAP_WIN_WIDTH * 27), { // start offset in buffer (17280)
0x4C54DE, 0x4C5424 // wmRefreshTabs_
});
SafeWrite32(0x4C52E5, WMAP_WIN_HEIGHT - 480 + 178 - 19); // height (178)
// Buttons of cities, now 15
SafeWrite32(0x4C2BD9, WMAP_WIN_WIDTH - (640 - 508)); // offset of the buttons by X (508)
SafeWriteBatch<BYTE>(WMAP_TOWN_BUTTONS * 4, {0x4C2C01, 0x4C21B6, 0x4C2289}); // number of buttons (28 = 7 * 4)
int btn = (mapSlotsScrollLimit) ? WMAP_TOWN_BUTTONS : WMAP_TOWN_BUTTONS + 1;
SafeWrite32(0x4C21FD, 27 * btn); // scroll limit for buttons
// number of city labels (6) wmRefreshTabs_
SafeWriteBatch<BYTE>(WMAP_TOWN_BUTTONS - 1, {0x4C54F6, 0x4C542A});
SafeWrite8(0x4C555E, 0);
SafeWrite32(0x4C0348, 350 + WMAP_TOWN_BUTTONS); // buttons input code (wmWorldMap_)
SafeWrite32(0x4C2BFB, (DWORD)&wmTownMapSubButtonIds[0]); // wmInterfaceInit_
SafeWriteBatch<DWORD>((DWORD)&wmTownMapSubButtonIds[1], {
0x4C22DD, 0x4C230A, // wmInterfaceScrollTabsUpdate_ (never called)
0x4C227B, // wmInterfaceScrollTabsStop_
0x4C21A8 // wmInterfaceScrollTabsStart_
});
// WMTBEDGE.frm (wmRefreshTabs_)
BlockCall(0x4C55BF);
// Town map frm images (wmTownMapRefresh_)
SafeWrite32(0x4C4BE4, (WMAP_WIN_WIDTH * 21) + 22); // start offset for town map image (13462)
dlogr(" Done", DL_INIT);
}
static void WorldMapInterfacePatch() {
if (GetConfigInt("Misc", "WorldMapFontPatch", 0)) {
dlog("Applying world map font patch.", DL_INIT);
HookCall(0x4C2343, wmInterfaceInit_text_font_hook);
dlogr(" Done", DL_INIT);
}
// Fix images for up/down buttons
SafeWrite32(0x4C2C0A, 199); // index of UPARWOFF.FRM
SafeWrite8(0x4C2C7C, 0x43); // dec ebx > inc ebx
SafeWrite32(0x4C2C92, 181); // index of DNARWOFF.FRM
SafeWrite8(0x4C2D04, 0x46); // dec esi > inc esi
//if(GetConfigInt("Misc", "WorldMapCitiesListFix", 0)) {
dlog("Applying world map cities list patch.", DL_INIT);
HookCalls(ScrollCityListFix, {0x4C04B9, 0x4C04C8, 0x4C4A34, 0x4C4A3D});
dlogr(" Done", DL_INIT);
//}
DWORD wmSlots = GetConfigInt("Misc", "WorldMapSlots", 0);
if (wmSlots && wmSlots < 128) {
dlog("Applying world map slots patch.", DL_INIT);
if (wmSlots < 7) wmSlots = 7;
mapSlotsScrollMax = (wmSlots - 7) * 27; // height value after which scrolling is not possible
mapSlotsScrollLimit = wmSlots * 27;
SafeWrite32(0x4C21FD, 189); // 27 * 7
SafeWrite32(0x4C21F1, (DWORD)&mapSlotsScrollLimit);
dlogr(" Done", DL_INIT);
}
if (hrpIsEnabled) {
if (worldmapInterface = GetConfigInt("Interface", "WorldMapInterface", 0)) {
LoadGameHook::OnAfterGameInit() += WorldmapViewportPatch; // Note: must be applied after WorldMapSlots patch
}
}
}
void Interface::init() {
hrpIsEnabled = (*(DWORD*)0x4E4480 != 0x278805C7); // check if HRP is enabled
if (GetConfigInt("Interface", "ActionPointsBar", 0)) {
ActionPointsBarPatch();
if (hrpIsEnabled) LoadGameHook::OnAfterGameInit() += APBarRectPatch;
}
WorldMapInterfacePatch();
}
void Interface::exit() {
if (ifaceFrm) delete ifaceFrm;
}
}
+15
View File
@@ -0,0 +1,15 @@
#pragma once
#include "Module.h"
namespace sfall
{
class Interface : public Module {
public:
const char* name() { return "Interface"; }
void init();
void exit() override;
};
}
+16 -360
View File
@@ -1,27 +1,26 @@
/*
* sfall
* Copyright (C) 2008-2017 The sfall team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
* sfall
* Copyright (C) 2008-2017 The sfall team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <map>
#include <math.h>
#include "..\main.h"
#include "..\FalloutEngine\Fallout2.h"
#include "Graphics.h"
#include "LoadGameHook.h"
#include "ScriptExtender.h"
#include "SpeedPatch.h"
@@ -47,9 +46,6 @@ static bool restMap;
static bool restMode;
static bool restTime;
static int mapSlotsScrollMax = 27 * (17 - 7);
static int mapSlotsScrollLimit = 0;
static DWORD worldMapDelay;
static DWORD worldMapTicks;
@@ -124,26 +120,6 @@ end:
}
}
static __declspec(naked) void ScrollCityListFix() {
__asm {
push ebx;
mov ebx, ds:[0x672F10]; // _wmLastTabsYOffset
test eax, eax;
jl up;
cmp ebx, mapSlotsScrollMax;
pop ebx;
jl run;
retn;
up:
test ebx, ebx;
pop ebx;
jnz run;
retn;
run:
jmp fo::funcoffs::wmInterfaceScrollTabsStart_;
}
}
static void __stdcall WorldmapLoopHook() {
onWorldmapLoop.invoke();
}
@@ -286,13 +262,6 @@ static __declspec(naked) void PathfinderFix() {
}
}
static void __declspec(naked) wmInterfaceInit_text_font_hook() {
__asm {
mov eax, 0x65; // normal text font
jmp fo::funcoffs::text_font_;
}
}
static void __declspec(naked) critter_can_obj_dude_rest_hook() {
using namespace fo;
__asm {
@@ -370,12 +339,6 @@ void WorldLimitsPatches() {
dlogr(" Done", DL_INIT);
}
//if(GetConfigInt("Misc", "WorldMapCitiesListFix", 0)) {
dlog("Applying world map cities list patch.", DL_INIT);
HookCalls(ScrollCityListFix, {0x4C04B9, 0x4C04C8, 0x4C4A34, 0x4C4A3D});
dlogr(" Done", DL_INIT);
//}
//if(GetConfigInt("Misc", "CitiesLimitFix", 0)) {
dlog("Applying cities limit patch.", DL_INIT);
if (*((BYTE*)0x4BF3BB) != 0xEB) {
@@ -383,17 +346,6 @@ void WorldLimitsPatches() {
}
dlogr(" Done", DL_INIT);
//}
DWORD wmSlots = GetConfigInt("Misc", "WorldMapSlots", 0);
if (wmSlots && wmSlots < 128) {
dlog("Applying world map slots patch.", DL_INIT);
if (wmSlots < 7) wmSlots = 7;
mapSlotsScrollMax = (wmSlots - 7) * 27; // height value after which scrolling is not possible
mapSlotsScrollLimit = wmSlots * 27;
SafeWrite32(0x4C21FD, 189); // 27 * 7
SafeWrite32(0x4C21F1, (DWORD)&mapSlotsScrollLimit);
dlogr(" Done", DL_INIT);
}
}
void TimeLimitPatch() {
@@ -525,19 +477,6 @@ void StartingStatePatches() {
if (ViewportX != -1 || ViewportY != -1) HookCall(0x4BCF07, ViewportHook); // game_reset_
}
void WorldMapInterfacePatch() {
if (GetConfigInt("Misc", "WorldMapFontPatch", 0)) {
dlog("Applying world map font patch.", DL_INIT);
HookCall(0x4C2343, wmInterfaceInit_text_font_hook);
dlogr(" Done", DL_INIT);
}
// Fix images for up/down buttons
SafeWrite32(0x4C2C0A, 199); // index of UPARWOFF.FRM
SafeWrite8(0x4C2C7C, 0x43); // dec ebx > inc ebx
SafeWrite32(0x4C2C92, 181); // index of DNARWOFF.FRM
SafeWrite8(0x4C2D04, 0x46); // dec esi > inc esi
}
void PipBoyAutomapsPatch() {
dlog("Applying Pip-Boy automaps patch.", DL_INIT);
MakeCall(0x4BF931, wmMapInit_hack, 2);
@@ -657,284 +596,6 @@ long __fastcall Worldmap::GetRestMapLevel(long elev, int mapId) {
return -1;
}
////////////////////////////// WORLDMAP INTERFACE //////////////////////////////
#define WMAP_WIN_WIDTH (890)
#define WMAP_WIN_HEIGHT (720)
#define WMAP_TOWN_BUTTONS (15)
static DWORD wmTownMapSubButtonIds[WMAP_TOWN_BUTTONS + 1]; // replace _wmTownMapSubButtonIds (index 0 - unused element)
static int worldmapInterface;
// Window width
static const DWORD wmWinWidth[] = {
// wmInterfaceInit_
0x4C239E, 0x4C247A,
// wmInterfaceRefresh_
0x4C38EA, 0x4C3978,
// wmInterfaceDrawCircleOverlay_
0x4C3FCA, 0x4C408E,
// wmRefreshInterfaceDial_
0x4C5757,
// wmInterfaceRefreshDate_
0x4C3D0A, 0x4C3D79, 0x4C3DBB, 0x4C3E87, 0x4C3E1F,
// wmRefreshTabs_
0x4C52BF, 0x4C53F5, 0x4C55A5, 0x4C557E, 0x4C54B2, 0x4C53E8,
// wmRefreshInterfaceOverlay_
0x4C50FD, 0x4C51CF, 0x4C51F8, 0x4C517F,
// wmInterfaceRefreshCarFuel_
0x4C528B, 0x4C529F, 0x4C52AA,
// wmInterfaceDrawSubTileList_
0x4C41C1, 0x4C41D2,
// wmTownMapRefresh_
0x4C4BDF,
// wmDrawCursorStopped_
0x4C42EE, 0x4C43C8, 0x4C445F,
// wmTownMapRefresh_
0x4C4BDF
};
// Right limit of the viewport (450)
static const DWORD wmViewportEndRight[] = {
// 0x4BC91F, // wmWorldMap_init_
0x4C3937, 0x4C393E, 0x4C39BB, 0x4C3B2F, 0x4C3B36, 0x4C3C4B, // wmInterfaceRefresh_
0x4C4288, 0x4C436A, 0x4C4409, // wmDrawCursorStopped_
0x4C44B4, // wmCursorIsVisible_
};
// Bottom limit of viewport (443)
static const DWORD wmViewportEndBottom[] = {
// 0x4BC947, // wmWorldMap_init_
0x4C3963, 0x4C38D7, 0x4C39DA, 0x4C3B62, 0x4C3AE7, 0x4C3C74, // wmInterfaceRefresh_
0x4C429A, 0x4C4378, 0x4C4413, // wmDrawCursorStopped_
0x4C44BE, // wmCursorIsVisible_
};
static const DWORD wmInterfaceInit_Ret = 0x4C23A7;
static void __declspec(naked) wmInterfaceInit_hack() {
__asm {
push eax;
mov eax, 640 - WMAP_WIN_WIDTH;
mov edx, 480 - WMAP_WIN_HEIGHT;
jmp wmInterfaceInit_Ret;
}
}
static void __declspec(naked) wmInterfaceDrawSubTileList_hack() {
__asm {
mov edx, [esp + 0x10 - 0x10 + 4];
imul edx, WMAP_WIN_WIDTH;
add edx, ecx;
retn;
}
}
static void __declspec(naked) wmInterfaceDrawCircleOverlay_hack() {
__asm {
mov eax, ecx;
imul eax, WMAP_WIN_WIDTH;
retn;
}
}
static void __declspec(naked) wmDrawCursorStopped_hack0() {
__asm {
mov ebx, ecx;
imul ebx, WMAP_WIN_WIDTH;
retn;
}
}
static void __declspec(naked) wmDrawCursorStopped_hack1() {
__asm {
mov ebx, eax;
imul ebx, WMAP_WIN_WIDTH;
retn;
}
}
static void __declspec(naked) wmRefreshTabs_hook() {
__asm {
mov eax, edx;
imul eax, WMAP_WIN_WIDTH;
sub ebp, eax;
retn;
}
}
static void __declspec(naked) wmTownMapRefresh_hook() {
__asm {
cmp edx, 700; //_wmTownWidth
jl scale;
cmp ebx, 682; //_wmTownHeight
jl scale;
jmp fo::funcoffs::buf_to_buf_;
scale:
push WMAP_WIN_WIDTH; // to_width
push 684; // height
push 702; // width
push eax; // to_buff
mov ecx, edx; // from_width
mov eax, esi; // from_buff
call fo::funcoffs::cscale_;
retn; // don't delete
}
}
static void __declspec(naked) wmTownMapRefresh_hook_textpos() {
__asm {
push eax;
push ebx;
mov eax, ecx; // xpos
shr ebx, 2; // text_width / 4
test ebx, ebx;
jz skipX;
sub ebx, 5; // x adjust
skipX:
sar eax, 1;
add ecx, eax; // xpos * 1.5
add ecx, ebx;
pop ebx;
mov eax, dword ptr [esp + 8]; // ypos
sar eax, 1;
test eax, eax;
jz skipY;
sub eax, 5; // y adjust
skipY:
add dword ptr [esp + 8], eax; // ypos * 1.5
pop eax;
jmp fo::funcoffs::win_print_;
}
}
static void __declspec(naked) wmTownMapInit_hook() {
__asm {
push eax;
mov eax, edx; // xpos
shr eax, 1;
add edx, eax; // xpos * 1.5
mov eax, ebx; // ypos
shr eax, 1;
add ebx, eax; // ypos * 1.5
pop eax;
jmp fo::funcoffs::win_register_button_;
}
}
void WorldmapViewportPatch() {
if (Graphics::GetGameHeightRes() < WMAP_WIN_HEIGHT || Graphics::GetGameWidthRes() < WMAP_WIN_WIDTH) return;
if (!fo::func::db_access("art\\intrface\\worldmap.frm")) return;
dlog("Applying world map interface patch.", DL_INIT);
mapSlotsScrollMax -= 216;
if (mapSlotsScrollMax < 0) mapSlotsScrollMax = 0;
fo::var::wmViewportRightScrlLimit = (350 * fo::var::wmNumHorizontalTiles) - (WMAP_WIN_WIDTH - (640 - 450));
fo::var::wmViewportBottomtScrlLimit = (300 * (fo::var::wmMaxTileNum / fo::var::wmNumHorizontalTiles)) - (WMAP_WIN_HEIGHT - (480 - 443));
SafeWriteBatch<DWORD>(135, {0x4C23BD, 0x4C2408}); // use unused worldmap.frm for new world map interface (wmInterfaceInit_)
// x/y axis offset of interface window
MakeJump(0x4C23A2, wmInterfaceInit_hack);
// size of the created window/buffer
SafeWriteBatch<DWORD>(WMAP_WIN_WIDTH, wmWinWidth); // width
SafeWrite32(0x4C238B, WMAP_WIN_HEIGHT); // height (wmInterfaceInit_)
// Mouse scrolling area (wmMouseBkProc_)
SafeWrite32(0x4C331D, WMAP_WIN_WIDTH - 1);
SafeWrite32(0x4C3337, WMAP_WIN_HEIGHT - 1);
MakeCall(0x4C41A4, wmInterfaceDrawSubTileList_hack); // 640 * 21
MakeCall(0x4C4082, wmInterfaceDrawCircleOverlay_hack); // 640 * y
MakeCall(0x4C4452, wmDrawCursorStopped_hack1);
MakeCalls(wmDrawCursorStopped_hack0, {0x4C43BB, 0x4C42E1});
MakeCall(0x4C5325, wmRefreshTabs_hook);
HookCall(0x4C4BFF, wmTownMapRefresh_hook);
if (worldmapInterface == 1) {
HookCall(0x4C4CD5, wmTownMapRefresh_hook_textpos);
HookCall(0x4C4B8F, wmTownMapInit_hook);
}
// up/down buttons of the location list (wmInterfaceInit_)
SafeWriteBatch<DWORD>(WMAP_WIN_WIDTH - (640 - 480), { // offset by X (480)
0x4C2D3C,
0x4C2D7A
});
// town/world button (wmInterfaceInit_)
SafeWrite32(0x4C2B9B, WMAP_WIN_HEIGHT - (480 - 439)); // offset by Y (439)
SafeWrite32(0x4C2BAF, WMAP_WIN_WIDTH - (640 - 519)); // offset by X (508)
// viewport size for mouse click
SafeWriteBatch<DWORD>(WMAP_WIN_HEIGHT - (480 - 465), { // height/offset by Y (465 - 21 = 444 (443))
0x4C0154, 0x4C02BA, // wmWorldMap_
0x4C3A47, // wmInterfaceRefresh_
});
SafeWriteBatch<DWORD>(WMAP_WIN_WIDTH - (640 - 472), { // width/offset by X (472 - 22 = 450)
0x4C0159, 0x4C02BF, // wmWorldMap_
0x4C3A3A, // wmInterfaceRefresh_
0x4C417C, 0x4C4184 // wmInterfaceDrawSubTileList_
});
SafeWriteBatch<DWORD>(WMAP_WIN_HEIGHT - (480 - 464), { // width/offset by X (464)
0x4C3FED, // wmInterfaceDrawCircleOverlay_
0x4C4157, 0x4C415F, // wmInterfaceDrawSubTileList_
});
// right limit of the viewport (450)
SafeWriteBatch<DWORD>(WMAP_WIN_WIDTH - (640 - 450), wmViewportEndRight); // 890 - 190 = 700 + 22 = 722
// bottom limit of the viewport (443)
SafeWriteBatch<DWORD>(WMAP_WIN_HEIGHT - (480 - 443), wmViewportEndBottom); // 720 - 37 = 683 + 21 = 704
// Night/Day frm (wmRefreshInterfaceDial_)
SafeWrite32(0x4C577F, WMAP_WIN_WIDTH - (640 - 532)); // X offset (532)
SafeWrite32(0x4C575D, (WMAP_WIN_WIDTH * 49) - ((640 * 49) - 31252)); // start offset in buffer (31252 / 640 = 49)
// Date/Time frm
SafeWrite32(0x4C3EC7, WMAP_WIN_WIDTH - (640 - 487)); // start offset by X (487)
SafeWrite32(0x4C3ED1, WMAP_WIN_WIDTH - (640 - 630)); // end offset by X (630)
SafeWrite32(0x4C3D10, (WMAP_WIN_WIDTH * 13) - ((640 * 13) - 8167)); // 8167 start offset in buffer (12327)
SafeWrite32(0x4C3DC1, WMAP_WIN_WIDTH + (666 - 640)); // 666
// WMCARMVE/WMGLOBE/WMSCREEN frms (wmRefreshInterfaceOverlay_)
SafeWrite32(0x4C51D5, (WMAP_WIN_WIDTH * 577) - ((640 * 337) - 215554)); // start offset for image WMCARMVE
SafeWrite32(0x4C5184, (WMAP_WIN_WIDTH * 571) - ((640 * 331) - 211695)); // start offset for image WMGLOBE
SafeWrite32(0x4C51FD, (WMAP_WIN_WIDTH * 571) - ((640 * 331) - 211699)); // start offset for image WMSCREEN
// Car gas indicator
SafeWrite32(0x4C527E, (WMAP_WIN_WIDTH * 580) - ((640 * 340) - 217460)); // start offset in buffer (217460 / 640 = 340 + (720 - 480) = 580 Y-axes)
// WMTABS.frm
SafeWriteBatch<DWORD>((WMAP_WIN_WIDTH * 136) - ((640 * 136) - 86901), {
0x4C52C4, 0x4C55AA // wmRefreshTabs_
});
SafeWrite32(0x4C52FF, (WMAP_WIN_WIDTH * 139) - ((640 * 139) - 88850)); // wmRefreshTabs_
SafeWriteBatch<DWORD>((WMAP_WIN_WIDTH * 27), { // start offset in buffer (17280)
0x4C54DE, 0x4C5424 // wmRefreshTabs_
});
SafeWrite32(0x4C52E5, WMAP_WIN_HEIGHT - 480 + 178 - 19); // height (178)
// Buttons of cities, now 15
SafeWrite32(0x4C2BD9, WMAP_WIN_WIDTH - (640 - 508)); // offset of the buttons by X (508)
SafeWriteBatch<BYTE>(WMAP_TOWN_BUTTONS * 4, {0x4C2C01, 0x4C21B6, 0x4C2289}); // number of buttons (28 = 7 * 4)
int btn = (mapSlotsScrollLimit) ? WMAP_TOWN_BUTTONS : WMAP_TOWN_BUTTONS + 1;
SafeWrite32(0x4C21FD, 27 * btn); // scroll limit for buttons
// number of city labels (6) wmRefreshTabs_
SafeWriteBatch<BYTE>(WMAP_TOWN_BUTTONS - 1, {0x4C54F6, 0x4C542A});
SafeWrite8(0x4C555E, 0);
SafeWrite32(0x4C0348, 350 + WMAP_TOWN_BUTTONS); // buttons input code (wmWorldMap_)
SafeWrite32(0x4C2BFB, (DWORD)&wmTownMapSubButtonIds[0]); // wmInterfaceInit_
SafeWriteBatch<DWORD>((DWORD)&wmTownMapSubButtonIds[1], {
0x4C22DD, 0x4C230A, // wmInterfaceScrollTabsUpdate_ (never called)
0x4C227B, // wmInterfaceScrollTabsStop_
0x4C21A8 // wmInterfaceScrollTabsStart_
});
// WMTBEDGE.frm (wmRefreshTabs_)
BlockCall(0x4C55BF);
// Town map frm images (wmTownMapRefresh_)
SafeWrite32(0x4C4BE4, (WMAP_WIN_WIDTH * 21) + 22); // start offset for town map image (13462)
dlogr(" Done", DL_INIT);
}
void Worldmap::init() {
PathfinderFixInit();
StartingStatePatches();
@@ -942,13 +603,8 @@ void Worldmap::init() {
TownMapsHotkeyFix();
WorldLimitsPatches();
WorldmapFpsPatch();
WorldMapInterfacePatch();
PipBoyAutomapsPatch();
worldmapInterface = GetConfigInt("Misc", "WorldMapInterface", 0);
if (worldmapInterface && *(DWORD*)0x4E4480 != 0x278805C7) { // check if HRP is enabled
LoadGameHook::OnAfterGameInit() += WorldmapViewportPatch; // Note: must be applied after WorldMapSlots patch
}
LoadGameHook::OnGameReset() += []() {
SetCarInterfaceArt(433); // set index
if (restTime) SetRestHealTime(180);
+3
View File
@@ -259,6 +259,7 @@
<ForcedIncludeFiles>stdafx.h;%(ForcedIncludeFiles)</ForcedIncludeFiles>
<MinimalRebuild>true</MinimalRebuild>
<FunctionLevelLinking>false</FunctionLevelLinking>
<AssemblerOutput>AssemblyAndSourceCode</AssemblerOutput>
</ClCompile>
<Link>
<AdditionalDependencies>kernel32.lib;user32.lib;d3d9.lib;d3dx9.lib;Strmiids.lib;dinput.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
@@ -295,6 +296,7 @@
<ClInclude Include="FalloutEngine\Variables.h" />
<ClInclude Include="FalloutEngine\Functions.h" />
<ClInclude Include="FalloutEngine\Functions_def.h" />
<ClInclude Include="Modules\Interface.h" />
<ClInclude Include="Modules\Drugs.h" />
<ClInclude Include="Modules\HookScripts\CombatHs.h" />
<ClInclude Include="Modules\HookScripts\Common.h" />
@@ -385,6 +387,7 @@
<ClCompile Include="FalloutEngine\FunctionOffsets.cpp" />
<ClCompile Include="FalloutEngine\Variables.cpp" />
<ClCompile Include="FalloutEngine\Functions.cpp" />
<ClCompile Include="Modules\Interface.cpp" />
<ClCompile Include="Modules\Drugs.cpp" />
<ClCompile Include="Modules\HookScripts\CombatHs.cpp" />
<ClCompile Include="Modules\HookScripts\Common.cpp" />
+6
View File
@@ -281,6 +281,9 @@
<ClInclude Include="Modules\ScriptShaders.h">
<Filter>Modules</Filter>
</ClInclude>
<ClInclude Include="Modules\Interface.h">
<Filter>Modules</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp" />
@@ -522,6 +525,9 @@
<ClCompile Include="Modules\ScriptShaders.cpp">
<Filter>Modules</Filter>
</ClCompile>
<ClCompile Include="Modules\Interface.cpp">
<Filter>Modules</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="version.rc" />
+4 -2
View File
@@ -45,6 +45,7 @@
#include "Modules\HookScripts.h"
#include "Modules\HeroAppearance.h"
#include "Modules\Input.h"
#include "Modules\Interface.h"
#include "Modules\Inventory.h"
#include "Modules\Karma.h"
#include "Modules\KillCounter.h"
@@ -139,6 +140,7 @@ static void InitModules() {
manager.add<SpeedPatch>();
manager.add<Graphics>();
manager.add<Input>();
manager.add<LoadOrder>();
manager.add<LoadGameHook>();
manager.add<MainLoopHook>();
manager.add<Movies>();
@@ -151,7 +153,6 @@ static void InitModules() {
manager.add<Combat>();
manager.add<Skills>();
manager.add<FileSystem>();
manager.add<LoadOrder>();
manager.add<Karma>();
manager.add<Tiles>();
manager.add<Credits>();
@@ -171,7 +172,8 @@ static void InitModules() {
manager.add<Message>();
manager.add<Elevators>();
manager.add<KillCounter>();
manager.add<Interface>();
//
manager.add<AI>();
manager.add<DamageMod>();
manager.add<AnimationsAtOnce>();