|
@@ -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;
|