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); } /**