File diff r13023:9f6499c8d4fb → r13024:48c81d0b078a
src/station_cmd.cpp
Show inline comments
 
@@ -406,49 +406,49 @@ void Station::GetTileArea(TileArea *ta, 
 
			ta->tile = this->dock_tile;
 
			break;
 

	
 
		default: NOT_REACHED();
 
	}
 

	
 
	ta->w = 1;
 
	ta->h = 1;
 
}
 

	
 
/**
 
 * Update the virtual coords needed to draw the station sign.
 
 */
 
void Station::UpdateVirtCoord()
 
{
 
	Point pt = RemapCoords2(TileX(this->xy) * TILE_SIZE, TileY(this->xy) * TILE_SIZE);
 

	
 
	pt.y -= 32;
 
	if ((this->facilities & FACIL_AIRPORT) && this->airport_type == AT_OILRIG) pt.y -= 16;
 

	
 
	SetDParam(0, this->index);
 
	SetDParam(1, this->facilities);
 
	this->sign.UpdatePosition(pt.x, pt.y, STR_VIEWPORT_STATION);
 

	
 
	InvalidateWindow(WC_STATION_VIEW, this->index);
 
	SetWindowDirty(WC_STATION_VIEW, this->index);
 
}
 

	
 
/** Update the virtual coords needed to draw the station sign for all stations. */
 
void UpdateAllStationVirtCoords()
 
{
 
	BaseStation *st;
 

	
 
	FOR_ALL_BASE_STATIONS(st) {
 
		st->UpdateVirtCoord();
 
	}
 
}
 

	
 
/** Get a mask of the cargo types that the station accepts.
 
 * @param st Station to query
 
 * @return the expected mask
 
 */
 
static uint GetAcceptanceMask(const Station *st)
 
{
 
	uint mask = 0;
 

	
 
	for (CargoID i = 0; i < NUM_CARGO; i++) {
 
		if (HasBit(st->goods[i].acceptance_pickup, GoodsEntry::ACCEPTANCE)) mask |= 1 << i;
 
	}
 
	return mask;
 
@@ -600,49 +600,49 @@ void UpdateStationAcceptance(Station *st
 
		uint num_acc = 0;
 
		uint num_rej = 0;
 

	
 
		/* Test each cargo type to see if its acceptange has changed */
 
		for (CargoID i = 0; i < NUM_CARGO; i++) {
 
			if (HasBit(new_acc, i)) {
 
				if (!HasBit(old_acc, i) && num_acc < lengthof(accepts)) {
 
					/* New cargo is accepted */
 
					accepts[num_acc++] = i;
 
				}
 
			} else {
 
				if (HasBit(old_acc, i) && num_rej < lengthof(rejects)) {
 
					/* Old cargo is no longer accepted */
 
					rejects[num_rej++] = i;
 
				}
 
			}
 
		}
 

	
 
		/* Show news message if there are any changes */
 
		if (num_acc > 0) ShowRejectOrAcceptNews(st, num_acc, accepts, accept_msg[num_acc - 1]);
 
		if (num_rej > 0) ShowRejectOrAcceptNews(st, num_rej, rejects, reject_msg[num_rej - 1]);
 
	}
 

	
 
	/* redraw the station view since acceptance changed */
 
	InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_ACCEPTLIST);
 
	SetWindowWidgetDirty(WC_STATION_VIEW, st->index, SVW_ACCEPTLIST);
 
}
 

	
 
static void UpdateStationSignCoord(BaseStation *st)
 
{
 
	const StationRect *r = &st->rect;
 

	
 
	if (r->IsEmpty()) return; // no tiles belong to this station
 

	
 
	/* clamp sign coord to be inside the station rect */
 
	st->xy = TileXY(ClampU(TileX(st->xy), r->left, r->right), ClampU(TileY(st->xy), r->top, r->bottom));
 
	st->UpdateVirtCoord();
 
}
 

	
 
/** This is called right after a station was deleted.
 
 * It checks if the whole station is free of substations, and if so, the station will be
 
 * deleted after a little while.
 
 * @param st Station
 
 */
 
static void DeleteStationIfEmpty(BaseStation *st)
 
