diff --git a/src/openrct2/Context.cpp b/src/openrct2/Context.cpp index 152d7f2e6f..543af3ae70 100644 --- a/src/openrct2/Context.cpp +++ b/src/openrct2/Context.cpp @@ -118,7 +118,8 @@ namespace OpenRCT2 bool _initialised = false; bool _isWindowMinimised = false; uint32_t _lastTick = 0; - uint32_t _accumulator = 0; + float _accumulator = 0.0f; + float _timeScale = 1.0f; uint32_t _lastUpdateTime = 0; bool _variableFrame = false; @@ -978,9 +979,9 @@ namespace OpenRCT2 _lastTick = currentTick; } - uint32_t elapsed = currentTick - _lastTick; + float elapsed = (currentTick - _lastTick) * _timeScale; _lastTick = currentTick; - _accumulator = std::min(_accumulator + elapsed, static_cast(GAME_UPDATE_MAX_THRESHOLD)); + _accumulator = std::min(_accumulator + elapsed, static_cast(GAME_UPDATE_MAX_THRESHOLD)); _uiContext->ProcessMessages(); @@ -1021,10 +1022,10 @@ namespace OpenRCT2 _lastTick = currentTick; } - uint32_t elapsed = currentTick - _lastTick; + float elapsed = (currentTick - _lastTick) * _timeScale; _lastTick = currentTick; - _accumulator = std::min(_accumulator + elapsed, static_cast(GAME_UPDATE_MAX_THRESHOLD)); + _accumulator = std::min(_accumulator + elapsed, static_cast(GAME_UPDATE_MAX_THRESHOLD)); _uiContext->ProcessMessages(); @@ -1048,7 +1049,7 @@ namespace OpenRCT2 if (draw) { - const float alpha = std::min(static_cast(_accumulator) / GAME_UPDATE_TIME_MS, 1.0f); + const float alpha = std::min(_accumulator / static_cast(GAME_UPDATE_TIME_MS), 1.0f); tweener.Tween(alpha); _drawingEngine->BeginDraw(); @@ -1220,6 +1221,16 @@ namespace OpenRCT2 { return &_newVersionInfo; } + + void SetTimeScale(float newScale) override + { + _timeScale = std::clamp(newScale, GAME_MIN_TIME_SCALE, GAME_MAX_TIME_SCALE); + } + + float GetTimeScale() const override + { + return _timeScale; + } }; Context* Context::Instance = nullptr; @@ -1240,6 +1251,7 @@ namespace OpenRCT2 { return Context::Instance; } + } // namespace OpenRCT2 void context_init() diff --git a/src/openrct2/Context.h b/src/openrct2/Context.h index 28634b58e6..ed88b99bf0 100644 --- a/src/openrct2/Context.h +++ b/src/openrct2/Context.h @@ -1,4 +1,4 @@ -/***************************************************************************** +/***************************************************************************** * Copyright (c) 2014-2020 OpenRCT2 developers * * For a complete list of all authors, please refer to contributors.md @@ -150,6 +150,9 @@ namespace OpenRCT2 * This is deprecated, use IPlatformEnvironment. */ virtual std::string GetPathLegacy(int32_t pathId) abstract; + + virtual void SetTimeScale(float newScale) abstract; + virtual float GetTimeScale() const abstract; }; std::unique_ptr CreateContext(); @@ -171,6 +174,9 @@ enum GAME_UPDATE_MAX_THRESHOLD = GAME_UPDATE_TIME_MS * GAME_MAX_UPDATES, }; +constexpr float GAME_MIN_TIME_SCALE = 0.1f; +constexpr float GAME_MAX_TIME_SCALE = 5.0f; + /** * Legacy get_file_path IDs. * Remove when context_get_path_legacy is removed. diff --git a/src/openrct2/interface/InteractiveConsole.cpp b/src/openrct2/interface/InteractiveConsole.cpp index f7949af113..15275c8b25 100644 --- a/src/openrct2/interface/InteractiveConsole.cpp +++ b/src/openrct2/interface/InteractiveConsole.cpp @@ -693,6 +693,10 @@ static int32_t cc_get(InteractiveConsole& console, const arguments_t& argv) { console.WriteFormatLine("current_rotation %d", get_current_rotation()); } + else if (argv[0] == "host_timescale") + { + console.WriteFormatLine("host_timescale %.02f", OpenRCT2::GetContext()->GetTimeScale()); + } #ifndef NO_TTF else if (argv[0] == "enable_hinting") { @@ -1011,6 +1015,14 @@ static int32_t cc_set(InteractiveConsole& console, const arguments_t& argv) } console.Execute("get current_rotation"); } + else if (argv[0] == "host_timescale" && invalidArguments(&invalidArgs, double_valid[0])) + { + float newScale = static_cast(double_val[0]); + + OpenRCT2::GetContext()->SetTimeScale(newScale); + + console.Execute("get host_timescale"); + } #ifndef NO_TTF else if (argv[0] == "enable_hinting" && invalidArguments(&invalidArgs, int_valid[0])) {