Implemented drawing red dots while traveling on the world map

(from rotators/Fo1in2#3 by ghost22238)
This commit is contained in:
NovaRain
2020-01-02 00:38:01 +08:00
parent 1af1eb2c70
commit 85e70fe056
6 changed files with 105 additions and 7 deletions
+4 -1
View File
@@ -1,5 +1,5 @@
;sfall configuration settings
;v4.2.2
;v4.2.3
[Main]
;Change to 1 if you want to use command line args to tell sfall to use another ini file.
@@ -119,6 +119,9 @@ ExpandWorldMap=0
;The minimum supported version of High Resolution Patch is 4.1.8
ActionPointsBar=0
;Set to 1 to enable drawing a dotted line when moving around on the world map (similar to Fallout 1)
WorldTravelMarkers=0
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
[Input]
;Set to 1 to enable the mouse scroll wheel to scroll through the inventory, barter, and loot screens
+1
View File
@@ -239,6 +239,7 @@
#define FO_VAR_wd_obj 0x59E98C
#define FO_VAR_window 0x6ADE58
#define FO_VAR_wmAreaInfoList 0x51DDF8
#define FO_VAR_wmBkWinBuf 0x51DE24
#define FO_VAR_wmLastRndTime 0x51DEA0
#define FO_VAR_wmMaxMapNum 0x51DE10
#define FO_VAR_wmMaxTileNum 0x51DDF0
+2 -2
View File
@@ -212,8 +212,8 @@ VAR_(wmMaxTileNum, DWORD)
VAR_(wmNumHorizontalTiles, DWORD)
VAR_(wmViewportRightScrlLimit, DWORD)
VAR_(wmViewportBottomtScrlLimit, DWORD)
VAR_(wmWorldOffsetX, DWORD)
VAR_(wmWorldOffsetY, DWORD)
VAR_(wmWorldOffsetX, long)
VAR_(wmWorldOffsetY, long)
VAR_(world_xpos, DWORD)
VAR_(world_ypos, DWORD)
VAR_(WorldMapCurrArea, DWORD)
+96 -2
View File
@@ -186,6 +186,8 @@ static void __declspec(naked) wmInterfaceInit_text_font_hook() {
static DWORD wmTownMapSubButtonIds[WMAP_TOWN_BUTTONS + 1]; // replace _wmTownMapSubButtonIds (index 0 - unused element)
static int worldmapInterface;
static long wmapWinWidth = 640;
static long wmapViewPortWidth = 450;
static long wmapViewPortHeight = 443;
// Window width
static const DWORD wmWinWidth[] = {
@@ -400,9 +402,11 @@ static void WorldmapViewportPatch() {
0x4C4157, 0x4C415F, // wmInterfaceDrawSubTileList_
});
// right limit of the viewport (450)
SafeWriteBatch<DWORD>(WMAP_WIN_WIDTH - (640 - 450), wmViewportEndRight); // 890 - 190 = 700 + 22 = 722
wmapViewPortWidth = WMAP_WIN_WIDTH - (640 - 450); // 890 - 190 = 700 + 22 = 722
SafeWriteBatch<DWORD>(wmapViewPortWidth, wmViewportEndRight);
// bottom limit of the viewport (443)
SafeWriteBatch<DWORD>(WMAP_WIN_HEIGHT - (480 - 443), wmViewportEndBottom); // 720 - 37 = 683 + 21 = 704
wmapViewPortHeight = WMAP_WIN_HEIGHT - (480 - 443); // 720 - 37 = 683 + 21 = 704
SafeWriteBatch<DWORD>(wmapViewPortHeight, wmViewportEndBottom);
// Night/Day frm (wmRefreshInterfaceDial_)
SafeWrite32(0x4C577F, WMAP_WIN_WIDTH - (640 - 532)); // X offset (532)
@@ -455,6 +459,84 @@ static void WorldmapViewportPatch() {
dlogr(" Done", DL_INIT);
}
struct DotPosition {
long x;
long y;
};
static std::vector<DotPosition> dots;
static long spaceLen = 2;
static long dotLen = 1;
static long dot_xpos = 0;
static long dot_ypos = 0;
static void AddNewDot() {
dot_xpos = fo::var::world_xpos;
dot_ypos = fo::var::world_ypos;
if (dotLen <= 0 && spaceLen) {
spaceLen--;
if (!spaceLen) dotLen = 1; // set dot length
return;
}
dotLen--;
DotPosition dot;
dot.x = dot_xpos;
dot.y = dot_ypos;
dots.push_back(std::move(dot));
spaceLen = 2;
}
static void __declspec(naked) wmInterfaceRefresh_hook() {
long x_offset, y_offset;
__asm {
pushad;
mov ebp, esp; // prolog
sub esp, __LOCAL_SIZE;
}
if ((fo::var::target_xpos || fo::var::target_ypos) && (dot_xpos != fo::var::world_xpos || dot_ypos != fo::var::world_ypos)) {
AddNewDot();
}
x_offset = 22 - fo::var::wmWorldOffsetX;
y_offset = 21 - fo::var::wmWorldOffsetY;
for (const auto &dot : dots) { // redraws all dots
if (dot.x < fo::var::wmWorldOffsetX || dot.y < fo::var::wmWorldOffsetY) continue; // the pixel is out of viewport
if (dot.x > fo::var::wmWorldOffsetX + wmapViewPortWidth || dot.y > fo::var::wmWorldOffsetY + wmapViewPortHeight) continue;
long wmPixelX = (dot.x + x_offset);
long wmPixelY = (dot.y + y_offset);
wmPixelY *= wmapWinWidth;
BYTE* wmWinBuf = *(BYTE**)FO_VAR_wmBkWinBuf;
BYTE* wmWinBuf_xy = (wmPixelY + wmPixelX) + wmWinBuf;
// put pixel to interface window buffer
if (wmWinBuf_xy > wmWinBuf) *wmWinBuf_xy = 133; // index color in palette: R = 252, G = 0, B = 0
// TODO: fix dots for car travel
}
__asm {
mov esp, ebp; // epilog
popad;
jmp fo::funcoffs::wmInterfaceDrawSubTileList_;
}
}
static void __declspec(naked) wmInterfaceRefresh_hook_stop() {
if (!fo::var::target_xpos && !fo::var::target_ypos) {
dots.clear();
dotLen = 1;
spaceLen = 2;
}
__asm jmp fo::funcoffs::wmDrawCursorStopped_;
}
static void __declspec(naked) wmInterfaceRefreshCarFuel_hack_empty() {
__asm {
mov byte ptr [eax - 1], 13;
@@ -481,6 +563,8 @@ static void __declspec(naked) wmInterfaceRefreshCarFuel_hack() {
}
static void WorldMapInterfacePatch() {
BlockCall(0x4C2380); // Remove disabling palette animations (can be used as a place to call a hack function in wmInterfaceInit_)
if (GetConfigInt("Misc", "WorldMapFontPatch", 0)) {
dlog("Applying world map font patch.", DL_INIT);
HookCall(0x4C2343, wmInterfaceInit_text_font_hook);
@@ -514,6 +598,16 @@ static void WorldMapInterfacePatch() {
LoadGameHook::OnAfterGameInit() += WorldmapViewportPatch; // Note: must be applied after WorldMapSlots patch
}
}
if (GetConfigInt("Interface", "WorldTravelMarkers", 0)) {
HookCall(0x4C3BE6, wmInterfaceRefresh_hook); // when calling wmInterfaceDrawSubTileList_
HookCall(0x4C3C7E, wmInterfaceRefresh_hook_stop);
dots.reserve(512);
LoadGameHook::OnGameReset() += []() {
dots.clear();
};
}
// Car fuel gauge graphics patch
MakeCall(0x4C528A, wmInterfaceRefreshCarFuel_hack_empty);
MakeCall(0x4C529E, wmInterfaceRefreshCarFuel_hack);
+1 -1
View File
@@ -664,7 +664,7 @@ void MiscPatches::init() {
}
// Increase the max text width of the information card in the character screen
SafeWriteBatch<BYTE>(144, {0x43ACD5, 0x43DD37}); // 136, 133
SafeWriteBatch<BYTE>(145, {0x43ACD5, 0x43DD37}); // 136, 133
F1EngineBehaviorPatch();
DialogueFix();
+1 -1
View File
@@ -410,7 +410,7 @@ void WorldmapFpsPatch() {
if (GetConfigInt("Misc", "WorldMapEncounterFix", 0)) {
dlog("Applying world map encounter patch.", DL_INIT);
WorldMapEncounterRate = GetConfigInt("Misc", "WorldMapEncounterRate", 5);
SafeWrite32(0x4C232D, 0x01EBC031); // xor eax, eax; jmps 0x4C2332 (wmInterfaceInit_)
SafeWrite32(0x4C232D, 0xB8); // mov eax, 0; (wmInterfaceInit_)
HookCall(0x4BFEE0, wmWorldMapFunc_hook);
MakeCall(0x4C0667, wmRndEncounterOccurred_hack);
dlogr(" Done", DL_INIT);