Timetable: Implement autofill/automate for taken conditional orders.

Fix wrong timetable values being set after using skip or send to depot.
Add timetabled flag for conditional order branch taken travel time.
pull/30/merge
Jonathan G Rennison 7 years ago
parent 102c55bc57
commit 218085c535

@ -41,6 +41,7 @@ void BaseConsist::CopyConsistPropertiesFrom(const BaseConsist *src)
this->cur_real_order_index = src->cur_real_order_index;
this->cur_implicit_order_index = src->cur_implicit_order_index;
this->cur_timetable_order_index = src->cur_timetable_order_index;
if (HasBit(src->vehicle_flags, VF_TIMETABLE_STARTED)) SetBit(this->vehicle_flags, VF_TIMETABLE_STARTED);
if (HasBit(src->vehicle_flags, VF_AUTOFILL_TIMETABLE)) SetBit(this->vehicle_flags, VF_AUTOFILL_TIMETABLE);

@ -30,6 +30,7 @@ struct BaseConsist {
VehicleOrderID cur_real_order_index;///< The index to the current real (non-implicit) order
VehicleOrderID cur_implicit_order_index;///< The index to the current implicit order
VehicleOrderID cur_timetable_order_index;///< The index to the current real (non-implicit) order used for timetable updates
uint16 vehicle_flags; ///< Used for gradual loading and other miscellaneous things (@see VehicleFlags enum)

@ -272,6 +272,13 @@ DepartureList* MakeDepartureList(StationID station, bool show_vehicle_types[5],
const Order *order = (*v)->GetOrder((*v)->cur_implicit_order_index % (*v)->GetNumOrders());
DateTicks start_date = date_fract_scaled - (*v)->current_order_time;
if ((*v)->cur_timetable_order_index != INVALID_VEH_ORDER_ID && (*v)->cur_timetable_order_index != (*v)->cur_real_order_index) {
/* vehicle is taking a conditional order branch, adjust start time to compensate */
const Order *real_current_order = (*v)->GetOrder((*v)->cur_real_order_index);
const Order *real_timetable_order = (*v)->GetOrder((*v)->cur_timetable_order_index);
assert(real_timetable_order->IsType(OT_CONDITIONAL));
start_date += (real_timetable_order->GetWaitTime() - real_current_order->GetTravelTime());
}
DepartureStatus status = D_TRAVELLING;
bool should_reset_lateness = false;
uint waiting_time = 0;

@ -89,6 +89,7 @@ void OrderBackup::DoRestore(Vehicle *v)
/* Make sure orders are in range */
v->UpdateRealOrderIndex();
if (v->cur_implicit_order_index >= v->GetNumOrders()) v->cur_implicit_order_index = v->cur_real_order_index;
if (v->cur_timetable_order_index >= v->GetNumOrders()) v->cur_timetable_order_index = INVALID_VEH_ORDER_ID;
/* Restore vehicle group */
DoCommand(0, this->group, v->index, DC_EXEC, CMD_ADD_VEHICLE_GROUP);

@ -32,6 +32,7 @@ extern OrderListPool _orderlist_pool;
struct OrderExtraInfo {
uint8 cargo_type_flags[NUM_CARGO] = {}; ///< Load/unload types for each cargo type.
uint8 xflags = 0; ///< Extra flags
};
/* If you change this, keep in mind that it is saved on 3 places:
@ -72,6 +73,17 @@ private:
if (!this->extra) this->AllocExtraInfo();
}
inline uint8 GetXFlags() const
{
return this->extra != nullptr ? this->extra->xflags : 0;
}
inline uint8 &GetXFlagsRef()
{
CheckExtraInfoAlloced();
return this->extra->xflags;
}
public:
Order *next; ///< Pointer to next order. If NULL, end of list
@ -340,7 +352,7 @@ public:
* explicitly set (but travel_time is actually unused for conditionals). */
/** Does this order have an explicit wait time set? */
inline bool IsWaitTimetabled() const { return this->IsType(OT_CONDITIONAL) ? this->wait_time > 0 : HasBit(this->flags, 3); }
inline bool IsWaitTimetabled() const { return this->IsType(OT_CONDITIONAL) ? HasBit(this->GetXFlags(), 0) : HasBit(this->flags, 3); }
/** Does this order have an explicit travel time set? */
inline bool IsTravelTimetabled() const { return this->IsType(OT_CONDITIONAL) ? this->travel_time > 0 : HasBit(this->flags, 7); }
@ -361,7 +373,15 @@ public:
inline uint16 GetMaxSpeed() const { return this->max_speed; }
/** Set if the wait time is explicitly timetabled (unless the order is conditional). */
inline void SetWaitTimetabled(bool timetabled) { if (!this->IsType(OT_CONDITIONAL)) SB(this->flags, 3, 1, timetabled ? 1 : 0); }
inline void SetWaitTimetabled(bool timetabled)
{
if (this->IsType(OT_CONDITIONAL)) {
SB(this->GetXFlagsRef(), 0, 1, timetabled ? 1 : 0);
} else {
SB(this->flags, 3, 1, timetabled ? 1 : 0);
}
}
/** Set if the travel time is explicitly timetabled (unless the order is conditional). */
inline void SetTravelTimetabled(bool timetabled) { if (!this->IsType(OT_CONDITIONAL)) SB(this->flags, 7, 1, timetabled ? 1 : 0); }
@ -494,7 +514,7 @@ private:
Ticks timetable_duration; ///< NOSAVE: Total timetabled duration of the order list.
Ticks total_duration; ///< NOSAVE: Total (timetabled or not) duration of the order list.
std::vector<uint32> scheduled_dispatch; ///< Scheduled dispatch time
uint32 scheduled_dispatch_duration; ///< Scheduled dispatch duration
Date scheduled_dispatch_start_date; ///< Scheduled dispatch start date
@ -531,6 +551,8 @@ public:
Order *GetOrderAt(int index) const;
VehicleOrderID GetIndexOfOrder(const Order *order) const;
/**
* Get the last order of the order chain.
* @return the last order of the chain.
@ -636,7 +658,7 @@ public:
* @return first scheduled dispatch
*/
inline const std::vector<uint32> &GetScheduledDispatch() { return this->scheduled_dispatch; }
void AddScheduledDispatch(uint32 offset);
void RemoveScheduledDispatch(uint32 offset);
void UpdateScheduledDispatch();

@ -375,8 +375,10 @@ void OrderList::Initialize(Order *chain, Vehicle *v)
for (Order *o = this->first; o != NULL; o = o->next) {
++this->num_orders;
if (!o->IsType(OT_IMPLICIT)) ++this->num_manual_orders;
this->timetable_duration += o->GetTimetabledWait() + o->GetTimetabledTravel();
this->total_duration += o->GetWaitTime() + o->GetTravelTime();
if (!o->IsType(OT_CONDITIONAL)) {
this->timetable_duration += o->GetTimetabledWait() + o->GetTimetabledTravel();
this->total_duration += o->GetWaitTime() + o->GetTravelTime();
}
}
for (Vehicle *u = this->first_shared->PreviousShared(); u != NULL; u = u->PreviousShared()) {
@ -427,6 +429,24 @@ Order *OrderList::GetOrderAt(int index) const
return order;
}
/**
* Get the index of an order of the order chain, or INVALID_VEH_ORDER_ID.
* @param order order to get the index of.
* @return the position index of the given order, or INVALID_VEH_ORDER_ID.
*/
VehicleOrderID OrderList::GetIndexOfOrder(const Order *order) const
{
VehicleOrderID index = 0;
const Order *o = this->first;
while (o != nullptr) {
if (o == order) return index;
index++;
o = o->next;
}
return INVALID_VEH_ORDER_ID;
}
/**
* Get the next order which will make the given vehicle stop at a station
* or refit at a depot or evaluate a non-trivial condition.
@ -580,8 +600,10 @@ void OrderList::InsertOrderAt(Order *new_order, int index)
}
++this->num_orders;
if (!new_order->IsType(OT_IMPLICIT)) ++this->num_manual_orders;
this->timetable_duration += new_order->GetTimetabledWait() + new_order->GetTimetabledTravel();
this->total_duration += new_order->GetWaitTime() + new_order->GetTravelTime();
if (!new_order->IsType(OT_CONDITIONAL)) {
this->timetable_duration += new_order->GetTimetabledWait() + new_order->GetTimetabledTravel();
this->total_duration += new_order->GetWaitTime() + new_order->GetTravelTime();
}
/* We can visit oil rigs and buoys that are not our own. They will be shown in
* the list of stations. So, we need to invalidate that window if needed. */
@ -613,8 +635,10 @@ void OrderList::DeleteOrderAt(int index)
}
--this->num_orders;
if (!to_remove->IsType(OT_IMPLICIT)) --this->num_manual_orders;
this->timetable_duration -= (to_remove->GetTimetabledWait() + to_remove->GetTimetabledTravel());
this->total_duration -= (to_remove->GetWaitTime() + to_remove->GetTravelTime());
if (!to_remove->IsType(OT_CONDITIONAL)) {
this->timetable_duration -= (to_remove->GetTimetabledWait() + to_remove->GetTimetabledTravel());
this->total_duration -= (to_remove->GetWaitTime() + to_remove->GetTravelTime());
}
delete to_remove;
}
@ -716,8 +740,10 @@ void OrderList::DebugCheckSanity() const
for (const Order *o = this->first; o != NULL; o = o->next) {
++check_num_orders;
if (!o->IsType(OT_IMPLICIT)) ++check_num_manual_orders;
check_timetable_duration += o->GetTimetabledWait() + o->GetTimetabledTravel();
check_total_duration += o->GetWaitTime() + o->GetTravelTime();
if (!o->IsType(OT_CONDITIONAL)) {
check_timetable_duration += o->GetTimetabledWait() + o->GetTimetabledTravel();
check_total_duration += o->GetWaitTime() + o->GetTravelTime();
}
}
assert_msg(this->num_orders == check_num_orders, "%u, %u", this->num_orders, check_num_orders);
assert_msg(this->num_manual_orders == check_num_manual_orders, "%u, %u", this->num_manual_orders, check_num_manual_orders);
@ -1103,6 +1129,13 @@ void InsertOrder(Vehicle *v, Order *new_o, VehicleOrderID sel_ord)
u->cur_implicit_order_index = cur;
}
}
if (sel_ord <= u->cur_timetable_order_index) {
uint cur = u->cur_timetable_order_index + 1;
/* Check if we don't go out of bound */
if (cur < u->GetNumOrders()) {
u->cur_timetable_order_index = cur;
}
}
/* Update any possible open window of the vehicle */
InvalidateVehicleOrder(u, INVALID_VEH_ORDER_ID | (sel_ord << 8));
}
@ -1245,6 +1278,12 @@ void DeleteOrder(Vehicle *v, VehicleOrderID sel_ord)
}
}
if (sel_ord < u->cur_timetable_order_index) {
u->cur_timetable_order_index--;
} else if (sel_ord == u->cur_timetable_order_index) {
u->cur_timetable_order_index = INVALID_VEH_ORDER_ID;
}
/* Update any possible open window of the vehicle */
InvalidateVehicleOrder(u, sel_ord | (INVALID_VEH_ORDER_ID << 8));
}
@ -1296,6 +1335,7 @@ CommandCost CmdSkipToOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
v->cur_implicit_order_index = v->cur_real_order_index = sel_ord;
v->UpdateRealOrderIndex();
v->cur_timetable_order_index = INVALID_VEH_ORDER_ID;
InvalidateVehicleOrder(v, VIWD_MODIFY_ORDERS);
@ -1384,6 +1424,8 @@ CommandCost CmdMoveOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
u->cur_implicit_order_index++;
}
u->cur_timetable_order_index = INVALID_VEH_ORDER_ID;
assert(v->orders.list == u->orders.list);
/* Update any possible open window of the vehicle */
InvalidateVehicleOrder(u, moving_order | (target_order << 8));
@ -2169,6 +2211,7 @@ void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist, bool reset_order_indic
if (reset_order_indices) {
v->cur_implicit_order_index = v->cur_real_order_index = 0;
v->cur_timetable_order_index = INVALID_VEH_ORDER_ID;
if (v->current_order.IsType(OT_LOADING)) {
CancelLoadingDueToDeletedOrder(v);
}
@ -2408,7 +2451,7 @@ bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth, bool
UpdateVehicleTimetable(v, false);
v->cur_implicit_order_index = v->cur_real_order_index = next_order;
v->UpdateRealOrderIndex();
v->current_order_time += v->GetOrder(v->cur_real_order_index)->GetTimetabledTravel();
v->cur_timetable_order_index = v->GetIndexOfOrder(order);
/* Disable creation of implicit orders.
* When inserting them we do not know that we would have to make the conditional orders point to them. */
@ -2417,6 +2460,7 @@ bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth, bool
SetBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
}
} else {
v->cur_timetable_order_index = INVALID_VEH_ORDER_ID;
UpdateVehicleTimetable(v, true);
v->IncrementRealOrderIndex();
}

