Allow timetable start dates to be set with full precision.

This avoids rounding of start dates when using minutes and
day length > 1.
pull/8/head
Jonathan G Rennison 8 years ago
parent f82673bed8
commit d8a083b666

@ -35,6 +35,7 @@ void BaseConsist::CopyConsistPropertiesFrom(const BaseConsist *src)
this->current_order_time = src->current_order_time;
this->lateness_counter = src->lateness_counter;
this->timetable_start = src->timetable_start;
this->timetable_start_subticks = src->timetable_start_subticks;
this->service_interval = src->service_interval;

@ -24,6 +24,7 @@ struct BaseConsist {
uint32 current_order_time; ///< How many ticks have passed since this order started.
int32 lateness_counter; ///< How many ticks late (or early if negative) this vehicle is.
DateTicks timetable_start; ///< When the vehicle is supposed to start the timetable.
uint16 timetable_start_subticks; ///< When the vehicle is supposed to start the timetable: sub-ticks.
uint16 service_interval; ///< The interval for (automatic) servicing; either in days or %.

@ -148,7 +148,10 @@ struct SetDateWindow : Window {
ShowDateDropDown(widget);
break;
case WID_SD_SET_DATE:
if (this->callback != NULL) this->callback(this, ConvertYMDToDate(this->date.year, this->date.month, this->date.day) * DAY_TICKS);
if (this->callback != NULL) {
this->callback(this, ConvertYMDToDate(this->date.year, this->date.month, this->date.day)
* DAY_TICKS * _settings_game.economy.day_length_factor);
}
delete this;
break;
}
@ -178,9 +181,9 @@ struct SetMinutesWindow : SetDateWindow
Minutes minutes;
/** Constructor. */
SetMinutesWindow(WindowDesc *desc, WindowNumber window_number, Window *parent, DateTicks initial_date, Year min_year, Year max_year, SetDateCallback *callback) :
SetMinutesWindow(WindowDesc *desc, WindowNumber window_number, Window *parent, DateTicksScaled initial_date, Year min_year, Year max_year, SetDateCallback *callback) :
SetDateWindow(desc, window_number, parent, initial_date, min_year, max_year, callback),
minutes(initial_date * _settings_game.economy.day_length_factor / _settings_client.gui.ticks_per_minute)
minutes(initial_date / _settings_client.gui.ticks_per_minute)
{
}
@ -264,8 +267,7 @@ struct SetMinutesWindow : SetDateWindow
case WID_SD_SET_DATE:
if (this->callback != NULL) {
this->callback(this, (((DateTicks)minutes - _settings_client.gui.clock_offset) * _settings_client.gui.ticks_per_minute)
/ _settings_game.economy.day_length_factor);
this->callback(this, ((DateTicks)minutes - _settings_client.gui.clock_offset) * _settings_client.gui.ticks_per_minute);
}
delete this;
break;
@ -358,13 +360,15 @@ static WindowDesc _set_minutes_desc(
* @param max_year the maximum year (inclusive) to show in the year dropdown
* @param callback the callback to call once a date has been selected
*/
void ShowSetDateWindow(Window *parent, int window_number, DateTicks initial_date, Year min_year, Year max_year, SetDateCallback *callback)
void ShowSetDateWindow(Window *parent, int window_number, DateTicksScaled initial_date, Year min_year, Year max_year, SetDateCallback *callback)
{
DeleteWindowByClass(WC_SET_DATE);
if (!_settings_client.gui.time_in_minutes) {
new SetDateWindow(&_set_date_desc, window_number, parent, initial_date / DAY_TICKS, min_year, max_year, callback);
new SetDateWindow(&_set_date_desc, window_number, parent, initial_date / (DAY_TICKS * _settings_game.economy.day_length_factor), min_year, max_year, callback);
} else {
new SetMinutesWindow(&_set_minutes_desc, window_number, parent, initial_date + (_settings_client.gui.clock_offset * _settings_client.gui.ticks_per_minute), min_year, max_year, callback);
new SetMinutesWindow(&_set_minutes_desc, window_number, parent,
initial_date + (_settings_game.economy.day_length_factor * (_settings_client.gui.clock_offset * _settings_client.gui.ticks_per_minute)),
min_year, max_year, callback);
}
}

@ -20,8 +20,8 @@
* @param w the window that sends the callback
* @param date the date that has been chosen
*/
typedef void SetDateCallback(const Window *w, DateTicks date);
typedef void SetDateCallback(const Window *w, DateTicksScaled date);
void ShowSetDateWindow(Window *parent, int window_number, DateTicks initial_date, Year min_year, Year max_year, SetDateCallback *callback);
void ShowSetDateWindow(Window *parent, int window_number, DateTicksScaled initial_date, Year min_year, Year max_year, SetDateCallback *callback);
#endif /* DATE_GUI_H */

@ -3113,6 +3113,12 @@ bool AfterLoadGame()
}
}
}
if (!SlXvIsFeaturePresent(XSLFI_TIMETABLES_START_TICKS, 2)) {
Vehicle *v;
FOR_ALL_VEHICLES(v) {
v->timetable_start_subticks = 0;
}
}
if (SlXvIsFeaturePresent(XSLFI_SPRINGPP, 1, 1)) {
/*

@ -52,7 +52,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
{ XSLFI_PROG_SIGS, XSCF_NULL, 1, 1, "programmable_signals", NULL, NULL, "SPRG" },
{ XSLFI_ADJACENT_CROSSINGS, XSCF_NULL, 1, 1, "adjacent_crossings", NULL, NULL, NULL },
{ XSLFI_DEPARTURE_BOARDS, XSCF_IGNORABLE_UNKNOWN, 1, 1, "departure_boards", NULL, NULL, NULL },
{ XSLFI_TIMETABLES_START_TICKS, XSCF_NULL, 1, 1, "timetable_start_ticks", NULL, NULL, NULL },
{ XSLFI_TIMETABLES_START_TICKS, XSCF_NULL, 2, 2, "timetable_start_ticks", NULL, NULL, NULL },
{ XSLFI_TOWN_CARGO_ADJ, XSCF_IGNORABLE_UNKNOWN, 1, 1, "town_cargo_adj", NULL, NULL, NULL },
{ XSLFI_SIG_TUNNEL_BRIDGE, XSCF_NULL, 2, 2, "signal_tunnel_bridge", NULL, NULL, NULL },
{ XSLFI_IMPROVED_BREAKDOWNS, XSCF_NULL, 3, 3, "improved_breakdowns", NULL, NULL, NULL },

@ -266,6 +266,7 @@ const SaveLoad *GetOrderBackupDescription()
SLE_CONDVAR(OrderBackup, current_order_time, SLE_UINT32, 176, SL_MAX_VERSION),
SLE_CONDVAR(OrderBackup, lateness_counter, SLE_INT32, 176, SL_MAX_VERSION),
SLE_CONDVAR(OrderBackup, timetable_start, SLE_INT32, 176, SL_MAX_VERSION),
SLE_CONDVAR_X(OrderBackup,timetable_start_subticks, SLE_UINT16, 0, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TIMETABLES_START_TICKS, 2)),
SLE_CONDVAR(OrderBackup, vehicle_flags, SLE_FILE_U8 | SLE_VAR_U16, 176, 179),
SLE_CONDVAR(OrderBackup, vehicle_flags, SLE_UINT16, 180, SL_MAX_VERSION),
SLE_REF(OrderBackup, orders, REF_ORDER),

@ -673,6 +673,7 @@ const SaveLoad *GetVehicleDescription(VehicleType vt)
SLE_CONDVAR(Vehicle, current_order.travel_time, SLE_UINT16, 67, SL_MAX_VERSION),
SLE_CONDVAR(Vehicle, current_order.max_speed, SLE_UINT16, 174, SL_MAX_VERSION),
SLE_CONDVAR(Vehicle, timetable_start, SLE_INT32, 129, SL_MAX_VERSION),
SLE_CONDVAR_X(Vehicle, timetable_start_subticks, SLE_UINT16, 0, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TIMETABLES_START_TICKS, 2)),
SLE_CONDREF(Vehicle, orders, REF_ORDER, 0, 104),
SLE_CONDREF(Vehicle, orders, REF_ORDERLIST, 105, SL_MAX_VERSION),

@ -315,6 +315,7 @@ static int CDECL VehicleTimetableSorter(Vehicle * const *ap, Vehicle * const *bp
* @param p1 Various bitstuffed elements
* - p1 = (bit 0-19) - Vehicle ID.
* - p1 = (bit 20) - Set to 1 to set timetable start for all vehicles sharing this order
* - p1 = (bit 21-31)- Timetable start date: sub-ticks
* @param p2 The timetable start date.
* @param text Not used.
* @return The error or cost of the operation.
@ -323,6 +324,7 @@ CommandCost CmdSetTimetableStart(TileIndex tile, DoCommandFlag flags, uint32 p1,
{
bool timetable_all = HasBit(p1, 20);
Vehicle *v = Vehicle::GetIfValid(GB(p1, 0, 20));
uint16 sub_ticks = GB(p1, 21, 11);
if (v == NULL || !v->IsPrimaryVehicle() || v->orders.list == NULL) return CMD_ERROR;
CommandCost ret = CheckOwnership(v->owner);
@ -330,7 +332,8 @@ CommandCost CmdSetTimetableStart(TileIndex tile, DoCommandFlag flags, uint32 p1,
if (timetable_all && !v->orders.list->IsCompleteTimetable()) return CMD_ERROR;
DateTicks start_date = ((DateTicks)_date * DAY_TICKS) + _date_fract + (DateTicks)(int32)p2;
const DateTicksScaled now = CURRENT_SCALED_TICKS;
DateTicksScaled start_date_scaled = (_settings_game.economy.day_length_factor * (((DateTicks)_date * DAY_TICKS) + _date_fract + (DateTicks)(int32)p2)) + sub_ticks;
if (flags & DC_EXEC) {
SmallVector<Vehicle *, 8> vehs;
@ -359,10 +362,12 @@ CommandCost CmdSetTimetableStart(TileIndex tile, DoCommandFlag flags, uint32 p1,
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 * _settings_game.economy.day_length_factor);
if (w->timetable_start < (((DateTicks)_date * DAY_TICKS) + _date_fract) && idx < 0) {
w->timetable_start += (total_duration / _settings_game.economy.day_length_factor);
DateTicksScaled tt_start = start_date_scaled + ((idx * total_duration) / num_vehs);
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;
SetWindowDirty(WC_VEHICLE_TIMETABLE, w->index);
}
@ -407,6 +412,7 @@ CommandCost CmdAutofillTimetable(TileIndex tile, DoCommandFlag flags, uint32 p1,
if (HasBit(p2, 1)) SetBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME);
v->timetable_start = 0;
v->timetable_start_subticks = 0;
v->lateness_counter = 0;
} else {
ClrBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE);
@ -457,6 +463,7 @@ CommandCost CmdAutomateTimetable(TileIndex index, DoCommandFlag flags, uint32 p1
ClrBit(v2->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME);
ClrBit(v2->vehicle_flags, VF_TIMETABLE_STARTED);
v2->timetable_start = 0;
v->timetable_start_subticks = 0;
v2->lateness_counter = 0;
v2->current_loading_time = 0;
v2->ClearSeparation();
@ -470,6 +477,7 @@ CommandCost CmdAutomateTimetable(TileIndex index, DoCommandFlag flags, uint32 p1
/* Ctrl wasn't pressed, so clear all timetabled times. */
SetBit(v2->vehicle_flags, VF_TIMETABLE_STARTED);
v2->timetable_start = 0;
v->timetable_start_subticks = 0;
v2->lateness_counter = 0;
v2->current_loading_time = 0;
OrderList *orders = v2->orders.list;
@ -690,8 +698,9 @@ void UpdateVehicleTimetable(Vehicle *v, bool travelling)
just_started = !HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED);
if (v->timetable_start != 0) {
v->lateness_counter = ((_date * DAY_TICKS) + _date_fract - v->timetable_start) * _settings_game.economy.day_length_factor + _tick_skip_counter;
v->lateness_counter = CURRENT_SCALED_TICKS - ((_settings_game.economy.day_length_factor * v->timetable_start) + v->timetable_start_subticks);
v->timetable_start = 0;
v->timetable_start_subticks = 0;
}
SetBit(v->vehicle_flags, VF_TIMETABLE_STARTED);