{
 
	if (!st->IsInUse()) {
 
		st->delete_ctr = 0;
 
		InvalidateWindowData(WC_STATION_LIST, st->owner, 0);
 
	}
 
@@ -1132,49 +1132,49 @@ CommandCost CmdBuildRailStation(TileInde
 
				}
 

	
 
				tile += tile_delta;
 
			} while (--w);
 
			AddTrackToSignalBuffer(tile_org, track, _current_company);
 
			YapfNotifyTrackLayoutChange(tile_org, track);
 
			tile_org += tile_delta ^ TileDiffXY(1, 1); // perpendicular to tile_delta
 
		} while (--numtracks);
 

	
 
		for (uint i = 0; i < affected_vehicles.Length(); ++i) {
 
			/* Restore reservations of trains. */
 
			Train *v = affected_vehicles[i];
 
			if (IsRailStationTile(v->tile)) SetRailStationPlatformReservation(v->tile, TrackdirToExitdir(v->GetVehicleTrackdir()), true);
 
			TryPathReserve(v, true, true);
 
			for (; v->Next() != NULL; v = v->Next()) ;
 
			if (IsRailStationTile(v->tile)) SetRailStationPlatformReservation(v->tile, TrackdirToExitdir(ReverseTrackdir(v->GetVehicleTrackdir())), true);
 
		}
 

	
 
		st->MarkTilesDirty(false);
 
		st->UpdateVirtCoord();
 
		UpdateStationAcceptance(st, false);
 
		st->RecomputeIndustriesNear();
 
		InvalidateWindowData(WC_SELECT_STATION, 0, 0);
 
		InvalidateWindowData(WC_STATION_LIST, st->owner, 0);
 
		InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_TRAINS);
 
		SetWindowWidgetDirty(WC_STATION_VIEW, st->index, SVW_TRAINS);
 
	}
 

	
 
	return cost;
 
}
 

	
 
static void MakeRailStationAreaSmaller(BaseStation *st)
 
{
 
	TileArea ta = st->train_station;
 

	
 
restart:
 

	
 
	/* too small? */
 
	if (ta.w != 0 && ta.h != 0) {
 
		/* check the left side, x = constant, y changes */
 
		for (uint i = 0; !st->TileBelongsToRailStation(ta.tile + TileDiffXY(0, i));) {
 
			/* the left side is unused? */
 
			if (++i == ta.h) {
 
				ta.tile += TileDiffXY(1, 0);
 
				ta.w--;
 
				goto restart;
 
			}
 
		}
 

	
 
		/* check the right side, x = constant, y changes */
 
@@ -1289,84 +1289,84 @@ CommandCost RemoveFromRailBaseStation(Ti
 
				for (; v->Next() != NULL; v = v->Next()) ;
 
				if (IsRailStationTile(v->tile)) SetRailStationPlatformReservation(v->tile, TrackdirToExitdir(ReverseTrackdir(v->GetVehicleTrackdir())), true);
 
			}
 
		}
 
		if (keep_rail) {
 
			/* Don't refund the 'steel' of the track! */
 
			total_cost.AddCost(-_price.remove_rail);
 
		}
 
	}
 

	
 
	if (quantity == 0) return CMD_ERROR;
 

	
 
	for (T **stp = affected_stations.Begin(); stp != affected_stations.End(); stp++) {
 
		T *st = *stp;
 

	
 
		/* now we need to make the "spanned" area of the railway station smaller
 
		 * if we deleted something at the edges.
 
		 * we also need to adjust train_tile. */
 
		MakeRailStationAreaSmaller(st);
 
		UpdateStationSignCoord(st);
 

	
 
		/* if we deleted the whole station, delete the train facility. */
 
		if (st->train_station.tile == INVALID_TILE) {
 
			st->facilities &= ~FACIL_TRAIN;
 
			InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_TRAINS);
 
			SetWindowWidgetDirty(WC_STATION_VIEW, st->index, SVW_TRAINS);
 
			st->UpdateVirtCoord();
 
			DeleteStationIfEmpty(st);
 
		}
 
	}
 

	
 
	total_cost.AddCost(quantity * removal_cost);
 
	return total_cost;
 
}
 

	
 
/** Remove a single tile from a rail station.
 
 * This allows for custom-built station with holes and weird layouts
 
 * @param start tile of station piece to remove
 
 * @param flags operation to perform
 
 * @param p1 start_tile
 
 * @param p2 various bitstuffed elements
 
 * - p2 = bit 0 - if set keep the rail
 
 * @param text unused
 
 * @return cost of operation or error
 
 */
 
