diff --git a/src/animation.cc b/src/animation.cc index 36b27d2..bbfa628 100644 --- a/src/animation.cc +++ b/src/animation.cc @@ -2787,7 +2787,7 @@ void _object_animate() Object* object = sad->obj; - unsigned int time = getTicks(); + unsigned int time = getMultipliedTicks(); if (getTicksBetween(time, sad->animationTimestamp) < sad->ticksPerFrame) { continue; } diff --git a/src/input.cc b/src/input.cc index 9d61b69..4c97edc 100644 --- a/src/input.cc +++ b/src/input.cc @@ -1,6 +1,7 @@ #include "input.h" #include +#include #include "audio_engine.h" #include "color.h" @@ -9,6 +10,7 @@ #include "kb.h" #include "memory.h" #include "mouse.h" +#include "sfall_config.h" #include "svga.h" #include "text_font.h" #include "vcr.h" @@ -116,6 +118,15 @@ static TickerListNode* gTickerListHead; // 0x6AC788 static unsigned int gTickerLastTimestamp; +static bool gSpeedPatchEnabled; +static int gSpeedMultiInitial; +static float gSpeedMulti; +static unsigned int gLastTickCount; +static unsigned int gStoredTickCount; +static float gTickCountFraction; +static time_t gStartTime; + + // 0x4C8A70 int inputInit(int a1) { @@ -155,6 +166,17 @@ int inputInit(int a1) // CE: Prevents frying CPU when window is not focused. inputSetIdleFunc(idleImpl); + // SFALL: Speed patch + gSpeedPatchEnabled = false; + configGetBool(&gSfallConfig, SFALL_CONFIG_SPEED_KEY, SFALL_CONFIG_SPEED_ENABLE_KEY, &gSpeedPatchEnabled); + gSpeedMultiInitial = 100; + configGetInt(&gSfallConfig, SFALL_CONFIG_SPEED_KEY, SFALL_CONFIG_SPEED_MULTI_INITIAL_KEY, &gSpeedMultiInitial); + gSpeedMulti = gSpeedMultiInitial / 100.0f; + gLastTickCount = SDL_GetTicks(); + gStoredTickCount = 0; + gTickCountFraction = 0.0f; + gStartTime = time(NULL); + return 0; } @@ -606,16 +628,56 @@ void screenshotHandlerConfigure(int keyCode, ScreenshotHandler* handler) } // 0x4C9370 +// Returns the original tick count (unaffected by the sfall speed patch). unsigned int getTicks() { return SDL_GetTicks(); } +// Inspired by sfall SpeedPatch.cpp. +// Returns the potentially sped up (multiplied) tick count. +unsigned int getMultipliedTicks() +{ + unsigned int newTickCount = SDL_GetTicks(); + if (newTickCount == gLastTickCount) return gStoredTickCount; + + // Just in case someone's been running their computer for 49 days straight + if (gLastTickCount > newTickCount) { + gLastTickCount = newTickCount; + return gStoredTickCount; + } + + float elapsed = static_cast(newTickCount - gLastTickCount); + gLastTickCount = newTickCount; + + // Multiply the tick count difference by the multiplier + /* TODO janiczek: Original condition was: + if (IsGameLoaded() && enabled && (!(mode = GetLoopFlags()) || mode == LoopFlag::COMBAT || mode == (LoopFlag::COMBAT | LoopFlag::PCOMBAT) || (mode & LoopFlag::WORLDMAP)) && !slideShow) + */ + if (gSpeedPatchEnabled) { + elapsed *= gSpeedMulti; + elapsed += gTickCountFraction; + gTickCountFraction = modff(gTickCountFraction, &gTickCountFraction); + } + + gStoredTickCount += static_cast(elapsed); + + return gStoredTickCount; +} + +// Done by sfall (presumably) because this time gets converted to game time. +// If you've played the game at 8x speed for a while, you'll want the time in +// the savefile to agree with the time in the game at the time you saved it. +time_t getLocalTimeAfterSpeedup() +{ + return gStartTime + gStoredTickCount / 1000; +} + // 0x4C937C void inputPauseForTocks(unsigned int delay) { // NOTE: Uninline. - unsigned int start = getTicks(); + unsigned int start = getMultipliedTicks(); unsigned int end = getTicks(); // NOTE: Uninline. @@ -644,7 +706,10 @@ void inputBlockForTocks(unsigned int ms) // 0x4C93E0 unsigned int getTicksSince(unsigned int start) { - unsigned int end = SDL_GetTicks(); + // TODO janiczek: this one was supposed to be patched, but the game seems to work better without that. + // We can retry after implementing the big condition, it will likely fix + // all the issues, eg. with inventory animation spinning too fast etc. + unsigned int end = getTicks(); // NOTE: Uninline. return getTicksBetween(end, start); diff --git a/src/input.h b/src/input.h index 6728480..8344b6d 100644 --- a/src/input.h +++ b/src/input.h @@ -1,6 +1,8 @@ #ifndef FALLOUT_INPUT_H_ #define FALLOUT_INPUT_H_ +#include + namespace fallout { typedef void(IdleFunc)(); @@ -26,6 +28,8 @@ void takeScreenshot(); int screenshotHandlerDefaultImpl(int width, int height, unsigned char* data, unsigned char* palette); void screenshotHandlerConfigure(int keyCode, ScreenshotHandler* handler); unsigned int getTicks(); +unsigned int getMultipliedTicks(); +time_t getLocalTimeAfterSpeedup(); void inputPauseForTocks(unsigned int ms); void inputBlockForTocks(unsigned int ms); unsigned int getTicksSince(unsigned int a1); diff --git a/src/loadsave.cc b/src/loadsave.cc index a23c01f..2efb329 100644 --- a/src/loadsave.cc +++ b/src/loadsave.cc @@ -1714,7 +1714,7 @@ static int lsgSaveHeaderInSlot(int slot) return -1; } - time_t now = time(NULL); + time_t now = getLocalTimeAfterSpeedup(); struct tm* local = localtime(&now); temp[0] = local->tm_mday; diff --git a/src/sfall_config.h b/src/sfall_config.h index 7b4f83e..5e72b61 100644 --- a/src/sfall_config.h +++ b/src/sfall_config.h @@ -7,6 +7,7 @@ namespace fallout { #define SFALL_CONFIG_FILE_NAME "ddraw.ini" +#define SFALL_CONFIG_SPEED_KEY "Speed" #define SFALL_CONFIG_MISC_KEY "Misc" #define SFALL_CONFIG_DUDE_NATIVE_LOOK_JUMPSUIT_MALE_KEY "MaleDefaultModel" @@ -59,6 +60,8 @@ namespace fallout { #define SFALL_CONFIG_TWEAKS_FILE_KEY "TweaksFile" #define SFALL_CONFIG_GAME_DIALOG_GENDER_WORDS_KEY "DialogGenderWords" #define SFALL_CONFIG_TOWN_MAP_HOTKEYS_FIX "TownMapHotkeysFix" +#define SFALL_CONFIG_SPEED_ENABLE_KEY "Enable" +#define SFALL_CONFIG_SPEED_MULTI_INITIAL_KEY "SpeedMultiInitial" #define SFALL_CONFIG_BURST_MOD_DEFAULT_CENTER_MULTIPLIER 1 #define SFALL_CONFIG_BURST_MOD_DEFAULT_CENTER_DIVISOR 3