From 02e48dde63f80805b0c911f691fc9d4412818bc9 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Sun, 7 Feb 2021 21:27:36 +0800 Subject: [PATCH] Rewrote ASM code of WorldMapFPSPatch in C++ --- artifacts/ddraw.ini | 3 +- sfall/AI.cpp | 4 +- sfall/SpeedPatch.cpp | 21 +++++++---- sfall/SpeedPatch.h | 9 +++-- sfall/Worldmap.cpp | 90 ++++++++++++++++++++++---------------------- 5 files changed, 67 insertions(+), 60 deletions(-) diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index 82f784aa..771b088e 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -1,5 +1,5 @@ ;sfall configuration settings -;v3.8.29 +;v3.8.30 [Main] ;Change to 1 if you want to use command line args to tell sfall to use another ini file. @@ -233,6 +233,7 @@ WorldMapTimeMod=100 WorldMapFPSPatch=1 ;Controls the world map speed if WorldMapFPSPatch is 1. Higher values cause slower movement +;Default is 66 milliseconds WorldMapDelay2=66 ;Set to 1 to enable Ray's patch to make world map encounter rate independent of your travel speed diff --git a/sfall/AI.cpp b/sfall/AI.cpp index 18aaa081..7e6c7a29 100644 --- a/sfall/AI.cpp +++ b/sfall/AI.cpp @@ -318,7 +318,7 @@ static long __fastcall CheckWeaponRangeAndApCost(TGameObj* source, TGameObj* tar long targetDist = fo_obj_dist(source, target); if (targetDist > weaponRange) return 0; // don't use secondary mode - return (source->critter.movePoints >= sf_item_w_mp_cost(source, ATKTYPE_RWEAPON_SECONDARY, 0)); // 1 - allow secondary mode + return (source->critter.movePoints >= sfgame_item_w_mp_cost(source, ATKTYPE_RWEAPON_SECONDARY, 0)); // 1 - allow secondary mode } static void __declspec(naked) ai_pick_hit_mode_hook() { @@ -353,7 +353,7 @@ static void __declspec(naked) cai_perform_distance_prefs_hack() { mov ecx, esi; push 0; // no called shot mov edx, ATKTYPE_RWEAPON_PRIMARY; - call sf_item_w_mp_cost; + call sfgame_item_w_mp_cost; mov edx, [esi + movePoints]; sub edx, eax; // ap - cost = free AP's jle moveAway; // <= 0 diff --git a/sfall/SpeedPatch.cpp b/sfall/SpeedPatch.cpp index ab67f3c0..748632e6 100644 --- a/sfall/SpeedPatch.cpp +++ b/sfall/SpeedPatch.cpp @@ -19,11 +19,12 @@ #include #include "main.h" - #include "FalloutEngine.h" #include "InputFuncs.h" #include "LoadGameHook.h" +#include "SpeedPatch.h" + static const DWORD offsets[] = { // GetTickCount calls 0x4C9375, 0x4C93E8, 0x4C93C0, 0x4FE01E, @@ -35,8 +36,12 @@ static const DWORD offsets[] = { 0x4F4E53, 0x4F5542, 0x4F56CC, 0x4F59C6, // for mve }; -DWORD sf_GetTickCount = (DWORD)&GetTickCount; -DWORD sf_GetLocalTime; +static DWORD getLocalTimeOffs; +DWORD getTickCountOffs = (DWORD)&GetTickCount; + +DWORD SpeedPatch_getTickCount() { + return ((DWORD (__stdcall*)())getTickCountOffs)(); +} static bool enabled = true; static bool toggled = false; @@ -142,7 +147,7 @@ void TimerInit() { char buf[2], spKey[10] = "SpeedKey#"; char spMulti[12] = "SpeedMulti#"; for (int i = 0; i < 10; i++) { - _itoa_s(i, buf, 10); + _itoa(i, buf, 10); spKey[8] = spMulti[10] = buf[0]; speed[i].key = GetConfigInt("Input", spKey, 0); speed[i].multiplier = GetConfigInt("Speed", spMulti, 0) / 100.0; @@ -160,16 +165,16 @@ void SpeedPatch_Init() { multi = (double)init / 100.0; toggleKey = GetConfigInt("Input", "SpeedToggleKey", 0); - sf_GetTickCount = (DWORD)&FakeGetTickCount; - sf_GetLocalTime = (DWORD)&FakeGetLocalTime; + getTickCountOffs = (DWORD)&FakeGetTickCount; + getLocalTimeOffs = (DWORD)&FakeGetLocalTime; int size = sizeof(offsets) / 4; if (GetConfigInt("Speed", "AffectPlayback", 0) == 0) size -= 4; for (int i = 0; i < size; i++) { - SafeWrite32(offsets[i], (DWORD)&sf_GetTickCount); + SafeWrite32(offsets[i], (DWORD)&getTickCountOffs); } - SafeWrite32(0x4FDF58, (DWORD)&sf_GetLocalTime); + SafeWrite32(0x4FDF58, (DWORD)&getLocalTimeOffs); HookCall(0x4A433E, scripts_check_state_hook); TimerInit(); diff --git a/sfall/SpeedPatch.h b/sfall/SpeedPatch.h index 35abf7df..483d90e5 100644 --- a/sfall/SpeedPatch.h +++ b/sfall/SpeedPatch.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009 The sfall team + * 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 @@ -18,7 +18,10 @@ #pragma once -extern DWORD sf_GetTickCount; - void SpeedPatch_Init(); void SpeedPatch_Exit(); + +extern DWORD getTickCountOffs; + +// sfall implementation of the GetTickCount() function +DWORD __stdcall SpeedPatch_getTickCount(); diff --git a/sfall/Worldmap.cpp b/sfall/Worldmap.cpp index a44490e1..fd0aa50e 100644 --- a/sfall/Worldmap.cpp +++ b/sfall/Worldmap.cpp @@ -32,6 +32,7 @@ static DWORD ViewportY; std::vector> wmTerrainTypeNames; // pair first: x + y * number of horizontal sub-tiles std::tr1::unordered_map wmAreaHotSpotTitle; +static bool worldMapLongDelay = false; static DWORD worldMapDelay; static DWORD worldMapTicks; @@ -104,52 +105,42 @@ end: } } -static void __declspec(naked) WorldMapFpsPatch() { +static void WorldMapFPS() { + DWORD prevTicks = worldMapTicks; // previous ticks + while (true) { + RunGlobalScripts3(); + if (worldMapLongDelay) { + __asm call process_bk_; + } + + DWORD tick; // current ticks + while (true) { + tick = SpeedPatch_getTickCount(); + // get elapsed time + if ((tick - prevTicks) >= 10) break; // delay 10 ms (GetTickCount returns a difference of 10-16 ms) + } + prevTicks = tick; + + // get elapsed time + if ((tick - worldMapTicks) >= worldMapDelay) break; + } + worldMapTicks = prevTicks; +} + +static void __declspec(naked) wmWorldMap_hook_patch1() { __asm { push dword ptr ds:[FO_VAR_last_buttons]; - push dword ptr ds:[0x6AC7B0]; // _mouse_buttons - mov esi, worldMapTicks; - mov ebx, esi; // previous ticks -loopDelay: - call RunGlobalScripts3; - call process_bk_; -subLoop: - call ds:[sf_GetTickCount]; // current ticks - mov edx, eax; - sub eax, ebx; // get elapsed time (cur.ticks - prev.ticks) - cmp eax, 10; // delay - GetTickCount returns minimum difference of 15 units - jb subLoop; // elapsed < invoke delay - mov ebx, edx; - sub edx, esi; // get elapsed time (cur.ticks - worldMapTicks) - cmp edx, worldMapDelay; - jb loopDelay; // elapsed < worldMapDelay - - pop dword ptr ds:[0x6AC7B0]; // _mouse_buttons + push dword ptr ds:[FO_VAR_mouse_buttons]; + call WorldMapFPS; + pop dword ptr ds:[FO_VAR_mouse_buttons]; pop dword ptr ds:[FO_VAR_last_buttons]; - call ds:[sf_GetTickCount]; - mov worldMapTicks, eax; jmp get_input_; } } -static void __declspec(naked) WorldMapFpsPatch2() { +static void __declspec(naked) wmWorldMap_hook_patch2() { __asm { - mov esi, worldMapTicks; - mov ebx, esi; -loopDelay: - call RunGlobalScripts3; -subLoop: - call ds:[sf_GetTickCount]; // current ticks - mov edx, eax; - sub eax, ebx; // get elapsed time - jz subLoop; - mov ebx, edx; - sub edx, esi; // get elapsed time - cmp edx, worldMapDelay; - jb loopDelay; // elapsed < worldMapDelay - - call ds:[sf_GetTickCount]; - mov worldMapTicks, eax; + call WorldMapFPS; jmp get_input_; } } @@ -157,9 +148,14 @@ subLoop: // Only used if the world map speed patch is disabled, so that world map scripts are still run static void __declspec(naked) wmWorldMap_hook() { __asm { - //pushadc; + call ds:[getTickCountOffs]; // current ticks + mov edx, eax; + sub eax, worldMapTicks; // get elapsed time (cur.ticks - prev.ticks) + cmp eax, 10; // delay 10 ms (GetTickCount returns a difference of 10-16 ms) + jb skipHook; + mov worldMapTicks, edx; call RunGlobalScripts3; - //popadc; +skipHook: jmp get_input_; } } @@ -223,6 +219,7 @@ static __declspec(naked) void PathfinderFix() { } static const char* automap = "automap"; // no/yes overrides the value in the table to display the automap in pipboy + static void __declspec(naked) wmMapInit_hack() { __asm { mov esi, [esp + 0xA0 - 0x20 + 4]; // curent map number @@ -345,12 +342,12 @@ static void WorldmapFpsPatch() { bool fpsPatchOK = (*(DWORD*)0x4BFE5E == 0x8D16); if (GetConfigInt("Misc", "WorldMapFPSPatch", 0)) { dlog("Applying world map fps patch.", DL_INIT); - if (!fpsPatchOK) { - dlogr(" Failed", DL_INIT); - } else { + if (fpsPatchOK) { int delay = GetConfigInt("Misc", "WorldMapDelay2", 66); worldMapDelay = max(1, delay); dlogr(" Done", DL_INIT); + } else { + dlogr(" Failed", DL_INIT); } } if (fpsPatchOK) { @@ -358,11 +355,12 @@ static void WorldmapFpsPatch() { if (worldMapDelay == 0) { func = wmWorldMap_hook; } else if (worldMapDelay > 25) { - func = WorldMapFpsPatch; + worldMapLongDelay = true; + func = wmWorldMap_hook_patch1; } else { - func = WorldMapFpsPatch2; + func = wmWorldMap_hook_patch2; } - HookCall(0x4BFE5D, func); + HookCall(0x4BFE5D, func); // wmWorldMap_ availableGlobalScriptTypes |= 2; }