CommandCost CmdRemoveFromRailStation(TileIndex start, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	TileIndex end = p1 == 0 ? start : p1;
 
	if (start >= MapSize() || end >= MapSize()) return CMD_ERROR;
 

	
 
	TileArea ta(start, end);
 
	SmallVector<Station *, 4> affected_stations;
 

	
 
	CommandCost ret = RemoveFromRailBaseStation(ta, affected_stations, flags, _price.remove_rail_station, HasBit(p2, 0));
 
	if (ret.Failed()) return ret;
 

	
 
	/* Do all station specific functions here. */
 
	for (Station **stp = affected_stations.Begin(); stp != affected_stations.End(); stp++) {
 
		Station *st = *stp;
 

	
 
		if (st->train_station.tile == INVALID_TILE) InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_TRAINS);
 
		if (st->train_station.tile == INVALID_TILE) SetWindowWidgetDirty(WC_STATION_VIEW, st->index, SVW_TRAINS);
 
		st->MarkTilesDirty(false);
 
		st->RecomputeIndustriesNear();
 
	}
 

	
 
	/* Now apply the rail cost to the number that we deleted */
 
	return ret;
 
}
 

	
 
/** Remove a single tile from a waypoint.
 
 * This allows for custom-built waypoint with holes and weird layouts
 
 * @param start tile of waypoint piece to remove
 
 * @param flags operation to perform
 
 * @param p1 start_tile
 
 * @param p2 various bitstuffed elements
 
 * - p2 = bit 0 - if set keep the rail
 
 * @param text unused
 
 * @return cost of operation or error
 
 */
 
CommandCost CmdRemoveFromRailWaypoint(TileIndex start, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	TileIndex end = p1 == 0 ? start : p1;
 
	if (start >= MapSize() || end >= MapSize()) return CMD_ERROR;
 

	
 
	TileArea ta(start, end);
 
@@ -1412,49 +1412,49 @@ CommandCost RemoveRailStation(T *st, DoC
 
				v = GetTrainForReservation(tile, track);
 
				if (v != NULL) FreeTrainTrackReservation(v);
 
			}
 
			DoClearSquare(tile);
 
			AddTrackToSignalBuffer(tile, track, owner);
 
			YapfNotifyTrackLayoutChange(tile, track);
 
			if (v != NULL) TryPathReserve(v, true);
 
		}
 
	}
 

	
 
	if (flags & DC_EXEC) {
 
		st->rect.AfterRemoveRect(st, st->train_station.tile, st->train_station.w, st->train_station.h);
 

	
 
		st->train_station.tile = INVALID_TILE;
 
		st->train_station.w = 0;
 
		st->train_station.h = 0;
 

	
 
		st->facilities &= ~FACIL_TRAIN;
 

	
 
		free(st->speclist);
 
		st->num_specs = 0;
 
		st->speclist  = NULL;
 
		st->cached_anim_triggers = 0;
 

	
 
		InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_TRAINS);
 
		SetWindowWidgetDirty(WC_STATION_VIEW, st->index, SVW_TRAINS);
 
		st->UpdateVirtCoord();
 
		DeleteStationIfEmpty(st);
 
	}
 

	
 
	return cost;
 
}
 

	
 
/**
 
 * Remove a rail road station
 
 * @param tile TileIndex been queried
 
 * @param flags operation to perform
 
 * @return cost or failure of operation
 
 */
 
static CommandCost RemoveRailStation(TileIndex tile, DoCommandFlag flags)
 
