diff --git a/src/base_consist.cpp b/src/base_consist.cpp index 69ad9c9d3e..3af6df77a4 100644 --- a/src/base_consist.cpp +++ b/src/base_consist.cpp @@ -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); diff --git a/src/base_consist.h b/src/base_consist.h index 6877539d9a..18bfd4b626 100644 --- a/src/base_consist.h +++ b/src/base_consist.h @@ -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) diff --git a/src/departures.cpp b/src/departures.cpp index 60e2f2fdb2..32c5dc4f4d 100644 --- a/src/departures.cpp +++ b/src/departures.cpp @@ -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; diff --git a/src/order_backup.cpp b/src/order_backup.cpp index de0517cf71..4d0a3f6d64 100644 --- a/src/order_backup.cpp +++ b/src/order_backup.cpp @@ -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); diff --git a/src/order_base.h b/src/order_base.h index 5e911e8d7b..2ed546e567 100644 --- a/src/order_base.h +++ b/src/order_base.h @@ -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 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 &GetScheduledDispatch() { return this->scheduled_dispatch; } - + void AddScheduledDispatch(uint32 offset); void RemoveScheduledDispatch(uint32 offset); void UpdateScheduledDispatch(); diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index 9152ad8be3..070fcaf7c4 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -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(); } diff --git a/src/order_cmd.h b/src/order_cmd.h index bbb6c1dc59..a463899460 100644 --- a/src/order_cmd.h +++ b/src/order_cmd.h @@ -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); diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index b2ce60b052..c05d22439a 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -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(); diff --git a/src/saveload/extended_ver_sl.cpp b/src/saveload/extended_ver_sl.cpp index a0861ab7a1..d6c3bc7c0b 100644 --- a/src/saveload/extended_ver_sl.cpp +++ b/src/saveload/extended_ver_sl.cpp @@ -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 }; diff --git a/src/saveload/extended_ver_sl.h b/src/saveload/extended_ver_sl.h index 89c84fe346..0a6cef1b0d 100644 --- a/src/saveload/extended_ver_sl.h +++ b/src/saveload/extended_ver_sl.h @@ -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 diff --git a/src/saveload/order_sl.cpp b/src/saveload/order_sl.cpp index 76d609d55d..53926a9a92 100644 --- a/src/saveload/order_sl.cpp +++ b/src/saveload/order_sl.cpp @@ -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), diff --git a/src/saveload/vehicle_sl.cpp b/src/saveload/vehicle_sl.cpp index c12fb5bb78..0aa6c24b74 100644 --- a/src/saveload/vehicle_sl.cpp +++ b/src/saveload/vehicle_sl.cpp @@ -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), diff --git a/src/timetable_cmd.cpp b/src/timetable_cmd.cpp index 5f6ec72260..5e4045b3db 100644 --- a/src/timetable_cmd.cpp +++ b/src/timetable_cmd.cpp @@ -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); } } diff --git a/src/timetable_gui.cpp b/src/timetable_gui.cpp index 3f0398332a..65b8b50a49 100644 --- a/src/timetable_gui.cpp +++ b/src/timetable_gui.cpp @@ -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); diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 517a98879e..193bb0698c 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -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(); } diff --git a/src/vehicle_base.h b/src/vehicle_base.h index 3829a5d850..bb78e496ad 100644 --- a/src/vehicle_base.h +++ b/src/vehicle_base.h @@ -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