diff --git a/src/aircraft_cmd.cpp b/src/aircraft_cmd.cpp index 76227e1430..d81a1e3f16 100644 --- a/src/aircraft_cmd.cpp +++ b/src/aircraft_cmd.cpp @@ -1481,6 +1481,13 @@ static void AircraftEventHandler_InHangar(Aircraft *v, const AirportFTAClass *ap return; } + if (v->current_order.IsWaitTimetabled()) { + v->HandleWaiting(false); + } + if (v->current_order.IsType(OT_WAITING)) { + return; + } + /* if we were sent to the depot, stay there */ if (v->current_order.IsType(OT_GOTO_DEPOT) && (v->vehstatus & VS_STOPPED)) { v->current_order.Free(); diff --git a/src/order_base.h b/src/order_base.h index a67cf69bb4..4f0d0b489a 100644 --- a/src/order_base.h +++ b/src/order_base.h @@ -78,6 +78,7 @@ public: void MakeDummy(); void MakeConditional(VehicleOrderID order); void MakeImplicit(StationID destination); + void MakeWaiting(); /** * Is this a 'goto' order with a real destination? diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index 57b29f3f53..2dd2bc427b 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -158,6 +158,11 @@ void Order::MakeImplicit(StationID destination) this->dest = destination; } +void Order::MakeWaiting() +{ + this->type = OT_WAITING; +} + /** * Make this depot/station order also a refit order. * @param cargo the cargo type to change to. @@ -1155,6 +1160,7 @@ CommandCost CmdSkipToOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 if (flags & DC_EXEC) { if (v->current_order.IsType(OT_LOADING)) v->LeaveStation(); + if (v->current_order.IsType(OT_WAITING)) v->HandleWaiting(true); v->cur_implicit_order_index = v->cur_real_order_index = sel_ord; v->UpdateRealOrderIndex(); @@ -2165,6 +2171,9 @@ bool ProcessOrders(Vehicle *v) case OT_LOADING: return false; + case OT_WAITING: + return false; + case OT_LEAVESTATION: if (v->type != VEH_AIRCRAFT) return false; break; diff --git a/src/order_gui.cpp b/src/order_gui.cpp index d4feae35ca..e686aef725 100644 --- a/src/order_gui.cpp +++ b/src/order_gui.cpp @@ -312,6 +312,13 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int SetDParam(5, (order->GetDepotActionType() & ODATFB_HALT) ? STR_ORDER_REFIT_STOP_ORDER : STR_ORDER_REFIT_ORDER); SetDParam(6, CargoSpec::Get(order->GetRefitCargo())->name); } + + if (timetable) { + if (order->GetWaitTime() > 0) { + SetDParam(5, order->IsWaitTimetabled() ? STR_TIMETABLE_STAY_FOR : STR_TIMETABLE_STAY_FOR_ESTIMATED); + SetTimetableParams(6, 7, order->GetWaitTime()); + } + } break; case OT_GOTO_WAYPOINT: diff --git a/src/order_type.h b/src/order_type.h index aba2616a10..aa772bc58b 100644 --- a/src/order_type.h +++ b/src/order_type.h @@ -45,6 +45,7 @@ enum OrderType { OT_GOTO_WAYPOINT = 6, OT_CONDITIONAL = 7, OT_IMPLICIT = 8, + OT_WAITING = 9, OT_END }; diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp index 12d4a6c04c..91b34d1fa0 100644 --- a/src/roadveh_cmd.cpp +++ b/src/roadveh_cmd.cpp @@ -1540,6 +1540,9 @@ static bool RoadVehController(RoadVehicle *v) if (v->current_order.IsType(OT_LOADING)) return true; + v->HandleWaiting(false); + if (v->current_order.IsType(OT_WAITING)) return true; + if (v->IsInDepot() && RoadVehLeaveDepot(v, true)) return true; v->ShowVisualEffect(); diff --git a/src/saveload/extended_ver_sl.cpp b/src/saveload/extended_ver_sl.cpp index de32eac9b0..78da9c5468 100644 --- a/src/saveload/extended_ver_sl.cpp +++ b/src/saveload/extended_ver_sl.cpp @@ -54,6 +54,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_TOWN_CARGO_ADJ, XSCF_IGNORABLE_UNKNOWN, 1, 1, "town_cargo_adj", NULL, NULL, NULL }, { XSLFI_SIG_TUNNEL_BRIDGE, XSCF_NULL, 1, 1, "signal_tunnel_bridge", NULL, NULL, NULL }, { XLSFI_IMPROVED_BREAKDOWNS, XSCF_NULL, 1, 1, "improved_breakdowns", NULL, NULL, NULL }, + { XSLFI_TT_WAIT_IN_DEPOT, XSCF_NULL, 1, 1, "tt_wait_in_depot", NULL, NULL, NULL }, { 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 55f11ac6f4..97a3aef69c 100644 --- a/src/saveload/extended_ver_sl.h +++ b/src/saveload/extended_ver_sl.h @@ -29,6 +29,7 @@ enum SlXvFeatureIndex { XSLFI_TOWN_CARGO_ADJ, ///< Town cargo adjustment patch XSLFI_SIG_TUNNEL_BRIDGE, ///< Signals on tunnels and bridges XLSFI_IMPROVED_BREAKDOWNS, ///< Improved breakdowns patch + XSLFI_TT_WAIT_IN_DEPOT, ///< Timetabling waiting time in depot patch XSLFI_SIZE, ///< Total count of features, including null feature }; diff --git a/src/ship_cmd.cpp b/src/ship_cmd.cpp index e7e2961bdd..40d5942302 100644 --- a/src/ship_cmd.cpp +++ b/src/ship_cmd.cpp @@ -318,6 +318,13 @@ static bool CheckShipLeaveDepot(Ship *v) { if (!v->IsChainInDepot()) return false; + if (v->current_order.IsWaitTimetabled()) { + v->HandleWaiting(false); + } + if (v->current_order.IsType(OT_WAITING)) { + return true; + } + /* We are leaving a depot, but have to go to the exact same one; re-enter */ if (v->current_order.IsType(OT_GOTO_DEPOT) && IsShipDepotTile(v->tile) && GetDepotIndex(v->tile) == v->current_order.GetDestination()) { diff --git a/src/timetable_cmd.cpp b/src/timetable_cmd.cpp index 2fde4d3808..4f5735c964 100644 --- a/src/timetable_cmd.cpp +++ b/src/timetable_cmd.cpp @@ -145,6 +145,9 @@ CommandCost CmdChangeTimetable(TileIndex tile, DoCommandFlag flags, uint32 p1, u if (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) return_cmd_error(STR_ERROR_TIMETABLE_NOT_STOPPING_HERE); break; + case OT_GOTO_DEPOT: + break; + case OT_CONDITIONAL: break; diff --git a/src/timetable_gui.cpp b/src/timetable_gui.cpp index efd41f8474..34ba261db2 100644 --- a/src/timetable_gui.cpp +++ b/src/timetable_gui.cpp @@ -189,7 +189,7 @@ struct TimetableWindow : Window { { assert(HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED)); - bool travelling = (!v->current_order.IsType(OT_LOADING) || 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 = _date_fract - v->current_order_time; FillTimetableArrivalDepartureTable(v, v->cur_real_order_index % v->GetNumOrders(), travelling, table, start_time); @@ -320,7 +320,9 @@ struct TimetableWindow : Window { if (selected % 2 == 1) { disable = order != NULL && (order->IsType(OT_CONDITIONAL) || order->IsType(OT_IMPLICIT)); } else { - disable = order == NULL || ((!order->IsType(OT_GOTO_STATION) || (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION)) && !order->IsType(OT_CONDITIONAL)); + disable = (order == NULL) || + ((!(order->IsType(OT_GOTO_STATION) || (order->IsType(OT_GOTO_DEPOT) && !(order->GetDepotActionType() & ODATFB_HALT))) || + (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION)) && !order->IsType(OT_CONDITIONAL)); } } bool disable_speed = disable || selected % 2 != 1 || v->type == VEH_AIRCRAFT; diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index ac2c380351..ca74a8b2ee 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -2229,6 +2229,13 @@ static bool CheckTrainStayInDepot(Train *v) return true; } + if (v->current_order.IsWaitTimetabled()) { + v->HandleWaiting(false); + } + if (v->current_order.IsType(OT_WAITING)) { + return true; + } + SigSegState seg_state; if (v->force_proceed == TFP_NONE) { diff --git a/src/vehicle.cpp b/src/vehicle.cpp index a06010c3e5..a00577fb8b 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -1663,12 +1663,21 @@ void VehicleEnterDepot(Vehicle *v) } } + /* Handle the ODTFB_PART_OF_ORDERS case. If there is a timetabled wait time, hold the train, otherwise skip to the next order. + Note that if there is a only a travel_time, but no wait_time defined for the order, and the train arrives to the depot sooner as scheduled, + he doesn't wait in it, as it would in stations. Thus, the original behaviour is maintained if there's no defined wait_time.*/ if (v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) { - /* Part of orders */ v->DeleteUnreachedImplicitOrders(); UpdateVehicleTimetable(v, true); - v->IncrementImplicitOrderIndex(); + if (v->current_order.IsWaitTimetabled()) { + v->current_order.MakeWaiting(); + v->current_order.SetNonStopType(ONSF_NO_STOP_AT_ANY_STATION); + return; + } else { + v->IncrementImplicitOrderIndex(); + } } + if (v->current_order.GetDepotActionType() & ODATFB_HALT) { /* Vehicles are always stopped on entering depots. Do not restart this one. */ _vehicles_to_autoreplace[v] = false; @@ -2389,6 +2398,34 @@ void Vehicle::HandleLoading(bool mode) this->IncrementImplicitOrderIndex(); } +/** + * Handle the waiting time everywhere else as in stations (basically in depot but, eventually, also elsewhere ?) + * Function is called when order's wait_time is defined. + * @param stop_waiting should we stop waiting (or definitely avoid) even if there is still time left to wait ? + */ +void Vehicle::HandleWaiting(bool stop_waiting) +{ + switch (this->current_order.GetType()) { + case OT_WAITING: { + uint wait_time = max(this->current_order.GetTimetabledWait() - this->lateness_counter, 0); + /* Vehicles holds on until waiting Timetabled time expires. */ + if (!stop_waiting && this->current_order_time < wait_time) { + return; + } + + /* When wait_time is expired, we move on. */ + UpdateVehicleTimetable(this, false); + this->IncrementImplicitOrderIndex(); + this->current_order.MakeDummy(); + + break; + } + + default: + return; + } +} + /** * Get a map of cargoes and free capacities in the consist. * @param capacities Map to be filled with cargoes and capacities. diff --git a/src/vehicle_base.h b/src/vehicle_base.h index 7a385d785f..f89234f254 100644 --- a/src/vehicle_base.h +++ b/src/vehicle_base.h @@ -294,6 +294,8 @@ public: void HandleLoading(bool mode = false); + void HandleWaiting(bool stop_waiting = false); + void GetConsistFreeCapacities(SmallMap &capacities) const; uint GetConsistTotalCapacity() const;