mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
183 lines
4.8 KiB
C++
183 lines
4.8 KiB
C++
/*
|
|
* 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 <cmath>
|
|
|
|
#include "main.h"
|
|
|
|
#include "FalloutEngine.h"
|
|
#include "input.h"
|
|
#include "LoadGameHook.h"
|
|
|
|
static const DWORD offsets[] = {
|
|
// GetTickCount calls
|
|
0x4C9375, 0x4C93E8, 0x4C93C0, 0x4FE01E,
|
|
0x4C9384, 0x4C9D2E, 0x4C8D34,
|
|
// Delayed GetTickCount calls
|
|
0x4FDF64,
|
|
// timeGetTime calls
|
|
0x4A3179, 0x4A325D, 0x4F482B, 0x4FE036,
|
|
0x4F4E53, 0x4F5542, 0x4F56CC, 0x4F59C6, // for mve
|
|
};
|
|
|
|
DWORD sf_GetTickCount = (DWORD)&GetTickCount;
|
|
DWORD sf_GetLocalTime;
|
|
|
|
static bool enabled = true;
|
|
static bool toggled = false;
|
|
static bool slideShow = false;
|
|
|
|
static double multi;
|
|
static DWORD storedTickCount = 0;
|
|
static DWORD lastTickCount;
|
|
static double tickCountFraction = 0.0;
|
|
|
|
static __int64 startTime;
|
|
|
|
static struct SpeedCfg {
|
|
int key;
|
|
double multiplier;
|
|
} *speed = nullptr;
|
|
|
|
static int modKey;
|
|
static int toggleKey;
|
|
|
|
static DWORD _stdcall FakeGetTickCount() {
|
|
// Keyboard control
|
|
if (modKey && ((modKey > 0 && KeyDown(modKey))
|
|
|| (modKey == -1 && (KeyDown(DIK_LCONTROL) || KeyDown(DIK_RCONTROL)))
|
|
|| (modKey == -2 && (KeyDown(DIK_LMENU) || KeyDown(DIK_RMENU)))
|
|
|| (modKey == -3 && (KeyDown(DIK_LSHIFT) || KeyDown(DIK_RSHIFT)))))
|
|
{
|
|
if (toggleKey && KeyDown(toggleKey)) {
|
|
if (!toggled) {
|
|
toggled = true;
|
|
enabled = !enabled;
|
|
}
|
|
} else {
|
|
toggled = false;
|
|
for (int i = 0; i < 10; i++) {
|
|
int key = speed[i].key;
|
|
if (key && KeyDown(key)) {
|
|
multi = speed[i].multiplier;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
DWORD newTickCount = GetTickCount();
|
|
// Just in case someone's been running their computer for 49 days straight
|
|
if (newTickCount < lastTickCount) {
|
|
newTickCount = lastTickCount;
|
|
return storedTickCount;
|
|
}
|
|
|
|
double elapsed = (double)(newTickCount - lastTickCount);
|
|
lastTickCount = newTickCount;
|
|
|
|
// Multiply the tick count difference by the multiplier
|
|
if (enabled && !slideShow
|
|
&& !(GetCurrentLoops() & (INVENTORY | INTFACEUSE | INTFACELOOT | DIALOG)))
|
|
{
|
|
elapsed *= multi;
|
|
tickCountFraction += modf(elapsed, &elapsed);
|
|
}
|
|
storedTickCount += (DWORD)elapsed;
|
|
|
|
if (tickCountFraction > 1.0) {
|
|
tickCountFraction -= 1.0;
|
|
storedTickCount++;
|
|
}
|
|
return storedTickCount;
|
|
}
|
|
|
|
void _stdcall FakeGetLocalTime(LPSYSTEMTIME time) {
|
|
__int64 currentTime = startTime + storedTickCount * 10000;
|
|
FileTimeToSystemTime((FILETIME*)¤tTime, time);
|
|
}
|
|
|
|
//Could divide 'uDelay' by 'Multi', but doesn't seem to have any effect.
|
|
/*MMRESULT _stdcall fTimeSetEvent(UINT uDelay, UINT uResolution, LPTIMECALLBACK lpTimeProc, DWORD_PTR dwUser, UINT fuEvent ) {
|
|
return timeSetEvent(uDelay, uResolution, lpTimeProc, dwUser, fuEvent);
|
|
}
|
|
|
|
MMRESULT _stdcall fTimeKillEvent(UINT id) {
|
|
return timeKillEvent(id);
|
|
}*/
|
|
|
|
static void __declspec(naked) scripts_check_state_hook() {
|
|
__asm {
|
|
inc slideShow;
|
|
call endgame_slideshow_;
|
|
dec slideShow;
|
|
retn;
|
|
}
|
|
}
|
|
|
|
void TimerInit() {
|
|
lastTickCount = GetTickCount();
|
|
|
|
SYSTEMTIME time;
|
|
GetLocalTime(&time);
|
|
SystemTimeToFileTime(&time, (FILETIME*)&startTime);
|
|
|
|
speed = new SpeedCfg[10];
|
|
|
|
char buf[2], spKey[10] = "SpeedKey#";
|
|
char spMulti[12] = "SpeedMulti#";
|
|
for (int i = 0; i < 10; i++) {
|
|
_itoa_s(i, buf, 10);
|
|
spKey[8] = spMulti[10] = buf[0];
|
|
speed[i].key = GetPrivateProfileIntA("Input", spKey, 0, ini);
|
|
speed[i].multiplier = GetPrivateProfileIntA("Speed", spMulti, 0, ini) / 100.0;
|
|
}
|
|
}
|
|
|
|
void SpeedPatchInit() {
|
|
if (GetPrivateProfileIntA("Speed", "Enable", 0, ini)) {
|
|
modKey = GetPrivateProfileIntA("Input", "SpeedModKey", 0, ini);
|
|
int init = GetPrivateProfileIntA("Speed", "SpeedMultiInitial", 100, ini);
|
|
if (init == 100 && !modKey) return;
|
|
|
|
dlog("Applying speed patch.", DL_INIT);
|
|
|
|
multi = (double)init / 100.0;
|
|
toggleKey = GetPrivateProfileIntA("Input", "SpeedToggleKey", 0, ini);
|
|
|
|
sf_GetTickCount = (DWORD)&FakeGetTickCount;
|
|
sf_GetLocalTime = (DWORD)&FakeGetLocalTime;
|
|
|
|
int size = sizeof(offsets) / 4;
|
|
if (GetPrivateProfileIntA("Speed", "AffectPlayback", 0, ini) == 0) size -= 4;
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
SafeWrite32(offsets[i], (DWORD)&sf_GetTickCount);
|
|
}
|
|
SafeWrite32(0x4FDF58, (DWORD)&sf_GetLocalTime);
|
|
HookCall(0x4A433E, scripts_check_state_hook);
|
|
|
|
TimerInit();
|
|
dlogr(" Done", DL_INIT);
|
|
}
|
|
}
|
|
|
|
void SpeedPatchExit() {
|
|
if (speed) delete[] speed;
|
|
}
|