{
 
	/* if there is flooding and non-uniform stations are enabled, remove platforms tile by tile */
 
	if (_current_company == OWNER_WATER && _settings_game.station.nonuniform_stations) {
 
		return DoCommand(tile, 0, 0, DC_EXEC, CMD_REMOVE_FROM_RAIL_STATION);
 
	}
 

	
 
	Station *st = Station::GetByTile(tile);
 
	CommandCost cost = RemoveRailStation(st, flags);
 

	
 
	if (flags & DC_EXEC) st->RecomputeIndustriesNear();
 
@@ -1615,49 +1615,49 @@ CommandCost CmdBuildRoadStop(TileIndex t
 

	
 
	if (flags & DC_EXEC) {
 
		RoadStop *road_stop = new RoadStop(tile);
 
		/* Insert into linked list of RoadStops */
 
		RoadStop **currstop = FindRoadStopSpot(type, st);
 
		*currstop = road_stop;
 

	
 
		/* initialize an empty station */
 
		st->AddFacility((type) ? FACIL_TRUCK_STOP : FACIL_BUS_STOP, tile);
 

	
 
		st->rect.BeforeAddTile(tile, StationRect::ADD_TRY);
 

	
 
		RoadStopType rs_type = type ? ROADSTOP_TRUCK : ROADSTOP_BUS;
 
		if (is_drive_through) {
 
			MakeDriveThroughRoadStop(tile, st->owner, road_owner, tram_owner, st->index, rs_type, rts, (Axis)p1);
 
		} else {
 
			MakeRoadStop(tile, st->owner, st->index, rs_type, rts, (DiagDirection)p1);
 
		}
 

	
 
		st->UpdateVirtCoord();
 
		UpdateStationAcceptance(st, false);
 
		st->RecomputeIndustriesNear();
 
		InvalidateWindowData(WC_SELECT_STATION, 0, 0);
 
		InvalidateWindowData(WC_STATION_LIST, st->owner, 0);
 
		InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_ROADVEHS);
 
		SetWindowWidgetDirty(WC_STATION_VIEW, st->index, SVW_ROADVEHS);
 
	}
 
	return cost;
 
}
 

	
 

	
 
static Vehicle *ClearRoadStopStatusEnum(Vehicle *v, void *)
 
{
 
	if (v->type == VEH_ROAD) RoadVehicle::From(v)->state &= RVSB_ROAD_STOP_TRACKDIR_MASK;
 

	
 
	return NULL;
 
}
 

	
 

	
 
/**
 
 * Remove a bus station/truck stop
 
 * @param tile TileIndex been queried
 
 * @param flags operation to perform
 
 * @return cost or failure of operation
 
 */
 
static CommandCost RemoveRoadStop(TileIndex tile, DoCommandFlag flags)
 
{
 
	Station *st = Station::GetByTile(tile);
 

	
 
	if (_current_company != OWNER_WATER && !CheckOwnership(st->owner)) {
 
@@ -1680,49 +1680,49 @@ static CommandCost RemoveRoadStop(TileIn
 

	
 
	/* don't do the check for drive-through road stops when company bankrupts */
 
	if (IsDriveThroughStopTile(tile) && (flags & DC_BANKRUPT)) {
 
		/* remove the 'going through road stop' status from all vehicles on that tile */
 
		if (flags & DC_EXEC) FindVehicleOnPos(tile, NULL, &ClearRoadStopStatusEnum);
 
	} else {
 
		if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
 
	}
 

	
 
	if (flags & DC_EXEC) {
 
		if (*primary_stop == cur_stop) {
 
			/* removed the first stop in the list */
 
			*primary_stop = cur_stop->next;
 
			/* removed the only stop? */
 
			if (*primary_stop == NULL) {
 
				st->facilities &= (is_truck ? ~FACIL_TRUCK_STOP : ~FACIL_BUS_STOP);
 
			}
 
		} else {
 
			/* tell the predecessor in the list to skip this stop */
 
			RoadStop *pred = *primary_stop;
 
			while (pred->next != cur_stop) pred = pred->next;
 
			pred->next = cur_stop->next;
 
		}
 

	
 
		InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_ROADVEHS);
 
		SetWindowWidgetDirty(WC_STATION_VIEW, st->index, SVW_ROADVEHS);
 
		delete cur_stop;
 

	
 
		/* Make sure no vehicle is going to the old roadstop */
 
		RoadVehicle *v;
 
		FOR_ALL_ROADVEHICLES(v) {
 
			if (v->First() == v && v->current_order.IsType(OT_GOTO_STATION) &&
 
					v->dest_tile == tile) {
 
				v->dest_tile = v->GetOrderStationLocation(st->index);
 
			}
 
		}
 

	
 
		DoClearSquare(tile);
 
		st->rect.AfterRemoveTile(st, tile);
 

	
 
		st->UpdateVirtCoord();
 
		st->RecomputeIndustriesNear();
 
		DeleteStationIfEmpty(st);
 
	}
 

	
 
	return CommandCost(EXPENSES_CONSTRUCTION, (is_truck) ? _price.remove_truck_station : _price.remove_bus_station);
 
}
 

	
 
/** Remove a bus or truck stop
 
 * @param tile tile to remove the stop from
 
@@ -1980,52 +1980,52 @@ CommandCost CmdBuildAirport(TileIndex ti
 

	
 
		/* if airport was demolished while planes were en-route to it, the
 
		 * positions can no longer be the same (v->u.air.pos), since different
 
		 * airports have different indexes. So update all planes en-route to this
 
		 * airport. Only update if
 
		 * 1. airport is upgraded
 
		 * 2. airport is added to existing station (unfortunately unavoideable)
 
		 */
 
		if (airport_upgrade) UpdateAirplanesOnNewStation(st);
 

	
 
		{
 
			const byte *b = _airport_sections[p1];
 

	
 
			TILE_LOOP(tile_cur, w, h, tile) {
 
				MakeAirport(tile_cur, st->owner, st->index, *b);
 
				b++;
 
			}
 
		}
 

	
 
		st->UpdateVirtCoord();
 
		UpdateStationAcceptance(st, false);
 
		st->RecomputeIndustriesNear();
 
		InvalidateWindowData(WC_SELECT_STATION, 0, 0);
 
		InvalidateWindowData(WC_STATION_LIST, st->owner, 0);
 
		InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_PLANES);
 
		SetWindowWidgetDirty(WC_STATION_VIEW, st->index, SVW_PLANES);
 

	
 
		if (_settings_game.economy.station_noise_level) {
 
			InvalidateWindow(WC_TOWN_VIEW, st->town->index);
 
			SetWindowDirty(WC_TOWN_VIEW, st->town->index);
 
		}
 
	}
 

	
 
	return cost;
 
}
 

	
 