@ -42,9 +42,9 @@ restart:
}
/* Clear wait time */
v->orders.list->UpdateTotalDuration(-order->GetWaitTime());
if (!order->IsType(OT_CONDITIONAL)) v->orders.list->UpdateTotalDuration(-order->GetWaitTime());
if (order->IsWaitTimetabled()) {
v->orders.list->UpdateTimetableDuration(-order->GetTimetabledWait());
if (!order->IsType(OT_CONDITIONAL)) v->orders.list->UpdateTimetableDuration(-order->GetTimetabledWait());
order->SetWaitTimetabled(false);
}
order->SetWaitTime(0);

@ -3415,6 +3415,27 @@ bool AfterLoadGame()
}
}
if (SlXvIsFeatureMissing(XSLFI_TIMETABLE_EXTRA)) {
Vehicle *v;
FOR_ALL_VEHICLES(v) {
v->cur_timetable_order_index = v->GetNumManualOrders() > 0 ? v->cur_real_order_index : INVALID_VEH_ORDER_ID;
}
OrderBackup *bckup;
FOR_ALL_ORDER_BACKUPS(bckup) {
bckup->cur_timetable_order_index = INVALID_VEH_ORDER_ID;
}
Order *order;
FOR_ALL_ORDERS(order) {
if (order->IsType(OT_CONDITIONAL)) {
assert(order->GetTravelTime() == 0);
}
}
OrderList *order_list;
FOR_ALL_ORDER_LISTS(order_list) {
order_list->DebugCheckSanity();
}
}
/* Road stops is 'only' updating some caches */
AfterLoadRoadStops();
AfterLoadLabelMaps();

@ -79,6 +79,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
{ XSLFI_SCHEDULED_DISPATCH, XSCF_NULL, 1, 1, "scheduled_dispatch", NULL, NULL, NULL },
{ XSLFI_MORE_TOWN_GROWTH_RATES, XSCF_NULL, 1, 1, "more_town_growth_rates", NULL, NULL, NULL },
{ XSLFI_MULTIPLE_DOCKS, XSCF_NULL, 1, 1, "multiple_docks", NULL, NULL, "DOCK" },
{ XSLFI_TIMETABLE_EXTRA, XSCF_NULL, 1, 1, "timetable_extra", NULL, NULL, "ORDX" },
{ XSLFI_NULL, XSCF_NULL, 0, 0, NULL, NULL, NULL, NULL },// This is the end marker
};

@ -53,6 +53,7 @@ enum SlXvFeatureIndex {
XSLFI_SCHEDULED_DISPATCH, ///< Scheduled vehicle dispatching
XSLFI_MORE_TOWN_GROWTH_RATES, ///< More town growth rates
XSLFI_MULTIPLE_DOCKS, ///< Multiple docks
XSLFI_TIMETABLE_EXTRA, ///< Vehicle timetable extra fields
XSLFI_RIFF_HEADER_60_BIT, ///< Size field in RIFF chunk header is 60 bit
XSLFI_HEIGHT_8_BIT, ///< Map tile height is 8 bit instead of 4 bit, but savegame version may be before this became true in trunk

@ -192,6 +192,8 @@ static void Load_ORDR()
if (IsSavegameVersionBefore(190)) {
order->SetTravelTimetabled(order->GetTravelTime() > 0);
order->SetWaitTimetabled(order->GetWaitTime() > 0);
} else if (order->IsType(OT_CONDITIONAL) && SlXvIsFeatureMissing(XSLFI_TIMETABLE_EXTRA)) {
order->SetWaitTimetabled(order->GetWaitTime() > 0);
}
}
}
@ -201,6 +203,7 @@ const SaveLoad *GetOrderExtraInfoDescription()
{
static const SaveLoad _order_extra_info_desc[] = {
SLE_ARR(OrderExtraInfo, cargo_type_flags, SLE_UINT8, NUM_CARGO),
SLE_CONDVAR_X(OrderExtraInfo, xflags, SLE_UINT8, 0, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TIMETABLE_EXTRA)),
SLE_END()
};
@ -302,6 +305,7 @@ const SaveLoad *GetOrderBackupDescription()
SLE_CONDREF(OrderBackup, clone, REF_VEHICLE, 192, SL_MAX_VERSION),
SLE_VAR(OrderBackup, cur_real_order_index, SLE_UINT8),
SLE_CONDVAR(OrderBackup, cur_implicit_order_index, SLE_UINT8, 176, SL_MAX_VERSION),
SLE_CONDVAR_X(OrderBackup, cur_timetable_order_index, SLE_UINT8, 0, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TIMETABLE_EXTRA)),
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),

