From 3877bb31ef26d837f5263b44c05e755cfaad0a2d Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Thu, 15 Dec 2022 22:54:42 +0000 Subject: [PATCH] Changing day length or date no longer changes time in minutes Add offset variables for scaled date ticks. Adjust offset when changing day length or date, such that scaled date ticks remain the same. Store _scaled_tick_counter and scaled date ticks offset in the savagame. --- src/date.cpp | 51 +++++++++++++++++++++++++++++--- src/date_func.h | 38 +++++++++++++++++++++++- src/date_gui.cpp | 6 ++-- src/departures.cpp | 2 +- src/misc.cpp | 4 ++- src/newgrf.cpp | 6 ++++ src/openttd.cpp | 4 +-- src/saveload/afterload.cpp | 5 +++- src/saveload/extended_ver_sl.cpp | 2 +- src/saveload/misc_sl.cpp | 4 +++ src/schdispatch.h | 8 ++--- src/settings.cpp | 10 ++----- src/statusbar_gui.cpp | 2 +- src/strings.cpp | 10 +++---- src/timetable_cmd.cpp | 7 ++--- src/timetable_gui.cpp | 7 +++-- src/tracerestrict.cpp | 4 +-- src/vehicle.cpp | 5 ---- 18 files changed, 127 insertions(+), 48 deletions(-) diff --git a/src/date.cpp b/src/date.cpp index 6e60b8feb7..a12ca1feab 100644 --- a/src/date.cpp +++ b/src/date.cpp @@ -33,6 +33,7 @@ uint64 _tick_counter; ///< Ever incrementing tick counter for setting off vario uint8 _tick_skip_counter; ///< Counter for ticks, when only vehicles are moving and nothing else happens uint64 _scaled_tick_counter; ///< Tick counter in daylength-scaled ticks DateTicksScaled _scaled_date_ticks; ///< Date as ticks in daylength-scaled ticks +DateTicksScaled _scaled_date_ticks_offset; ///< Offset to add when generating _scaled_date_ticks uint32 _quit_after_days; ///< Quit after this many days of run time YearMonthDay _game_load_cur_date_ymd; @@ -41,12 +42,48 @@ uint8 _game_load_tick_skip_counter; extern void ClearOutOfDateSignalSpeedRestrictions(); +void CheckScaledDateTicksWrap() +{ + DateTicksScaled tick_adjust = 0; + auto get_tick_adjust = [&](DateTicksScaled target) { + int32 rounding = _settings_time.time_in_minutes * 1440; + return target - (target % rounding); + }; + if (_scaled_date_ticks >= ((int64)1 << 60)) { + tick_adjust = get_tick_adjust(_scaled_date_ticks); + } else if (_scaled_date_ticks <= -((int64)1 << 60)) { + tick_adjust = -get_tick_adjust(-_scaled_date_ticks); + } else { + return; + } + + _scaled_date_ticks_offset -= tick_adjust; + _scaled_date_ticks -= tick_adjust; + + extern void AdjustAllSignalSpeedRestrictionTickValues(DateTicksScaled delta); + AdjustAllSignalSpeedRestrictionTickValues(-tick_adjust); + + extern void AdjustVehicleScaledTickBase(int64 delta); + AdjustVehicleScaledTickBase(-tick_adjust); +} + +void RebaseScaledDateTicksBase() +{ + DateTicksScaled old_scaled_date_ticks = _scaled_date_ticks; + SetScaledTickVariables(); + _scaled_date_ticks_offset += (old_scaled_date_ticks - _scaled_date_ticks); + SetScaledTickVariables(); + assert(old_scaled_date_ticks == _scaled_date_ticks); + + CheckScaledDateTicksWrap(); +} + /** * Set the date. * @param date New date * @param fract The number of ticks that have passed on this date. */ -void SetDate(Date date, DateFract fract) +void SetDate(Date date, DateFract fract, bool preserve_scaled_ticks) { assert(fract < DAY_TICKS); @@ -56,14 +93,17 @@ void SetDate(Date date, DateFract fract) _date_fract = fract; ConvertDateToYMD(date, &ymd); _cur_date_ymd = ymd; - SetScaledTickVariables(); + if (preserve_scaled_ticks) { + RebaseScaledDateTicksBase(); + } else { + SetScaledTickVariables(); + } UpdateCachedSnowLine(); } void SetScaledTickVariables() { - _scaled_date_ticks = ((((DateTicksScaled)_date * DAY_TICKS) + _date_fract) * _settings_game.economy.day_length_factor) + _tick_skip_counter; - _scaled_tick_counter = (uint64)((_tick_counter * _settings_game.economy.day_length_factor) + _tick_skip_counter); + _scaled_date_ticks = ((((DateTicksScaled)_date * DAY_TICKS) + _date_fract) * _settings_game.economy.day_length_factor) + _tick_skip_counter + _scaled_date_ticks_offset; } #define M(a, b) ((a << 5) | b) @@ -236,12 +276,15 @@ static void OnNewYear() for (LinkGraph *lg : LinkGraph::Iterate()) lg->ShiftDates(-days_this_year); ShiftOrderDates(-days_this_year); ShiftVehicleDates(-days_this_year); + _scaled_date_ticks_offset += ((int64)days_this_year) * (DAY_TICKS * _settings_game.economy.day_length_factor); /* Because the _date wraps here, and text-messages expire by game-days, we have to clean out * all of them if the date is set back, else those messages will hang for ever */ NetworkInitChatMessage(); } + CheckScaledDateTicksWrap(); + if (_settings_client.gui.auto_euro) CheckSwitchToEuro(); IConsoleCmdExec("exec scripts/on_newyear.scr 0"); } diff --git a/src/date_func.h b/src/date_func.h index e0e765c71e..3b9b673558 100644 --- a/src/date_func.h +++ b/src/date_func.h @@ -11,6 +11,8 @@ #define DATE_FUNC_H #include "date_type.h" +#include "settings_type.h" +#include extern YearMonthDay _cur_date_ymd; extern Date _date; @@ -19,13 +21,14 @@ extern uint64 _tick_counter; extern uint8 _tick_skip_counter; extern uint64 _scaled_tick_counter; extern DateTicksScaled _scaled_date_ticks; +extern DateTicksScaled _scaled_date_ticks_offset; extern uint32 _quit_after_days; extern YearMonthDay _game_load_cur_date_ymd; extern DateFract _game_load_date_fract; extern uint8 _game_load_tick_skip_counter; -void SetDate(Date date, DateFract fract); +void SetDate(Date date, DateFract fract, bool preserve_scaled_ticks = true); void ConvertDateToYMD(Date date, YearMonthDay *ymd); Date ConvertYMDToDate(Year year, Month month, Day day); void SetScaledTickVariables(); @@ -47,4 +50,37 @@ static inline bool IsLeapYear(Year yr) return yr % 4 == 0 && (yr % 100 != 0 || yr % 400 == 0); } +static inline Date ScaledDateTicksToDate(DateTicksScaled ticks) +{ + return (ticks - _scaled_date_ticks_offset) / (DAY_TICKS * _settings_game.economy.day_length_factor); +} + +static inline DateTicksScaled DateToScaledDateTicks(Date date) +{ + return ((int64)date * DAY_TICKS * _settings_game.economy.day_length_factor) + _scaled_date_ticks_offset; +} + +static inline DateTicks ScaledDateTicksToDateTicks(DateTicksScaled ticks) +{ + return (ticks - _scaled_date_ticks_offset) / _settings_game.economy.day_length_factor; +} + +static inline DateTicksScaled DateTicksToScaledDateTicks(DateTicks date_ticks) +{ + return ((int64)date_ticks * _settings_game.economy.day_length_factor) + _scaled_date_ticks_offset; +} + +static inline std::pair ScaledDateTicksToDateTicksAndSubTicks(DateTicksScaled ticks) +{ + ticks -= _scaled_date_ticks_offset; + return std::make_pair(ticks / _settings_game.economy.day_length_factor, ticks % _settings_game.economy.day_length_factor); +} + +static inline std::pair ScaledDateTicksToDateAndFullSubTicks(DateTicksScaled ticks) +{ + ticks -= _scaled_date_ticks_offset; + const int full_date = _settings_game.economy.day_length_factor * DAY_TICKS; + return std::make_pair(ticks / full_date, ticks % full_date); +} + #endif /* DATE_FUNC_H */ diff --git a/src/date_gui.cpp b/src/date_gui.cpp index eb6dff40e3..550759df71 100644 --- a/src/date_gui.cpp +++ b/src/date_gui.cpp @@ -154,8 +154,7 @@ struct SetDateWindow : Window { break; case WID_SD_SET_DATE: if (this->callback != nullptr) { - this->callback(this, ConvertYMDToDate(this->date.year, this->date.month, this->date.day) - * DAY_TICKS * _settings_game.economy.day_length_factor); + this->callback(this, DateToScaledDateTicks(ConvertYMDToDate(this->date.year, this->date.month, this->date.day))); } delete this; break; @@ -372,8 +371,7 @@ void ShowSetDateWindow(Window *parent, int window_number, DateTicksScaled initia DeleteWindowByClass(WC_SET_DATE); if (!_settings_time.time_in_minutes) { - new SetDateWindow(&_set_date_desc, window_number, parent, initial_date / (DAY_TICKS * _settings_game.economy.day_length_factor), - min_year, max_year, callback, button_text, button_tooltip); + new SetDateWindow(&_set_date_desc, window_number, parent, ScaledDateTicksToDate(initial_date), min_year, max_year, callback, button_text, button_tooltip); } else { new SetMinutesWindow(&_set_minutes_desc, window_number, parent, initial_date + (_settings_game.economy.day_length_factor * (_settings_time.clock_offset * _settings_time.ticks_per_minute)), diff --git a/src/departures.cpp b/src/departures.cpp index be90892ec0..efad95196a 100644 --- a/src/departures.cpp +++ b/src/departures.cpp @@ -241,7 +241,7 @@ DepartureList* MakeDepartureList(StationID station, const std::vectorGetInt64(SCC_DATE_WALLCLOCK_LONG), last, _settings_client.gui.date_with_time, next_substr_case_index); } else { - buff = FormatYmdString(buff, args->GetInt64(SCC_DATE_WALLCLOCK_LONG) / (DAY_TICKS * _settings_game.economy.day_length_factor), last, next_substr_case_index); + buff = FormatYmdString(buff, ScaledDateTicksToDate(args->GetInt64(SCC_DATE_WALLCLOCK_LONG)), last, next_substr_case_index); } break; } @@ -1517,7 +1517,7 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg if (_settings_time.time_in_minutes) { buff = FormatWallClockString(buff, args->GetInt64(SCC_DATE_WALLCLOCK_SHORT), last, _settings_client.gui.date_with_time, next_substr_case_index); } else { - buff = FormatYmdString(buff, args->GetInt64(SCC_DATE_WALLCLOCK_SHORT) / (DAY_TICKS * _settings_game.economy.day_length_factor), last, next_substr_case_index); + buff = FormatYmdString(buff, ScaledDateTicksToDate(args->GetInt64(SCC_DATE_WALLCLOCK_SHORT)), last, next_substr_case_index); } break; } @@ -1526,7 +1526,7 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg if (_settings_time.time_in_minutes) { buff = FormatWallClockString(buff, args->GetInt64(SCC_DATE_WALLCLOCK_TINY), last, false, next_substr_case_index); } else { - buff = FormatTinyOrISODate(buff, args->GetInt64(SCC_DATE_WALLCLOCK_TINY) / (DAY_TICKS * _settings_game.economy.day_length_factor), STR_FORMAT_DATE_TINY, last); + buff = FormatTinyOrISODate(buff, ScaledDateTicksToDate(args->GetInt64(SCC_DATE_WALLCLOCK_TINY)), STR_FORMAT_DATE_TINY, last); } break; } @@ -1535,7 +1535,7 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg if (_settings_time.time_in_minutes) { buff = FormatWallClockString(buff, args->GetInt64(SCC_DATE_WALLCLOCK_ISO), last, false, next_substr_case_index); } else { - buff = FormatTinyOrISODate(buff, args->GetInt64(SCC_DATE_WALLCLOCK_ISO) / (DAY_TICKS * _settings_game.economy.day_length_factor), STR_FORMAT_DATE_ISO, last); + buff = FormatTinyOrISODate(buff, ScaledDateTicksToDate(args->GetInt64(SCC_DATE_WALLCLOCK_ISO)), STR_FORMAT_DATE_ISO, last); } break; } diff --git a/src/timetable_cmd.cpp b/src/timetable_cmd.cpp index adb119b327..264274a711 100644 --- a/src/timetable_cmd.cpp +++ b/src/timetable_cmd.cpp @@ -461,7 +461,7 @@ CommandCost CmdSetTimetableStart(TileIndex tile, DoCommandFlag flags, uint32 p1, if (timetable_all && !v->orders->IsCompleteTimetable()) return CMD_ERROR; const DateTicksScaled now = _scaled_date_ticks; - DateTicksScaled start_date_scaled = (_settings_game.economy.day_length_factor * (((DateTicksScaled)_date * DAY_TICKS) + _date_fract + (DateTicksScaled)(int32)p2)) + sub_ticks; + DateTicksScaled start_date_scaled = DateToScaledDateTicks(_date * DAY_TICKS + _date_fract + (int32)p2) + sub_ticks; if (flags & DC_EXEC) { std::vector vehs; @@ -493,8 +493,7 @@ CommandCost CmdSetTimetableStart(TileIndex tile, DoCommandFlag flags, uint32 p1, if (tt_start < now && idx < 0) { tt_start += total_duration; } - w->timetable_start = tt_start / _settings_game.economy.day_length_factor; - w->timetable_start_subticks = tt_start % _settings_game.economy.day_length_factor; + std::tie(w->timetable_start, w->timetable_start_subticks) = ScaledDateTicksToDateTicksAndSubTicks(tt_start); ++idx; } @@ -863,7 +862,7 @@ void UpdateVehicleTimetable(Vehicle *v, bool travelling) if (!set_scheduled_dispatch) just_started = !HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED); if (v->timetable_start != 0) { - v->lateness_counter = _scaled_date_ticks - ((_settings_game.economy.day_length_factor * ((DateTicksScaled) v->timetable_start)) + v->timetable_start_subticks); + v->lateness_counter = _scaled_date_ticks - (DateTicksToScaledDateTicks(v->timetable_start) + v->timetable_start_subticks); v->timetable_start = 0; v->timetable_start_subticks = 0; } diff --git a/src/timetable_gui.cpp b/src/timetable_gui.cpp index b7bbf34316..23a5eb5e4f 100644 --- a/src/timetable_gui.cpp +++ b/src/timetable_gui.cpp @@ -251,8 +251,9 @@ static void FillTimetableArrivalDepartureTable(const Vehicle *v, VehicleOrderID */ static void ChangeTimetableStartIntl(uint32 p1, DateTicksScaled date) { - DateTicks date_part = date / _settings_game.economy.day_length_factor; - uint32 sub_ticks = date % _settings_game.economy.day_length_factor; + DateTicks date_part; + uint16 sub_ticks; + std::tie(date_part, sub_ticks) = ScaledDateTicksToDateTicksAndSubTicks(date); DoCommandP(0, p1 | (sub_ticks << 21), (Ticks)(date_part - (((DateTicks)_date * DAY_TICKS) + _date_fract)), CMD_SET_TIMETABLE_START | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE)); } @@ -815,7 +816,7 @@ struct TimetableWindow : GeneralVehicleWindow { /* We are running towards the first station so we can start the * timetable at the given time. */ SetDParam(0, STR_JUST_DATE_WALLCLOCK_TINY); - SetDParam(1, (((DateTicksScaled) v->timetable_start) * _settings_game.economy.day_length_factor) + v->timetable_start_subticks); + SetDParam(1, DateTicksToScaledDateTicks(v->timetable_start) + v->timetable_start_subticks); DrawString(tr, STR_TIMETABLE_STATUS_START_AT); } else if (!HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED)) { /* We aren't running on a timetable yet, so how can we be "on time" diff --git a/src/tracerestrict.cpp b/src/tracerestrict.cpp index 63f96770c3..d420985889 100644 --- a/src/tracerestrict.cpp +++ b/src/tracerestrict.cpp @@ -2023,13 +2023,13 @@ int GetTraceRestrictTimeDateValueFromDate(TraceRestrictTimeDateValueField type, case TRTDVF_DAY: { YearMonthDay ymd; - ConvertDateToYMD(scaled_date_ticks / (DAY_TICKS * _settings_game.economy.day_length_factor), &ymd); + ConvertDateToYMD(ScaledDateTicksToDate(scaled_date_ticks), &ymd); return ymd.day; } case TRTDVF_MONTH: { YearMonthDay ymd; - ConvertDateToYMD(scaled_date_ticks / (DAY_TICKS * _settings_game.economy.day_length_factor), &ymd); + ConvertDateToYMD(ScaledDateTicksToDate(scaled_date_ticks), &ymd); return ymd.month + 1; } diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 4283a72022..9966bfaa05 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -4575,11 +4575,6 @@ void ShiftVehicleDates(int interval) for (Vehicle *v : Vehicle::Iterate()) { v->date_of_last_service += interval; } - - extern void AdjustAllSignalSpeedRestrictionTickValues(DateTicksScaled delta); - AdjustAllSignalSpeedRestrictionTickValues(interval * DAY_TICKS * _settings_game.economy.day_length_factor); - - AdjustVehicleScaledTickBase(interval * DAY_TICKS * _settings_game.economy.day_length_factor); } /**