/**
 
 * Remove an airport
 
 * @param tile TileIndex been queried
 
 * @param flags operation to perform
 
 * @return cost or failure of operation
 
 */
 
static CommandCost RemoveAirport(TileIndex tile, DoCommandFlag flags)
 
{
 
	Station *st = Station::GetByTile(tile);
 

	
 
	if (_current_company != OWNER_WATER && !CheckOwnership(st->owner)) {
 
		return CMD_ERROR;
 
	}
 

	
 
	tile = st->airport_tile;
 

	
 
	const AirportFTAClass *afc = st->Airport();
 
	int w = afc->size_x;
 
@@ -2045,52 +2045,52 @@ static CommandCost RemoveAirport(TileInd
 
		if (flags & DC_EXEC) {
 
			DeleteAnimatedTile(tile_cur);
 
			DoClearSquare(tile_cur);
 
		}
 
	}
 

	
 
	if (flags & DC_EXEC) {
 
		for (uint i = 0; i < afc->nof_depots; ++i) {
 
			DeleteWindowById(
 
				WC_VEHICLE_DEPOT, tile + ToTileIndexDiff(afc->airport_depots[i])
 
			);
 
		}
 

	
 
		/* Go get the final noise level, that is base noise minus factor from distance to town center.
 
		 * And as for construction, always remove it, even if the setting is not set, in order to avoid the
 
		 * need of recalculation */
 
		Town *nearest = AirportGetNearestTown(afc, tile);
 
		nearest->noise_reached -= GetAirportNoiseLevelForTown(afc, nearest->xy, tile);
 

	
 
		st->rect.AfterRemoveRect(st, tile, w, h);
 

	
 
		st->airport_tile = INVALID_TILE;
 
		st->facilities &= ~FACIL_AIRPORT;
 

	
 
		InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_PLANES);
 
		SetWindowWidgetDirty(WC_STATION_VIEW, st->index, SVW_PLANES);
 

	
 
		if (_settings_game.economy.station_noise_level) {
 
			InvalidateWindow(WC_TOWN_VIEW, st->town->index);
 
			SetWindowDirty(WC_TOWN_VIEW, st->town->index);
 
		}
 

	
 
		st->UpdateVirtCoord();
 
		st->RecomputeIndustriesNear();
 
		DeleteStationIfEmpty(st);
 
	}
 

	
 
	return cost;
 
}
 

	
 
/**
 
 * Tests whether the company's vehicles have this station in orders
 
 * When company == INVALID_COMPANY, then check all vehicles
 
 * @param station station ID
 
 * @param company company ID, INVALID_COMPANY to disable the check
 
 */
 
