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.
This commit is contained in:
@@ -41,6 +41,7 @@ void BaseConsist::CopyConsistPropertiesFrom(const BaseConsist *src)
|
|||||||
|
|
||||||
this->cur_real_order_index = src->cur_real_order_index;
|
this->cur_real_order_index = src->cur_real_order_index;
|
||||||
this->cur_implicit_order_index = src->cur_implicit_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_TIMETABLE_STARTED)) SetBit(this->vehicle_flags, VF_TIMETABLE_STARTED);
|
||||||
if (HasBit(src->vehicle_flags, VF_AUTOFILL_TIMETABLE)) SetBit(this->vehicle_flags, VF_AUTOFILL_TIMETABLE);
|
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_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_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)
|
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());
|
const Order *order = (*v)->GetOrder((*v)->cur_implicit_order_index % (*v)->GetNumOrders());
|
||||||
DateTicks start_date = date_fract_scaled - (*v)->current_order_time;
|
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;
|
DepartureStatus status = D_TRAVELLING;
|
||||||
bool should_reset_lateness = false;
|
bool should_reset_lateness = false;
|
||||||
uint waiting_time = 0;
|
uint waiting_time = 0;
|
||||||
|
@@ -89,6 +89,7 @@ void OrderBackup::DoRestore(Vehicle *v)
|
|||||||
/* Make sure orders are in range */
|
/* Make sure orders are in range */
|
||||||
v->UpdateRealOrderIndex();
|
v->UpdateRealOrderIndex();
|
||||||
if (v->cur_implicit_order_index >= v->GetNumOrders()) v->cur_implicit_order_index = v->cur_real_order_index;
|
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 */
|
/* Restore vehicle group */
|
||||||
DoCommand(0, this->group, v->index, DC_EXEC, CMD_ADD_VEHICLE_GROUP);
|
DoCommand(0, this->group, v->index, DC_EXEC, CMD_ADD_VEHICLE_GROUP);
|
||||||
|
@@ -32,6 +32,7 @@ extern OrderListPool _orderlist_pool;
|
|||||||
|
|
||||||
struct OrderExtraInfo {
|
struct OrderExtraInfo {
|
||||||
uint8 cargo_type_flags[NUM_CARGO] = {}; ///< Load/unload types for each cargo type.
|
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:
|
/* If you change this, keep in mind that it is saved on 3 places:
|
||||||
@@ -72,6 +73,17 @@ private:
|
|||||||
if (!this->extra) this->AllocExtraInfo();
|
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:
|
public:
|
||||||
Order *next; ///< Pointer to next order. If NULL, end of list
|
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). */
|
* explicitly set (but travel_time is actually unused for conditionals). */
|
||||||
|
|
||||||
/** Does this order have an explicit wait time set? */
|
/** 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? */
|
/** 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); }
|
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; }
|
inline uint16 GetMaxSpeed() const { return this->max_speed; }
|
||||||
|
|
||||||
/** Set if the wait time is explicitly timetabled (unless the order is conditional). */
|
/** 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). */
|
/** 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); }
|
inline void SetTravelTimetabled(bool timetabled) { if (!this->IsType(OT_CONDITIONAL)) SB(this->flags, 7, 1, timetabled ? 1 : 0); }
|
||||||
|
|
||||||
@@ -531,6 +551,8 @@ public:
|
|||||||
|
|
||||||
Order *GetOrderAt(int index) const;
|
Order *GetOrderAt(int index) const;
|
||||||
|
|
||||||
|
VehicleOrderID GetIndexOfOrder(const Order *order) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the last order of the order chain.
|
* Get the last order of the order chain.
|
||||||
* @return the last order of the chain.
|
* @return the last order of the chain.
|
||||||
|
@@ -375,8 +375,10 @@ void OrderList::Initialize(Order *chain, Vehicle *v)
|
|||||||
for (Order *o = this->first; o != NULL; o = o->next) {
|
for (Order *o = this->first; o != NULL; o = o->next) {
|
||||||
++this->num_orders;
|
++this->num_orders;
|
||||||
if (!o->IsType(OT_IMPLICIT)) ++this->num_manual_orders;
|
if (!o->IsType(OT_IMPLICIT)) ++this->num_manual_orders;
|
||||||
this->timetable_duration += o->GetTimetabledWait() + o->GetTimetabledTravel();
|
if (!o->IsType(OT_CONDITIONAL)) {
|
||||||
this->total_duration += o->GetWaitTime() + o->GetTravelTime();
|
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()) {
|
for (Vehicle *u = this->first_shared->PreviousShared(); u != NULL; u = u->PreviousShared()) {
|
||||||
@@ -427,6 +429,24 @@ Order *OrderList::GetOrderAt(int index) const
|
|||||||
return order;
|
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
|
* 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.
|
* 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;
|
++this->num_orders;
|
||||||
if (!new_order->IsType(OT_IMPLICIT)) ++this->num_manual_orders;
|
if (!new_order->IsType(OT_IMPLICIT)) ++this->num_manual_orders;
|
||||||
this->timetable_duration += new_order->GetTimetabledWait() + new_order->GetTimetabledTravel();
|
if (!new_order->IsType(OT_CONDITIONAL)) {
|
||||||
this->total_duration += new_order->GetWaitTime() + new_order->GetTravelTime();
|
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
|
/* 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. */
|
* 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;
|
--this->num_orders;
|
||||||
if (!to_remove->IsType(OT_IMPLICIT)) --this->num_manual_orders;
|
if (!to_remove->IsType(OT_IMPLICIT)) --this->num_manual_orders;
|
||||||
this->timetable_duration -= (to_remove->GetTimetabledWait() + to_remove->GetTimetabledTravel());
|
if (!to_remove->IsType(OT_CONDITIONAL)) {
|
||||||
this->total_duration -= (to_remove->GetWaitTime() + to_remove->GetTravelTime());
|
this->timetable_duration -= (to_remove->GetTimetabledWait() + to_remove->GetTimetabledTravel());
|
||||||
|
this->total_duration -= (to_remove->GetWaitTime() + to_remove->GetTravelTime());
|
||||||
|
}
|
||||||
delete to_remove;
|
delete to_remove;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -716,8 +740,10 @@ void OrderList::DebugCheckSanity() const
|
|||||||
for (const Order *o = this->first; o != NULL; o = o->next) {
|
for (const Order *o = this->first; o != NULL; o = o->next) {
|
||||||
++check_num_orders;
|
++check_num_orders;
|
||||||
if (!o->IsType(OT_IMPLICIT)) ++check_num_manual_orders;
|
if (!o->IsType(OT_IMPLICIT)) ++check_num_manual_orders;
|
||||||
check_timetable_duration += o->GetTimetabledWait() + o->GetTimetabledTravel();
|
if (!o->IsType(OT_CONDITIONAL)) {
|
||||||
check_total_duration += o->GetWaitTime() + o->GetTravelTime();
|
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_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);
|
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;
|
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 */
|
/* Update any possible open window of the vehicle */
|
||||||
InvalidateVehicleOrder(u, INVALID_VEH_ORDER_ID | (sel_ord << 8));
|
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 */
|
/* Update any possible open window of the vehicle */
|
||||||
InvalidateVehicleOrder(u, sel_ord | (INVALID_VEH_ORDER_ID << 8));
|
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->cur_implicit_order_index = v->cur_real_order_index = sel_ord;
|
||||||
v->UpdateRealOrderIndex();
|
v->UpdateRealOrderIndex();
|
||||||
|
v->cur_timetable_order_index = INVALID_VEH_ORDER_ID;
|
||||||
|
|
||||||
InvalidateVehicleOrder(v, VIWD_MODIFY_ORDERS);
|
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_implicit_order_index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u->cur_timetable_order_index = INVALID_VEH_ORDER_ID;
|
||||||
|
|
||||||
assert(v->orders.list == u->orders.list);
|
assert(v->orders.list == u->orders.list);
|
||||||
/* Update any possible open window of the vehicle */
|
/* Update any possible open window of the vehicle */
|
||||||
InvalidateVehicleOrder(u, moving_order | (target_order << 8));
|
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) {
|
if (reset_order_indices) {
|
||||||
v->cur_implicit_order_index = v->cur_real_order_index = 0;
|
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)) {
|
if (v->current_order.IsType(OT_LOADING)) {
|
||||||
CancelLoadingDueToDeletedOrder(v);
|
CancelLoadingDueToDeletedOrder(v);
|
||||||
}
|
}
|
||||||
@@ -2408,7 +2451,7 @@ bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth, bool
|
|||||||
UpdateVehicleTimetable(v, false);
|
UpdateVehicleTimetable(v, false);
|
||||||
v->cur_implicit_order_index = v->cur_real_order_index = next_order;
|
v->cur_implicit_order_index = v->cur_real_order_index = next_order;
|
||||||
v->UpdateRealOrderIndex();
|
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.
|
/* Disable creation of implicit orders.
|
||||||
* When inserting them we do not know that we would have to make the conditional orders point to them. */
|
* 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);
|
SetBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
v->cur_timetable_order_index = INVALID_VEH_ORDER_ID;
|
||||||
UpdateVehicleTimetable(v, true);
|
UpdateVehicleTimetable(v, true);
|
||||||
v->IncrementRealOrderIndex();
|
v->IncrementRealOrderIndex();
|
||||||
}
|
}
|
||||||
|
@@ -42,9 +42,9 @@ restart:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Clear wait time */
|
/* Clear wait time */
|
||||||
v->orders.list->UpdateTotalDuration(-order->GetWaitTime());
|
if (!order->IsType(OT_CONDITIONAL)) v->orders.list->UpdateTotalDuration(-order->GetWaitTime());
|
||||||
if (order->IsWaitTimetabled()) {
|
if (order->IsWaitTimetabled()) {
|
||||||
v->orders.list->UpdateTimetableDuration(-order->GetTimetabledWait());
|
if (!order->IsType(OT_CONDITIONAL)) v->orders.list->UpdateTimetableDuration(-order->GetTimetabledWait());
|
||||||
order->SetWaitTimetabled(false);
|
order->SetWaitTimetabled(false);
|
||||||
}
|
}
|
||||||
order->SetWaitTime(0);
|
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 */
|
/* Road stops is 'only' updating some caches */
|
||||||
AfterLoadRoadStops();
|
AfterLoadRoadStops();
|
||||||
AfterLoadLabelMaps();
|
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_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_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_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
|
{ 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_SCHEDULED_DISPATCH, ///< Scheduled vehicle dispatching
|
||||||
XSLFI_MORE_TOWN_GROWTH_RATES, ///< More town growth rates
|
XSLFI_MORE_TOWN_GROWTH_RATES, ///< More town growth rates
|
||||||
XSLFI_MULTIPLE_DOCKS, ///< Multiple docks
|
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_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
|
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)) {
|
if (IsSavegameVersionBefore(190)) {
|
||||||
order->SetTravelTimetabled(order->GetTravelTime() > 0);
|
order->SetTravelTimetabled(order->GetTravelTime() > 0);
|
||||||
order->SetWaitTimetabled(order->GetWaitTime() > 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[] = {
|
static const SaveLoad _order_extra_info_desc[] = {
|
||||||
SLE_ARR(OrderExtraInfo, cargo_type_flags, SLE_UINT8, NUM_CARGO),
|
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()
|
SLE_END()
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -302,6 +305,7 @@ const SaveLoad *GetOrderBackupDescription()
|
|||||||
SLE_CONDREF(OrderBackup, clone, REF_VEHICLE, 192, SL_MAX_VERSION),
|
SLE_CONDREF(OrderBackup, clone, REF_VEHICLE, 192, SL_MAX_VERSION),
|
||||||
SLE_VAR(OrderBackup, cur_real_order_index, SLE_UINT8),
|
SLE_VAR(OrderBackup, cur_real_order_index, SLE_UINT8),
|
||||||
SLE_CONDVAR(OrderBackup, cur_implicit_order_index, SLE_UINT8, 176, SL_MAX_VERSION),
|
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, current_order_time, SLE_UINT32, 176, SL_MAX_VERSION),
|
||||||
SLE_CONDVAR(OrderBackup, lateness_counter, SLE_INT32, 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(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_VAR(Vehicle, cur_implicit_order_index, SLE_UINT8),
|
||||||
SLE_CONDVAR(Vehicle, cur_real_order_index, SLE_UINT8, 158, SL_MAX_VERSION),
|
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 */
|
/* num_orders is now part of OrderList and is not saved but counted */
|
||||||
SLE_CONDNULL(1, 0, 104),
|
SLE_CONDNULL(1, 0, 104),
|
||||||
|
|
||||||
|
@@ -21,6 +21,7 @@
|
|||||||
#include "company_base.h"
|
#include "company_base.h"
|
||||||
#include "core/sort_func.hpp"
|
#include "core/sort_func.hpp"
|
||||||
#include "settings_type.h"
|
#include "settings_type.h"
|
||||||
|
#include "scope.h"
|
||||||
|
|
||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
|
|
||||||
@@ -42,15 +43,20 @@ static void ChangeTimetable(Vehicle *v, VehicleOrderID order_number, uint16 val,
|
|||||||
|
|
||||||
switch (mtf) {
|
switch (mtf) {
|
||||||
case MTF_WAIT_TIME:
|
case MTF_WAIT_TIME:
|
||||||
total_delta = val - order->GetWaitTime();
|
if (!order->IsType(OT_CONDITIONAL)) {
|
||||||
timetable_delta = (timetabled ? val : 0) - order->GetTimetabledWait();
|
total_delta = val - order->GetWaitTime();
|
||||||
|
timetable_delta = (timetabled ? val : 0) - order->GetTimetabledWait();
|
||||||
|
}
|
||||||
order->SetWaitTime(val);
|
order->SetWaitTime(val);
|
||||||
order->SetWaitTimetabled(timetabled);
|
order->SetWaitTimetabled(timetabled);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MTF_TRAVEL_TIME:
|
case MTF_TRAVEL_TIME:
|
||||||
total_delta = val - order->GetTravelTime();
|
if (!order->IsType(OT_CONDITIONAL)) {
|
||||||
timetable_delta = (timetabled ? val : 0) - order->GetTimetabledTravel();
|
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->SetTravelTime(val);
|
||||||
order->SetTravelTimetabled(timetabled);
|
order->SetTravelTimetabled(timetabled);
|
||||||
break;
|
break;
|
||||||
@@ -714,6 +720,12 @@ void UpdateVehicleTimetable(Vehicle *v, bool travelling)
|
|||||||
|
|
||||||
if (v->cur_real_order_index >= v->GetNumOrders()) return;
|
if (v->cur_real_order_index >= v->GetNumOrders()) return;
|
||||||
Order *real_current_order = v->GetOrder(v->cur_real_order_index);
|
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;
|
VehicleOrderID first_manual_order = 0;
|
||||||
for (Order *o = v->GetFirstOrder(); o != NULL && o->IsType(OT_IMPLICIT); o = o->next) {
|
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 (!HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED)) return;
|
||||||
|
if (real_timetable_order == nullptr) return;
|
||||||
|
|
||||||
bool autofilling = HasBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE);
|
bool autofilling = HasBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE);
|
||||||
bool remeasure_wait_time = !real_current_order->IsWaitTimetabled() ||
|
bool is_conditional = real_timetable_order->IsType(OT_CONDITIONAL);
|
||||||
(autofilling && !HasBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME));
|
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) {
|
if (travelling && remeasure_wait_time) {
|
||||||
/* We just finished travelling and want to remeasure the loading 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);
|
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;
|
if (just_started) return;
|
||||||
|
|
||||||
/* Before modifying waiting times, check whether we want to preserve bigger ones. */
|
/* Before modifying waiting times, check whether we want to preserve bigger ones. */
|
||||||
if (!real_current_order->IsType(OT_CONDITIONAL) &&
|
if ((travelling || time_taken > real_timetable_order->GetWaitTime() || remeasure_wait_time)) {
|
||||||
(travelling || time_taken > real_current_order->GetWaitTime() || remeasure_wait_time)) {
|
|
||||||
/* Round the time taken up to the nearest timetable rounding factor
|
/* Round the time taken up to the nearest timetable rounding factor
|
||||||
* (default: day), as this will avoid confusion for people who are
|
* (default: day), as this will avoid confusion for people who are
|
||||||
* timetabling in days, and can be adjusted later by people who aren't.
|
* 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 rounding_factor = owner ? owner->settings.timetable_autofill_rounding : DAY_TICKS;
|
||||||
uint time_to_set = CeilDiv(max(time_taken, 1U), rounding_factor) * rounding_factor;
|
uint time_to_set = CeilDiv(max(time_taken, 1U), rounding_factor) * rounding_factor;
|
||||||
|
|
||||||
if (travelling && (autofilling || !real_current_order->IsTravelTimetabled())) {
|
if (travel_field && (autofilling || !real_timetable_order->IsTravelTimetabled())) {
|
||||||
ChangeTimetable(v, v->cur_real_order_index, time_to_set, MTF_TRAVEL_TIME, autofilling);
|
ChangeTimetable(v, v->cur_timetable_order_index, time_to_set, MTF_TRAVEL_TIME, autofilling);
|
||||||
} else if (!travelling && (autofilling || !real_current_order->IsWaitTimetabled())) {
|
} else if (!travel_field && (autofilling || !real_timetable_order->IsWaitTimetabled())) {
|
||||||
ChangeTimetable(v, v->cur_real_order_index, time_to_set, MTF_WAIT_TIME, autofilling);
|
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;
|
if (autofilling) return;
|
||||||
|
|
||||||
uint timetabled = travelling ? real_current_order->GetTimetabledTravel() :
|
uint timetabled = travel_field ? real_timetable_order->GetTimetabledTravel() :
|
||||||
real_current_order->GetTimetabledWait();
|
real_timetable_order->GetTimetabledWait();
|
||||||
|
|
||||||
/* Update the timetable to gradually shift order times towards the actual travel times. */
|
/* Update the timetable to gradually shift order times towards the actual travel times. */
|
||||||
if (timetabled != 0 && HasBit(v->vehicle_flags, VF_AUTOMATE_TIMETABLE)) {
|
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) {
|
if (new_time > (int32)timetabled * 4 && travelling) {
|
||||||
/* Possible jam, clear time and restart timetable for all vehicles.
|
/* Possible jam, clear time and restart timetable for all vehicles.
|
||||||
* Otherwise we risk trains blocking 1-lane stations for long times. */
|
* 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()) {
|
for (Vehicle *v2 = v->FirstShared(); v2 != NULL; v2 = v2->NextShared()) {
|
||||||
v2->ClearSeparation();
|
v2->ClearSeparation();
|
||||||
ClrBit(v2->vehicle_flags, VF_TIMETABLE_STARTED);
|
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 < 1) new_time = 1;
|
||||||
if (new_time != (int32)timetabled) {
|
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)) {
|
} else if (timetabled == 0 && HasBit(v->vehicle_flags, VF_AUTOMATE_TIMETABLE)) {
|
||||||
/* Add times for orders that are not yet timetabled, even while not autofilling */
|
/* Add times for orders that are not yet timetabled, even while not autofilling */
|
||||||
if (travelling) {
|
const int32 new_time = travelling ? time_taken : time_loading;
|
||||||
ChangeTimetable(v, v->cur_real_order_index, time_taken, MTF_TRAVEL_TIME, true);
|
if (travel_field) {
|
||||||
|
ChangeTimetable(v, v->cur_timetable_order_index, new_time, MTF_TRAVEL_TIME, true);
|
||||||
} else {
|
} 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);
|
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;
|
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);
|
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();
|
this->current_order.MakeDummy();
|
||||||
SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
|
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();
|
return CommandCost();
|
||||||
}
|
}
|
||||||
|
@@ -855,8 +855,10 @@ private:
|
|||||||
this->cur_real_order_index++;
|
this->cur_real_order_index++;
|
||||||
if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0;
|
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));
|
} while (this->GetOrder(this->cur_real_order_index)->IsType(OT_IMPLICIT));
|
||||||
|
this->cur_timetable_order_index = this->cur_real_order_index;
|
||||||
} else {
|
} else {
|
||||||
this->cur_real_order_index = 0;
|
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);
|
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
|
* Returns the last order of a vehicle, or NULL if it doesn't exists
|
||||||
* @return last order of a vehicle, if available
|
* @return last order of a vehicle, if available
|
||||||
|
Reference in New Issue
Block a user