Codechange: Use ticks for timetable start date

This commit is contained in:
Tyler Trahan 2023-11-11 08:31:27 -05:00
parent 3902acb13d
commit d28caa3ced
7 changed files with 63 additions and 11 deletions

View File

@ -11,7 +11,7 @@
#define BASE_CONSIST_H
#include "order_type.h"
#include "timer/timer_game_calendar.h"
#include "timer/timer_game_tick.h"
/** Various front vehicle properties that are preserved when autoreplacing, using order-backup or switching front engines within a consist. */
struct BaseConsist {
@ -20,7 +20,7 @@ struct BaseConsist {
/* Used for timetabling. */
uint32_t current_order_time; ///< How many ticks have passed since this order started.
int32_t lateness_counter; ///< How many ticks late (or early if negative) this vehicle is.
TimerGameCalendar::Date timetable_start; ///< When the vehicle is supposed to start the timetable.
TimerGameTick::TickCounter timetable_start; ///< At what tick of TimerGameTick::counter the vehicle should start its timetable.
uint16_t service_interval; ///< The interval for (automatic) servicing; either in days or %.

View File

@ -363,6 +363,7 @@ enum SaveLoadVersion : uint16_t {
SLV_CARGO_TRAVELLED, ///< 319 PR#11283 CargoPacket now tracks how far it travelled inside a vehicle.
SLV_STATION_RATING_CHEAT, ///< 320 PR#11346 Add cheat to fix station ratings at 100%.
SLV_TIMETABLE_START_TICKS, ///< 321 PR#11468 Convert timetable start from a date to ticks.
SL_MAX_VERSION, ///< Highest possible saveload version
};

View File

@ -17,6 +17,7 @@
#include "../roadveh.h"
#include "../ship.h"
#include "../aircraft.h"
#include "../timetable.h"
#include "../station_base.h"
#include "../effectvehicle_base.h"
#include "../company_base.h"
@ -373,6 +374,16 @@ void AfterLoadVehicles(bool part_of_load)
s->rotation_y_pos = s->y_pos;
}
}
if (IsSavegameVersionBefore(SLV_TIMETABLE_START_TICKS)) {
/* Convert timetable start from a date to an absolute tick in TimerGameTick::counter. */
for (Vehicle *v : Vehicle::Iterate()) {
/* If the start date is 0, the vehicle is not waiting to start and can be ignored. */
if (v->timetable_start == 0) continue;
v->timetable_start = GetStartTickFromDate(v->timetable_start);
}
}
}
CheckValidVehicles();
@ -663,7 +674,8 @@ public:
SLE_CONDVAR(Vehicle, current_order.wait_time, SLE_UINT16, SLV_67, SL_MAX_VERSION),
SLE_CONDVAR(Vehicle, current_order.travel_time, SLE_UINT16, SLV_67, SL_MAX_VERSION),
SLE_CONDVAR(Vehicle, current_order.max_speed, SLE_UINT16, SLV_174, SL_MAX_VERSION),
SLE_CONDVAR(Vehicle, timetable_start, SLE_INT32, SLV_129, SL_MAX_VERSION),
SLE_CONDVAR(Vehicle, timetable_start, SLE_FILE_I32 | SLE_VAR_U64, SLV_129, SLV_TIMETABLE_START_TICKS),
SLE_CONDVAR(Vehicle, timetable_start, SLE_UINT64, SLV_TIMETABLE_START_TICKS, SL_MAX_VERSION),
SLE_CONDREF(Vehicle, orders, REF_ORDER, SL_MIN_VERSION, SLV_105),
SLE_CONDREF(Vehicle, orders, REF_ORDERLIST, SLV_105, SL_MAX_VERSION),

View File

@ -16,6 +16,9 @@
static const TimerGameCalendar::Year MAX_TIMETABLE_START_YEARS = 15; ///< The maximum start date offset, in years.
TimerGameTick::TickCounter GetStartTickFromDate(TimerGameCalendar::Date start_date);
TimerGameCalendar::Date GetDateFromStartTick(TimerGameTick::TickCounter start_tick);
void ShowTimetableWindow(const Vehicle *v);
void UpdateVehicleTimetable(Vehicle *v, bool travelling);
void SetTimetableParams(int param1, int param2, TimerGameTick::Ticks ticks);

View File