@ -152,9 +152,11 @@ static void FillTimetableArrivalDepartureTable(const Vehicle *v, VehicleOrderID
* @param p1 The p1 parameter to send to CmdSetTimetableStart
* @param date the actually chosen date
*/
static void ChangeTimetableStartIntl(uint32 p1, DateTicks date)
static void ChangeTimetableStartIntl(uint32 p1, DateTicksScaled date)
{
DoCommandP(0, p1, (Ticks)(date - (((DateTicks)_date * DAY_TICKS) + _date_fract)), CMD_SET_TIMETABLE_START | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE));
DateTicks date_part = date / _settings_game.economy.day_length_factor;
uint32 sub_ticks = date % _settings_game.economy.day_length_factor;
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));
}
/**
@ -162,7 +164,7 @@ static void ChangeTimetableStartIntl(uint32 p1, DateTicks date)
* @param window the window related to the setting of the date
* @param date the actually chosen date
*/
static void ChangeTimetableStartCallback(const Window *w, DateTicks date)
static void ChangeTimetableStartCallback(const Window *w, DateTicksScaled date)
{
ChangeTimetableStartIntl(w->window_number, date);
}
@ -524,7 +526,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_WALLCLOCK_TINY);
SetDParam(1, v->timetable_start * _settings_game.economy.day_length_factor);
SetDParam(1, (v->timetable_start * _settings_game.economy.day_length_factor) + v->timetable_start_subticks);
DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, 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"
@ -583,7 +585,7 @@ struct TimetableWindow : Window {
ShowQueryString(str, STR_TIMETABLE_STARTING_DATE, 31, this, CS_NUMERAL, QSF_ACCEPT_UNCHANGED);
} else {
ShowSetDateWindow(this, v->index | (v->orders.list->IsCompleteTimetable() && _ctrl_pressed ? 1U << 20 : 0),
((DateTicks)_date * DAY_TICKS) + _date_fract, _cur_year, _cur_year + 15, ChangeTimetableStartCallback);
CURRENT_SCALED_TICKS, _cur_year, _cur_year + 15, ChangeTimetableStartCallback);
}
break;
@ -720,7 +722,6 @@ struct TimetableWindow : Window {
if (val < (CURRENT_MINUTE - 60)) val += 60 * 24;
val *= _settings_client.gui.ticks_per_minute;
val /= _settings_game.economy.day_length_factor;
ChangeTimetableStartIntl(v->index | (this->set_start_date_all ? 1 << 20 : 0), val);
}
break;

Loading…
Cancel
Save