bool HasStationInUse(StationID station, CompanyID company)
 
{
 
	const Vehicle *v;
 
	FOR_ALL_VEHICLES(v) {
 
		if (company == INVALID_COMPANY || v->owner == company) {
 
			const Order *order;
 
			FOR_VEHICLE_ORDERS(v, order) {
 
				if ((order->IsType(OT_GOTO_STATION) || order->IsType(OT_GOTO_WAYPOINT)) && order->GetDestination() == station) {
 
@@ -2190,84 +2190,84 @@ CommandCost CmdBuildDock(TileIndex tile,
 
			st->town = ClosestTownFromTile(tile, UINT_MAX);
 
			st->string_id = GenerateStationName(st, tile, STATIONNAMING_DOCK);
 

	
 
			if (Company::IsValidID(_current_company)) {
 
				SetBit(st->town->have_ratings, _current_company);
 
			}
 
		}
 
	}
 

	
 
	if (flags & DC_EXEC) {
 
		st->dock_tile = tile;
 
		st->AddFacility(FACIL_DOCK, tile);
 

	
 
		st->rect.BeforeAddRect(
 
				tile + ToTileIndexDiff(_dock_tileoffs_chkaround[direction]),
 
				_dock_w_chk[direction], _dock_h_chk[direction], StationRect::ADD_TRY);
 

	
 
		MakeDock(tile, st->owner, st->index, direction, wc);
 

	
 
		st->UpdateVirtCoord();
 
		UpdateStationAcceptance(st, false);
 
		st->RecomputeIndustriesNear();
 
		InvalidateWindowData(WC_SELECT_STATION, 0, 0);
 
		InvalidateWindowData(WC_STATION_LIST, st->owner, 0);
 
		InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_SHIPS);
 
		SetWindowWidgetDirty(WC_STATION_VIEW, st->index, SVW_SHIPS);
 
	}
 

	
 
	return CommandCost(EXPENSES_CONSTRUCTION, _price.build_dock);
 
}
 

	
 
/**
 
 * Remove a dock
 
 * @param tile TileIndex been queried
 
 * @param flags operation to perform
 
 * @return cost or failure of operation
 
 */
 
static CommandCost RemoveDock(TileIndex tile, DoCommandFlag flags)
 
{
 
	Station *st = Station::GetByTile(tile);
 
	if (!CheckOwnership(st->owner)) return CMD_ERROR;
 

	
 
	TileIndex tile1 = st->dock_tile;
 
	TileIndex tile2 = tile1 + TileOffsByDiagDir(GetDockDirection(tile1));
 

	
 
	if (!EnsureNoVehicleOnGround(tile1)) return CMD_ERROR;
 
	if (!EnsureNoVehicleOnGround(tile2)) return CMD_ERROR;
 

	
 
	if (flags & DC_EXEC) {
 
		DoClearSquare(tile1);
 
		MakeWaterKeepingClass(tile2, st->owner);
 

	
 
		st->rect.AfterRemoveTile(st, tile1);
 
		st->rect.AfterRemoveTile(st, tile2);
 

	
 
		MarkTileDirtyByTile(tile2);
 

	
 
		st->dock_tile = INVALID_TILE;
 
		st->facilities &= ~FACIL_DOCK;
 

	
 
		InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_SHIPS);
 
		SetWindowWidgetDirty(WC_STATION_VIEW, st->index, SVW_SHIPS);
 
		st->UpdateVirtCoord();
 
		st->RecomputeIndustriesNear();
 
		DeleteStationIfEmpty(st);
 
	}
 

	
 
	return CommandCost(EXPENSES_CONSTRUCTION, _price.remove_dock);
 
}
 

	
 
#include "table/station_land.h"
 

	
 
const DrawTileSprites *GetStationTileLayout(StationType st, byte gfx)
 
{
 
	return &_station_display_datas[st][gfx];
 
}
 

	
 
static void DrawTile_Station(TileInfo *ti)
 
{
 
	const DrawTileSprites *t = NULL;
 
	RoadTypes roadtypes;
 
	int32 total_offset;
 
	int32 custom_ground_offset;
 

	
 
	if (HasStationRail(ti->tile)) {
 
		const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
 
@@ -2802,51 +2802,51 @@ static void UpdateStationRating(Station 
 
				}
 

	
 
				/* At some point we really must cap the cargo. Previously this
 
				 * was a strict 4095, but now we'll have a less strict, but
 
				 * increasingly agressive truncation of the amount of cargo. */
 
				static const uint WAITING_CARGO_THRESHOLD  = 1 << 12;
 
				static const uint WAITING_CARGO_CUT_FACTOR = 1 <<  6;
 
				static const uint MAX_WAITING_CARGO        = 1 << 15;
 

	
 
				if (waiting > WAITING_CARGO_THRESHOLD) {
 
					uint difference = waiting - WAITING_CARGO_THRESHOLD;
 
					waiting -= (difference / WAITING_CARGO_CUT_FACTOR);
 

	
 
					waiting = min(waiting, MAX_WAITING_CARGO);
 
					waiting_changed = true;
 
				}
 

	
 
				if (waiting_changed) ge->cargo.Truncate(waiting);
 
			}
 
		}
 
	} while (++ge != endof(st->goods));
 

	
 
	StationID index = st->index;
 
	if (waiting_changed) {
 
		InvalidateWindow(WC_STATION_VIEW, index); // update whole window
 
		SetWindowDirty(WC_STATION_VIEW, index); // update whole window
 
	} else {
 
		InvalidateWindowWidget(WC_STATION_VIEW, index, SVW_RATINGLIST); // update only ratings list
 
		SetWindowWidgetDirty(WC_STATION_VIEW, index, SVW_RATINGLIST); // update only ratings list
 
	}
 
}
 

	
 
