@@ -3031,212 +3031,209 @@ static TrackStatus GetTileTrackStatus_St
/* buoy is coded as a station, it is always on open water */
if (IsBuoy(tile)) {
trackbits = TRACK_BIT_ALL;
/* remove tracks that connect NE map edge */
if (TileX(tile) == 0) trackbits &= ~(TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_RIGHT);
/* remove tracks that connect NW map edge */
if (TileY(tile) == 0) trackbits &= ~(TRACK_BIT_Y | TRACK_BIT_LEFT | TRACK_BIT_UPPER);
}
break;
case TRANSPORT_ROAD:
if ((GetRoadTypes(tile) & sub_mode) != 0 && IsRoadStop(tile)) {
DiagDirection dir = GetRoadStopDir(tile);
Axis axis = DiagDirToAxis(dir);
if (side != INVALID_DIAGDIR) {
if (axis != DiagDirToAxis(side) || (IsStandardRoadStopTile(tile) && dir != side)) break;
trackbits = AxisToTrackBits(axis);
default:
return CombineTrackStatus(TrackBitsToTrackdirBits(trackbits), TRACKDIR_BIT_NONE);
static void TileLoop_Station(TileIndex tile)
{
/* FIXME -- GetTileTrackStatus_Station -> animated stationtiles
* hardcoded.....not good */
switch (GetStationType(tile)) {
case STATION_AIRPORT:
AirportTileAnimationTrigger(Station::GetByTile(tile), tile, AAT_TILELOOP);
case STATION_DOCK:
if (GetTileSlope(tile) != SLOPE_FLAT) break; // only handle water part
/* FALL THROUGH */
case STATION_OILRIG: //(station part)
case STATION_BUOY:
TileLoop_Water(tile);
default: break;
static void AnimateTile_Station(TileIndex tile)
if (HasStationRail(tile)) {
AnimateStationTile(tile);
return;
if (IsAirport(tile)) {
AnimateAirportTile(tile);
static bool ClickTile_Station(TileIndex tile)
const BaseStation *bst = BaseStation::GetByTile(tile);
if (bst->facilities & FACIL_WAYPOINT) {
ShowWaypointWindow(Waypoint::From(bst));
} else if (IsHangar(tile)) {
const Station *st = Station::From(bst);
ShowDepotWindow(st->airport.GetHangarTile(st->airport.GetHangarNum(tile)), VEH_AIRCRAFT);
} else {
ShowStationViewWindow(bst->index);
return true;
static VehicleEnterTileStatus VehicleEnter_Station(Vehicle *v, TileIndex tile, int x, int y)
if (v->type == VEH_TRAIN) {
StationID station_id = GetStationIndex(tile);
if (!v->current_order.ShouldStopAtStation(v, station_id)) return VETSB_CONTINUE;
if (!IsRailStation(tile) || !v->IsFrontEngine()) return VETSB_CONTINUE;
int station_ahead;
int station_length;
int stop = GetTrainStopLocation(station_id, tile, Train::From(v), &station_ahead, &station_length);
/* Stop whenever that amount of station ahead + the distance from the
* begin of the platform to the stop location is longer than the length
* of the platform. Station ahead 'includes' the current tile where the
* vehicle is on, so we need to subtract that. */
if (!IsInsideBS(stop + station_ahead, station_length, TILE_SIZE)) return VETSB_CONTINUE;
if (stop + station_ahead - (int)TILE_SIZE >= station_length) return VETSB_CONTINUE;
DiagDirection dir = DirToDiagDir(v->direction);
x &= 0xF;
y &= 0xF;
if (DiagDirToAxis(dir) != AXIS_X) Swap(x, y);
if (y == TILE_SIZE / 2) {
if (dir != DIAGDIR_SE && dir != DIAGDIR_SW) x = TILE_SIZE - 1 - x;
stop &= TILE_SIZE - 1;
if (x == stop) return VETSB_ENTERED_STATION | (VehicleEnterTileStatus)(station_id << VETS_STATION_ID_OFFSET); // enter station
if (x < stop) {
uint16 spd;
v->vehstatus |= VS_TRAIN_SLOWING;
spd = max(0, (stop - x) * 20 - 15);
if (spd < v->cur_speed) v->cur_speed = spd;
if (x >= stop) return VETSB_ENTERED_STATION | (VehicleEnterTileStatus)(station_id << VETS_STATION_ID_OFFSET); // enter station
uint16 spd = max(0, (stop - x) * 20 - 15);
} else if (v->type == VEH_ROAD) {
RoadVehicle *rv = RoadVehicle::From(v);
if (rv->state < RVSB_IN_ROAD_STOP && !IsReversingRoadTrackdir((Trackdir)rv->state) && rv->frame == 0) {
if (IsRoadStop(tile) && rv->IsFrontEngine()) {
/* Attempt to allocate a parking bay in a road stop */
return RoadStop::GetByTile(tile, GetRoadStopType(tile))->Enter(rv) ? VETSB_CONTINUE : VETSB_CANNOT_ENTER;
return VETSB_CONTINUE;
/**
* Run the watched cargo callback for all houses in the catchment area.
* @param st Station.
*/
void TriggerWatchedCargoCallbacks(Station *st)
/* Collect cargoes accepted since the last big tick. */
uint cargoes = 0;
for (CargoID cid = 0; cid < NUM_CARGO; cid++) {
if (HasBit(st->goods[cid].acceptance_pickup, GoodsEntry::GES_ACCEPTED_BIGTICK)) SetBit(cargoes, cid);
/* Anything to do? */
if (cargoes == 0) return;
/* Loop over all houses in the catchment. */
Rect r = st->GetCatchmentRect();
TileArea ta(TileXY(r.left, r.top), TileXY(r.right, r.bottom));
TILE_AREA_LOOP(tile, ta) {
if (IsTileType(tile, MP_HOUSE)) {
WatchedCargoCallback(tile, cargoes);
* This function is called for each station once every 250 ticks.
* Not all stations will get the tick at the same time.
* @param st the station receiving the tick.
* @return true if the station is still valid (wasn't deleted)
static bool StationHandleBigTick(BaseStation *st)
if (!st->IsInUse()) {
if (++st->delete_ctr >= 8) delete st;
return false;
if (Station::IsExpected(st)) {
TriggerWatchedCargoCallbacks(Station::From(st));
for (CargoID i = 0; i < NUM_CARGO; i++) {
ClrBit(Station::From(st)->goods[i].acceptance_pickup, GoodsEntry::GES_ACCEPTED_BIGTICK);
if ((st->facilities & FACIL_WAYPOINT) == 0) UpdateStationAcceptance(Station::From(st), true);
static inline void byte_inc_sat(byte *p)
byte b = *p + 1;
if (b != 0) *p = b;
static void UpdateStationRating(Station *st)
bool waiting_changed = false;
byte_inc_sat(&st->time_since_load);
byte_inc_sat(&st->time_since_unload);
const CargoSpec *cs;
FOR_ALL_CARGOSPECS(cs) {
GoodsEntry *ge = &st->goods[cs->Index()];
/* Slowly increase the rating back to his original level in the case we
* didn't deliver cargo yet to this station. This happens when a bribe
* failed while you didn't moved that cargo yet to a station. */
if (!ge->HasRating() && ge->rating < INITIAL_STATION_RATING) {
ge->rating++;
/* Only change the rating if we are moving this cargo */
if (ge->HasRating()) {
byte_inc_sat(&ge->time_since_pickup);
bool skip = false;
int rating = 0;
uint waiting = ge->cargo.TotalCount();
Status change: