@@ -791,30 +791,23 @@ static void ProcessRoadVehOrder(Vehicle
}
v->current_order = *order;
switch (order->type) {
case OT_GOTO_STATION: {
const RoadStop* rs;
if (order->dest == v->last_station_visited) {
v->last_station_visited = INVALID_STATION;
rs = GetStation(order->dest)->GetPrimaryRoadStop(
IsCargoInClass(v->cargo_type, CC_PASSENGERS) ? RoadStop::BUS : RoadStop::TRUCK
);
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->next) {
/* The vehicle cannot go to this roadstop */
if ((GetRoadTypes(rs->xy) & v->u.road.compatible_roadtypes) == ROADTYPES_NONE) continue;
for (; rs != NULL; rs = rs->GetNextRoadStop(v)) {
uint dist = DistanceManhattan(v->tile, rs->xy);
if (dist < mindist) {
mindist = dist;
dest = rs->xy;
@@ -1140,36 +1133,37 @@ static Trackdir RoadFindPathToDest(Vehic
#define return_track(x) { best_track = (Trackdir)x; goto found_best_track; }
TileIndex desttile;
FindRoadToChooseData frd;
Trackdir best_track;
uint32 r = GetTileTrackStatus(tile, TRANSPORT_ROAD, v->u.road.compatible_roadtypes);
TrackdirBits signal = (TrackdirBits)GB(r, 16, 16);
TrackdirBits trackdirs = (TrackdirBits)GB(r, 0, 16);
if (IsTileType(tile, MP_ROAD)) {
if (GetRoadTileType(tile) == ROAD_TILE_DEPOT && (!IsTileOwner(tile, v->owner) || GetRoadDepotDirection(tile) == enterdir || (GetRoadTypes(tile) & v->u.road.compatible_roadtypes) == 0)) {
/* Road depot owned by another player or with the wrong orientation */
trackdirs = TRACKDIR_BIT_NONE;
} else if (IsTileType(tile, MP_STATION) && IsStandardRoadStopTile(tile)) {
/* Standard road stop (drive-through stops are treated as normal road) */
if (!IsTileOwner(tile, v->owner) || GetRoadStopDir(tile) == enterdir) {
/* different station owner or wrong orientation */
if (!IsTileOwner(tile, v->owner) || GetRoadStopDir(tile) == enterdir || RoadVehHasArticPart(v)) {
/* different station owner or wrong orientation or the vehicle has articulated parts */
} else {
/* Our station */
RoadStop::Type rstype = IsCargoInClass(v->cargo_type, CC_PASSENGERS) ? RoadStop::BUS : RoadStop::TRUCK;
if (GetRoadStopType(tile) != rstype) {
/* Wrong station type */
/* Proper station type, check if there is free loading bay */
if (!_patches.roadveh_queue && IsStandardRoadStopTile(tile) &&
!GetRoadStopByTile(tile, rstype)->HasFreeBay()) {
/* Station is full and RV queuing is off */
@@ -1919,15 +1913,15 @@ void OnNewDay_RoadVeh(Vehicle *v)
if (v->vehstatus & VS_STOPPED) return;
/* update destination */
if (v->current_order.type == OT_GOTO_STATION && v->u.road.slot == NULL && !(v->vehstatus & VS_CRASHED)) {
Station* st = GetStation(v->current_order.dest);
RoadStop* rs = st->GetPrimaryRoadStop(IsCargoInClass(v->cargo_type, CC_PASSENGERS) ? RoadStop::BUS : RoadStop::TRUCK);
RoadStop* best = NULL;
Station *st = GetStation(v->current_order.dest);
RoadStop *rs = st->GetPrimaryRoadStop(v);
RoadStop *best = NULL;
/* We try to obtain a slot if:
* 1) we're reasonably close to the primary road stop
* or
* 2) we're somewhere close to the station rectangle (to make sure we do assign
@@ -1938,13 +1932,13 @@ void OnNewDay_RoadVeh(Vehicle *v)
uint minbadness = UINT_MAX;
DEBUG(ms, 2, "Attempting to obtain a slot for vehicle %d (index %d) at station %d (0x%X)",
v->unitnumber, v->index, st->index, st->xy
/* Now we find the nearest road stop that has a free slot */
dist = RoadFindPathToStop(v, rs->xy);
if (dist == UINT_MAX) {
DEBUG(ms, 4, " stop 0x%X is unreachable, not treating further", rs->xy);
continue;
badness = (rs->num_vehicles + 1) * (rs->num_vehicles + 1) + dist;
@@ -31,12 +31,14 @@
#include "industry_map.h"
#include "newgrf_callbacks.h"
#include "newgrf_station.h"
#include "yapf/yapf.h"
#include "date.h"
#include "helpers.hpp"
#include "cargotype.h"
#include "roadveh.h"
Station::Station(TileIndex tile)
{
DEBUG(station, cDebugCtorLevel, "I+%3d", index);
xy = tile;
@@ -89,12 +91,35 @@ Station::~Station()
for (CargoID c = 0; c < NUM_CARGO; c++) {
goods[c].cargo.Truncate(0);
/**
* Get the primary road stop (the first road stop) that the given vehicle can load/unload.
* @param v the vehicle to get the first road stop for
* @return the first roadstop that this vehicle can load at
*/
RoadStop *Station::GetPrimaryRoadStop(const Vehicle *v) const
RoadStop *rs = this->GetPrimaryRoadStop(IsCargoInClass(v->cargo_type, CC_PASSENGERS) ? RoadStop::BUS : RoadStop::TRUCK);
/* The vehicle cannot go to this roadstop (different roadtype) */
/* The vehicle is articulated and can therefor not go the a standard road stop */
if (IsStandardRoadStopTile(rs->xy) && RoadVehHasArticPart(v)) continue;
/* The vehicle can actually go to this road stop. So, return it! */
break;
return rs;
/** Called when new facility is built on the station. If it is the first facility
* it initializes also 'xy' and 'random_bits' members */
void Station::AddFacility(byte new_facility_bit, TileIndex facil_xy)
if (facilities == 0) {
xy = facil_xy;
@@ -477,6 +502,26 @@ bool RoadStop::IsEntranceBusy() const
/** Makes an entrance occupied or free */
void RoadStop::SetEntranceBusy(bool busy)
SB(status, 7, 1, busy);
* Get the next road stop accessible by this vehicle.
* @param v the vehicle to get the next road stop for.
* @return the next road stop accessible.
RoadStop *RoadStop::GetNextRoadStop(const Vehicle *v) const
for (RoadStop *rs = this->next; rs != NULL; rs = rs->next) {
if ((GetRoadTypes(rs->xy) & v->u.road.compatible_roadtypes) != ROADTYPES_NONE) continue;
return NULL;
@@ -67,12 +67,14 @@ struct RoadStop : PoolItem<RoadStop, Roa
bool IsFreeBay(uint nr) const;
uint AllocateBay();
void AllocateDriveThroughBay(uint nr);
void FreeBay(uint nr);
bool IsEntranceBusy() const;
void SetEntranceBusy(bool busy);
RoadStop *GetNextRoadStop(const Vehicle *v) const;
};
struct StationSpecList {
const StationSpec *spec;
uint32 grfid; ///< GRF ID of this custom station
uint8 localidx; ///< Station ID within GRF of station
@@ -99,23 +101,25 @@ struct StationRect : public Rect {
static bool ScanForStationTiles(StationID st_id, int left_a, int top_a, int right_a, int bottom_a);
StationRect& operator = (Rect src);
struct Station : PoolItem<Station, StationID, &_Station_pool> {
public:
RoadStop *GetPrimaryRoadStop(RoadStop::Type type) const
return type == RoadStop::BUS ? bus_stops : truck_stops;
const AirportFTAClass *Airport() const
if (airport_tile == 0) return GetAirport(AT_DUMMY);
return GetAirport(airport_type);
RoadStop *GetPrimaryRoadStop(const Vehicle *v) const;
TileIndex xy;
RoadStop *bus_stops;
RoadStop *truck_stops;
TileIndex train_tile;
TileIndex airport_tile;
@@ -2340,14 +2340,14 @@ static uint32 VehicleEnter_Station(Vehic
/* Indicate a drive-through stop */
SETBIT(v->u.road.state, RVS_IN_DT_ROAD_STOP);
return VETSB_CONTINUE;
/* For normal (non drive-through) road stops */
/* Check if station is busy or if there are no free bays. */
if (rs->IsEntranceBusy() || !rs->HasFreeBay()) return VETSB_CANNOT_ENTER;
/* Check if station is busy or if there are no free bays or whether it is a articulated vehicle. */
if (rs->IsEntranceBusy() || !rs->HasFreeBay() || RoadVehHasArticPart(v)) return VETSB_CANNOT_ENTER;
SETBIT(v->u.road.state, RVS_IN_ROAD_STOP);
/* Allocate a bay and update the road state */
uint bay_nr = rs->AllocateBay();
SB(v->u.road.state, RVS_USING_SECOND_BAY, 1, bay_nr);
Status change: