diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index 82a1a613ac..82a24597b0 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -23,6 +23,8 @@ #include "settings_type.h" #include "string_func.h" #include "newgrf_cargo.h" +#include "timetable.h" +#include "vehicle_func.h" #include "table/strings.h" @@ -1275,6 +1277,118 @@ Date GetServiceIntervalClamped(uint index) return (_patches.servint_ispercent) ? Clamp(index, MIN_SERVINT_PERCENT, MAX_SERVINT_PERCENT) : Clamp(index, MIN_SERVINT_DAYS, MAX_SERVINT_DAYS); } +/** + * Handle the orders of a vehicle and determine the next place + * to go to if needed. + * @param v the vehicle to do this for. + * @return true *if* the vehicle is eligible for reversing + * (basically only when leaving a station). + */ +bool ProcessOrders(Vehicle *v) +{ + switch (v->current_order.type) { + case OT_GOTO_DEPOT: + /* Let a depot order in the orderlist interrupt. */ + if (!(v->current_order.flags & OFB_PART_OF_ORDERS)) return false; + + if ((v->current_order.flags & OFB_SERVICE_IF_NEEDED) && !VehicleNeedsService(v)) { + UpdateVehicleTimetable(v, true); + v->cur_order_index++; + } + break; + + case OT_LOADING: + case OT_LEAVESTATION: + return false; + + default: break; + } + + /** + * Reversing because of order change is allowed only just after leaving a + * station (and the difficulty setting to allowed, of course) + * this can be detected because only after OT_LEAVESTATION, current_order + * will be reset to nothing. (That also happens if no order, but in that case + * it won't hit the point in code where may_reverse is checked) + */ + bool may_reverse = v->current_order.type == OT_NOTHING; + + /* Check if we've reached the waypoint? */ + if (v->current_order.type == OT_GOTO_WAYPOINT && v->tile == v->dest_tile) { + UpdateVehicleTimetable(v, true); + v->cur_order_index++; + } + + /* Check if we've reached a non-stop station while TTDPatch nonstop is enabled.. */ + if (_patches.new_nonstop && + v->current_order.flags & OFB_NON_STOP && + IsTileType(v->tile, MP_STATION) && + v->current_order.dest == GetStationIndex(v->tile)) { + UpdateVehicleTimetable(v, true); + v->cur_order_index++; + } + + /* Get the current order */ + if (v->cur_order_index >= v->num_orders) v->cur_order_index = 0; + + const Order *order = GetVehicleOrder(v, v->cur_order_index); + + /* If no order, do nothing. */ + if (order == NULL) { + v->current_order.Free(); + v->dest_tile = 0; + if (v->type == VEH_ROAD) ClearSlot(v); + return false; + } + + /* If it is unchanged, keep it. */ + if (order->type == v->current_order.type && + order->flags == v->current_order.flags && + order->dest == v->current_order.dest && + (v->type != VEH_SHIP || order->type != OT_GOTO_STATION || GetStation(order->dest)->dock_tile != 0)) { + return false; + } + + /* Otherwise set it, and determine the destination tile. */ + v->current_order = *order; + + InvalidateVehicleOrder(v); + switch (v->type) { + default: + NOT_REACHED(); + + case VEH_ROAD: + case VEH_TRAIN: + break; + + case VEH_SHIP: + InvalidateWindowClasses(v->GetVehicleListWindowClass()); + break; + } + + switch (order->type) { + case OT_GOTO_STATION: + if (order->dest == v->last_station_visited) { + v->last_station_visited = INVALID_STATION; + } + v->dest_tile = v->GetOrderStationLocation(order->dest); + break; + + case OT_GOTO_DEPOT: + v->dest_tile = GetDepot(order->dest)->xy; + break; + + case OT_GOTO_WAYPOINT: + v->dest_tile = GetWaypoint(order->dest)->xy; + break; + + default: + v->dest_tile = 0; + return false; + } + + return may_reverse; +} /** * diff --git a/src/order_func.h b/src/order_func.h index 3351ea23b0..c6a06a8ae8 100644 --- a/src/order_func.h +++ b/src/order_func.h @@ -36,6 +36,7 @@ bool VehicleHasDepotOrders(const Vehicle *v); void CheckOrders(const Vehicle*); void DeleteVehicleOrders(Vehicle *v); bool CheckForValidOrders(const Vehicle* v); +bool ProcessOrders(Vehicle *v); #define MIN_SERVINT_PERCENT 5 #define MAX_SERVINT_PERCENT 90 diff --git a/src/roadveh.h b/src/roadveh.h index 60e6d5a9d3..ac121d0426 100644 --- a/src/roadveh.h +++ b/src/roadveh.h @@ -76,6 +76,7 @@ struct RoadVehicle : public Vehicle { bool IsInDepot() const { return this->u.road.state == RVSB_IN_DEPOT; } void Tick(); void OnNewDay(); + TileIndex GetOrderStationLocation(StationID station); }; byte GetRoadVehLength(const Vehicle *v); diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp index 6353bbbef3..21081cef1b 100644 --- a/src/roadveh_cmd.cpp +++ b/src/roadveh_cmd.cpp @@ -10,7 +10,6 @@ #include "road_map.h" #include "roadveh.h" #include "station_map.h" -#include "timetable.h" #include "command_func.h" #include "station_base.h" #include "news_func.h" @@ -755,89 +754,31 @@ static void HandleBrokenRoadVeh(Vehicle *v) } } -static void ProcessRoadVehOrder(Vehicle *v) +TileIndex RoadVehicle::GetOrderStationLocation(StationID station) { - const Order *order; - - switch (v->current_order.type) { - case OT_GOTO_DEPOT: - /* Let a depot order in the orderlist interrupt. */ - if (!(v->current_order.flags & OFB_PART_OF_ORDERS)) return; - if (v->current_order.flags & OFB_SERVICE_IF_NEEDED && - !VehicleNeedsService(v)) { - UpdateVehicleTimetable(v, true); - v->cur_order_index++; - } - break; - - case OT_LOADING: - case OT_LEAVESTATION: - return; - - default: break; - } - - if (v->cur_order_index >= v->num_orders) v->cur_order_index = 0; - - order = GetVehicleOrder(v, v->cur_order_index); - - if (order == NULL) { - v->current_order.Free(); - v->dest_tile = 0; - ClearSlot(v); - return; - } - - if (order->type == v->current_order.type && - order->flags == v->current_order.flags && - order->dest == v->current_order.dest) { - return; - } + TileIndex dest = INVALID_TILE; - v->current_order = *order; + const RoadStop *rs = GetStation(station)->GetPrimaryRoadStop(this); + if (rs != NULL) { + uint mindist = MAX_UVALUE(uint); - switch (order->type) { - case OT_GOTO_STATION: { - if (order->dest == v->last_station_visited) { - v->last_station_visited = INVALID_STATION; - } - - const RoadStop *rs = GetStation(order->dest)->GetPrimaryRoadStop(v); - - TileIndex dest = INVALID_TILE; - if (rs != NULL) { - uint mindist = MAX_UVALUE(uint); - - for (; rs != NULL; rs = rs->GetNextRoadStop(v)) { - uint dist = DistanceManhattan(v->tile, rs->xy); + for (; rs != NULL; rs = rs->GetNextRoadStop(this)) { + uint dist = DistanceManhattan(this->tile, rs->xy); - if (dist < mindist) { - mindist = dist; - dest = rs->xy; - } - } + if (dist < mindist) { + mindist = dist; + dest = rs->xy; } - - if (dest != INVALID_TILE) { - v->dest_tile = dest; - } else { - /* There is no stop left at the station, so don't even TRY to go there */ - v->cur_order_index++; - v->dest_tile = 0; - } - break; } - - case OT_GOTO_DEPOT: - v->dest_tile = GetDepot(order->dest)->xy; - break; - - default: - v->dest_tile = 0; - break; } - InvalidateVehicleOrder(v); + if (dest != INVALID_TILE) { + return dest; + } else { + /* There is no stop left at the station, so don't even TRY to go there */ + this->cur_order_index++; + return 0; + } } static void StartRoadVehSound(const Vehicle* v) @@ -1939,7 +1880,7 @@ static void RoadVehController(Vehicle *v) if (v->vehstatus & VS_STOPPED) return; - ProcessRoadVehOrder(v); + ProcessOrders(v); v->HandleLoading(); if (v->current_order.type == OT_LOADING) return; diff --git a/src/ship.h b/src/ship.h index 2a90ed0b48..50f42611b5 100644 --- a/src/ship.h +++ b/src/ship.h @@ -42,6 +42,7 @@ struct Ship: public Vehicle { bool IsInDepot() const { return this->u.ship.state == 0x80; } void Tick(); void OnNewDay(); + TileIndex GetOrderStationLocation(StationID station); }; #endif /* SHIP_H */ diff --git a/src/ship_cmd.cpp b/src/ship_cmd.cpp index baac1285b4..0d814003e9 100644 --- a/src/ship_cmd.cpp +++ b/src/ship_cmd.cpp @@ -242,66 +242,15 @@ void Ship::PlayLeaveStationSound() const PlayShipSound(this); } -static void ProcessShipOrder(Vehicle *v) +TileIndex Ship::GetOrderStationLocation(StationID station) { - const Order *order; - - switch (v->current_order.type) { - case OT_GOTO_DEPOT: - if (!(v->current_order.flags & OFB_PART_OF_ORDERS)) return; - if (v->current_order.flags & OFB_SERVICE_IF_NEEDED && - !VehicleNeedsService(v)) { - UpdateVehicleTimetable(v, true); - v->cur_order_index++; - } - break; - - case OT_LOADING: - case OT_LEAVESTATION: - return; - - default: break; - } - - if (v->cur_order_index >= v->num_orders) v->cur_order_index = 0; - - order = GetVehicleOrder(v, v->cur_order_index); - - if (order == NULL) { - v->current_order.Free(); - v->dest_tile = 0; - return; - } - - if (order->type == v->current_order.type && - order->flags == v->current_order.flags && - order->dest == v->current_order.dest && - (order->type != OT_GOTO_STATION || GetStation(order->dest)->dock_tile != 0)) - return; - - v->current_order = *order; - - if (order->type == OT_GOTO_STATION) { - const Station *st; - - if (order->dest == v->last_station_visited) - v->last_station_visited = INVALID_STATION; - - st = GetStation(order->dest); - if (st->dock_tile != 0) { - v->dest_tile = TILE_ADD(st->dock_tile, ToTileIndexDiff(GetDockOffset(st->dock_tile))); - } else { - v->cur_order_index++; - } - } else if (order->type == OT_GOTO_DEPOT) { - v->dest_tile = GetDepot(order->dest)->xy; + Station *st = GetStation(station); + if (st->dock_tile != 0) { + return TILE_ADD(st->dock_tile, ToTileIndexDiff(GetDockOffset(st->dock_tile))); } else { - v->dest_tile = 0; + this->cur_order_index++; + return 0; } - - InvalidateVehicleOrder(v); - - InvalidateWindowClasses(WC_SHIPS_LIST); } void Ship::UpdateDeltaXY(Direction direction) @@ -650,7 +599,7 @@ static void ShipController(Vehicle *v) if (v->vehstatus & VS_STOPPED) return; - ProcessShipOrder(v); + ProcessOrders(v); v->HandleLoading(); if (v->current_order.type == OT_LOADING) return; diff --git a/src/train.h b/src/train.h index 677f669152..ab3d04190f 100644 --- a/src/train.h +++ b/src/train.h @@ -306,6 +306,7 @@ struct Train : public Vehicle { bool IsStoppedInDepot() const { return CheckTrainStoppedInDepot(this) >= 0; } void Tick(); void OnNewDay(); + TileIndex GetOrderStationLocation(StationID station); }; #endif /* TRAIN_H */ diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index e641c484d6..a58bf01726 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -11,7 +11,6 @@ #include "gui.h" #include "station_map.h" #include "tunnel_map.h" -#include "timetable.h" #include "articulated_vehicles.h" #include "command_func.h" #include "pathfind.h" @@ -2616,94 +2615,9 @@ bad:; return reverse_best != 0; } -static bool ProcessTrainOrder(Vehicle *v) +TileIndex Train::GetOrderStationLocation(StationID station) { - switch (v->current_order.type) { - case OT_GOTO_DEPOT: - if (!(v->current_order.flags & OFB_PART_OF_ORDERS)) return false; - if ((v->current_order.flags & OFB_SERVICE_IF_NEEDED) && - !VehicleNeedsService(v)) { - UpdateVehicleTimetable(v, true); - v->cur_order_index++; - } - break; - - case OT_LOADING: - case OT_LEAVESTATION: - return false; - - default: break; - } - - /** - * Reversing because of order change is allowed only just after leaving a - * station (and the difficulty setting to allowed, of course) - * this can be detected because only after OT_LEAVESTATION, current_order - * will be reset to nothing. (That also happens if no order, but in that case - * it won't hit the point in code where may_reverse is checked) - */ - bool may_reverse = v->current_order.type == OT_NOTHING; - - /* check if we've reached the waypoint? */ - if (v->current_order.type == OT_GOTO_WAYPOINT && v->tile == v->dest_tile) { - UpdateVehicleTimetable(v, true); - v->cur_order_index++; - } - - /* check if we've reached a non-stop station while TTDPatch nonstop is enabled.. */ - if (_patches.new_nonstop && - v->current_order.flags & OFB_NON_STOP && - IsTileType(v->tile, MP_STATION) && - v->current_order.dest == GetStationIndex(v->tile)) { - UpdateVehicleTimetable(v, true); - v->cur_order_index++; - } - - /* Get the current order */ - if (v->cur_order_index >= v->num_orders) v->cur_order_index = 0; - - const Order *order = GetVehicleOrder(v, v->cur_order_index); - - /* If no order, do nothing. */ - if (order == NULL) { - v->current_order.Free(); - v->dest_tile = 0; - return false; - } - - /* If it is unchanged, keep it. */ - if (order->type == v->current_order.type && - order->flags == v->current_order.flags && - order->dest == v->current_order.dest) - return false; - - /* Otherwise set it, and determine the destination tile. */ - v->current_order = *order; - - v->dest_tile = 0; - - InvalidateVehicleOrder(v); - - switch (order->type) { - case OT_GOTO_STATION: - if (order->dest == v->last_station_visited) - v->last_station_visited = INVALID_STATION; - v->dest_tile = GetStation(order->dest)->xy; - break; - - case OT_GOTO_DEPOT: - v->dest_tile = GetDepot(order->dest)->xy; - break; - - case OT_GOTO_WAYPOINT: - v->dest_tile = GetWaypoint(order->dest)->xy; - break; - - default: - return false; - } - - return may_reverse && CheckReverseTrain(v); + return GetStation(station)->xy; } void Train::MarkDirty() @@ -3565,7 +3479,7 @@ static void TrainLocoHandler(Vehicle *v, bool mode) /* exit if train is stopped */ if (v->vehstatus & VS_STOPPED && v->cur_speed == 0) return; - if (ProcessTrainOrder(v)) { + if (ProcessOrders(v) && CheckReverseTrain(v)) { v->load_unload_time_rem = 0; v->cur_speed = 0; v->subspeed = 0; diff --git a/src/vehicle_base.h b/src/vehicle_base.h index c2eb7f9e9f..2aaba064a0 100644 --- a/src/vehicle_base.h +++ b/src/vehicle_base.h @@ -488,6 +488,15 @@ public: inline bool IsOrderListShared() const { return this->next_shared != NULL || this->prev_shared != NULL; }; bool NeedsAutorenewing(const Player *p) const; + + /** + * Determine the location for the station where the vehicle goes to next. + * Things done for example are allocating slots in a road stop or exact + * location of the platform is determined for ships. + * @param station the station to make the next location of the vehicle. + * @return the location (tile) to aim for. + */ + virtual TileIndex GetOrderStationLocation(StationID station) { return INVALID_TILE; } }; /**