/* called for every station each tick */
 
static void StationHandleSmallTick(BaseStation *st)
 
{
 
	if ((st->facilities & FACIL_WAYPOINT) != 0 || !st->IsInUse()) return;
 

	
 
	byte b = st->delete_ctr + 1;
 
	if (b >= 185) b = 0;
 
	st->delete_ctr = b;
 

	
 
	if (b == 0) UpdateStationRating(Station::From(st));
 
}
 

	
 
void OnTick_Station()
 
{
 
	if (_game_mode == GM_EDITOR) return;
 

	
 
	BaseStation *st;
 
	FOR_ALL_BASE_STATIONS(st) {
 
		StationHandleSmallTick(st);
 

	
 
		/* Run 250 tick interval trigger for station animation.
 
@@ -2870,49 +2870,49 @@ void ModifyStationRatingAround(TileIndex
 
{
 
	Station *st;
 

	
 
	FOR_ALL_STATIONS(st) {
 
		if (st->owner == owner &&
 
				DistanceManhattan(tile, st->xy) <= radius) {
 
			for (CargoID i = 0; i < NUM_CARGO; i++) {
 
				GoodsEntry *ge = &st->goods[i];
 

	
 
				if (ge->acceptance_pickup != 0) {
 
					ge->rating = Clamp(ge->rating + amount, 0, 255);
 
				}
 
			}
 
		}
 
	}
 
}
 

	
 
static void UpdateStationWaiting(Station *st, CargoID type, uint amount, SourceType source_type, SourceID source_id)
 
{
 
	st->goods[type].cargo.Append(new CargoPacket(st->index, amount, source_type, source_id));
 
	SetBit(st->goods[type].acceptance_pickup, GoodsEntry::PICKUP);
 

	
 
	StationAnimationTrigger(st, st->xy, STAT_ANIM_NEW_CARGO, type);
 

	
 
	InvalidateWindow(WC_STATION_VIEW, st->index);
 
	SetWindowDirty(WC_STATION_VIEW, st->index);
 
	st->MarkTilesDirty(true);
 
}
 

	
 
static bool IsUniqueStationName(const char *name)
 
{
 
	const Station *st;
 

	
 
	FOR_ALL_STATIONS(st) {
 
		if (st->name != NULL && strcmp(st->name, name) == 0) return false;
 
	}
 

	
 
	return true;
 
}
 

	
 
/** Rename a station
 
 * @param tile unused
 
 * @param flags operation to perform
 
 * @param p1 station ID that is to be renamed
 
 * @param p2 unused
 
 */
 
CommandCost CmdRenameStation(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	Station *st = Station::GetIfValid(p1);
 
	if (st == NULL || !CheckOwnership(st->owner)) return CMD_ERROR;