@ -632,6 +632,7 @@ const SaveLoad *GetVehicleDescription(VehicleType vt)
SLE_VAR(Vehicle, cur_implicit_order_index, SLE_UINT8),
SLE_CONDVAR(Vehicle, cur_real_order_index, SLE_UINT8, 158, SL_MAX_VERSION),
SLE_CONDVAR_X(Vehicle, cur_timetable_order_index, SLE_UINT8, 0, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TIMETABLE_EXTRA)),
/* num_orders is now part of OrderList and is not saved but counted */
SLE_CONDNULL(1, 0, 104),

@ -21,6 +21,7 @@
#include "company_base.h"
#include "core/sort_func.hpp"
#include "settings_type.h"
#include "scope.h"
#include "table/strings.h"
@ -42,15 +43,20 @@ static void ChangeTimetable(Vehicle *v, VehicleOrderID order_number, uint16 val,
switch (mtf) {
case MTF_WAIT_TIME:
total_delta = val - order->GetWaitTime();
timetable_delta = (timetabled ? val : 0) - order->GetTimetabledWait();
if (!order->IsType(OT_CONDITIONAL)) {
total_delta = val - order->GetWaitTime();
timetable_delta = (timetabled ? val : 0) - order->GetTimetabledWait();
}
order->SetWaitTime(val);
order->SetWaitTimetabled(timetabled);
break;
case MTF_TRAVEL_TIME:
total_delta = val - order->GetTravelTime();
timetable_delta = (timetabled ? val : 0) - order->GetTimetabledTravel();
if (!order->IsType(OT_CONDITIONAL)) {
total_delta = val - order->GetTravelTime();
timetable_delta = (timetabled ? val : 0) - order->GetTimetabledTravel();
}
if (order->IsType(OT_CONDITIONAL)) assert_msg(val == order->GetTravelTime(), "%u == %u", val, order->GetTravelTime());
order->SetTravelTime(val);
order->SetTravelTimetabled(timetabled);
break;
@ -714,6 +720,12 @@ void UpdateVehicleTimetable(Vehicle *v, bool travelling)
if (v->cur_real_order_index >= v->GetNumOrders()) return;
Order *real_current_order = v->GetOrder(v->cur_real_order_index);
Order *real_timetable_order = v->cur_timetable_order_index != INVALID_VEH_ORDER_ID ? v->GetOrder(v->cur_timetable_order_index) : nullptr;
auto guard = scope_guard([v, travelling]() {
/* On next call, when updating waiting time, use current order even if travel field of current order isn't being updated */
if (travelling) v->cur_timetable_order_index = v->cur_real_order_index;
});
VehicleOrderID first_manual_order = 0;
for (Order *o = v->GetFirstOrder(); o != NULL && o->IsType(OT_IMPLICIT); o = o->next) {
@ -768,10 +780,12 @@ void UpdateVehicleTimetable(Vehicle *v, bool travelling)
}
if (!HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED)) return;
if (real_timetable_order == nullptr) return;
bool autofilling = HasBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE);
bool remeasure_wait_time = !real_current_order->IsWaitTimetabled() ||
(autofilling && !HasBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME));
bool is_conditional = real_timetable_order->IsType(OT_CONDITIONAL);
bool remeasure_wait_time = !is_conditional && (!real_timetable_order->IsWaitTimetabled() ||
(autofilling && !HasBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME)));
if (travelling && remeasure_wait_time) {
/* We just finished travelling and want to remeasure the loading time,
@ -779,11 +793,23 @@ void UpdateVehicleTimetable(Vehicle *v, bool travelling)
v->current_order.SetWaitTime(0);
}
bool travel_field = travelling;
if (is_conditional) {
if (travelling) {
/* conditional orders use the wait field for the jump-taken travel time */
travel_field = false;
} else {
/* doesn't make sense to update wait time for conditional orders */
return;
}
} else {
assert(real_timetable_order == real_current_order);
}
if (just_started) return;
/* Before modifying waiting times, check whether we want to preserve bigger ones. */
if (!real_current_order->IsType(OT_CONDITIONAL) &&
(travelling || time_taken > real_current_order->GetWaitTime() || remeasure_wait_time)) {
if ((travelling || time_taken > real_timetable_order->GetWaitTime() || remeasure_wait_time)) {
/* Round the time taken up to the nearest timetable rounding factor
* (default: day), as this will avoid confusion for people who are
* timetabling in days, and can be adjusted later by people who aren't.
@ -797,10 +823,10 @@ void UpdateVehicleTimetable(Vehicle *v, bool travelling)
uint rounding_factor = owner ? owner->settings.timetable_autofill_rounding : DAY_TICKS;
uint time_to_set = CeilDiv(max(time_taken, 1U), rounding_factor) * rounding_factor;
if (travelling && (autofilling || !real_current_order->IsTravelTimetabled())) {
ChangeTimetable(v, v->cur_real_order_index, time_to_set, MTF_TRAVEL_TIME, autofilling);
} else if (!travelling && (autofilling || !real_current_order->IsWaitTimetabled())) {
ChangeTimetable(v, v->cur_real_order_index, time_to_set, MTF_WAIT_TIME, autofilling);
if (travel_field && (autofilling || !real_timetable_order->IsTravelTimetabled())) {
ChangeTimetable(v, v->cur_timetable_order_index, time_to_set, MTF_TRAVEL_TIME, autofilling);
} else if (!travel_field && (autofilling || !real_timetable_order->IsWaitTimetabled())) {
ChangeTimetable(v, v->cur_timetable_order_index, time_to_set, MTF_WAIT_TIME, autofilling);
}
}
@ -814,8 +840,8 @@ void UpdateVehicleTimetable(Vehicle *v, bool travelling)
if (autofilling) return;
uint timetabled = travelling ? real_current_order->GetTimetabledTravel() :
real_current_order->GetTimetabledWait();
uint timetabled = travel_field ? real_timetable_order->GetTimetabledTravel() :
real_timetable_order->GetTimetabledWait();
/* Update the timetable to gradually shift order times towards the actual travel times. */
if (timetabled != 0 && HasBit(v->vehicle_flags, VF_AUTOMATE_TIMETABLE)) {
@ -829,7 +855,7 @@ void UpdateVehicleTimetable(Vehicle *v, bool travelling)
if (new_time > (int32)timetabled * 4 && travelling) {
/* Possible jam, clear time and restart timetable for all vehicles.
* Otherwise we risk trains blocking 1-lane stations for long times. */
ChangeTimetable(v, v->cur_real_order_index, 0, travelling ? MTF_TRAVEL_TIME : MTF_WAIT_TIME, true);
ChangeTimetable(v, v->cur_timetable_order_index, 0, travel_field ? MTF_TRAVEL_TIME : MTF_WAIT_TIME, true);
for (Vehicle *v2 = v->FirstShared(); v2 != NULL; v2 = v2->NextShared()) {
v2->ClearSeparation();
ClrBit(v2->vehicle_flags, VF_TIMETABLE_STARTED);
@ -849,14 +875,15 @@ void UpdateVehicleTimetable(Vehicle *v, bool travelling)
if (new_time < 1) new_time = 1;
if (new_time != (int32)timetabled) {
ChangeTimetable(v, v->cur_real_order_index, new_time, travelling ? MTF_TRAVEL_TIME : MTF_WAIT_TIME, true);
ChangeTimetable(v, v->cur_timetable_order_index, new_time, travel_field ? MTF_TRAVEL_TIME : MTF_WAIT_TIME, true);
}
} else if (timetabled == 0 && HasBit(v->vehicle_flags, VF_AUTOMATE_TIMETABLE)) {
/* Add times for orders that are not yet timetabled, even while not autofilling */
if (travelling) {
ChangeTimetable(v, v->cur_real_order_index, time_taken, MTF_TRAVEL_TIME, true);
const int32 new_time = travelling ? time_taken : time_loading;
if (travel_field) {
ChangeTimetable(v, v->cur_timetable_order_index, new_time, MTF_TRAVEL_TIME, true);
} else {
ChangeTimetable(v, v->cur_real_order_index, time_loading, MTF_WAIT_TIME, true);
ChangeTimetable(v, v->cur_timetable_order_index, new_time, MTF_WAIT_TIME, true);
}
}

@ -217,6 +217,13 @@ struct TimetableWindow : Window {
bool travelling = (!(v->current_order.IsType(OT_LOADING) || v->current_order.IsType(OT_WAITING)) || v->current_order.GetNonStopType() == ONSF_STOP_EVERYWHERE);
Ticks start_time = -v->current_order_time;
if (v->cur_timetable_order_index != INVALID_VEH_ORDER_ID && v->cur_timetable_order_index != v->cur_real_order_index) {
/* vehicle is taking a conditional order branch, adjust start time to compensate */
const Order *real_current_order = v->GetOrder(v->cur_real_order_index);
const Order *real_timetable_order = v->GetOrder(v->cur_timetable_order_index);
assert(real_timetable_order->IsType(OT_CONDITIONAL));
start_time += (real_timetable_order->GetWaitTime() - real_current_order->GetTravelTime());
}
FillTimetableArrivalDepartureTable(v, v->cur_real_order_index % v->GetNumOrders(), travelling, table, start_time);

@ -2892,6 +2892,9 @@ CommandCost Vehicle::SendToDepot(DoCommandFlag flags, DepotCommand command, Tile
this->current_order.MakeDummy();
SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
}
/* prevent any attempt to update timetable for current order, as actual travel time will be incorrect due to depot command */
this->cur_timetable_order_index = INVALID_VEH_ORDER_ID;
}
return CommandCost();
}

@ -855,8 +855,10 @@ private:
this->cur_real_order_index++;
if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0;
} while (this->GetOrder(this->cur_real_order_index)->IsType(OT_IMPLICIT));
this->cur_timetable_order_index = this->cur_real_order_index;
} else {
this->cur_real_order_index = 0;
this->cur_timetable_order_index = INVALID_VEH_ORDER_ID;
}
}
@ -931,6 +933,16 @@ public:
return (this->orders.list == NULL) ? NULL : this->orders.list->GetOrderAt(index);
}
/**
* Get the index of an order of the order chain, or INVALID_VEH_ORDER_ID.
* @param order order to get the index of.
* @return the position index of the given order, or INVALID_VEH_ORDER_ID.
*/
inline VehicleOrderID GetIndexOfOrder(const Order *order) const
{
return (this->orders.list == NULL) ? INVALID_VEH_ORDER_ID : this->orders.list->GetIndexOfOrder(order);
}
/**
* Returns the last order of a vehicle, or NULL if it doesn't exists
* @return last order of a vehicle, if available

Loading…
Cancel
Save