Rewrote ASM code of WorldMapFPSPatch in C++

This commit is contained in:
NovaRain
2021-02-07 21:27:36 +08:00
parent 60a187de30
commit 02e48dde63
5 changed files with 67 additions and 60 deletions
+2 -1
View File
@@ -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
+2 -2
View File
@@ -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
+13 -8
View File
@@ -19,11 +19,12 @@
#include <cmath>
#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();
+6 -3
View File
@@ -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();
+44 -46
View File
@@ -32,6 +32,7 @@ static DWORD ViewportY;
std::vector<std::pair<long, std::string>> wmTerrainTypeNames; // pair first: x + y * number of horizontal sub-tiles
std::tr1::unordered_map<long, std::string> 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;
}