@ -21,6 +21,40 @@
#include "safeguards.h"
/**
* Get the TimerGameTick::TickCounter tick of a given date.
* @param start_date The date when the timetable starts.
* @return The first tick of this date.
*/
TimerGameTick::TickCounter GetStartTickFromDate(TimerGameCalendar::Date start_date)
{
/* Calculate the offset in ticks from the current date. */
TimerGameTick::Ticks tick_offset = (start_date - TimerGameCalendar::date).base() * Ticks::DAY_TICKS;
/* Compensate for the current date_fract. */
tick_offset -= TimerGameCalendar::date_fract;
/* Return the current tick plus the offset. */
return TimerGameTick::counter + tick_offset;
}
/**
* Get a date from a given start tick of timetable.
* @param start_tick The TimerGameTick::TickCounter when the timetable starts.
* @return The date when we reach this tick.
*/
TimerGameCalendar::Date GetDateFromStartTick(TimerGameTick::TickCounter start_tick)
{
/* Calculate the offset in ticks from the current counter tick. */
TimerGameTick::Ticks tick_offset = start_tick - TimerGameTick::counter;
/* Compensate for the current date_fract. */
tick_offset += TimerGameCalendar::date_fract;
/* Return the current date plus the offset in days. */
return TimerGameCalendar::date + (tick_offset / Ticks::DAY_TICKS);
}
/**
* Change/update a particular timetable entry.
* @param v The vehicle to change the timetable of.
@ -300,10 +334,10 @@ static bool VehicleTimetableSorter(Vehicle * const &a, Vehicle * const &b)
* @param flags Operation to perform.
* @param veh_id Vehicle ID.
* @param timetable_all Set to set timetable start for all vehicles sharing this order
* @param start_date The timetable start date.
* @param start_tick The TimerGameTick::counter tick when the timetable starts.
* @return The error or cost of the operation.
*/
CommandCost CmdSetTimetableStart(DoCommandFlag flags, VehicleID veh_id, bool timetable_all, TimerGameCalendar::Date start_date)
CommandCost CmdSetTimetableStart(DoCommandFlag flags, VehicleID veh_id, bool timetable_all, TimerGameTick::TickCounter start_tick)
{
Vehicle *v = Vehicle::GetIfValid(veh_id);
if (v == nullptr || !v->IsPrimaryVehicle() || v->orders == nullptr) return CMD_ERROR;
@ -313,6 +347,8 @@ CommandCost CmdSetTimetableStart(DoCommandFlag flags, VehicleID veh_id, bool tim
TimerGameTick::Ticks total_duration = v->orders->GetTimetableTotalDuration();
TimerGameCalendar::Date start_date = GetDateFromStartTick(start_tick);
/* Don't let a timetable start at an invalid date. */
if (start_date < 0 || start_date > CalendarTime::MAX_DATE) return CMD_ERROR;
@ -351,7 +387,7 @@ CommandCost CmdSetTimetableStart(DoCommandFlag flags, VehicleID veh_id, bool tim
w->lateness_counter = 0;
ClrBit(w->vehicle_flags, VF_TIMETABLE_STARTED);
/* Do multiplication, then division to reduce rounding errors. */
w->timetable_start = start_date + idx * total_duration / num_vehs / Ticks::DAY_TICKS;
w->timetable_start = start_tick + (idx * total_duration / num_vehs);
SetWindowDirty(WC_VEHICLE_TIMETABLE, w->index);
++idx;
}
@ -444,7 +480,7 @@ void UpdateVehicleTimetable(Vehicle *v, bool travelling)
just_started = !HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED);
if (v->timetable_start != 0) {
v->lateness_counter = (TimerGameCalendar::date - v->timetable_start).base() * Ticks::DAY_TICKS + TimerGameCalendar::date_fract;
v->lateness_counter = TimerGameTick::counter - v->timetable_start;
v->timetable_start = 0;
}

View File

@ -11,13 +11,13 @@
#define TIMETABLE_CMD_H
#include "command_type.h"
#include "timer/timer_game_calendar.h"
#include "timer/timer_game_tick.h"
CommandCost CmdChangeTimetable(DoCommandFlag flags, VehicleID veh, VehicleOrderID order_number, ModifyTimetableFlags mtf, uint16_t data);
CommandCost CmdBulkChangeTimetable(DoCommandFlag flags, VehicleID veh, ModifyTimetableFlags mtf, uint16_t data);
CommandCost CmdSetVehicleOnTime(DoCommandFlag flags, VehicleID veh, bool apply_to_group);
CommandCost CmdAutofillTimetable(DoCommandFlag flags, VehicleID veh, bool autofill, bool preserve_wait_time);
CommandCost CmdSetTimetableStart(DoCommandFlag flags, VehicleID veh_id, bool timetable_all, TimerGameCalendar::Date start_date);
CommandCost CmdSetTimetableStart(DoCommandFlag flags, VehicleID veh_id, bool timetable_all, TimerGameTick::TickCounter start_tick);
DEF_CMD_TRAIT(CMD_CHANGE_TIMETABLE, CmdChangeTimetable, 0, CMDT_ROUTE_MANAGEMENT)
DEF_CMD_TRAIT(CMD_BULK_CHANGE_TIMETABLE, CmdBulkChangeTimetable, 0, CMDT_ROUTE_MANAGEMENT)

View File

@ -145,7 +145,7 @@ static void FillTimetableArrivalDepartureTable(const Vehicle *v, VehicleOrderID
*/
static void ChangeTimetableStartCallback(const Window *w, TimerGameCalendar::Date date, void *data)
{
Command<CMD_SET_TIMETABLE_START>::Post(STR_ERROR_CAN_T_TIMETABLE_VEHICLE, (VehicleID)w->window_number, reinterpret_cast<std::uintptr_t>(data) != 0, date);
Command<CMD_SET_TIMETABLE_START>::Post(STR_ERROR_CAN_T_TIMETABLE_VEHICLE, (VehicleID)w->window_number, reinterpret_cast<std::uintptr_t>(data) != 0, GetStartTickFromDate(date));
}
@ -494,7 +494,7 @@ struct TimetableWindow : Window {
/* We are running towards the first station so we can start the
* timetable at the given time. */
SetDParam(0, STR_JUST_DATE_TINY);
SetDParam(1, v->timetable_start);
SetDParam(1, GetDateFromStartTick(v->timetable_start));
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"