station_cmd.cpp

Go to the documentation of this file.
00001 /* $Id$ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00012 #include "stdafx.h"
00013 #include "aircraft.h"
00014 #include "bridge_map.h"
00015 #include "cmd_helper.h"
00016 #include "viewport_func.h"
00017 #include "command_func.h"
00018 #include "town.h"
00019 #include "news_func.h"
00020 #include "train.h"
00021 #include "roadveh.h"
00022 #include "industry.h"
00023 #include "newgrf_cargo.h"
00024 #include "newgrf_debug.h"
00025 #include "newgrf_station.h"
00026 #include "pathfinder/yapf/yapf_cache.h"
00027 #include "road_internal.h" /* For drawing catenary/checking road removal */
00028 #include "autoslope.h"
00029 #include "water.h"
00030 #include "station_gui.h"
00031 #include "strings_func.h"
00032 #include "clear_func.h"
00033 #include "window_func.h"
00034 #include "date_func.h"
00035 #include "vehicle_func.h"
00036 #include "string_func.h"
00037 #include "animated_tile_func.h"
00038 #include "elrail_func.h"
00039 #include "station_base.h"
00040 #include "roadstop_base.h"
00041 #include "newgrf_railtype.h"
00042 #include "waypoint_base.h"
00043 #include "waypoint_func.h"
00044 #include "pbs.h"
00045 #include "debug.h"
00046 #include "core/random_func.hpp"
00047 #include "company_base.h"
00048 #include "moving_average.h"
00049 #include "table/airporttile_ids.h"
00050 #include "newgrf_airporttiles.h"
00051 #include "order_backup.h"
00052 #include "company_gui.h"
00053 
00054 #include "table/strings.h"
00055 
00062 bool IsHangar(TileIndex t)
00063 {
00064   assert(IsTileType(t, MP_STATION));
00065 
00066   /* If the tile isn't an airport there's no chance it's a hangar. */
00067   if (!IsAirport(t)) return false;
00068 
00069   const Station *st = Station::GetByTile(t);
00070   const AirportSpec *as = st->airport.GetSpec();
00071 
00072   for (uint i = 0; i < as->nof_depots; i++) {
00073     if (st->airport.GetHangarTile(i) == t) return true;
00074   }
00075 
00076   return false;
00077 }
00078 
00086 template <class T>
00087 CommandCost GetStationAround(TileArea ta, StationID closest_station, T **st)
00088 {
00089   ta.tile -= TileDiffXY(1, 1);
00090   ta.w    += 2;
00091   ta.h    += 2;
00092 
00093   /* check around to see if there's any stations there */
00094   TILE_AREA_LOOP(tile_cur, ta) {
00095     if (IsTileType(tile_cur, MP_STATION)) {
00096       StationID t = GetStationIndex(tile_cur);
00097       if (!T::IsValidID(t)) continue;
00098 
00099       if (closest_station == INVALID_STATION) {
00100         closest_station = t;
00101       } else if (closest_station != t) {
00102         return_cmd_error(STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING);
00103       }
00104     }
00105   }
00106   *st = (closest_station == INVALID_STATION) ? NULL : T::Get(closest_station);
00107   return CommandCost();
00108 }
00109 
00115 typedef bool (*CMSAMatcher)(TileIndex tile);
00116 
00123 static int CountMapSquareAround(TileIndex tile, CMSAMatcher cmp)
00124 {
00125   int num = 0;
00126 
00127   for (int dx = -3; dx <= 3; dx++) {
00128     for (int dy = -3; dy <= 3; dy++) {
00129       TileIndex t = TileAddWrap(tile, dx, dy);
00130       if (t != INVALID_TILE && cmp(t)) num++;
00131     }
00132   }
00133 
00134   return num;
00135 }
00136 
00142 static bool CMSAMine(TileIndex tile)
00143 {
00144   /* No industry */
00145   if (!IsTileType(tile, MP_INDUSTRY)) return false;
00146 
00147   const Industry *ind = Industry::GetByTile(tile);
00148 
00149   /* No extractive industry */
00150   if ((GetIndustrySpec(ind->type)->life_type & INDUSTRYLIFE_EXTRACTIVE) == 0) return false;
00151 
00152   for (uint i = 0; i < lengthof(ind->produced_cargo); i++) {
00153     /* The industry extracts something non-liquid, i.e. no oil or plastic, so it is a mine.
00154      * Also the production of passengers and mail is ignored. */
00155     if (ind->produced_cargo[i] != CT_INVALID &&
00156         (CargoSpec::Get(ind->produced_cargo[i])->classes & (CC_LIQUID | CC_PASSENGERS | CC_MAIL)) == 0) {
00157       return true;
00158     }
00159   }
00160 
00161   return false;
00162 }
00163 
00169 static bool CMSAWater(TileIndex tile)
00170 {
00171   return IsTileType(tile, MP_WATER) && IsWater(tile);
00172 }
00173 
00179 static bool CMSATree(TileIndex tile)
00180 {
00181   return IsTileType(tile, MP_TREES);
00182 }
00183 
00189 static bool CMSAForest(TileIndex tile)
00190 {
00191   /* No industry */
00192   if (!IsTileType(tile, MP_INDUSTRY)) return false;
00193 
00194   const Industry *ind = Industry::GetByTile(tile);
00195 
00196   /* No extractive industry */
00197   if ((GetIndustrySpec(ind->type)->life_type & INDUSTRYLIFE_ORGANIC) == 0) return false;
00198 
00199   for (uint i = 0; i < lengthof(ind->produced_cargo); i++) {
00200     /* The industry produces wood. */
00201     if (ind->produced_cargo[i] != CT_INVALID && CargoSpec::Get(ind->produced_cargo[i])->label == 'WOOD') return true;
00202   }
00203 
00204   return false;
00205 }
00206 
00207 #define M(x) ((x) - STR_SV_STNAME)
00208 
00209 enum StationNaming {
00210   STATIONNAMING_RAIL,
00211   STATIONNAMING_ROAD,
00212   STATIONNAMING_AIRPORT,
00213   STATIONNAMING_OILRIG,
00214   STATIONNAMING_DOCK,
00215   STATIONNAMING_HELIPORT,
00216 };
00217 
00219 struct StationNameInformation {
00220   uint32 free_names; 
00221   bool *indtypes;    
00222 };
00223 
00232 static bool FindNearIndustryName(TileIndex tile, void *user_data)
00233 {
00234   /* All already found industry types */
00235   StationNameInformation *sni = (StationNameInformation*)user_data;
00236   if (!IsTileType(tile, MP_INDUSTRY)) return false;
00237 
00238   /* If the station name is undefined it means that it doesn't name a station */
00239   IndustryType indtype = GetIndustryType(tile);
00240   if (GetIndustrySpec(indtype)->station_name == STR_UNDEFINED) return false;
00241 
00242   /* In all cases if an industry that provides a name is found two of
00243    * the standard names will be disabled. */
00244   sni->free_names &= ~(1 << M(STR_SV_STNAME_OILFIELD) | 1 << M(STR_SV_STNAME_MINES));
00245   return !sni->indtypes[indtype];
00246 }
00247 
00248 static StringID GenerateStationName(Station *st, TileIndex tile, StationNaming name_class)
00249 {
00250   static const uint32 _gen_station_name_bits[] = {
00251     0,                                       // STATIONNAMING_RAIL
00252     0,                                       // STATIONNAMING_ROAD
00253     1U << M(STR_SV_STNAME_AIRPORT),          // STATIONNAMING_AIRPORT
00254     1U << M(STR_SV_STNAME_OILFIELD),         // STATIONNAMING_OILRIG
00255     1U << M(STR_SV_STNAME_DOCKS),            // STATIONNAMING_DOCK
00256     1U << M(STR_SV_STNAME_HELIPORT),         // STATIONNAMING_HELIPORT
00257   };
00258 
00259   const Town *t = st->town;
00260   uint32 free_names = UINT32_MAX;
00261 
00262   bool indtypes[NUM_INDUSTRYTYPES];
00263   memset(indtypes, 0, sizeof(indtypes));
00264 
00265   const Station *s;
00266   FOR_ALL_STATIONS(s) {
00267     if (s != st && s->town == t) {
00268       if (s->indtype != IT_INVALID) {
00269         indtypes[s->indtype] = true;
00270         continue;
00271       }
00272       uint str = M(s->string_id);
00273       if (str <= 0x20) {
00274         if (str == M(STR_SV_STNAME_FOREST)) {
00275           str = M(STR_SV_STNAME_WOODS);
00276         }
00277         ClrBit(free_names, str);
00278       }
00279     }
00280   }
00281 
00282   TileIndex indtile = tile;
00283   StationNameInformation sni = { free_names, indtypes };
00284   if (CircularTileSearch(&indtile, 7, FindNearIndustryName, &sni)) {
00285     /* An industry has been found nearby */
00286     IndustryType indtype = GetIndustryType(indtile);
00287     const IndustrySpec *indsp = GetIndustrySpec(indtype);
00288     /* STR_NULL means it only disables oil rig/mines */
00289     if (indsp->station_name != STR_NULL) {
00290       st->indtype = indtype;
00291       return STR_SV_STNAME_FALLBACK;
00292     }
00293   }
00294 
00295   /* Oil rigs/mines name could be marked not free by looking for a near by industry. */
00296   free_names = sni.free_names;
00297 
00298   /* check default names */
00299   uint32 tmp = free_names & _gen_station_name_bits[name_class];
00300   if (tmp != 0) return STR_SV_STNAME + FindFirstBit(tmp);
00301 
00302   /* check mine? */
00303   if (HasBit(free_names, M(STR_SV_STNAME_MINES))) {
00304     if (CountMapSquareAround(tile, CMSAMine) >= 2) {
00305       return STR_SV_STNAME_MINES;
00306     }
00307   }
00308 
00309   /* check close enough to town to get central as name? */
00310   if (DistanceMax(tile, t->xy) < 8) {
00311     if (HasBit(free_names, M(STR_SV_STNAME))) return STR_SV_STNAME;
00312 
00313     if (HasBit(free_names, M(STR_SV_STNAME_CENTRAL))) return STR_SV_STNAME_CENTRAL;
00314   }
00315 
00316   /* Check lakeside */
00317   if (HasBit(free_names, M(STR_SV_STNAME_LAKESIDE)) &&
00318       DistanceFromEdge(tile) < 20 &&
00319       CountMapSquareAround(tile, CMSAWater) >= 5) {
00320     return STR_SV_STNAME_LAKESIDE;
00321   }
00322 
00323   /* Check woods */
00324   if (HasBit(free_names, M(STR_SV_STNAME_WOODS)) && (
00325         CountMapSquareAround(tile, CMSATree) >= 8 ||
00326         CountMapSquareAround(tile, CMSAForest) >= 2)
00327       ) {
00328     return _settings_game.game_creation.landscape == LT_TROPIC ? STR_SV_STNAME_FOREST : STR_SV_STNAME_WOODS;
00329   }
00330 
00331   /* check elevation compared to town */
00332   uint z = GetTileZ(tile);
00333   uint z2 = GetTileZ(t->xy);
00334   if (z < z2) {
00335     if (HasBit(free_names, M(STR_SV_STNAME_VALLEY))) return STR_SV_STNAME_VALLEY;
00336   } else if (z > z2) {
00337     if (HasBit(free_names, M(STR_SV_STNAME_HEIGHTS))) return STR_SV_STNAME_HEIGHTS;
00338   }
00339 
00340   /* check direction compared to town */
00341   static const int8 _direction_and_table[] = {
00342     ~( (1 << M(STR_SV_STNAME_WEST))  | (1 << M(STR_SV_STNAME_EAST)) | (1 << M(STR_SV_STNAME_NORTH)) ),
00343     ~( (1 << M(STR_SV_STNAME_SOUTH)) | (1 << M(STR_SV_STNAME_WEST)) | (1 << M(STR_SV_STNAME_NORTH)) ),
00344     ~( (1 << M(STR_SV_STNAME_SOUTH)) | (1 << M(STR_SV_STNAME_EAST)) | (1 << M(STR_SV_STNAME_NORTH)) ),
00345     ~( (1 << M(STR_SV_STNAME_SOUTH)) | (1 << M(STR_SV_STNAME_WEST)) | (1 << M(STR_SV_STNAME_EAST)) ),
00346   };
00347 
00348   free_names &= _direction_and_table[
00349     (TileX(tile) < TileX(t->xy)) +
00350     (TileY(tile) < TileY(t->xy)) * 2];
00351 
00352   tmp = free_names & ((1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 6) | (1 << 7) | (1 << 12) | (1 << 26) | (1 << 27) | (1 << 28) | (1 << 29) | (1 << 30));
00353   return (tmp == 0) ? STR_SV_STNAME_FALLBACK : (STR_SV_STNAME + FindFirstBit(tmp));
00354 }
00355 #undef M
00356 
00362 static Station *GetClosestDeletedStation(TileIndex tile)
00363 {
00364   uint threshold = 8;
00365   Station *best_station = NULL;
00366   Station *st;
00367 
00368   FOR_ALL_STATIONS(st) {
00369     if (!st->IsInUse() && st->owner == _current_company) {
00370       uint cur_dist = DistanceManhattan(tile, st->xy);
00371 
00372       if (cur_dist < threshold) {
00373         threshold = cur_dist;
00374         best_station = st;
00375       }
00376     }
00377   }
00378 
00379   return best_station;
00380 }
00381 
00382 
00383 void Station::GetTileArea(TileArea *ta, StationType type) const
00384 {
00385   switch (type) {
00386     case STATION_RAIL:
00387       *ta = this->train_station;
00388       return;
00389 
00390     case STATION_AIRPORT:
00391       *ta = this->airport;
00392       return;
00393 
00394     case STATION_TRUCK:
00395       *ta = this->truck_station;
00396       return;
00397 
00398     case STATION_BUS:
00399       *ta = this->bus_station;
00400       return;
00401 
00402     case STATION_DOCK:
00403     case STATION_OILRIG:
00404       ta->tile = this->dock_tile;
00405       break;
00406 
00407     default: NOT_REACHED();
00408   }
00409 
00410   ta->w = 1;
00411   ta->h = 1;
00412 }
00413 
00417 void Station::UpdateVirtCoord()
00418 {
00419   Point pt = RemapCoords2(TileX(this->xy) * TILE_SIZE, TileY(this->xy) * TILE_SIZE);
00420 
00421   pt.y -= 32;
00422   if ((this->facilities & FACIL_AIRPORT) && this->airport.type == AT_OILRIG) pt.y -= 16;
00423 
00424   SetDParam(0, this->index);
00425   SetDParam(1, this->facilities);
00426   this->sign.UpdatePosition(pt.x, pt.y, STR_VIEWPORT_STATION);
00427 
00428   SetWindowDirty(WC_STATION_VIEW, this->index);
00429 }
00430 
00432 void UpdateAllStationVirtCoords()
00433 {
00434   BaseStation *st;
00435 
00436   FOR_ALL_BASE_STATIONS(st) {
00437     st->UpdateVirtCoord();
00438   }
00439 }
00440 
00446 static uint GetAcceptanceMask(const Station *st)
00447 {
00448   uint mask = 0;
00449 
00450   for (CargoID i = 0; i < NUM_CARGO; i++) {
00451     if (HasBit(st->goods[i].acceptance_pickup, GoodsEntry::GES_ACCEPTANCE)) mask |= 1 << i;
00452   }
00453   return mask;
00454 }
00455 
00460 static void ShowRejectOrAcceptNews(const Station *st, uint num_items, CargoID *cargo, StringID msg)
00461 {
00462   for (uint i = 0; i < num_items; i++) {
00463     SetDParam(i + 1, CargoSpec::Get(cargo[i])->name);
00464   }
00465 
00466   SetDParam(0, st->index);
00467   AddNewsItem(msg, NS_ACCEPTANCE, NR_STATION, st->index);
00468 }
00469 
00477 CargoArray GetProductionAroundTiles(TileIndex tile, int w, int h, int rad)
00478 {
00479   CargoArray produced;
00480 
00481   int x = TileX(tile);
00482   int y = TileY(tile);
00483 
00484   /* expand the region by rad tiles on each side
00485    * while making sure that we remain inside the board. */
00486   int x2 = min(x + w + rad, MapSizeX());
00487   int x1 = max(x - rad, 0);
00488 
00489   int y2 = min(y + h + rad, MapSizeY());
00490   int y1 = max(y - rad, 0);
00491 
00492   assert(x1 < x2);
00493   assert(y1 < y2);
00494   assert(w > 0);
00495   assert(h > 0);
00496 
00497   TileArea ta(TileXY(x1, y1), TileXY(x2 - 1, y2 - 1));
00498 
00499   /* Loop over all tiles to get the produced cargo of
00500    * everything except industries */
00501   TILE_AREA_LOOP(tile, ta) AddProducedCargo(tile, produced);
00502 
00503   /* Loop over the industries. They produce cargo for
00504    * anything that is within 'rad' from their bounding
00505    * box. As such if you have e.g. a oil well the tile
00506    * area loop might not hit an industry tile while
00507    * the industry would produce cargo for the station.
00508    */
00509   const Industry *i;
00510   FOR_ALL_INDUSTRIES(i) {
00511     if (!ta.Intersects(i->location)) continue;
00512 
00513     for (uint j = 0; j < lengthof(i->produced_cargo); j++) {
00514       CargoID cargo = i->produced_cargo[j];
00515       if (cargo != CT_INVALID) produced[cargo]++;
00516     }
00517   }
00518 
00519   return produced;
00520 }
00521 
00530 CargoArray GetAcceptanceAroundTiles(TileIndex tile, int w, int h, int rad, uint32 *always_accepted)
00531 {
00532   CargoArray acceptance;
00533   if (always_accepted != NULL) *always_accepted = 0;
00534 
00535   int x = TileX(tile);
00536   int y = TileY(tile);
00537 
00538   /* expand the region by rad tiles on each side
00539    * while making sure that we remain inside the board. */
00540   int x2 = min(x + w + rad, MapSizeX());
00541   int y2 = min(y + h + rad, MapSizeY());
00542   int x1 = max(x - rad, 0);
00543   int y1 = max(y - rad, 0);
00544 
00545   assert(x1 < x2);
00546   assert(y1 < y2);
00547   assert(w > 0);
00548   assert(h > 0);
00549 
00550   for (int yc = y1; yc != y2; yc++) {
00551     for (int xc = x1; xc != x2; xc++) {
00552       TileIndex tile = TileXY(xc, yc);
00553       AddAcceptedCargo(tile, acceptance, always_accepted);
00554     }
00555   }
00556 
00557   return acceptance;
00558 }
00559 
00565 void UpdateStationAcceptance(Station *st, bool show_msg)
00566 {
00567   /* old accepted goods types */
00568   uint old_acc = GetAcceptanceMask(st);
00569 
00570   /* And retrieve the acceptance. */
00571   CargoArray acceptance;
00572   if (!st->rect.IsEmpty()) {
00573     acceptance = GetAcceptanceAroundTiles(
00574       TileXY(st->rect.left, st->rect.top),
00575       st->rect.right  - st->rect.left + 1,
00576       st->rect.bottom - st->rect.top  + 1,
00577       st->GetCatchmentRadius(),
00578       &st->always_accepted
00579     );
00580   }
00581 
00582   /* Adjust in case our station only accepts fewer kinds of goods */
00583   for (CargoID i = 0; i < NUM_CARGO; i++) {
00584     uint amt = min(acceptance[i], 15);
00585 
00586     /* Make sure the station can accept the goods type. */
00587     bool is_passengers = IsCargoInClass(i, CC_PASSENGERS);
00588     if ((!is_passengers && !(st->facilities & ~FACIL_BUS_STOP)) ||
00589         (is_passengers && !(st->facilities & ~FACIL_TRUCK_STOP))) {
00590       amt = 0;
00591     }
00592 
00593     SB(st->goods[i].acceptance_pickup, GoodsEntry::GES_ACCEPTANCE, 1, amt >= 8);
00594   }
00595 
00596   /* Only show a message in case the acceptance was actually changed. */
00597   uint new_acc = GetAcceptanceMask(st);
00598   if (old_acc == new_acc) return;
00599 
00600   /* show a message to report that the acceptance was changed? */
00601   if (show_msg && st->owner == _local_company && st->IsInUse()) {
00602     /* List of accept and reject strings for different number of
00603      * cargo types */
00604     static const StringID accept_msg[] = {
00605       STR_NEWS_STATION_NOW_ACCEPTS_CARGO,
00606       STR_NEWS_STATION_NOW_ACCEPTS_CARGO_AND_CARGO,
00607     };
00608     static const StringID reject_msg[] = {
00609       STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO,
00610       STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO_OR_CARGO,
00611     };
00612 
00613     /* Array of accepted and rejected cargo types */
00614     CargoID accepts[2] = { CT_INVALID, CT_INVALID };
00615     CargoID rejects[2] = { CT_INVALID, CT_INVALID };
00616     uint num_acc = 0;
00617     uint num_rej = 0;
00618 
00619     /* Test each cargo type to see if its acceptange has changed */
00620     for (CargoID i = 0; i < NUM_CARGO; i++) {
00621       if (HasBit(new_acc, i)) {
00622         if (!HasBit(old_acc, i) && num_acc < lengthof(accepts)) {
00623           /* New cargo is accepted */
00624           accepts[num_acc++] = i;
00625         }
00626       } else {
00627         if (HasBit(old_acc, i) && num_rej < lengthof(rejects)) {
00628           /* Old cargo is no longer accepted */
00629           rejects[num_rej++] = i;
00630         }
00631       }
00632     }
00633 
00634     /* Show news message if there are any changes */
00635     if (num_acc > 0) ShowRejectOrAcceptNews(st, num_acc, accepts, accept_msg[num_acc - 1]);
00636     if (num_rej > 0) ShowRejectOrAcceptNews(st, num_rej, rejects, reject_msg[num_rej - 1]);
00637   }
00638 
00639   /* redraw the station view since acceptance changed */
00640   SetWindowWidgetDirty(WC_STATION_VIEW, st->index, SVW_ACCEPTLIST);
00641 }
00642 
00643 static void UpdateStationSignCoord(BaseStation *st)
00644 {
00645   const StationRect *r = &st->rect;
00646 
00647   if (r->IsEmpty()) return; // no tiles belong to this station
00648 
00649   /* clamp sign coord to be inside the station rect */
00650   st->xy = TileXY(ClampU(TileX(st->xy), r->left, r->right), ClampU(TileY(st->xy), r->top, r->bottom));
00651   st->UpdateVirtCoord();
00652 }
00653 
00660 static void DeleteStationIfEmpty(BaseStation *st)
00661 {
00662   if (!st->IsInUse()) {
00663     st->delete_ctr = 0;
00664     InvalidateWindowData(WC_STATION_LIST, st->owner, 0);
00665   }
00666   /* station remains but it probably lost some parts - station sign should stay in the station boundaries */
00667   UpdateStationSignCoord(st);
00668 }
00669 
00670 CommandCost ClearTile_Station(TileIndex tile, DoCommandFlag flags);
00671 
00680 CommandCost CheckBuildableTile(TileIndex tile, uint invalid_dirs, int &allowed_z, bool check_bridge = true)
00681 {
00682   if (check_bridge && MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) {
00683     return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
00684   }
00685 
00686   CommandCost ret = EnsureNoVehicleOnGround(tile);
00687   if (ret.Failed()) return ret;
00688 
00689   uint z;
00690   Slope tileh = GetTileSlope(tile, &z);
00691 
00692   /* Prohibit building if
00693    *   1) The tile is "steep" (i.e. stretches two height levels).
00694    *   2) The tile is non-flat and the build_on_slopes switch is disabled.
00695    */
00696   if (IsSteepSlope(tileh) ||
00697       ((!_settings_game.construction.build_on_slopes) && tileh != SLOPE_FLAT)) {
00698     return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
00699   }
00700 
00701   CommandCost cost(EXPENSES_CONSTRUCTION);
00702   int flat_z = z;
00703   if (tileh != SLOPE_FLAT) {
00704     /* Forbid building if the tile faces a slope in a invalid direction. */
00705     if ((HasBit(invalid_dirs, DIAGDIR_NE) && !(tileh & SLOPE_NE)) ||
00706         (HasBit(invalid_dirs, DIAGDIR_SE) && !(tileh & SLOPE_SE)) ||
00707         (HasBit(invalid_dirs, DIAGDIR_SW) && !(tileh & SLOPE_SW)) ||
00708         (HasBit(invalid_dirs, DIAGDIR_NW) && !(tileh & SLOPE_NW))) {
00709       return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
00710     }
00711     cost.AddCost(_price[PR_BUILD_FOUNDATION]);
00712     flat_z += TILE_HEIGHT;
00713   }
00714 
00715   /* The level of this tile must be equal to allowed_z. */
00716   if (allowed_z < 0) {
00717     /* First tile. */
00718     allowed_z = flat_z;
00719   } else if (allowed_z != flat_z) {
00720     return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
00721   }
00722 
00723   return cost;
00724 }
00725 
00732 CommandCost CheckFlatLand(TileArea tile_area, DoCommandFlag flags)
00733 {
00734   CommandCost cost(EXPENSES_CONSTRUCTION);
00735   int allowed_z = -1;
00736 
00737   TILE_AREA_LOOP(tile_cur, tile_area) {
00738     CommandCost ret = CheckBuildableTile(tile_cur, 0, allowed_z);
00739     if (ret.Failed()) return ret;
00740     cost.AddCost(ret);
00741 
00742     ret = DoCommand(tile_cur, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00743     if (ret.Failed()) return ret;
00744     cost.AddCost(ret);
00745   }
00746 
00747   return cost;
00748 }
00749 
00760 static CommandCost CheckFlatLandRailStation(TileArea tile_area, DoCommandFlag flags, uint invalid_dirs, StationID *station, RailType rt, SmallVector<Train *, 4> &affected_vehicles)
00761 {
00762   CommandCost cost(EXPENSES_CONSTRUCTION);
00763   int allowed_z = -1;
00764 
00765   TILE_AREA_LOOP(tile_cur, tile_area) {
00766     CommandCost ret = CheckBuildableTile(tile_cur, invalid_dirs, allowed_z);
00767     if (ret.Failed()) return ret;
00768     cost.AddCost(ret);
00769 
00770     /* if station is set, then we have special handling to allow building on top of already existing stations.
00771      * so station points to INVALID_STATION if we can build on any station.
00772      * Or it points to a station if we're only allowed to build on exactly that station. */
00773     if (station != NULL && IsTileType(tile_cur, MP_STATION)) {
00774       if (!IsRailStation(tile_cur)) {
00775         return ClearTile_Station(tile_cur, DC_AUTO); // get error message
00776       } else {
00777         StationID st = GetStationIndex(tile_cur);
00778         if (*station == INVALID_STATION) {
00779           *station = st;
00780         } else if (*station != st) {
00781           return_cmd_error(STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING);
00782         }
00783       }
00784     } else {
00785       /* Rail type is only valid when building a railway station; if station to
00786        * build isn't a rail station it's INVALID_RAILTYPE. */
00787       if (rt != INVALID_RAILTYPE &&
00788           IsPlainRailTile(tile_cur) && !HasSignals(tile_cur) &&
00789           HasPowerOnRail(GetRailType(tile_cur), rt)) {
00790         /* Allow overbuilding if the tile:
00791          *  - has rail, but no signals
00792          *  - it has exactly one track
00793          *  - the track is in line with the station
00794          *  - the current rail type has power on the to-be-built type (e.g. convert normal rail to el rail)
00795          */
00796         TrackBits tracks = GetTrackBits(tile_cur);
00797         Track track = RemoveFirstTrack(&tracks);
00798         Track expected_track = HasBit(invalid_dirs, DIAGDIR_NE) ? TRACK_X : TRACK_Y;
00799 
00800         if (tracks == TRACK_BIT_NONE && track == expected_track) {
00801           /* Check for trains having a reservation for this tile. */
00802           if (HasBit(GetRailReservationTrackBits(tile_cur), track)) {
00803             Train *v = GetTrainForReservation(tile_cur, track);
00804             if (v != NULL) {
00805               *affected_vehicles.Append() = v;
00806             }
00807           }
00808           CommandCost ret = DoCommand(tile_cur, 0, track, flags, CMD_REMOVE_SINGLE_RAIL);
00809           if (ret.Failed()) return ret;
00810           cost.AddCost(ret);
00811           /* With flags & ~DC_EXEC CmdLandscapeClear would fail since the rail still exists */
00812           continue;
00813         }
00814       }
00815       ret = DoCommand(tile_cur, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00816       if (ret.Failed()) return ret;
00817       cost.AddCost(ret);
00818     }
00819   }
00820 
00821   return cost;
00822 }
00823 
00836 static CommandCost CheckFlatLandRoadStop(TileArea tile_area, DoCommandFlag flags, uint invalid_dirs, bool is_drive_through, bool is_truck_stop, Axis axis, StationID *station, RoadTypes rts)
00837 {
00838   CommandCost cost(EXPENSES_CONSTRUCTION);
00839   int allowed_z = -1;
00840 
00841   TILE_AREA_LOOP(cur_tile, tile_area) {
00842     CommandCost ret = CheckBuildableTile(cur_tile, invalid_dirs, allowed_z);
00843     if (ret.Failed()) return ret;
00844     cost.AddCost(ret);
00845 
00846     /* If station is set, then we have special handling to allow building on top of already existing stations.
00847      * Station points to INVALID_STATION if we can build on any station.
00848      * Or it points to a station if we're only allowed to build on exactly that station. */
00849     if (station != NULL && IsTileType(cur_tile, MP_STATION)) {
00850       if (!IsRoadStop(cur_tile)) {
00851         return ClearTile_Station(cur_tile, DC_AUTO); // Get error message.
00852       } else {
00853         if (is_truck_stop != IsTruckStop(cur_tile) ||
00854             is_drive_through != IsDriveThroughStopTile(cur_tile)) {
00855           return ClearTile_Station(cur_tile, DC_AUTO); // Get error message.
00856         }
00857         /* Drive-through station in the wrong direction. */
00858         if (is_drive_through && IsDriveThroughStopTile(cur_tile) && DiagDirToAxis(GetRoadStopDir(cur_tile)) != axis){
00859           return_cmd_error(STR_ERROR_DRIVE_THROUGH_DIRECTION);
00860         }
00861         StationID st = GetStationIndex(cur_tile);
00862         if (*station == INVALID_STATION) {
00863           *station = st;
00864         } else if (*station != st) {
00865           return_cmd_error(STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING);
00866         }
00867       }
00868     } else {
00869       bool build_over_road = is_drive_through && IsNormalRoadTile(cur_tile);
00870       /* Road bits in the wrong direction. */
00871       RoadBits rb = IsNormalRoadTile(cur_tile) ? GetAllRoadBits(cur_tile) : ROAD_NONE;
00872       if (build_over_road && (rb & (axis == AXIS_X ? ROAD_Y : ROAD_X)) != 0) {
00873         /* Someone was pedantic and *NEEDED* three fracking different error messages. */
00874         switch (CountBits(rb)) {
00875           case 1:
00876             return_cmd_error(STR_ERROR_DRIVE_THROUGH_DIRECTION);
00877 
00878           case 2:
00879             if (rb == ROAD_X || rb == ROAD_Y) return_cmd_error(STR_ERROR_DRIVE_THROUGH_DIRECTION);
00880             return_cmd_error(STR_ERROR_DRIVE_THROUGH_CORNER);
00881 
00882           default: // 3 or 4
00883             return_cmd_error(STR_ERROR_DRIVE_THROUGH_JUNCTION);
00884         }
00885       }
00886 
00887       RoadTypes cur_rts = IsNormalRoadTile(cur_tile) ? GetRoadTypes(cur_tile) : ROADTYPES_NONE;
00888       uint num_roadbits = 0;
00889       if (build_over_road) {
00890         /* There is a road, check if we can build road+tram stop over it. */
00891         if (HasBit(cur_rts, ROADTYPE_ROAD)) {
00892           Owner road_owner = GetRoadOwner(cur_tile, ROADTYPE_ROAD);
00893           if (road_owner == OWNER_TOWN) {
00894             if (!_settings_game.construction.road_stop_on_town_road) return_cmd_error(STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD);
00895           } else if (!_settings_game.construction.road_stop_on_competitor_road && road_owner != OWNER_NONE) {
00896             CommandCost ret = CheckOwnership(road_owner);
00897             if (ret.Failed()) return ret;
00898           }
00899           num_roadbits += CountBits(GetRoadBits(cur_tile, ROADTYPE_ROAD));
00900         }
00901 
00902         /* There is a tram, check if we can build road+tram stop over it. */
00903         if (HasBit(cur_rts, ROADTYPE_TRAM)) {
00904           Owner tram_owner = GetRoadOwner(cur_tile, ROADTYPE_TRAM);
00905           if (!_settings_game.construction.road_stop_on_competitor_road && tram_owner != OWNER_NONE) {
00906             CommandCost ret = CheckOwnership(tram_owner);
00907             if (ret.Failed()) return ret;
00908           }
00909           num_roadbits += CountBits(GetRoadBits(cur_tile, ROADTYPE_TRAM));
00910         }
00911 
00912         /* Take into account existing roadbits. */
00913         rts |= cur_rts;
00914       } else {
00915         ret = DoCommand(cur_tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00916         if (ret.Failed()) return ret;
00917         cost.AddCost(ret);
00918       }
00919 
00920       uint roadbits_to_build = CountBits(rts) * 2 - num_roadbits;
00921       cost.AddCost(_price[PR_BUILD_ROAD] * roadbits_to_build);
00922     }
00923   }
00924 
00925   return cost;
00926 }
00927 
00935 CommandCost CanExpandRailStation(const BaseStation *st, TileArea &new_ta, Axis axis)
00936 {
00937   TileArea cur_ta = st->train_station;
00938 
00939   /* determine new size of train station region.. */
00940   int x = min(TileX(cur_ta.tile), TileX(new_ta.tile));
00941   int y = min(TileY(cur_ta.tile), TileY(new_ta.tile));
00942   new_ta.w = max(TileX(cur_ta.tile) + cur_ta.w, TileX(new_ta.tile) + new_ta.w) - x;
00943   new_ta.h = max(TileY(cur_ta.tile) + cur_ta.h, TileY(new_ta.tile) + new_ta.h) - y;
00944   new_ta.tile = TileXY(x, y);
00945 
00946   /* make sure the final size is not too big. */
00947   if (new_ta.w > _settings_game.station.station_spread || new_ta.h > _settings_game.station.station_spread) {
00948     return_cmd_error(STR_ERROR_STATION_TOO_SPREAD_OUT);
00949   }
00950 
00951   return CommandCost();
00952 }
00953 
00954 static inline byte *CreateSingle(byte *layout, int n)
00955 {
00956   int i = n;
00957   do *layout++ = 0; while (--i);
00958   layout[((n - 1) >> 1) - n] = 2;
00959   return layout;
00960 }
00961 
00962 static inline byte *CreateMulti(byte *layout, int n, byte b)
00963 {
00964   int i = n;
00965   do *layout++ = b; while (--i);
00966   if (n > 4) {
00967     layout[0 - n] = 0;
00968     layout[n - 1 - n] = 0;
00969   }
00970   return layout;
00971 }
00972 
00980 void GetStationLayout(byte *layout, int numtracks, int plat_len, const StationSpec *statspec)
00981 {
00982   if (statspec != NULL && statspec->lengths >= plat_len &&
00983       statspec->platforms[plat_len - 1] >= numtracks &&
00984       statspec->layouts[plat_len - 1][numtracks - 1]) {
00985     /* Custom layout defined, follow it. */
00986     memcpy(layout, statspec->layouts[plat_len - 1][numtracks - 1],
00987       plat_len * numtracks);
00988     return;
00989   }
00990 
00991   if (plat_len == 1) {
00992     CreateSingle(layout, numtracks);
00993   } else {
00994     if (numtracks & 1) layout = CreateSingle(layout, plat_len);
00995     numtracks >>= 1;
00996 
00997     while (--numtracks >= 0) {
00998       layout = CreateMulti(layout, plat_len, 4);
00999       layout = CreateMulti(layout, plat_len, 6);
01000     }
01001   }
01002 }
01003 
01015 template <class T, StringID error_message>
01016 CommandCost FindJoiningBaseStation(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, T **st)
01017 {
01018   assert(*st == NULL);
01019   bool check_surrounding = true;
01020 
01021   if (_settings_game.station.adjacent_stations) {
01022     if (existing_station != INVALID_STATION) {
01023       if (adjacent && existing_station != station_to_join) {
01024         /* You can't build an adjacent station over the top of one that
01025          * already exists. */
01026         return_cmd_error(error_message);
01027       } else {
01028         /* Extend the current station, and don't check whether it will
01029          * be near any other stations. */
01030         *st = T::GetIfValid(existing_station);
01031         check_surrounding = (*st == NULL);
01032       }
01033     } else {
01034       /* There's no station here. Don't check the tiles surrounding this
01035        * one if the company wanted to build an adjacent station. */
01036       if (adjacent) check_surrounding = false;
01037     }
01038   }
01039 
01040   if (check_surrounding) {
01041     /* Make sure there are no similar stations around us. */
01042     CommandCost ret = GetStationAround(ta, existing_station, st);
01043     if (ret.Failed()) return ret;
01044   }
01045 
01046   /* Distant join */
01047   if (*st == NULL && station_to_join != INVALID_STATION) *st = T::GetIfValid(station_to_join);
01048 
01049   return CommandCost();
01050 }
01051 
01061 static CommandCost FindJoiningStation(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, Station **st)
01062 {
01063   return FindJoiningBaseStation<Station, STR_ERROR_MUST_REMOVE_RAILWAY_STATION_FIRST>(existing_station, station_to_join, adjacent, ta, st);
01064 }
01065 
01075 CommandCost FindJoiningWaypoint(StationID existing_waypoint, StationID waypoint_to_join, bool adjacent, TileArea ta, Waypoint **wp)
01076 {
01077   return FindJoiningBaseStation<Waypoint, STR_ERROR_MUST_REMOVE_RAILWAYPOINT_FIRST>(existing_waypoint, waypoint_to_join, adjacent, ta, wp);
01078 }
01079 
01097 CommandCost CmdBuildRailStation(TileIndex tile_org, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01098 {
01099   /* Unpack parameters */
01100   RailType rt    = Extract<RailType, 0, 4>(p1);
01101   Axis axis      = Extract<Axis, 4, 1>(p1);
01102   byte numtracks = GB(p1,  8, 8);
01103   byte plat_len  = GB(p1, 16, 8);
01104   bool adjacent  = HasBit(p1, 24);
01105 
01106   StationClassID spec_class = Extract<StationClassID, 0, 8>(p2);
01107   byte spec_index           = GB(p2, 8, 8);
01108   StationID station_to_join = GB(p2, 16, 16);
01109 
01110   /* Does the authority allow this? */
01111   CommandCost ret = CheckIfAuthorityAllowsNewStation(tile_org, flags);
01112   if (ret.Failed()) return ret;
01113 
01114   if (!ValParamRailtype(rt)) return CMD_ERROR;
01115 
01116   /* Check if the given station class is valid */
01117   if ((uint)spec_class >= StationClass::GetCount() || spec_class == STAT_CLASS_WAYP) return CMD_ERROR;
01118   if (spec_index >= StationClass::GetCount(spec_class)) return CMD_ERROR;
01119   if (plat_len == 0 || numtracks == 0) return CMD_ERROR;
01120 
01121   int w_org, h_org;
01122   if (axis == AXIS_X) {
01123     w_org = plat_len;
01124     h_org = numtracks;
01125   } else {
01126     h_org = plat_len;
01127     w_org = numtracks;
01128   }
01129 
01130   bool reuse = (station_to_join != NEW_STATION);
01131   if (!reuse) station_to_join = INVALID_STATION;
01132   bool distant_join = (station_to_join != INVALID_STATION);
01133 
01134   if (distant_join && (!_settings_game.station.distant_join_stations || !Station::IsValidID(station_to_join))) return CMD_ERROR;
01135 
01136   if (h_org > _settings_game.station.station_spread || w_org > _settings_game.station.station_spread) return CMD_ERROR;
01137 
01138   /* these values are those that will be stored in train_tile and station_platforms */
01139   TileArea new_location(tile_org, w_org, h_org);
01140 
01141   /* Make sure the area below consists of clear tiles. (OR tiles belonging to a certain rail station) */
01142   StationID est = INVALID_STATION;
01143   SmallVector<Train *, 4> affected_vehicles;
01144   /* Clear the land below the station. */
01145   CommandCost cost = CheckFlatLandRailStation(TileArea(tile_org, w_org, h_org), flags, 5 << axis, &est, rt, affected_vehicles);
01146   if (cost.Failed()) return cost;
01147   /* Add construction expenses. */
01148   cost.AddCost((numtracks * _price[PR_BUILD_STATION_RAIL] + _price[PR_BUILD_STATION_RAIL_LENGTH]) * plat_len);
01149   cost.AddCost(numtracks * plat_len * RailBuildCost(rt));
01150 
01151   Station *st = NULL;
01152   ret = FindJoiningStation(est, station_to_join, adjacent, new_location, &st);
01153   if (ret.Failed()) return ret;
01154 
01155   /* See if there is a deleted station close to us. */
01156   if (st == NULL && reuse) st = GetClosestDeletedStation(tile_org);
01157 
01158   if (st != NULL) {
01159     /* Reuse an existing station. */
01160     if (st->owner != _current_company) return_cmd_error(STR_ERROR_TOO_CLOSE_TO_ANOTHER_STATION);
01161 
01162     if (st->train_station.tile != INVALID_TILE) {
01163       CommandCost ret = CanExpandRailStation(st, new_location, axis);
01164       if (ret.Failed()) return ret;
01165     }
01166 
01167     /* XXX can't we pack this in the "else" part of the if above? */
01168     CommandCost ret = st->rect.BeforeAddRect(tile_org, w_org, h_org, StationRect::ADD_TEST);
01169     if (ret.Failed()) return ret;
01170   } else {
01171     /* allocate and initialize new station */
01172     if (!Station::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_STATIONS_LOADING);
01173 
01174     if (flags & DC_EXEC) {
01175       st = new Station(tile_org);
01176 
01177       st->town = ClosestTownFromTile(tile_org, UINT_MAX);
01178       st->string_id = GenerateStationName(st, tile_org, STATIONNAMING_RAIL);
01179 
01180       if (Company::IsValidID(_current_company)) {
01181         SetBit(st->town->have_ratings, _current_company);
01182       }
01183     }
01184   }
01185 
01186   /* Check if we can allocate a custom stationspec to this station */
01187   const StationSpec *statspec = StationClass::Get(spec_class, spec_index);
01188   int specindex = AllocateSpecToStation(statspec, st, (flags & DC_EXEC) != 0);
01189   if (specindex == -1) return_cmd_error(STR_ERROR_TOO_MANY_STATION_SPECS);
01190 
01191   if (statspec != NULL) {
01192     /* Perform NewStation checks */
01193 
01194     /* Check if the station size is permitted */
01195     if (HasBit(statspec->disallowed_platforms, numtracks - 1) || HasBit(statspec->disallowed_lengths, plat_len - 1)) {
01196       return CMD_ERROR;
01197     }
01198 
01199     /* Check if the station is buildable */
01200     if (HasBit(statspec->callback_mask, CBM_STATION_AVAIL) && GB(GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE), 0, 8) == 0) {
01201       return CMD_ERROR;
01202     }
01203   }
01204 
01205   if (flags & DC_EXEC) {
01206     TileIndexDiff tile_delta;
01207     byte *layout_ptr;
01208     byte numtracks_orig;
01209     Track track;
01210 
01211     st->train_station = new_location;
01212     st->AddFacility(FACIL_TRAIN, new_location.tile);
01213 
01214     st->rect.BeforeAddRect(tile_org, w_org, h_org, StationRect::ADD_TRY);
01215 
01216     if (statspec != NULL) {
01217       /* Include this station spec's animation trigger bitmask
01218        * in the station's cached copy. */
01219       st->cached_anim_triggers |= statspec->animation.triggers;
01220     }
01221 
01222     tile_delta = (axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
01223     track = AxisToTrack(axis);
01224 
01225     layout_ptr = AllocaM(byte, numtracks * plat_len);
01226     GetStationLayout(layout_ptr, numtracks, plat_len, statspec);
01227 
01228     numtracks_orig = numtracks;
01229 
01230     Company *c = Company::Get(st->owner);
01231 
01232     do {
01233       TileIndex tile = tile_org;
01234       int w = plat_len;
01235       do {
01236         byte layout = *layout_ptr++;
01237         if (IsRailStationTile(tile) && HasStationReservation(tile)) {
01238           /* Check for trains having a reservation for this tile. */
01239           Train *v = GetTrainForReservation(tile, AxisToTrack(GetRailStationAxis(tile)));
01240           if (v != NULL) {
01241             FreeTrainTrackReservation(v);
01242             *affected_vehicles.Append() = v;
01243             if (IsRailStationTile(v->tile)) SetRailStationPlatformReservation(v->tile, TrackdirToExitdir(v->GetVehicleTrackdir()), false);
01244             for (; v->Next() != NULL; v = v->Next()) { }
01245             if (IsRailStationTile(v->tile)) SetRailStationPlatformReservation(v->tile, TrackdirToExitdir(ReverseTrackdir(v->GetVehicleTrackdir())), false);
01246           }
01247         }
01248 
01249         /* Railtype can change when overbuilding. */
01250         if (IsRailStationTile(tile)) {
01251           if (!IsStationTileBlocked(tile)) c->rail_infrastructure[GetRailType(tile)]--;
01252           c->station_infrastructure--;
01253         }
01254 
01255         /* Remove animation if overbuilding */
01256         DeleteAnimatedTile(tile);
01257         byte old_specindex = HasStationTileRail(tile) ? GetCustomStationSpecIndex(tile) : 0;
01258         MakeRailStation(tile, st->owner, st->index, axis, layout & ~1, rt);
01259         /* Free the spec if we overbuild something */
01260         DeallocateSpecFromStation(st, old_specindex);
01261 
01262         SetCustomStationSpecIndex(tile, specindex);
01263         SetStationTileRandomBits(tile, GB(Random(), 0, 4));
01264         SetAnimationFrame(tile, 0);
01265 
01266         if (!IsStationTileBlocked(tile)) c->rail_infrastructure[rt]++;
01267         c->station_infrastructure++;
01268 
01269         if (statspec != NULL) {
01270           /* Use a fixed axis for GetPlatformInfo as our platforms / numtracks are always the right way around */
01271           uint32 platinfo = GetPlatformInfo(AXIS_X, 0, plat_len, numtracks_orig, plat_len - w, numtracks_orig - numtracks, false);
01272 
01273           /* As the station is not yet completely finished, the station does not yet exist. */
01274           uint16 callback = GetStationCallback(CBID_STATION_TILE_LAYOUT, platinfo, 0, statspec, NULL, tile);
01275           if (callback != CALLBACK_FAILED && callback < 8) SetStationGfx(tile, (callback & ~1) + axis);
01276 
01277           /* Trigger station animation -- after building? */
01278           TriggerStationAnimation(st, tile, SAT_BUILT);
01279         }
01280 
01281         tile += tile_delta;
01282       } while (--w);
01283       AddTrackToSignalBuffer(tile_org, track, _current_company);
01284       YapfNotifyTrackLayoutChange(tile_org, track);
01285       tile_org += tile_delta ^ TileDiffXY(1, 1); // perpendicular to tile_delta
01286     } while (--numtracks);
01287 
01288     for (uint i = 0; i < affected_vehicles.Length(); ++i) {
01289       /* Restore reservations of trains. */
01290       Train *v = affected_vehicles[i];
01291       if (IsRailStationTile(v->tile)) SetRailStationPlatformReservation(v->tile, TrackdirToExitdir(v->GetVehicleTrackdir()), true);
01292       TryPathReserve(v, true, true);
01293       for (; v->Next() != NULL; v = v->Next()) { }
01294       if (IsRailStationTile(v->tile)) SetRailStationPlatformReservation(v->tile, TrackdirToExitdir(ReverseTrackdir(v->GetVehicleTrackdir())), true);
01295     }
01296 
01297     st->MarkTilesDirty(false);
01298     st->UpdateVirtCoord();
01299     UpdateStationAcceptance(st, false);
01300     st->RecomputeIndustriesNear();
01301     InvalidateWindowData(WC_SELECT_STATION, 0, 0);
01302     InvalidateWindowData(WC_STATION_LIST, st->owner, 0);
01303     SetWindowWidgetDirty(WC_STATION_VIEW, st->index, SVW_TRAINS);
01304     DirtyCompanyInfrastructureWindows(st->owner);
01305   }
01306 
01307   return cost;
01308 }
01309 
01310 static void MakeRailStationAreaSmaller(BaseStation *st)
01311 {
01312   TileArea ta = st->train_station;
01313 
01314 restart:
01315 
01316   /* too small? */
01317   if (ta.w != 0 && ta.h != 0) {
01318     /* check the left side, x = constant, y changes */
01319     for (uint i = 0; !st->TileBelongsToRailStation(ta.tile + TileDiffXY(0, i));) {
01320       /* the left side is unused? */
01321       if (++i == ta.h) {
01322         ta.tile += TileDiffXY(1, 0);
01323         ta.w--;
01324         goto restart;
01325       }
01326     }
01327 
01328     /* check the right side, x = constant, y changes */
01329     for (uint i = 0; !st->TileBelongsToRailStation(ta.tile + TileDiffXY(ta.w - 1, i));) {
01330       /* the right side is unused? */
01331       if (++i == ta.h) {
01332         ta.w--;
01333         goto restart;
01334       }
01335     }
01336 
01337     /* check the upper side, y = constant, x changes */
01338     for (uint i = 0; !st->TileBelongsToRailStation(ta.tile + TileDiffXY(i, 0));) {
01339       /* the left side is unused? */
01340       if (++i == ta.w) {
01341         ta.tile += TileDiffXY(0, 1);
01342         ta.h--;
01343         goto restart;
01344       }
01345     }
01346 
01347     /* check the lower side, y = constant, x changes */
01348     for (uint i = 0; !st->TileBelongsToRailStation(ta.tile + TileDiffXY(i, ta.h - 1));) {
01349       /* the left side is unused? */
01350       if (++i == ta.w) {
01351         ta.h--;
01352         goto restart;
01353       }
01354     }
01355   } else {
01356     ta.Clear();
01357   }
01358 
01359   st->train_station = ta;
01360 }
01361 
01372 template <class T>
01373 CommandCost RemoveFromRailBaseStation(TileArea ta, SmallVector<T *, 4> &affected_stations, DoCommandFlag flags, Money removal_cost, bool keep_rail)
01374 {
01375   /* Count of the number of tiles removed */
01376   int quantity = 0;
01377   CommandCost total_cost(EXPENSES_CONSTRUCTION);
01378 
01379   /* Do the action for every tile into the area */
01380   TILE_AREA_LOOP(tile, ta) {
01381     /* Make sure the specified tile is a rail station */
01382     if (!HasStationTileRail(tile)) continue;
01383 
01384     /* If there is a vehicle on ground, do not allow to remove (flood) the tile */
01385     CommandCost ret = EnsureNoVehicleOnGround(tile);
01386     if (ret.Failed()) continue;
01387 
01388     /* Check ownership of station */
01389     T *st = T::GetByTile(tile);
01390     if (st == NULL) continue;
01391 
01392     if (_current_company != OWNER_WATER) {
01393       CommandCost ret = CheckOwnership(st->owner);
01394       if (ret.Failed()) continue;
01395     }
01396 
01397     /* If we reached here, the tile is valid so increase the quantity of tiles we will remove */
01398     quantity++;
01399 
01400     if (keep_rail || IsStationTileBlocked(tile)) {
01401       /* Don't refund the 'steel' of the track when we keep the
01402        *  rail, or when the tile didn't have any rail at all. */
01403       total_cost.AddCost(-_price[PR_CLEAR_RAIL]);
01404     }
01405 
01406     if (flags & DC_EXEC) {
01407       /* read variables before the station tile is removed */
01408       uint specindex = GetCustomStationSpecIndex(tile);
01409       Track track = GetRailStationTrack(tile);
01410       Owner owner = GetTileOwner(tile);
01411       RailType rt = GetRailType(tile);
01412       Train *v = NULL;
01413 
01414       if (HasStationReservation(tile)) {
01415         v = GetTrainForReservation(tile, track);
01416         if (v != NULL) {
01417           /* Free train reservation. */
01418           FreeTrainTrackReservation(v);
01419           if (IsRailStationTile(v->tile)) SetRailStationPlatformReservation(v->tile, TrackdirToExitdir(v->GetVehicleTrackdir()), false);
01420           Vehicle *temp = v;
01421           for (; temp->Next() != NULL; temp = temp->Next()) { }
01422           if (IsRailStationTile(temp->tile)) SetRailStationPlatformReservation(temp->tile, TrackdirToExitdir(ReverseTrackdir(temp->GetVehicleTrackdir())), false);
01423         }
01424       }
01425 
01426       bool build_rail = keep_rail && !IsStationTileBlocked(tile);
01427       if (!build_rail && !IsStationTileBlocked(tile)) Company::Get(owner)->rail_infrastructure[rt]--;
01428 
01429       DoClearSquare(tile);
01430       DeleteNewGRFInspectWindow(GSF_STATIONS, tile);
01431       if (build_rail) MakeRailNormal(tile, owner, TrackToTrackBits(track), rt);
01432       Company::Get(owner)->station_infrastructure--;
01433       DirtyCompanyInfrastructureWindows(owner);
01434 
01435       st->rect.AfterRemoveTile(st, tile);
01436       AddTrackToSignalBuffer(tile, track, owner);
01437       YapfNotifyTrackLayoutChange(tile, track);
01438 
01439       DeallocateSpecFromStation(st, specindex);
01440 
01441       affected_stations.Include(st);
01442 
01443       if (v != NULL) {
01444         /* Restore station reservation. */
01445         if (IsRailStationTile(v->tile)) SetRailStationPlatformReservation(v->tile, TrackdirToExitdir(v->GetVehicleTrackdir()), true);
01446         TryPathReserve(v, true, true);
01447         for (; v->Next() != NULL; v = v->Next()) { }
01448         if (IsRailStationTile(v->tile)) SetRailStationPlatformReservation(v->tile, TrackdirToExitdir(ReverseTrackdir(v->GetVehicleTrackdir())), true);
01449       }
01450     }
01451   }
01452 
01453   if (quantity == 0) return_cmd_error(STR_ERROR_THERE_IS_NO_STATION);
01454 
01455   for (T **stp = affected_stations.Begin(); stp != affected_stations.End(); stp++) {
01456     T *st = *stp;
01457 
01458     /* now we need to make the "spanned" area of the railway station smaller
01459      * if we deleted something at the edges.
01460      * we also need to adjust train_tile. */
01461     MakeRailStationAreaSmaller(st);
01462     UpdateStationSignCoord(st);
01463 
01464     /* if we deleted the whole station, delete the train facility. */
01465     if (st->train_station.tile == INVALID_TILE) {
01466       st->facilities &= ~FACIL_TRAIN;
01467       SetWindowWidgetDirty(WC_STATION_VIEW, st->index, SVW_TRAINS);
01468       st->UpdateVirtCoord();
01469       DeleteStationIfEmpty(st);
01470     }
01471   }
01472 
01473   total_cost.AddCost(quantity * removal_cost);
01474   return total_cost;
01475 }
01476 
01488 CommandCost CmdRemoveFromRailStation(TileIndex start, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01489 {
01490   TileIndex end = p1 == 0 ? start : p1;
01491   if (start >= MapSize() || end >= MapSize()) return CMD_ERROR;
01492 
01493   TileArea ta(start, end);
01494   SmallVector<Station *, 4> affected_stations;
01495 
01496   CommandCost ret = RemoveFromRailBaseStation(ta, affected_stations, flags, _price[PR_CLEAR_STATION_RAIL], HasBit(p2, 0));
01497   if (ret.Failed()) return ret;
01498 
01499   /* Do all station specific functions here. */
01500   for (Station **stp = affected_stations.Begin(); stp != affected_stations.End(); stp++) {
01501     Station *st = *stp;
01502 
01503     if (st->train_station.tile == INVALID_TILE) SetWindowWidgetDirty(WC_STATION_VIEW, st->index, SVW_TRAINS);
01504     st->MarkTilesDirty(false);
01505     st->RecomputeIndustriesNear();
01506   }
01507 
01508   /* Now apply the rail cost to the number that we deleted */
01509   return ret;
01510 }
01511 
01523 CommandCost CmdRemoveFromRailWaypoint(TileIndex start, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01524 {
01525   TileIndex end = p1 == 0 ? start : p1;
01526   if (start >= MapSize() || end >= MapSize()) return CMD_ERROR;
01527 
01528   TileArea ta(start, end);
01529   SmallVector<Waypoint *, 4> affected_stations;
01530 
01531   return RemoveFromRailBaseStation(ta, affected_stations, flags, _price[PR_CLEAR_WAYPOINT_RAIL], HasBit(p2, 0));
01532 }
01533 
01534 
01542 template <class T>
01543 CommandCost RemoveRailStation(T *st, DoCommandFlag flags)
01544 {
01545   /* Current company owns the station? */
01546   if (_current_company != OWNER_WATER) {
01547     CommandCost ret = CheckOwnership(st->owner);
01548     if (ret.Failed()) return ret;
01549   }
01550 
01551   /* determine width and height of platforms */
01552   TileArea ta = st->train_station;
01553 
01554   assert(ta.w != 0 && ta.h != 0);
01555 
01556   CommandCost cost(EXPENSES_CONSTRUCTION);
01557   /* clear all areas of the station */
01558   TILE_AREA_LOOP(tile, ta) {
01559     /* only remove tiles that are actually train station tiles */
01560     if (!st->TileBelongsToRailStation(tile)) continue;
01561 
01562     CommandCost ret = EnsureNoVehicleOnGround(tile);
01563     if (ret.Failed()) return ret;
01564 
01565     cost.AddCost(_price[PR_CLEAR_STATION_RAIL]);
01566     if (flags & DC_EXEC) {
01567       /* read variables before the station tile is removed */
01568       Track track = GetRailStationTrack(tile);
01569       Owner owner = GetTileOwner(tile); // _current_company can be OWNER_WATER
01570       Train *v = NULL;
01571       if (HasStationReservation(tile)) {
01572         v = GetTrainForReservation(tile, track);
01573         if (v != NULL) FreeTrainTrackReservation(v);
01574       }
01575       if (!IsStationTileBlocked(tile)) Company::Get(owner)->rail_infrastructure[GetRailType(tile)]--;
01576       Company::Get(owner)->station_infrastructure--;
01577       DoClearSquare(tile);
01578       DeleteNewGRFInspectWindow(GSF_STATIONS, tile);
01579       AddTrackToSignalBuffer(tile, track, owner);
01580       YapfNotifyTrackLayoutChange(tile, track);
01581       if (v != NULL) TryPathReserve(v, true);
01582     }
01583   }
01584 
01585   if (flags & DC_EXEC) {
01586     st->rect.AfterRemoveRect(st, st->train_station);
01587 
01588     st->train_station.Clear();
01589 
01590     st->facilities &= ~FACIL_TRAIN;
01591 
01592     free(st->speclist);
01593     st->num_specs = 0;
01594     st->speclist  = NULL;
01595     st->cached_anim_triggers = 0;
01596 
01597     DirtyCompanyInfrastructureWindows(st->owner);
01598     SetWindowWidgetDirty(WC_STATION_VIEW, st->index, SVW_TRAINS);
01599     st->UpdateVirtCoord();
01600     DeleteStationIfEmpty(st);
01601   }
01602 
01603   return cost;
01604 }
01605 
01612 static CommandCost RemoveRailStation(TileIndex tile, DoCommandFlag flags)
01613 {
01614   /* if there is flooding, remove platforms tile by tile */
01615   if (_current_company == OWNER_WATER) {
01616     return DoCommand(tile, 0, 0, DC_EXEC, CMD_REMOVE_FROM_RAIL_STATION);
01617   }
01618 
01619   Station *st = Station::GetByTile(tile);
01620   CommandCost cost = RemoveRailStation(st, flags);
01621 
01622   if (flags & DC_EXEC) st->RecomputeIndustriesNear();
01623 
01624   return cost;
01625 }
01626 
01633 static CommandCost RemoveRailWaypoint(TileIndex tile, DoCommandFlag flags)
01634 {
01635   /* if there is flooding, remove waypoints tile by tile */
01636   if (_current_company == OWNER_WATER) {
01637     return DoCommand(tile, 0, 0, DC_EXEC, CMD_REMOVE_FROM_RAIL_WAYPOINT);
01638   }
01639 
01640   return RemoveRailStation(Waypoint::GetByTile(tile), flags);
01641 }
01642 
01643 
01649 static RoadStop **FindRoadStopSpot(bool truck_station, Station *st)
01650 {
01651   RoadStop **primary_stop = (truck_station) ? &st->truck_stops : &st->bus_stops;
01652 
01653   if (*primary_stop == NULL) {
01654     /* we have no roadstop of the type yet, so write a "primary stop" */
01655     return primary_stop;
01656   } else {
01657     /* there are stops already, so append to the end of the list */
01658     RoadStop *stop = *primary_stop;
01659     while (stop->next != NULL) stop = stop->next;
01660     return &stop->next;
01661   }
01662 }
01663 
01664 static CommandCost RemoveRoadStop(TileIndex tile, DoCommandFlag flags);
01665 
01675 static CommandCost FindJoiningRoadStop(StationID existing_stop, StationID station_to_join, bool adjacent, TileArea ta, Station **st)
01676 {
01677   return FindJoiningBaseStation<Station, STR_ERROR_MUST_REMOVE_ROAD_STOP_FIRST>(existing_stop, station_to_join, adjacent, ta, st);
01678 }
01679 
01695 CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01696 {
01697   bool type = HasBit(p2, 0);
01698   bool is_drive_through = HasBit(p2, 1);
01699   RoadTypes rts = Extract<RoadTypes, 2, 2>(p2);
01700   StationID station_to_join = GB(p2, 16, 16);
01701   bool reuse = (station_to_join != NEW_STATION);
01702   if (!reuse) station_to_join = INVALID_STATION;
01703   bool distant_join = (station_to_join != INVALID_STATION);
01704 
01705   uint8 width = (uint8)GB(p1, 0, 8);
01706   uint8 lenght = (uint8)GB(p1, 8, 8);
01707 
01708   /* Check if the requested road stop is too big */
01709   if (width > _settings_game.station.station_spread || lenght > _settings_game.station.station_spread) return_cmd_error(STR_ERROR_STATION_TOO_SPREAD_OUT);
01710   /* Check for incorrect width / lenght. */
01711   if (width == 0 || lenght == 0) return CMD_ERROR;
01712   /* Check if the first tile and the last tile are valid */
01713   if (!IsValidTile(tile) || TileAddWrap(tile, width - 1, lenght - 1) == INVALID_TILE) return CMD_ERROR;
01714 
01715   TileArea roadstop_area(tile, width, lenght);
01716 
01717   if (distant_join && (!_settings_game.station.distant_join_stations || !Station::IsValidID(station_to_join))) return CMD_ERROR;
01718 
01719   if (!HasExactlyOneBit(rts) || !HasRoadTypesAvail(_current_company, rts)) return CMD_ERROR;
01720 
01721   /* Trams only have drive through stops */
01722   if (!is_drive_through && HasBit(rts, ROADTYPE_TRAM)) return CMD_ERROR;
01723 
01724   DiagDirection ddir = Extract<DiagDirection, 6, 2>(p2);
01725 
01726   /* Safeguard the parameters. */
01727   if (!IsValidDiagDirection(ddir)) return CMD_ERROR;
01728   /* If it is a drive-through stop, check for valid axis. */
01729   if (is_drive_through && !IsValidAxis((Axis)ddir)) return CMD_ERROR;
01730 
01731   CommandCost ret = CheckIfAuthorityAllowsNewStation(tile, flags);
01732   if (ret.Failed()) return ret;
01733 
01734   /* Total road stop cost. */
01735   CommandCost cost(EXPENSES_CONSTRUCTION, roadstop_area.w * roadstop_area.h * _price[type ? PR_BUILD_STATION_TRUCK : PR_BUILD_STATION_BUS]);
01736   StationID est = INVALID_STATION;
01737   ret = CheckFlatLandRoadStop(roadstop_area, flags, is_drive_through ? 5 << ddir : 1 << ddir, is_drive_through, type, DiagDirToAxis(ddir), &est, rts);
01738   if (ret.Failed()) return ret;
01739   cost.AddCost(ret);
01740 
01741   Station *st = NULL;
01742   ret = FindJoiningRoadStop(est, station_to_join, HasBit(p2, 5), roadstop_area, &st);
01743   if (ret.Failed()) return ret;
01744 
01745   /* Find a deleted station close to us */
01746   if (st == NULL && reuse) st = GetClosestDeletedStation(tile);
01747 
01748   /* Check if this number of road stops can be allocated. */
01749   if (!RoadStop::CanAllocateItem(roadstop_area.w * roadstop_area.h)) return_cmd_error(type ? STR_ERROR_TOO_MANY_TRUCK_STOPS : STR_ERROR_TOO_MANY_BUS_STOPS);
01750 
01751   if (st != NULL) {
01752     if (st->owner != _current_company) {
01753       return_cmd_error(STR_ERROR_TOO_CLOSE_TO_ANOTHER_STATION);
01754     }
01755 
01756     CommandCost ret = st->rect.BeforeAddRect(roadstop_area.tile, roadstop_area.w, roadstop_area.h, StationRect::ADD_TEST);
01757     if (ret.Failed()) return ret;
01758   } else {
01759     /* allocate and initialize new station */
01760     if (!Station::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_STATIONS_LOADING);
01761 
01762     if (flags & DC_EXEC) {
01763       st = new Station(tile);
01764 
01765       st->town = ClosestTownFromTile(tile, UINT_MAX);
01766       st->string_id = GenerateStationName(st, tile, STATIONNAMING_ROAD);
01767 
01768       if (Company::IsValidID(_current_company)) {
01769         SetBit(st->town->have_ratings, _current_company);
01770       }
01771     }
01772   }
01773 
01774   if (flags & DC_EXEC) {
01775     /* Check every tile in the area. */
01776     TILE_AREA_LOOP(cur_tile, roadstop_area) {
01777       RoadTypes cur_rts = GetRoadTypes(cur_tile);
01778       Owner road_owner = HasBit(cur_rts, ROADTYPE_ROAD) ? GetRoadOwner(cur_tile, ROADTYPE_ROAD) : _current_company;
01779       Owner tram_owner = HasBit(cur_rts, ROADTYPE_TRAM) ? GetRoadOwner(cur_tile, ROADTYPE_TRAM) : _current_company;
01780 
01781       if (IsTileType(cur_tile, MP_STATION) && IsRoadStop(cur_tile)) {
01782         RemoveRoadStop(cur_tile, flags);
01783       }
01784 
01785       RoadStop *road_stop = new RoadStop(cur_tile);
01786       /* Insert into linked list of RoadStops. */
01787       RoadStop **currstop = FindRoadStopSpot(type, st);
01788       *currstop = road_stop;
01789 
01790       if (type) {
01791         st->truck_station.Add(cur_tile);
01792       } else {
01793         st->bus_station.Add(cur_tile);
01794       }
01795 
01796       /* Initialize an empty station. */
01797       st->AddFacility((type) ? FACIL_TRUCK_STOP : FACIL_BUS_STOP, cur_tile);
01798 
01799       st->rect.BeforeAddTile(cur_tile, StationRect::ADD_TRY);
01800 
01801       RoadStopType rs_type = type ? ROADSTOP_TRUCK : ROADSTOP_BUS;
01802       if (is_drive_through) {
01803         /* Update company infrastructure counts. If the current tile is a normal
01804          * road tile, count only the new road bits needed to get a full diagonal road. */
01805         RoadType rt;
01806         FOR_EACH_SET_ROADTYPE(rt, cur_rts | rts) {
01807           Company *c = Company::GetIfValid(rt == ROADTYPE_ROAD ? road_owner : tram_owner);
01808           if (c != NULL) {
01809             c->road_infrastructure[rt] += 2 - (IsNormalRoadTile(cur_tile) && HasBit(cur_rts, rt) ? CountBits(GetRoadBits(cur_tile, rt)) : 0);
01810             DirtyCompanyInfrastructureWindows(c->index);
01811           }
01812         }
01813 
01814         MakeDriveThroughRoadStop(cur_tile, st->owner, road_owner, tram_owner, st->index, rs_type, rts | cur_rts, DiagDirToAxis(ddir));
01815         road_stop->MakeDriveThrough();
01816       } else {
01817         /* Non-drive-through stop never overbuild and always count as two road bits. */
01818         Company::Get(st->owner)->road_infrastructure[FIND_FIRST_BIT(rts)] += 2;
01819         MakeRoadStop(cur_tile, st->owner, st->index, rs_type, rts, ddir);
01820       }
01821       Company::Get(st->owner)->station_infrastructure++;
01822       DirtyCompanyInfrastructureWindows(st->owner);
01823 
01824       MarkTileDirtyByTile(cur_tile);
01825     }
01826   }
01827 
01828   if (st != NULL) {
01829     st->UpdateVirtCoord();
01830     UpdateStationAcceptance(st, false);
01831     st->RecomputeIndustriesNear();
01832     InvalidateWindowData(WC_SELECT_STATION, 0, 0);
01833     InvalidateWindowData(WC_STATION_LIST, st->owner, 0);
01834     SetWindowWidgetDirty(WC_STATION_VIEW, st->index, SVW_ROADVEHS);
01835   }
01836   return cost;
01837 }
01838 
01839 
01840 static Vehicle *ClearRoadStopStatusEnum(Vehicle *v, void *)
01841 {
01842   if (v->type == VEH_ROAD) {
01843     /* Okay... we are a road vehicle on a drive through road stop.
01844      * But that road stop has just been removed, so we need to make
01845      * sure we are in a valid state... however, vehicles can also
01846      * turn on road stop tiles, so only clear the 'road stop' state
01847      * bits and only when the state was 'in road stop', otherwise
01848      * we'll end up clearing the turn around bits. */
01849     RoadVehicle *rv = RoadVehicle::From(v);
01850     if (HasBit(rv->state, RVS_IN_DT_ROAD_STOP)) rv->state &= RVSB_ROAD_STOP_TRACKDIR_MASK;
01851   }
01852 
01853   return NULL;
01854 }
01855 
01856 
01863 static CommandCost RemoveRoadStop(TileIndex tile, DoCommandFlag flags)
01864 {
01865   Station *st = Station::GetByTile(tile);
01866 
01867   if (_current_company != OWNER_WATER) {
01868     CommandCost ret = CheckOwnership(st->owner);
01869     if (ret.Failed()) return ret;
01870   }
01871 
01872   bool is_truck = IsTruckStop(tile);
01873 
01874   RoadStop **primary_stop;
01875   RoadStop *cur_stop;
01876   if (is_truck) { // truck stop
01877     primary_stop = &st->truck_stops;
01878     cur_stop = RoadStop::GetByTile(tile, ROADSTOP_TRUCK);
01879   } else {
01880     primary_stop = &st->bus_stops;
01881     cur_stop = RoadStop::GetByTile(tile, ROADSTOP_BUS);
01882   }
01883 
01884   assert(cur_stop != NULL);
01885 
01886   /* don't do the check for drive-through road stops when company bankrupts */
01887   if (IsDriveThroughStopTile(tile) && (flags & DC_BANKRUPT)) {
01888     /* remove the 'going through road stop' status from all vehicles on that tile */
01889     if (flags & DC_EXEC) FindVehicleOnPos(tile, NULL, &ClearRoadStopStatusEnum);
01890   } else {
01891     CommandCost ret = EnsureNoVehicleOnGround(tile);
01892     if (ret.Failed()) return ret;
01893   }
01894 
01895   if (flags & DC_EXEC) {
01896     if (*primary_stop == cur_stop) {
01897       /* removed the first stop in the list */
01898       *primary_stop = cur_stop->next;
01899       /* removed the only stop? */
01900       if (*primary_stop == NULL) {
01901         st->facilities &= (is_truck ? ~FACIL_TRUCK_STOP : ~FACIL_BUS_STOP);
01902       }
01903     } else {
01904       /* tell the predecessor in the list to skip this stop */
01905       RoadStop *pred = *primary_stop;
01906       while (pred->next != cur_stop) pred = pred->next;
01907       pred->next = cur_stop->next;
01908     }
01909 
01910     /* Update company infrastructure counts. */
01911     RoadType rt;
01912     FOR_EACH_SET_ROADTYPE(rt, GetRoadTypes(tile)) {
01913       Company *c = Company::GetIfValid(GetRoadOwner(tile, rt));
01914       if (c != NULL) {
01915         c->road_infrastructure[rt] -= 2;
01916         DirtyCompanyInfrastructureWindows(c->index);
01917       }
01918     }
01919     Company::Get(st->owner)->station_infrastructure--;
01920 
01921     if (IsDriveThroughStopTile(tile)) {
01922       /* Clears the tile for us */
01923       cur_stop->ClearDriveThrough();
01924     } else {
01925       DoClearSquare(tile);
01926     }
01927 
01928     SetWindowWidgetDirty(WC_STATION_VIEW, st->index, SVW_ROADVEHS);
01929     delete cur_stop;
01930 
01931     /* Make sure no vehicle is going to the old roadstop */
01932     RoadVehicle *v;
01933     FOR_ALL_ROADVEHICLES(v) {
01934       if (v->First() == v && v->current_order.IsType(OT_GOTO_STATION) &&
01935           v->dest_tile == tile) {
01936         v->dest_tile = v->GetOrderStationLocation(st->index);
01937       }
01938     }
01939 
01940     st->rect.AfterRemoveTile(st, tile);
01941 
01942     st->UpdateVirtCoord();
01943     st->RecomputeIndustriesNear();
01944     DeleteStationIfEmpty(st);
01945 
01946     /* Update the tile area of the truck/bus stop */
01947     if (is_truck) {
01948       st->truck_station.Clear();
01949       for (const RoadStop *rs = st->truck_stops; rs != NULL; rs = rs->next) st->truck_station.Add(rs->xy);
01950     } else {
01951       st->bus_station.Clear();
01952       for (const RoadStop *rs = st->bus_stops; rs != NULL; rs = rs->next) st->bus_station.Add(rs->xy);
01953     }
01954   }
01955 
01956   return CommandCost(EXPENSES_CONSTRUCTION, _price[is_truck ? PR_CLEAR_STATION_TRUCK : PR_CLEAR_STATION_BUS]);
01957 }
01958 
01969 CommandCost CmdRemoveRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01970 {
01971   uint8 width = (uint8)GB(p1, 0, 8);
01972   uint8 height = (uint8)GB(p1, 8, 8);
01973 
01974   /* Check for incorrect width / height. */
01975   if (width == 0 || height == 0) return CMD_ERROR;
01976   /* Check if the first tile and the last tile are valid */
01977   if (!IsValidTile(tile) || TileAddWrap(tile, width - 1, height - 1) == INVALID_TILE) return CMD_ERROR;
01978 
01979   TileArea roadstop_area(tile, width, height);
01980 
01981   int quantity = 0;
01982   CommandCost cost(EXPENSES_CONSTRUCTION);
01983   TILE_AREA_LOOP(cur_tile, roadstop_area) {
01984     /* Make sure the specified tile is a road stop of the correct type */
01985     if (!IsTileType(cur_tile, MP_STATION) || !IsRoadStop(cur_tile) || (uint32)GetRoadStopType(cur_tile) != GB(p2, 0, 1)) continue;
01986 
01987     /* Save the stop info before it is removed */
01988     bool is_drive_through = IsDriveThroughStopTile(cur_tile);
01989     RoadTypes rts = GetRoadTypes(cur_tile);
01990     RoadBits road_bits = IsDriveThroughStopTile(cur_tile) ?
01991         ((GetRoadStopDir(cur_tile) == DIAGDIR_NE) ? ROAD_X : ROAD_Y) :
01992         DiagDirToRoadBits(GetRoadStopDir(cur_tile));
01993 
01994     Owner road_owner = GetRoadOwner(cur_tile, ROADTYPE_ROAD);
01995     Owner tram_owner = GetRoadOwner(cur_tile, ROADTYPE_TRAM);
01996     CommandCost ret = RemoveRoadStop(cur_tile, flags);
01997     if (ret.Failed()) return ret;
01998     cost.AddCost(ret);
01999 
02000     quantity++;
02001     /* If the stop was a drive-through stop replace the road */
02002     if ((flags & DC_EXEC) && is_drive_through) {
02003       MakeRoadNormal(cur_tile, road_bits, rts, ClosestTownFromTile(cur_tile, UINT_MAX)->index,
02004           road_owner, tram_owner);
02005 
02006       /* Update company infrastructure counts. */
02007       RoadType rt;
02008       FOR_EACH_SET_ROADTYPE(rt, rts) {
02009         Company *c = Company::GetIfValid(GetRoadOwner(cur_tile, rt));
02010         if (c != NULL) {
02011           c->road_infrastructure[rt] += CountBits(road_bits);
02012           DirtyCompanyInfrastructureWindows(c->index);
02013         }
02014       }
02015     }
02016   }
02017 
02018   if (quantity == 0) return_cmd_error(STR_ERROR_THERE_IS_NO_STATION);
02019 
02020   return cost;
02021 }
02022 
02030 static uint GetMinimalAirportDistanceToTile(const AirportSpec *as, TileIndex town_tile, TileIndex airport_tile)
02031 {
02032   uint ttx = TileX(town_tile); // X, Y of town
02033   uint tty = TileY(town_tile);
02034 
02035   uint atx = TileX(airport_tile); // X, Y of northern airport corner
02036   uint aty = TileY(airport_tile);
02037 
02038   uint btx = TileX(airport_tile) + as->size_x - 1; // X, Y of southern corner
02039   uint bty = TileY(airport_tile) + as->size_y - 1;
02040 
02041   /* if ttx < atx, dx = atx - ttx
02042    * if atx <= ttx <= btx, dx = 0
02043    * else, dx = ttx - btx (similiar for dy) */
02044   uint dx = ttx < atx ? atx - ttx : (ttx <= btx ? 0 : ttx - btx);
02045   uint dy = tty < aty ? aty - tty : (tty <= bty ? 0 : tty - bty);
02046 
02047   return dx + dy;
02048 }
02049 
02059 uint8 GetAirportNoiseLevelForTown(const AirportSpec *as, TileIndex town_tile, TileIndex tile)
02060 {
02061   /* 0 cannot be accounted, and 1 is the lowest that can be reduced from town.
02062    * So no need to go any further*/
02063   if (as->noise_level < 2) return as->noise_level;
02064 
02065   uint distance = GetMinimalAirportDistanceToTile(as, town_tile, tile);
02066 
02067   /* The steps for measuring noise reduction are based on the "magical" (and arbitrary) 8 base distance
02068    * adding the town_council_tolerance 4 times, as a way to graduate, depending of the tolerance.
02069    * Basically, it says that the less tolerant a town is, the bigger the distance before
02070    * an actual decrease can be granted */
02071   uint8 town_tolerance_distance = 8 + (_settings_game.difficulty.town_council_tolerance * 4);
02072 
02073   /* now, we want to have the distance segmented using the distance judged bareable by town
02074    * This will give us the coefficient of reduction the distance provides. */
02075   uint noise_reduction = distance / town_tolerance_distance;
02076 
02077   /* If the noise reduction equals the airport noise itself, don't give it for free.
02078    * Otherwise, simply reduce the airport's level. */
02079   return noise_reduction >= as->noise_level ? 1 : as->noise_level - noise_reduction;
02080 }
02081 
02089 Town *AirportGetNearestTown(const AirportSpec *as, TileIndex airport_tile)
02090 {
02091   Town *t, *nearest = NULL;
02092   uint add = as->size_x + as->size_y - 2; // GetMinimalAirportDistanceToTile can differ from DistanceManhattan by this much
02093   uint mindist = UINT_MAX - add; // prevent overflow
02094   FOR_ALL_TOWNS(t) {
02095     if (DistanceManhattan(t->xy, airport_tile) < mindist + add) { // avoid calling GetMinimalAirportDistanceToTile too often
02096       uint dist = GetMinimalAirportDistanceToTile(as, t->xy, airport_tile);
02097       if (dist < mindist) {
02098         nearest = t;
02099         mindist = dist;
02100       }
02101     }
02102   }
02103 
02104   return nearest;
02105 }
02106 
02107 
02109 void UpdateAirportsNoise()
02110 {
02111   Town *t;
02112   const Station *st;
02113 
02114   FOR_ALL_TOWNS(t) t->noise_reached = 0;
02115 
02116   FOR_ALL_STATIONS(st) {
02117     if (st->airport.tile != INVALID_TILE) {
02118       const AirportSpec *as = st->airport.GetSpec();
02119       Town *nearest = AirportGetNearestTown(as, st->airport.tile);
02120       nearest->noise_reached += GetAirportNoiseLevelForTown(as, nearest->xy, st->airport.tile);
02121     }
02122   }
02123 }
02124 
02138 CommandCost CmdBuildAirport(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
02139 {
02140   StationID station_to_join = GB(p2, 16, 16);
02141   bool reuse = (station_to_join != NEW_STATION);
02142   if (!reuse) station_to_join = INVALID_STATION;
02143   bool distant_join = (station_to_join != INVALID_STATION);
02144   byte airport_type = GB(p1, 0, 8);
02145   byte layout = GB(p1, 8, 8);
02146 
02147   if (distant_join && (!_settings_game.station.distant_join_stations || !Station::IsValidID(station_to_join))) return CMD_ERROR;
02148 
02149   if (airport_type >= NUM_AIRPORTS) return CMD_ERROR;
02150 
02151   CommandCost ret = CheckIfAuthorityAllowsNewStation(tile, flags);
02152   if (ret.Failed()) return ret;
02153 
02154   /* Check if a valid, buildable airport was chosen for construction */
02155   const AirportSpec *as = AirportSpec::Get(airport_type);
02156   if (!as->IsAvailable() || layout >= as->num_table) return CMD_ERROR;
02157 
02158   Direction rotation = as->rotation[layout];
02159   Town *t = ClosestTownFromTile(tile, UINT_MAX);
02160   int w = as->size_x;
02161   int h = as->size_y;
02162   if (rotation == DIR_E || rotation == DIR_W) Swap(w, h);
02163 
02164   if (w > _settings_game.station.station_spread || h > _settings_game.station.station_spread) {
02165     return_cmd_error(STR_ERROR_STATION_TOO_SPREAD_OUT);
02166   }
02167 
02168   CommandCost cost = CheckFlatLand(TileArea(tile, w, h), flags);
02169   if (cost.Failed()) return cost;
02170 
02171   /* The noise level is the noise from the airport and reduce it to account for the distance to the town center. */
02172   Town *nearest = AirportGetNearestTown(as, tile);
02173   uint newnoise_level = GetAirportNoiseLevelForTown(as, nearest->xy, tile);
02174 
02175   /* Check if local auth would allow a new airport */
02176   StringID authority_refuse_message = STR_NULL;
02177 
02178   if (_settings_game.economy.station_noise_level) {
02179     /* do not allow to build a new airport if this raise the town noise over the maximum allowed by town */
02180     if ((nearest->noise_reached + newnoise_level) > nearest->MaxTownNoise()) {
02181       authority_refuse_message = STR_ERROR_LOCAL_AUTHORITY_REFUSES_NOISE;
02182     }
02183   } else {
02184     uint num = 0;
02185     const Station *st;
02186     FOR_ALL_STATIONS(st) {
02187       if (st->town == t && (st->facilities & FACIL_AIRPORT) && st->airport.type != AT_OILRIG) num++;
02188     }
02189     if (num >= 2) {
02190       authority_refuse_message = STR_ERROR_LOCAL_AUTHORITY_REFUSES_AIRPORT;
02191     }
02192   }
02193 
02194   if (authority_refuse_message != STR_NULL) {
02195     SetDParam(0, t->index);
02196     return_cmd_error(authority_refuse_message);
02197   }
02198 
02199   Station *st = NULL;
02200   ret = FindJoiningStation(INVALID_STATION, station_to_join, HasBit(p2, 0), TileArea(tile, w, h), &st);
02201   if (ret.Failed()) return ret;
02202 
02203   /* Distant join */
02204   if (st == NULL && distant_join) st = Station::GetIfValid(station_to_join);
02205 
02206   /* Find a deleted station close to us */
02207   if (st == NULL && reuse) st = GetClosestDeletedStation(tile);
02208 
02209   if (st != NULL) {
02210     if (st->owner != _current_company) {
02211       return_cmd_error(STR_ERROR_TOO_CLOSE_TO_ANOTHER_STATION);
02212     }
02213 
02214     CommandCost ret = st->rect.BeforeAddRect(tile, w, h, StationRect::ADD_TEST);
02215     if (ret.Failed()) return ret;
02216 
02217     if (st->airport.tile != INVALID_TILE) {
02218       return_cmd_error(STR_ERROR_TOO_CLOSE_TO_ANOTHER_AIRPORT);
02219     }
02220   } else {
02221     /* allocate and initialize new station */
02222     if (!Station::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_STATIONS_LOADING);
02223 
02224     if (flags & DC_EXEC) {
02225       st = new Station(tile);
02226 
02227       st->town = t;
02228       st->string_id = GenerateStationName(st, tile, !(GetAirport(airport_type)->flags & AirportFTAClass::AIRPLANES) ? STATIONNAMING_HELIPORT : STATIONNAMING_AIRPORT);
02229 
02230       if (Company::IsValidID(_current_company)) {
02231         SetBit(st->town->have_ratings, _current_company);
02232       }
02233     }
02234   }
02235 
02236   const AirportTileTable *it = as->table[layout];
02237   do {
02238     cost.AddCost(_price[PR_BUILD_STATION_AIRPORT]);
02239   } while ((++it)->ti.x != -0x80);
02240 
02241   if (flags & DC_EXEC) {
02242     /* Always add the noise, so there will be no need to recalculate when option toggles */
02243     nearest->noise_reached += newnoise_level;
02244 
02245     st->AddFacility(FACIL_AIRPORT, tile);
02246     st->airport.type = airport_type;
02247     st->airport.layout = layout;
02248     st->airport.flags = 0;
02249     st->airport.rotation = rotation;
02250     st->airport.psa.ResetToZero();
02251 
02252     st->rect.BeforeAddRect(tile, w, h, StationRect::ADD_TRY);
02253 
02254     it = as->table[layout];
02255     do {
02256       TileIndex cur_tile = tile + ToTileIndexDiff(it->ti);
02257       MakeAirport(cur_tile, st->owner, st->index, it->gfx, WATER_CLASS_INVALID);
02258       SetStationTileRandomBits(cur_tile, GB(Random(), 0, 4));
02259       st->airport.Add(cur_tile);
02260 
02261       if (AirportTileSpec::Get(GetTranslatedAirportTileID(it->gfx))->animation.status != ANIM_STATUS_NO_ANIMATION) AddAnimatedTile(cur_tile);
02262     } while ((++it)->ti.x != -0x80);
02263 
02264     /* Only call the animation trigger after all tiles have been built */
02265     it = as->table[layout];
02266     do {
02267       TileIndex cur_tile = tile + ToTileIndexDiff(it->ti);
02268       AirportTileAnimationTrigger(st, cur_tile, AAT_BUILT);
02269     } while ((++it)->ti.x != -0x80);
02270 
02271     UpdateAirplanesOnNewStation(st);
02272 
02273     Company::Get(st->owner)->airport_infrastructure++;
02274     DirtyCompanyInfrastructureWindows(st->owner);
02275 
02276     st->UpdateVirtCoord();
02277     UpdateStationAcceptance(st, false);
02278     st->RecomputeIndustriesNear();
02279     InvalidateWindowData(WC_SELECT_STATION, 0, 0);
02280     InvalidateWindowData(WC_STATION_LIST, st->owner, 0);
02281     SetWindowWidgetDirty(WC_STATION_VIEW, st->index, SVW_PLANES);
02282 
02283     if (_settings_game.economy.station_noise_level) {
02284       SetWindowDirty(WC_TOWN_VIEW, st->town->index);
02285     }
02286   }
02287 
02288   return cost;
02289 }
02290 
02297 static CommandCost RemoveAirport(TileIndex tile, DoCommandFlag flags)
02298 {
02299   Station *st = Station::GetByTile(tile);
02300 
02301   if (_current_company != OWNER_WATER) {
02302     CommandCost ret = CheckOwnership(st->owner);
02303     if (ret.Failed()) return ret;
02304   }
02305 
02306   tile = st->airport.tile;
02307 
02308   CommandCost cost(EXPENSES_CONSTRUCTION);
02309 
02310   const Aircraft *a;
02311   FOR_ALL_AIRCRAFT(a) {
02312     if (!a->IsNormalAircraft()) continue;
02313     if (a->targetairport == st->index && a->state != FLYING) return CMD_ERROR;
02314   }
02315 
02316   TILE_AREA_LOOP(tile_cur, st->airport) {
02317     if (!st->TileBelongsToAirport(tile_cur)) continue;
02318 
02319     CommandCost ret = EnsureNoVehicleOnGround(tile_cur);
02320     if (ret.Failed()) return ret;
02321 
02322     cost.AddCost(_price[PR_CLEAR_STATION_AIRPORT]);
02323 
02324     if (flags & DC_EXEC) {
02325       if (IsHangarTile(tile_cur)) OrderBackup::Reset(tile_cur, false);
02326       DeleteAnimatedTile(tile_cur);
02327       DoClearSquare(tile_cur);
02328       DeleteNewGRFInspectWindow(GSF_AIRPORTTILES, tile_cur);
02329     }
02330   }
02331 
02332   if (flags & DC_EXEC) {
02333     const AirportSpec *as = st->airport.GetSpec();
02334     for (uint i = 0; i < st->airport.GetNumHangars(); ++i) {
02335       DeleteWindowById(
02336         WC_VEHICLE_DEPOT, st->airport.GetHangarTile(i)
02337       );
02338     }
02339 
02340     /* The noise level is the noise from the airport and reduce it to account for the distance to the town center.
02341      * And as for construction, always remove it, even if the setting is not set, in order to avoid the
02342      * need of recalculation */
02343     Town *nearest = AirportGetNearestTown(as, tile);
02344     nearest->noise_reached -= GetAirportNoiseLevelForTown(as, nearest->xy, tile);
02345 
02346     st->rect.AfterRemoveRect(st, st->airport);
02347 
02348     st->airport.Clear();
02349     st->facilities &= ~FACIL_AIRPORT;
02350     st->airport.psa.ResetToZero();
02351 
02352     SetWindowWidgetDirty(WC_STATION_VIEW, st->index, SVW_PLANES);
02353 
02354     if (_settings_game.economy.station_noise_level) {
02355       SetWindowDirty(WC_TOWN_VIEW, st->town->index);
02356     }
02357 
02358     Company::Get(st->owner)->airport_infrastructure--;
02359     DirtyCompanyInfrastructureWindows(st->owner);
02360 
02361     st->UpdateVirtCoord();
02362     st->RecomputeIndustriesNear();
02363     DeleteStationIfEmpty(st);
02364     DeleteNewGRFInspectWindow(GSF_AIRPORTS, st->index);
02365   }
02366 
02367   return cost;
02368 }
02369 
02376 bool HasStationInUse(StationID station, bool include_company, CompanyID company)
02377 {
02378   const Vehicle *v;
02379   FOR_ALL_VEHICLES(v) {
02380     if ((v->owner == company) == include_company) {
02381       const Order *order;
02382       FOR_VEHICLE_ORDERS(v, order) {
02383         if ((order->IsType(OT_GOTO_STATION) || order->IsType(OT_GOTO_WAYPOINT)) && order->GetDestination() == station) {
02384           return true;
02385         }
02386       }
02387     }
02388   }
02389   return false;
02390 }
02391 
02392 static const TileIndexDiffC _dock_tileoffs_chkaround[] = {
02393   {-1,  0},
02394   { 0,  0},
02395   { 0,  0},
02396   { 0, -1}
02397 };
02398 static const byte _dock_w_chk[4] = { 2, 1, 2, 1 };
02399 static const byte _dock_h_chk[4] = { 1, 2, 1, 2 };
02400 
02410 CommandCost CmdBuildDock(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
02411 {
02412   StationID station_to_join = GB(p2, 16, 16);
02413   bool reuse = (station_to_join != NEW_STATION);
02414   if (!reuse) station_to_join = INVALID_STATION;
02415   bool distant_join = (station_to_join != INVALID_STATION);
02416 
02417   if (distant_join && (!_settings_game.station.distant_join_stations || !Station::IsValidID(station_to_join))) return CMD_ERROR;
02418 
02419   DiagDirection direction = GetInclinedSlopeDirection(GetTileSlope(tile, NULL));
02420   if (direction == INVALID_DIAGDIR) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
02421   direction = ReverseDiagDir(direction);
02422 
02423   /* Docks cannot be placed on rapids */
02424   if (HasTileWaterGround(tile)) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
02425 
02426   CommandCost ret = CheckIfAuthorityAllowsNewStation(tile, flags);
02427   if (ret.Failed()) return ret;
02428 
02429   if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
02430 
02431   ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
02432   if (ret.Failed()) return ret;
02433 
02434   TileIndex tile_cur = tile + TileOffsByDiagDir(direction);
02435 
02436   if (!IsTileType(tile_cur, MP_WATER) || GetTileSlope(tile_cur, NULL) != SLOPE_FLAT) {
02437     return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
02438   }
02439 
02440   if (MayHaveBridgeAbove(tile_cur) && IsBridgeAbove(tile_cur)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
02441 
02442   /* Get the water class of the water tile before it is cleared.*/
02443   WaterClass wc = GetWaterClass(tile_cur);
02444 
02445   ret = DoCommand(tile_cur, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
02446   if (ret.Failed()) return ret;
02447 
02448   tile_cur += TileOffsByDiagDir(direction);
02449   if (!IsTileType(tile_cur, MP_WATER) || GetTileSlope(tile_cur, NULL) != SLOPE_FLAT) {
02450     return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
02451   }
02452 
02453   /* middle */
02454   Station *st = NULL;
02455   ret = FindJoiningStation(INVALID_STATION, station_to_join, HasBit(p1, 0),
02456       TileArea(tile + ToTileIndexDiff(_dock_tileoffs_chkaround[direction]),
02457           _dock_w_chk[direction], _dock_h_chk[direction]), &st);
02458   if (ret.Failed()) return ret;
02459 
02460   /* Distant join */
02461   if (st == NULL && distant_join) st = Station::GetIfValid(station_to_join);
02462 
02463   /* Find a deleted station close to us */
02464   if (st == NULL && reuse) st = GetClosestDeletedStation(tile);
02465 
02466   if (st != NULL) {
02467     if (st->owner != _current_company) {
02468       return_cmd_error(STR_ERROR_TOO_CLOSE_TO_ANOTHER_STATION);
02469     }
02470 
02471     CommandCost ret = st->rect.BeforeAddRect(
02472         tile + ToTileIndexDiff(_dock_tileoffs_chkaround[direction]),
02473         _dock_w_chk[direction], _dock_h_chk[direction], StationRect::ADD_TEST);
02474     if (ret.Failed()) return ret;
02475 
02476     if (st->dock_tile != INVALID_TILE) return_cmd_error(STR_ERROR_TOO_CLOSE_TO_ANOTHER_DOCK);
02477   } else {
02478     /* allocate and initialize new station */
02479     if (!Station::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_STATIONS_LOADING);
02480 
02481     if (flags & DC_EXEC) {
02482       st = new Station(tile);
02483 
02484       st->town = ClosestTownFromTile(tile, UINT_MAX);
02485       st->string_id = GenerateStationName(st, tile, STATIONNAMING_DOCK);
02486 
02487       if (Company::IsValidID(_current_company)) {
02488         SetBit(st->town->have_ratings, _current_company);
02489       }
02490     }
02491   }
02492 
02493   if (flags & DC_EXEC) {
02494     st->dock_tile = tile;
02495     st->AddFacility(FACIL_DOCK, tile);
02496 
02497     st->rect.BeforeAddRect(
02498         tile + ToTileIndexDiff(_dock_tileoffs_chkaround[direction]),
02499         _dock_w_chk[direction], _dock_h_chk[direction], StationRect::ADD_TRY);
02500 
02501     /* If the water part of the dock is on a canal, update infrastructure counts.
02502      * This is needed as we've unconditionally cleared that tile before. */
02503     if (wc == WATER_CLASS_CANAL) {
02504       Company::Get(st->owner)->water_infrastructure++;
02505     }
02506     Company::Get(st->owner)->station_infrastructure += 2;
02507     DirtyCompanyInfrastructureWindows(st->owner);
02508 
02509     MakeDock(tile, st->owner, st->index, direction, wc);
02510 
02511     st->UpdateVirtCoord();
02512     UpdateStationAcceptance(st, false);
02513     st->RecomputeIndustriesNear();
02514     InvalidateWindowData(WC_SELECT_STATION, 0, 0);
02515     InvalidateWindowData(WC_STATION_LIST, st->owner, 0);
02516     SetWindowWidgetDirty(WC_STATION_VIEW, st->index, SVW_SHIPS);
02517   }
02518 
02519   return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_STATION_DOCK]);
02520 }
02521 
02528 static CommandCost RemoveDock(TileIndex tile, DoCommandFlag flags)
02529 {
02530   Station *st = Station::GetByTile(tile);
02531   CommandCost ret = CheckOwnership(st->owner);
02532   if (ret.Failed()) return ret;
02533 
02534   TileIndex tile1 = st->dock_tile;
02535   TileIndex tile2 = tile1 + TileOffsByDiagDir(GetDockDirection(tile1));
02536 
02537   ret = EnsureNoVehicleOnGround(tile1);
02538   if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile2);
02539   if (ret.Failed()) return ret;
02540 
02541   if (flags & DC_EXEC) {
02542     DoClearSquare(tile1);
02543     MarkTileDirtyByTile(tile1);
02544     MakeWaterKeepingClass(tile2, st->owner);
02545 
02546     st->rect.AfterRemoveTile(st, tile1);
02547     st->rect.AfterRemoveTile(st, tile2);
02548 
02549     st->dock_tile = INVALID_TILE;
02550     st->facilities &= ~FACIL_DOCK;
02551 
02552     Company::Get(st->owner)->station_infrastructure -= 2;
02553     DirtyCompanyInfrastructureWindows(st->owner);
02554 
02555     SetWindowWidgetDirty(WC_STATION_VIEW, st->index, SVW_SHIPS);
02556     st->UpdateVirtCoord();
02557     st->RecomputeIndustriesNear();
02558     DeleteStationIfEmpty(st);
02559   }
02560 
02561   return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_STATION_DOCK]);
02562 }
02563 
02564 #include "table/station_land.h"
02565 
02566 const DrawTileSprites *GetStationTileLayout(StationType st, byte gfx)
02567 {
02568   return &_station_display_datas[st][gfx];
02569 }
02570 
02571 static void DrawTile_Station(TileInfo *ti)
02572 {
02573   const NewGRFSpriteLayout *layout = NULL;
02574   DrawTileSprites tmp_rail_layout;
02575   const DrawTileSprites *t = NULL;
02576   RoadTypes roadtypes;
02577   int32 total_offset;
02578   const RailtypeInfo *rti = NULL;
02579   uint32 relocation = 0;
02580   uint32 ground_relocation = 0;
02581   const BaseStation *st = NULL;
02582   const StationSpec *statspec = NULL;
02583   uint tile_layout = 0;
02584 
02585   if (HasStationRail(ti->tile)) {
02586     rti = GetRailTypeInfo(GetRailType(ti->tile));
02587     roadtypes = ROADTYPES_NONE;
02588     total_offset = rti->GetRailtypeSpriteOffset();
02589 
02590     if (IsCustomStationSpecIndex(ti->tile)) {
02591       /* look for customization */
02592       st = BaseStation::GetByTile(ti->tile);
02593       statspec = st->speclist[GetCustomStationSpecIndex(ti->tile)].spec;
02594 
02595       if (statspec != NULL) {
02596         tile_layout = GetStationGfx(ti->tile);
02597 
02598         if (HasBit(statspec->callback_mask, CBM_STATION_SPRITE_LAYOUT)) {
02599           uint16 callback = GetStationCallback(CBID_STATION_SPRITE_LAYOUT, 0, 0, statspec, st, ti->tile);
02600           if (callback != CALLBACK_FAILED) tile_layout = (callback & ~1) + GetRailStationAxis(ti->tile);
02601         }
02602 
02603         /* Ensure the chosen tile layout is valid for this custom station */
02604         if (statspec->renderdata != NULL) {
02605           layout = &statspec->renderdata[tile_layout < statspec->tiles ? tile_layout : (uint)GetRailStationAxis(ti->tile)];
02606           if (!layout->NeedsPreprocessing()) {
02607             t = layout;
02608             layout = NULL;
02609           }
02610         }
02611       }
02612     }
02613   } else {
02614     roadtypes = IsRoadStop(ti->tile) ? GetRoadTypes(ti->tile) : ROADTYPES_NONE;
02615     total_offset = 0;
02616   }
02617 
02618   if (IsAirport(ti->tile)) {
02619     StationGfx gfx = GetAirportGfx(ti->tile);
02620     if (gfx >= NEW_AIRPORTTILE_OFFSET) {
02621       const AirportTileSpec *ats = AirportTileSpec::Get(gfx);
02622       if (ats->grf_prop.spritegroup[0] != NULL && DrawNewAirportTile(ti, Station::GetByTile(ti->tile), gfx, ats)) {
02623         return;
02624       }
02625       /* No sprite group (or no valid one) found, meaning no graphics associated.
02626        * Use the substitute one instead */
02627       assert(ats->grf_prop.subst_id != INVALID_AIRPORTTILE);
02628       gfx = ats->grf_prop.subst_id;
02629     }
02630     switch (gfx) {
02631       case APT_RADAR_GRASS_FENCE_SW:
02632         t = &_station_display_datas_airport_radar_grass_fence_sw[GetAnimationFrame(ti->tile)];
02633         break;
02634       case APT_GRASS_FENCE_NE_FLAG:
02635         t = &_station_display_datas_airport_flag_grass_fence_ne[GetAnimationFrame(ti->tile)];
02636         break;
02637       case APT_RADAR_FENCE_SW:
02638         t = &_station_display_datas_airport_radar_fence_sw[GetAnimationFrame(ti->tile)];
02639         break;
02640       case APT_RADAR_FENCE_NE:
02641         t = &_station_display_datas_airport_radar_fence_ne[GetAnimationFrame(ti->tile)];
02642         break;
02643       case APT_GRASS_FENCE_NE_FLAG_2:
02644         t = &_station_display_datas_airport_flag_grass_fence_ne_2[GetAnimationFrame(ti->tile)];
02645         break;
02646     }
02647   }
02648 
02649   Owner owner = GetTileOwner(ti->tile);
02650 
02651   PaletteID palette;
02652   if (Company::IsValidID(owner)) {
02653     palette = COMPANY_SPRITE_COLOUR(owner);
02654   } else {
02655     /* Some stations are not owner by a company, namely oil rigs */
02656     palette = PALETTE_TO_GREY;
02657   }
02658 
02659   if (layout == NULL && (t == NULL || t->seq == NULL)) t = GetStationTileLayout(GetStationType(ti->tile), GetStationGfx(ti->tile));
02660 
02661   /* don't show foundation for docks */
02662   if (ti->tileh != SLOPE_FLAT && !IsDock(ti->tile)) {
02663     if (statspec != NULL && HasBit(statspec->flags, SSF_CUSTOM_FOUNDATIONS)) {
02664       /* Station has custom foundations.
02665        * Check whether the foundation continues beyond the tile's upper sides. */
02666       uint edge_info = 0;
02667       uint z;
02668       Slope slope = GetFoundationSlope(ti->tile, &z);
02669       if (!HasFoundationNW(ti->tile, slope, z)) SetBit(edge_info, 0);
02670       if (!HasFoundationNE(ti->tile, slope, z)) SetBit(edge_info, 1);
02671       SpriteID image = GetCustomStationFoundationRelocation(statspec, st, ti->tile, tile_layout, edge_info);
02672 
02673       if (HasBit(statspec->flags, SSF_EXTENDED_FOUNDATIONS)) {
02674         /* Station provides extended foundations. */
02675 
02676         static const uint8 foundation_parts[] = {
02677           0, 0, 0, 0, // Invalid,  Invalid,   Invalid,   SLOPE_SW
02678           0, 1, 2, 3, // Invalid,  SLOPE_EW,  SLOPE_SE,  SLOPE_WSE
02679           0, 4, 5, 6, // Invalid,  SLOPE_NW,  SLOPE_NS,  SLOPE_NWS
02680           7, 8, 9     // SLOPE_NE, SLOPE_ENW, SLOPE_SEN
02681         };
02682 
02683         AddSortableSpriteToDraw(image + foundation_parts[ti->tileh], PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z);
02684       } else {
02685         /* Draw simple foundations, built up from 8 possible foundation sprites. */
02686 
02687         /* Each set bit represents one of the eight composite sprites to be drawn.
02688          * 'Invalid' entries will not drawn but are included for completeness. */
02689         static const uint8 composite_foundation_parts[] = {
02690           /* Invalid  (00000000), Invalid   (11010001), Invalid   (11100100), SLOPE_SW  (11100000) */
02691              0x00,                0xD1,                 0xE4,                 0xE0,
02692           /* Invalid  (11001010), SLOPE_EW  (11001001), SLOPE_SE  (11000100), SLOPE_WSE (11000000) */
02693              0xCA,                0xC9,                 0xC4,                 0xC0,
02694           /* Invalid  (11010010), SLOPE_NW  (10010001), SLOPE_NS  (11100100), SLOPE_NWS (10100000) */
02695              0xD2,                0x91,                 0xE4,                 0xA0,
02696           /* SLOPE_NE (01001010), SLOPE_ENW (00001001), SLOPE_SEN (01000100) */
02697              0x4A,                0x09,                 0x44
02698         };
02699 
02700         uint8 parts = composite_foundation_parts[ti->tileh];
02701 
02702         /* If foundations continue beyond the tile's upper sides then
02703          * mask out the last two pieces. */
02704         if (HasBit(edge_info, 0)) ClrBit(parts, 6);
02705         if (HasBit(edge_info, 1)) ClrBit(parts, 7);
02706 
02707         if (parts == 0) {
02708           /* We always have to draw at least one sprite to make sure there is a boundingbox and a sprite with the
02709            * correct offset for the childsprites.
02710            * So, draw the (completely empty) sprite of the default foundations. */
02711           goto draw_default_foundation;
02712         }
02713 
02714         StartSpriteCombine();
02715         for (int i = 0; i < 8; i++) {
02716           if (HasBit(parts, i)) {
02717             AddSortableSpriteToDraw(image + i, PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z);
02718           }
02719         }
02720         EndSpriteCombine();
02721       }
02722 
02723       OffsetGroundSprite(31, 1);
02724       ti->z += ApplyFoundationToSlope(FOUNDATION_LEVELED, &ti->tileh);
02725     } else {
02726 draw_default_foundation:
02727       DrawFoundation(ti, FOUNDATION_LEVELED);
02728     }
02729   }
02730 
02731   if (IsBuoy(ti->tile) || IsDock(ti->tile) || (IsOilRig(ti->tile) && IsTileOnWater(ti->tile))) {
02732     if (ti->tileh == SLOPE_FLAT) {
02733       DrawWaterClassGround(ti);
02734     } else {
02735       assert(IsDock(ti->tile));
02736       TileIndex water_tile = ti->tile + TileOffsByDiagDir(GetDockDirection(ti->tile));
02737       WaterClass wc = GetWaterClass(water_tile);
02738       if (wc == WATER_CLASS_SEA) {
02739         DrawShoreTile(ti->tileh);
02740       } else {
02741         DrawClearLandTile(ti, 3);
02742       }
02743     }
02744   } else {
02745     if (layout != NULL) {
02746       /* Sprite layout which needs preprocessing */
02747       bool separate_ground = HasBit(statspec->flags, SSF_SEPARATE_GROUND);
02748       uint32 var10_values = layout->PrepareLayout(total_offset, rti->fallback_railtype, 0, separate_ground);
02749       uint8 var10;
02750       FOR_EACH_SET_BIT(var10, var10_values) {
02751         uint32 var10_relocation = GetCustomStationRelocation(statspec, st, ti->tile, var10);
02752         layout->ProcessRegisters(var10, var10_relocation, separate_ground);
02753       }
02754       tmp_rail_layout.seq = layout->GetLayout(&tmp_rail_layout.ground);
02755       t = &tmp_rail_layout;
02756       total_offset = 0;
02757     } else if (statspec != NULL) {
02758       /* Simple sprite layout */
02759       ground_relocation = relocation = GetCustomStationRelocation(statspec, st, ti->tile, 0);
02760       if (HasBit(statspec->flags, SSF_SEPARATE_GROUND)) {
02761         ground_relocation = GetCustomStationRelocation(statspec, st, ti->tile, 1);
02762       }
02763       ground_relocation += rti->fallback_railtype;
02764     }
02765 
02766     SpriteID image = t->ground.sprite;
02767     PaletteID pal  = t->ground.pal;
02768     if (rti != NULL && rti->UsesOverlay() && (image == SPR_RAIL_TRACK_X || image == SPR_RAIL_TRACK_Y)) {
02769       SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
02770       DrawGroundSprite(SPR_FLAT_GRASS_TILE, PAL_NONE);
02771       DrawGroundSprite(ground + (image == SPR_RAIL_TRACK_X ? RTO_X : RTO_Y), PAL_NONE);
02772 
02773       if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasStationReservation(ti->tile)) {
02774         SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
02775         DrawGroundSprite(overlay + (image == SPR_RAIL_TRACK_X ? RTO_X : RTO_Y), PALETTE_CRASH);
02776       }
02777     } else {
02778       image += HasBit(image, SPRITE_MODIFIER_CUSTOM_SPRITE) ? ground_relocation : total_offset;
02779       if (HasBit(pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) pal += ground_relocation;
02780       DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, palette));
02781 
02782       /* PBS debugging, draw reserved tracks darker */
02783       if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasStationRail(ti->tile) && HasStationReservation(ti->tile)) {
02784         const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
02785         DrawGroundSprite(GetRailStationAxis(ti->tile) == AXIS_X ? rti->base_sprites.single_x : rti->base_sprites.single_y, PALETTE_CRASH);
02786       }
02787     }
02788   }
02789 
02790   if (HasStationRail(ti->tile) && HasCatenaryDrawn(GetRailType(ti->tile)) && IsStationTileElectrifiable(ti->tile)) DrawCatenary(ti);
02791 
02792   if (HasBit(roadtypes, ROADTYPE_TRAM)) {
02793     Axis axis = GetRoadStopDir(ti->tile) == DIAGDIR_NE ? AXIS_X : AXIS_Y;
02794     DrawGroundSprite((HasBit(roadtypes, ROADTYPE_ROAD) ? SPR_TRAMWAY_OVERLAY : SPR_TRAMWAY_TRAM) + (axis ^ 1), PAL_NONE);
02795     DrawTramCatenary(ti, axis == AXIS_X ? ROAD_X : ROAD_Y);
02796   }
02797 
02798   if (IsRailWaypoint(ti->tile)) {
02799     /* Don't offset the waypoint graphics; they're always the same. */
02800     total_offset = 0;
02801   }
02802 
02803   DrawRailTileSeq(ti, t, TO_BUILDINGS, total_offset, relocation, palette);
02804 }
02805 
02806 void StationPickerDrawSprite(int x, int y, StationType st, RailType railtype, RoadType roadtype, int image)
02807 {
02808   int32 total_offset = 0;
02809   PaletteID pal = COMPANY_SPRITE_COLOUR(_local_company);
02810   const DrawTileSprites *t = GetStationTileLayout(st, image);
02811   const RailtypeInfo *rti = NULL;
02812 
02813   if (railtype != INVALID_RAILTYPE) {
02814     rti = GetRailTypeInfo(railtype);
02815     total_offset = rti->GetRailtypeSpriteOffset();
02816   }
02817 
02818   SpriteID img = t->ground.sprite;
02819   if ((img == SPR_RAIL_TRACK_X || img == SPR_RAIL_TRACK_Y) && rti->UsesOverlay()) {
02820     SpriteID ground = GetCustomRailSprite(rti, INVALID_TILE, RTSG_GROUND);
02821     DrawSprite(SPR_FLAT_GRASS_TILE, PAL_NONE, x, y);
02822     DrawSprite(ground + (img == SPR_RAIL_TRACK_X ? RTO_X : RTO_Y), PAL_NONE, x, y);
02823   } else {
02824     DrawSprite(img + total_offset, HasBit(img, PALETTE_MODIFIER_COLOUR) ? pal : PAL_NONE, x, y);
02825   }
02826 
02827   if (roadtype == ROADTYPE_TRAM) {
02828     DrawSprite(SPR_TRAMWAY_TRAM + (t->ground.sprite == SPR_ROAD_PAVED_STRAIGHT_X ? 1 : 0), PAL_NONE, x, y);
02829   }
02830 
02831   /* Default waypoint has no railtype specific sprites */
02832   DrawRailTileSeqInGUI(x, y, t, st == STATION_WAYPOINT ? 0 : total_offset, 0, pal);
02833 }
02834 
02835 static uint GetSlopeZ_Station(TileIndex tile, uint x, uint y)
02836 {
02837   return GetTileMaxZ(tile);
02838 }
02839 
02840 static Foundation GetFoundation_Station(TileIndex tile, Slope tileh)
02841 {
02842   return FlatteningFoundation(tileh);
02843 }
02844 
02845 static void GetTileDesc_Station(TileIndex tile, TileDesc *td)
02846 {
02847   td->owner[0] = GetTileOwner(tile);
02848   if (IsDriveThroughStopTile(tile)) {
02849     Owner road_owner = INVALID_OWNER;
02850     Owner tram_owner = INVALID_OWNER;
02851     RoadTypes rts = GetRoadTypes(tile);
02852     if (HasBit(rts, ROADTYPE_ROAD)) road_owner = GetRoadOwner(tile, ROADTYPE_ROAD);
02853     if (HasBit(rts, ROADTYPE_TRAM)) tram_owner = GetRoadOwner(tile, ROADTYPE_TRAM);
02854 
02855     /* Is there a mix of owners? */
02856     if ((tram_owner != INVALID_OWNER && tram_owner != td->owner[0]) ||
02857         (road_owner != INVALID_OWNER && road_owner != td->owner[0])) {
02858       uint i = 1;
02859       if (road_owner != INVALID_OWNER) {
02860         td->owner_type[i] = STR_LAND_AREA_INFORMATION_ROAD_OWNER;
02861         td->owner[i] = road_owner;
02862         i++;
02863       }
02864       if (tram_owner != INVALID_OWNER) {
02865         td->owner_type[i] = STR_LAND_AREA_INFORMATION_TRAM_OWNER;
02866         td->owner[i] = tram_owner;
02867       }
02868     }
02869   }
02870   td->build_date = BaseStation::GetByTile(tile)->build_date;
02871 
02872   if (HasStationTileRail(tile)) {
02873     const StationSpec *spec = GetStationSpec(tile);
02874 
02875     if (spec != NULL) {
02876       td->station_class = StationClass::GetName(spec->cls_id);
02877       td->station_name  = spec->name;
02878 
02879       if (spec->grf_prop.grffile != NULL) {
02880         const GRFConfig *gc = GetGRFConfig(spec->grf_prop.grffile->grfid);
02881         td->grf = gc->GetName();
02882       }
02883     }
02884 
02885     const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(tile));
02886     td->rail_speed = rti->max_speed;
02887   }
02888 
02889   if (IsAirport(tile)) {
02890     const AirportSpec *as = Station::GetByTile(tile)->airport.GetSpec();
02891     td->airport_class = AirportClass::GetName(as->cls_id);
02892     td->airport_name = as->name;
02893 
02894     const AirportTileSpec *ats = AirportTileSpec::GetByTile(tile);
02895     td->airport_tile_name = ats->name;
02896 
02897     if (as->grf_prop.grffile != NULL) {
02898       const GRFConfig *gc = GetGRFConfig(as->grf_prop.grffile->grfid);
02899       td->grf = gc->GetName();
02900     } else if (ats->grf_prop.grffile != NULL) {
02901       const GRFConfig *gc = GetGRFConfig(ats->grf_prop.grffile->grfid);
02902       td->grf = gc->GetName();
02903     }
02904   }
02905 
02906   StringID str;
02907   switch (GetStationType(tile)) {
02908     default: NOT_REACHED();
02909     case STATION_RAIL:     str = STR_LAI_STATION_DESCRIPTION_RAILROAD_STATION; break;
02910     case STATION_AIRPORT:
02911       str = (IsHangar(tile) ? STR_LAI_STATION_DESCRIPTION_AIRCRAFT_HANGAR : STR_LAI_STATION_DESCRIPTION_AIRPORT);
02912       break;
02913     case STATION_TRUCK:    str = STR_LAI_STATION_DESCRIPTION_TRUCK_LOADING_AREA; break;
02914     case STATION_BUS:      str = STR_LAI_STATION_DESCRIPTION_BUS_STATION; break;
02915     case STATION_OILRIG:   str = STR_INDUSTRY_NAME_OIL_RIG; break;
02916     case STATION_DOCK:     str = STR_LAI_STATION_DESCRIPTION_SHIP_DOCK; break;
02917     case STATION_BUOY:     str = STR_LAI_STATION_DESCRIPTION_BUOY; break;
02918     case STATION_WAYPOINT: str = STR_LAI_STATION_DESCRIPTION_WAYPOINT; break;
02919   }
02920   td->str = str;
02921 }
02922 
02923 
02924 static TrackStatus GetTileTrackStatus_Station(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
02925 {
02926   TrackBits trackbits = TRACK_BIT_NONE;
02927 
02928   switch (mode) {
02929     case TRANSPORT_RAIL:
02930       if (HasStationRail(tile) && !IsStationTileBlocked(tile)) {
02931         trackbits = TrackToTrackBits(GetRailStationTrack(tile));
02932       }
02933       break;
02934 
02935     case TRANSPORT_WATER:
02936       /* buoy is coded as a station, it is always on open water */
02937       if (IsBuoy(tile)) {
02938         trackbits = TRACK_BIT_ALL;
02939         /* remove tracks that connect NE map edge */
02940         if (TileX(tile) == 0) trackbits &= ~(TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_RIGHT);
02941         /* remove tracks that connect NW map edge */
02942         if (TileY(tile) == 0) trackbits &= ~(TRACK_BIT_Y | TRACK_BIT_LEFT | TRACK_BIT_UPPER);
02943       }
02944       break;
02945 
02946     case TRANSPORT_ROAD:
02947       if ((GetRoadTypes(tile) & sub_mode) != 0 && IsRoadStop(tile)) {
02948         DiagDirection dir = GetRoadStopDir(tile);
02949         Axis axis = DiagDirToAxis(dir);
02950 
02951         if (side != INVALID_DIAGDIR) {
02952           if (axis != DiagDirToAxis(side) || (IsStandardRoadStopTile(tile) && dir != side)) break;
02953         }
02954 
02955         trackbits = AxisToTrackBits(axis);
02956       }
02957       break;
02958 
02959     default:
02960       break;
02961   }
02962 
02963   return CombineTrackStatus(TrackBitsToTrackdirBits(trackbits), TRACKDIR_BIT_NONE);
02964 }
02965 
02966 
02967 static void TileLoop_Station(TileIndex tile)
02968 {
02969   /* FIXME -- GetTileTrackStatus_Station -> animated stationtiles
02970    * hardcoded.....not good */
02971   switch (GetStationType(tile)) {
02972     case STATION_AIRPORT:
02973       AirportTileAnimationTrigger(Station::GetByTile(tile), tile, AAT_TILELOOP);
02974       break;
02975 
02976     case STATION_DOCK:
02977       if (GetTileSlope(tile, NULL) != SLOPE_FLAT) break; // only handle water part
02978       /* FALL THROUGH */
02979     case STATION_OILRIG: //(station part)
02980     case STATION_BUOY:
02981       TileLoop_Water(tile);
02982       break;
02983 
02984     default: break;
02985   }
02986 }
02987 
02988 
02989 static void AnimateTile_Station(TileIndex tile)
02990 {
02991   if (HasStationRail(tile)) {
02992     AnimateStationTile(tile);
02993     return;
02994   }
02995 
02996   if (IsAirport(tile)) {
02997     AnimateAirportTile(tile);
02998   }
02999 }
03000 
03001 
03002 static bool ClickTile_Station(TileIndex tile)
03003 {
03004   const BaseStation *bst = BaseStation::GetByTile(tile);
03005 
03006   if (bst->facilities & FACIL_WAYPOINT) {
03007     ShowWaypointWindow(Waypoint::From(bst));
03008   } else if (IsHangar(tile)) {
03009     const Station *st = Station::From(bst);
03010     ShowDepotWindow(st->airport.GetHangarTile(st->airport.GetHangarNum(tile)), VEH_AIRCRAFT);
03011   } else {
03012     ShowStationViewWindow(bst->index);
03013   }
03014   return true;
03015 }
03016 
03017 static VehicleEnterTileStatus VehicleEnter_Station(Vehicle *v, TileIndex tile, int x, int y)
03018 {
03019   if (v->type == VEH_TRAIN) {
03020     StationID station_id = GetStationIndex(tile);
03021     if (!v->current_order.ShouldStopAtStation(v, station_id)) return VETSB_CONTINUE;
03022     if (!IsRailStation(tile) || !v->IsFrontEngine()) return VETSB_CONTINUE;
03023 
03024     int station_ahead;
03025     int station_length;
03026     int stop = GetTrainStopLocation(station_id, tile, Train::From(v), &station_ahead, &station_length);
03027 
03028     /* Stop whenever that amount of station ahead + the distance from the
03029      * begin of the platform to the stop location is longer than the length
03030      * of the platform. Station ahead 'includes' the current tile where the
03031      * vehicle is on, so we need to substract that. */
03032     if (!IsInsideBS(stop + station_ahead, station_length, TILE_SIZE)) return VETSB_CONTINUE;
03033 
03034     DiagDirection dir = DirToDiagDir(v->direction);
03035 
03036     x &= 0xF;
03037     y &= 0xF;
03038 
03039     if (DiagDirToAxis(dir) != AXIS_X) Swap(x, y);
03040     if (y == TILE_SIZE / 2) {
03041       if (dir != DIAGDIR_SE && dir != DIAGDIR_SW) x = TILE_SIZE - 1 - x;
03042       stop &= TILE_SIZE - 1;
03043 
03044       if (x == stop) return VETSB_ENTERED_STATION | (VehicleEnterTileStatus)(station_id << VETS_STATION_ID_OFFSET); // enter station
03045       if (x < stop) {
03046         uint16 spd;
03047 
03048         v->vehstatus |= VS_TRAIN_SLOWING;
03049         spd = max(0, (stop - x) * 20 - 15);
03050         if (spd < v->cur_speed) v->cur_speed = spd;
03051       }
03052     }
03053   } else if (v->type == VEH_ROAD) {
03054     RoadVehicle *rv = RoadVehicle::From(v);
03055     if (rv->state < RVSB_IN_ROAD_STOP && !IsReversingRoadTrackdir((Trackdir)rv->state) && rv->frame == 0) {
03056       if (IsRoadStop(tile) && rv->IsFrontEngine()) {
03057         /* Attempt to allocate a parking bay in a road stop */
03058         return RoadStop::GetByTile(tile, GetRoadStopType(tile))->Enter(rv) ? VETSB_CONTINUE : VETSB_CANNOT_ENTER;
03059       }
03060     }
03061   }
03062 
03063   return VETSB_CONTINUE;
03064 }
03065 
03072 static bool StationHandleBigTick(BaseStation *st)
03073 {
03074   if (!st->IsInUse() && ++st->delete_ctr >= 8) {
03075     delete st;
03076     return false;
03077   }
03078 
03079   if (Station::IsExpected(st)) {
03080     for (CargoID i = 0; i < NUM_CARGO; i++) {
03081       ClrBit(Station::From(st)->goods[i].acceptance_pickup, GoodsEntry::GES_ACCEPTED_BIGTICK);
03082     }
03083   }
03084 
03085 
03086   if ((st->facilities & FACIL_WAYPOINT) == 0) UpdateStationAcceptance(Station::From(st), true);
03087 
03088   return true;
03089 }
03090 
03091 static inline void byte_inc_sat(byte *p)
03092 {
03093   byte b = *p + 1;
03094   if (b != 0) *p = b;
03095 }
03096 
03097 static void UpdateStationRating(Station *st)
03098 {
03099   bool waiting_changed = false;
03100 
03101   byte_inc_sat(&st->time_since_load);
03102   byte_inc_sat(&st->time_since_unload);
03103 
03104   const CargoSpec *cs;
03105   FOR_ALL_CARGOSPECS(cs) {
03106     GoodsEntry *ge = &st->goods[cs->Index()];
03107     /* Slowly increase the rating back to his original level in the case we
03108      *  didn't deliver cargo yet to this station. This happens when a bribe
03109      *  failed while you didn't moved that cargo yet to a station. */
03110     if (!HasBit(ge->acceptance_pickup, GoodsEntry::GES_PICKUP) && ge->rating < INITIAL_STATION_RATING) {
03111       ge->rating++;
03112     }
03113 
03114     /* Only change the rating if we are moving this cargo */
03115     if (HasBit(ge->acceptance_pickup, GoodsEntry::GES_PICKUP)) {
03116       byte_inc_sat(&ge->days_since_pickup);
03117 
03118       bool skip = false;
03119       int rating = 0;
03120       uint waiting = ge->cargo.Count();
03121 
03122       /* num_dests is at least 1 if there is any cargo as
03123        * INVALID_STATION is also a destination.
03124        */
03125       uint num_dests = (uint)ge->cargo.Packets()->MapSize();
03126 
03127       /* Average amount of cargo per next hop, but prefer solitary stations
03128        * with only one or two next hops. They are allowed to have more
03129        * cargo waiting per next hop.
03130        * With manual cargo distribution waiting_avg = waiting / 2 as then
03131        * INVALID_STATION is the only destination.
03132        */
03133       uint waiting_avg = waiting / (num_dests + 1);
03134 
03135       if (HasBit(cs->callback_mask, CBM_CARGO_STATION_RATING_CALC)) {
03136         /* Perform custom station rating. If it succeeds the speed, days in transit and
03137          * waiting cargo ratings must not be executed. */
03138 
03139         /* NewGRFs expect last speed to be 0xFF when no vehicle has arrived yet. */
03140         uint last_speed = ge->last_speed;
03141         if (last_speed == 0) last_speed = 0xFF;
03142 
03143         uint32 var18 = min(ge->days_since_pickup, 0xFF) | (min(ge->max_waiting_cargo, 0xFFFF) << 8) | (min(last_speed, 0xFF) << 24);
03144         /* Convert to the 'old' vehicle types */
03145         uint32 var10 = (st->last_vehicle_type == VEH_INVALID) ? 0x0 : (st->last_vehicle_type + 0x10);
03146         uint16 callback = GetCargoCallback(CBID_CARGO_STATION_RATING_CALC, var10, var18, cs);
03147         if (callback != CALLBACK_FAILED) {
03148           skip = true;
03149           rating = GB(callback, 0, 14);
03150 
03151           /* Simulate a 15 bit signed value */
03152           if (HasBit(callback, 14)) rating -= 0x4000;
03153         }
03154       }
03155 
03156       if (!skip) {
03157         int b = ge->last_speed - 85;
03158         if (b >= 0) rating += b >> 2;
03159 
03160         byte days = ge->days_since_pickup;
03161         if (st->last_vehicle_type == VEH_SHIP) days >>= 2;
03162         (days > 21) ||
03163         (rating += 25, days > 12) ||
03164         (rating += 25, days > 6) ||
03165         (rating += 45, days > 3) ||
03166         (rating += 35, true);
03167 
03168         (rating -= 90, ge->max_waiting_cargo > 1500) ||
03169         (rating += 55, ge->max_waiting_cargo > 1000) ||
03170         (rating += 35, ge->max_waiting_cargo > 600) ||
03171         (rating += 10, ge->max_waiting_cargo > 300) ||
03172         (rating += 20, ge->max_waiting_cargo > 100) ||
03173         (rating += 10, true);
03174       }
03175 
03176       if (Company::IsValidID(st->owner) && HasBit(st->town->statues, st->owner)) rating += 26;
03177 
03178       byte age = ge->last_age;
03179       (age >= 3) ||
03180       (rating += 10, age >= 2) ||
03181       (rating += 10, age >= 1) ||
03182       (rating += 13, true);
03183 
03184       {
03185         int or_ = ge->rating; // old rating
03186 
03187         /* only modify rating in steps of -2, -1, 0, 1 or 2 */
03188         ge->rating = rating = or_ + Clamp(Clamp(rating, 0, 255) - or_, -2, 2);
03189 
03190         /* if rating is <= 64 and more than 100 items waiting on average per destination,
03191          * remove some random amount of goods from the station */
03192         if (rating <= 64 && waiting_avg >= 100) {
03193           int dec = Random() & 0x1F;
03194           if (waiting_avg < 200) dec &= 7;
03195           waiting -= (dec + 1) * num_dests;
03196           waiting_changed = true;
03197         }
03198 
03199         /* if rating is <= 127 and there are any items waiting, maybe remove some goods. */
03200         if (rating <= 127 && waiting != 0) {
03201           uint32 r = Random();
03202           if (rating <= (int)GB(r, 0, 7)) {
03203             /* Need to have int, otherwise it will just overflow etc. */
03204             waiting = max((int)waiting - (int)((GB(r, 8, 2) - 1) * num_dests), 0);
03205             waiting_changed = true;
03206           }
03207         }
03208 
03209         /* At some point we really must cap the cargo. Previously this
03210          * was a strict 4095, but now we'll have a less strict, but
03211          * increasingly agressive truncation of the amount of cargo. */
03212         static const uint WAITING_CARGO_THRESHOLD  = 1 << 12;
03213         static const uint WAITING_CARGO_CUT_FACTOR = 1 <<  6;
03214         static const uint MAX_WAITING_CARGO        = 1 << 15;
03215 
03216         if (waiting > WAITING_CARGO_THRESHOLD) {
03217           uint difference = waiting - WAITING_CARGO_THRESHOLD;
03218           waiting -= (difference / WAITING_CARGO_CUT_FACTOR);
03219 
03220           waiting = min(waiting, MAX_WAITING_CARGO);
03221           waiting_changed = true;
03222         }
03223 
03224         if (waiting_changed) {
03225           /* feed back the exact own waiting cargo at this station for the
03226            * next rating calculation.
03227            */
03228           ge->max_waiting_cargo = 0;
03229 
03230           /* If truncating also punish the source stations' ratings to
03231            * decrease the flow of incoming cargo. */
03232 
03233           StationCargoAmountMap waiting_per_source;
03234           ge->cargo.CountAndTruncate(waiting, waiting_per_source);
03235           for (StationCargoAmountMap::iterator i(waiting_per_source.begin()); i != waiting_per_source.end(); ++i) {
03236             Station *source_station = Station::GetIfValid(i->first);
03237             if (source_station == NULL) continue;
03238 
03239             GoodsEntry &source_ge = source_station->goods[cs->Index()];
03240             source_ge.max_waiting_cargo = max(source_ge.max_waiting_cargo, i->second);
03241           }
03242         } else {
03243           /* if the average number per next hop is low, be more forgiving. */
03244           ge->max_waiting_cargo = waiting_avg;
03245         }
03246       }
03247     }
03248   }
03249 
03250   StationID index = st->index;
03251   if (waiting_changed) {
03252     SetWindowDirty(WC_STATION_VIEW, index); // update whole window
03253   } else {
03254     SetWindowWidgetDirty(WC_STATION_VIEW, index, SVW_RATINGLIST); // update only ratings list
03255   }
03256 }
03257 
03264 void DeleteStaleFlows(StationID at, CargoID c_id, StationID to)
03265 {
03266   FlowStatMap &flows = Station::Get(at)->goods[c_id].flows;
03267   for (FlowStatMap::iterator f_it = flows.begin(); f_it != flows.end();) {
03268     FlowStatSet &s_flows = f_it->second;
03269     for (FlowStatSet::iterator s_it = s_flows.begin(); s_it != s_flows.end();) {
03270       if (s_it->Via() == to) {
03271         s_flows.erase(s_it++);
03272         break; // There can only be one flow stat for this remote station in each set.
03273       } else {
03274         ++s_it;
03275       }
03276     }
03277     if (s_flows.empty()) {
03278       flows.erase(f_it++);
03279     } else {
03280       ++f_it;
03281     }
03282   }
03283 }
03284 
03291 uint GetMovingAverageLength(const Station *from, const Station *to)
03292 {
03293   return LinkStat::MIN_AVERAGE_LENGTH + (DistanceManhattan(from->xy, to->xy) >> 2);
03294 }
03295 
03299 void Station::RunAverages()
03300 {
03301   FlowStatSet new_flows;
03302   for (int goods_index = 0; goods_index < NUM_CARGO; ++goods_index) {
03303     LinkStatMap &links = this->goods[goods_index].link_stats;
03304     for (LinkStatMap::iterator i = links.begin(); i != links.end();) {
03305       StationID id = i->first;
03306       Station *other = Station::GetIfValid(id);
03307       if (other == NULL) {
03308         this->goods[goods_index].cargo.RerouteStalePackets(id);
03309         links.erase(i++);
03310       } else {
03311         LinkStat &ls = i->second;
03312         ls.Decrease();
03313         if (ls.IsNull()) {
03314           DeleteStaleFlows(this->index, goods_index, id);
03315           this->goods[goods_index].cargo.RerouteStalePackets(id);
03316           links.erase(i++);
03317         } else {
03318           ++i;
03319         }
03320       }
03321     }
03322 
03323     if (_settings_game.linkgraph.GetDistributionType(goods_index) == DT_MANUAL) {
03324       this->goods[goods_index].flows.clear();
03325       continue;
03326     }
03327 
03328     FlowStatMap &flows = this->goods[goods_index].flows;
03329     for (FlowStatMap::iterator i = flows.begin(); i != flows.end();) {
03330       if (!Station::IsValidID(i->first)) {
03331         flows.erase(i++);
03332       } else {
03333         FlowStatSet &flow_set = i->second;
03334         for (FlowStatSet::iterator j = flow_set.begin(); j != flow_set.end(); ++j) {
03335           if (Station::IsValidID(j->Via())) {
03336             new_flows.insert(j->GetDecreasedCopy());
03337           }
03338         }
03339         flow_set.swap(new_flows);
03340         new_flows.clear();
03341         ++i;
03342       }
03343     }
03344   }
03345 }
03346 
03352 void RecalcFrozenIfLoading(const Vehicle *v)
03353 {
03354   if (v->current_order.IsType(OT_LOADING)) {
03355     RecalcFrozen(Station::Get(v->last_station_visited));
03356   }
03357 }
03358 
03364 void RecalcFrozen(Station *st)
03365 {
03366   for (CargoID cargo = 0; cargo < NUM_CARGO; ++cargo) {
03367     LinkStatMap &links = st->goods[cargo].link_stats;
03368     for (LinkStatMap::iterator i = links.begin(); i != links.end(); ++i) {
03369       i->second.Unfreeze();
03370     }
03371   }
03372 
03373   std::list<Vehicle *>::iterator v_it = st->loading_vehicles.begin();
03374   while (v_it != st->loading_vehicles.end()) {
03375     const Vehicle *front = *v_it;
03376     OrderList *orders = front->orders.list;
03377     if (orders != NULL) {
03378       StationID next_station_id = orders->GetNextStoppingStation(front->cur_implicit_order_index, st->index);
03379       if (next_station_id != INVALID_STATION && next_station_id != st->index) {
03380         IncreaseStats(st, front, next_station_id, true);
03381       }
03382     }
03383     ++v_it;
03384   }
03385 }
03386 
03394 void DecreaseFrozen(Station *st, const Vehicle *front, StationID next_station_id) {
03395   assert(st->index != next_station_id);
03396   assert(next_station_id != INVALID_STATION);
03397   for (const Vehicle *v = front; v != NULL; v = v->Next()) {
03398     if (v->cargo_cap <= 0) continue;
03399 
03400     LinkStatMap &link_stats = st->goods[v->cargo_type].link_stats;
03401     LinkStatMap::iterator lstat_it = link_stats.find(next_station_id);
03402     if (lstat_it == link_stats.end()) {
03403       DEBUG(misc, 1, "frozen not in linkstat list.");
03404       RecalcFrozen(st);
03405       return;
03406     }
03407 
03408     LinkStat &link_stat = lstat_it->second;
03409     if (link_stat.Frozen() < v->cargo_cap) {
03410       DEBUG(misc, 1, "frozen is smaller than cargo cap.");
03411       RecalcFrozen(st);
03412       return;
03413     }
03414     link_stat.Unfreeze(v->cargo_cap);
03415     assert(!link_stat.IsNull());
03416   }
03417 }
03418 
03427 void IncreaseStats(Station *st, const Vehicle *front, StationID next_station_id, bool freeze)
03428 {
03429   Station *next = Station::GetIfValid(next_station_id);
03430   assert(st->index != next_station_id && next != NULL);
03431   uint average_length = GetMovingAverageLength(st, next);
03432 
03433   for (const Vehicle *v = front; v != NULL; v = v->Next()) {
03434     if (v->cargo_cap > 0) {
03435       LinkStatMap &stats = st->goods[v->cargo_type].link_stats;
03436       LinkStatMap::iterator i = stats.find(next_station_id);
03437       if (i == stats.end()) {
03438         stats.insert(std::make_pair(next_station_id, LinkStat(average_length,
03439             v->cargo_cap, freeze ? v->cargo_cap : 0, freeze ? 0 : v->cargo.Count())));
03440       } else {
03441         LinkStat &link_stat = i->second;
03442         if (freeze) {
03443           link_stat.Freeze(v->cargo_cap);
03444         } else {
03445           link_stat.Increase(v->cargo_cap, v->cargo.Count());
03446         }
03447         assert(!link_stat.IsNull());
03448       }
03449     }
03450   }
03451 }
03452 
03453 /* Called for every station each tick. */
03454 static void StationHandleSmallTick(BaseStation *st)
03455 {
03456   if ((st->facilities & FACIL_WAYPOINT) != 0 || !st->IsInUse()) return;
03457 
03458   byte b = st->delete_ctr + 1;
03459   if (b >= STATION_RATING_TICKS) b = 0;
03460   st->delete_ctr = b;
03461 
03462   if (b == 0) UpdateStationRating(Station::From(st));
03463 }
03464 
03465 void OnTick_Station()
03466 {
03467   if (_game_mode == GM_EDITOR) return;
03468 
03469   RunAverages<Station>();
03470 
03471   BaseStation *st;
03472   FOR_ALL_BASE_STATIONS(st) {
03473     StationHandleSmallTick(st);
03474 
03475     /* Run STATION_ACCEPTANCE_TICKS = 250 tick interval trigger for station animation.
03476      * Station index is included so that triggers are not all done
03477      * at the same time. */
03478     if ((_tick_counter + st->index) % STATION_ACCEPTANCE_TICKS == 0) {
03479       /* Stop processing this station if it was deleted */
03480       if (!StationHandleBigTick(st)) continue;
03481       TriggerStationAnimation(st, st->xy, SAT_250_TICKS);
03482       if (Station::IsExpected(st)) AirportAnimationTrigger(Station::From(st), AAT_STATION_250_TICKS);
03483     }
03484   }
03485 }
03486 
03488 void StationMonthlyLoop()
03489 {
03490   Station *st;
03491 
03492   FOR_ALL_STATIONS(st) {
03493     for(int goods_index = 0; goods_index < NUM_CARGO; ++goods_index) {
03494       st->goods[goods_index].supply = st->goods[goods_index].supply_new;
03495       st->goods[goods_index].supply_new = 0;
03496     }
03497   }
03498 
03499   FOR_ALL_STATIONS(st) {
03500     for (CargoID i = 0; i < NUM_CARGO; i++) {
03501       GoodsEntry *ge = &st->goods[i];
03502       SB(ge->acceptance_pickup, GoodsEntry::GES_LAST_MONTH, 1, GB(ge->acceptance_pickup, GoodsEntry::GES_CURRENT_MONTH, 1));
03503       ClrBit(ge->acceptance_pickup, GoodsEntry::GES_CURRENT_MONTH);
03504     }
03505   }
03506 }
03507 
03508 
03509 void ModifyStationRatingAround(TileIndex tile, Owner owner, int amount, uint radius)
03510 {
03511   Station *st;
03512 
03513   FOR_ALL_STATIONS(st) {
03514     if (st->owner == owner &&
03515         DistanceManhattan(tile, st->xy) <= radius) {
03516       for (CargoID i = 0; i < NUM_CARGO; i++) {
03517         GoodsEntry *ge = &st->goods[i];
03518 
03519         if (ge->acceptance_pickup != 0) {
03520           ge->rating = Clamp(ge->rating + amount, 0, 255);
03521         }
03522       }
03523     }
03524   }
03525 }
03526 
03527 static uint UpdateStationWaiting(Station *st, CargoID type, uint amount, SourceType source_type, SourceID source_id)
03528 {
03529   /* We can't allocate a CargoPacket? Then don't do anything
03530    * at all; i.e. just discard the incoming cargo. */
03531   if (!CargoPacket::CanAllocateItem()) return 0;
03532 
03533   GoodsEntry &ge = st->goods[type];
03534   amount += ge.amount_fract;
03535   ge.amount_fract = GB(amount, 0, 8);
03536 
03537   amount >>= 8;
03538   /* No new "real" cargo item yet. */
03539   if (amount == 0) return 0;
03540 
03541   StationID id = st->index;
03542   StationID next = INVALID_STATION;
03543   FlowStatSet &flow_stats = ge.flows[id];
03544   FlowStatSet::iterator i = flow_stats.begin();
03545   if (i != flow_stats.end()) {
03546     next = i->Via();
03547     const FlowStat &f = *i;
03548 
03549     if (_settings_game.linkgraph.no_overload_links &&
03550         _settings_game.linkgraph.GetDistributionType(type) == DT_SYMMETRIC) {
03551       int limit = f.Planned() - f.Sent();
03552 
03553       LinkStatMap::const_iterator it = ge.link_stats.find(next);
03554       const LinkStat &ls = (it->second);
03555 
03556       /* Don't send more than was planned or if the link's usage is higher than permitted. */
03557       limit = min(limit, (ls.Capacity() * _settings_game.linkgraph.short_path_saturation) / 100 - ls.Usage());
03558 
03559       if (limit < 0) {
03560         limit = 0;
03561       }
03562 
03563       if (amount > (uint)limit) {
03564         amount = (uint)limit;
03565       }
03566     }
03567 
03568     ge.UpdateFlowStats(flow_stats, i, amount);
03569 
03570     if (amount == 0) {
03571       return amount;
03572     }
03573   }
03574 
03575   ge.cargo.Append(next, new CargoPacket(st->index, st->xy, amount, source_type, source_id));
03576   ge.supply_new += amount;
03577 
03578   if (!HasBit(ge.acceptance_pickup, GoodsEntry::GES_PICKUP)) {
03579     InvalidateWindowData(WC_STATION_LIST, st->index);
03580     SetBit(ge.acceptance_pickup, GoodsEntry::GES_PICKUP);
03581   }
03582 
03583   TriggerStationAnimation(st, st->xy, SAT_NEW_CARGO, type);
03584   AirportAnimationTrigger(st, AAT_STATION_NEW_CARGO, type);
03585 
03586   SetWindowDirty(WC_STATION_VIEW, st->index);
03587   st->MarkTilesDirty(true);
03588   return amount;
03589 }
03590 
03591 static bool IsUniqueStationName(const char *name)
03592 {
03593   const Station *st;
03594 
03595   FOR_ALL_STATIONS(st) {
03596     if (st->name != NULL && strcmp(st->name, name) == 0) return false;
03597   }
03598 
03599   return true;
03600 }
03601 
03611 CommandCost CmdRenameStation(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
03612 {
03613   Station *st = Station::GetIfValid(p1);
03614   if (st == NULL) return CMD_ERROR;
03615 
03616   CommandCost ret = CheckOwnership(st->owner);
03617   if (ret.Failed()) return ret;
03618 
03619   bool reset = StrEmpty(text);
03620 
03621   if (!reset) {
03622     if (Utf8StringLength(text) >= MAX_LENGTH_STATION_NAME_CHARS) return CMD_ERROR;
03623     if (!IsUniqueStationName(text)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE);
03624   }
03625 
03626   if (flags & DC_EXEC) {
03627     free(st->name);
03628     st->name = reset ? NULL : strdup(text);
03629 
03630     st->UpdateVirtCoord();
03631     InvalidateWindowData(WC_STATION_LIST, st->owner, 1);
03632   }
03633 
03634   return CommandCost();
03635 }
03636 
03643 void FindStationsAroundTiles(const TileArea &location, StationList *stations)
03644 {
03645   /* area to search = producer plus station catchment radius */
03646   int max_rad = (_settings_game.station.modified_catchment ? MAX_CATCHMENT : CA_UNMODIFIED);
03647 
03648   for (int dy = -max_rad; dy < location.h + max_rad; dy++) {
03649     for (int dx = -max_rad; dx < location.w + max_rad; dx++) {
03650       TileIndex cur_tile = TileAddWrap(location.tile, dx, dy);
03651       if (cur_tile == INVALID_TILE || !IsTileType(cur_tile, MP_STATION)) continue;
03652 
03653       Station *st = Station::GetByTile(cur_tile);
03654       if (st == NULL) continue;
03655 
03656       if (_settings_game.station.modified_catchment) {
03657         int rad = st->GetCatchmentRadius();
03658         if (dx < -rad || dx >= rad + location.w || dy < -rad || dy >= rad + location.h) continue;
03659       }
03660 
03661       /* Insert the station in the set. This will fail if it has
03662        * already been added.
03663        */
03664       stations->Include(st);
03665     }
03666   }
03667 }
03668 
03673 const StationList *StationFinder::GetStations()
03674 {
03675   if (this->tile != INVALID_TILE) {
03676     FindStationsAroundTiles(*this, &this->stations);
03677     this->tile = INVALID_TILE;
03678   }
03679   return &this->stations;
03680 }
03681 
03682 uint MoveGoodsToStation(CargoID type, uint amount, SourceType source_type, SourceID source_id, const StationList *all_stations)
03683 {
03684   /* Return if nothing to do. Also the rounding below fails for 0. */
03685   if (amount == 0) return 0;
03686 
03687   Station *st1 = NULL;   // Station with best rating
03688   Station *st2 = NULL;   // Second best station
03689   uint best_rating1 = 0; // rating of st1
03690   uint best_rating2 = 0; // rating of st2
03691 
03692   for (Station * const *st_iter = all_stations->Begin(); st_iter != all_stations->End(); ++st_iter) {
03693     Station *st = *st_iter;
03694 
03695     /* Is the station reserved exclusively for somebody else? */
03696     if (st->town->exclusive_counter > 0 && st->town->exclusivity != st->owner) continue;
03697 
03698     if (st->goods[type].rating == 0) continue; // Lowest possible rating, better not to give cargo anymore
03699 
03700     if (_settings_game.order.selectgoods && st->goods[type].last_speed == 0) continue; // Selectively servicing stations, and not this one
03701 
03702     if (IsCargoInClass(type, CC_PASSENGERS)) {
03703       if (st->facilities == FACIL_TRUCK_STOP) continue; // passengers are never served by just a truck stop
03704     } else {
03705       if (st->facilities == FACIL_BUS_STOP) continue; // non-passengers are never served by just a bus stop
03706     }
03707 
03708     /* This station can be used, add it to st1/st2 */
03709     if (st1 == NULL || st->goods[type].rating >= best_rating1) {
03710       st2 = st1; best_rating2 = best_rating1; st1 = st; best_rating1 = st->goods[type].rating;
03711     } else if (st2 == NULL || st->goods[type].rating >= best_rating2) {
03712       st2 = st; best_rating2 = st->goods[type].rating;
03713     }
03714   }
03715 
03716   /* no stations around at all? */
03717   if (st1 == NULL) return 0;
03718 
03719   /* From now we'll calculate with fractal cargo amounts.
03720    * First determine how much cargo we really have. */
03721   amount *= best_rating1 + 1;
03722 
03723   if (st2 == NULL) {
03724     /* only one station around */
03725     return UpdateStationWaiting(st1, type, amount, source_type, source_id);
03726   }
03727 
03728   /* several stations around, the best two (highest rating) are in st1 and st2 */
03729   assert(st1 != NULL);
03730   assert(st2 != NULL);
03731   assert(best_rating1 != 0 || best_rating2 != 0);
03732 
03733   /* Then determine the amount the worst station gets. We do it this way as the
03734    * best should get a bonus, which in this case is the rounding difference from
03735    * this calculation. In reality that will mean the bonus will be pretty low.
03736    * Nevertheless, the best station should always get the most cargo regardless
03737    * of rounding issues. */
03738   uint worst_cargo = amount * best_rating2 / (best_rating1 + best_rating2);
03739   assert(worst_cargo <= (amount - worst_cargo));
03740 
03741   /* And then send the cargo to the stations! */
03742   uint moved = UpdateStationWaiting(st1, type, amount - worst_cargo, source_type, source_id);
03743   /* These two UpdateStationWaiting's can't be in the statement as then the order
03744    * of execution would be undefined and that could cause desyncs with callbacks. */
03745   return moved + UpdateStationWaiting(st2, type, worst_cargo, source_type, source_id);
03746 }
03747 
03748 void BuildOilRig(TileIndex tile)
03749 {
03750   if (!Station::CanAllocateItem()) {
03751     DEBUG(misc, 0, "Can't allocate station for oilrig at 0x%X, reverting to oilrig only", tile);
03752     return;
03753   }
03754 
03755   Station *st = new Station(tile);
03756   st->town = ClosestTownFromTile(tile, UINT_MAX);
03757 
03758   st->string_id = GenerateStationName(st, tile, STATIONNAMING_OILRIG);
03759 
03760   assert(IsTileType(tile, MP_INDUSTRY));
03761   DeleteAnimatedTile(tile);
03762   MakeOilrig(tile, st->index, GetWaterClass(tile));
03763 
03764   st->owner = OWNER_NONE;
03765   st->airport.type = AT_OILRIG;
03766   st->airport.Add(tile);
03767   st->dock_tile = tile;
03768   st->facilities = FACIL_AIRPORT | FACIL_DOCK;
03769   st->build_date = _date;
03770 
03771   st->rect.BeforeAddTile(tile, StationRect::ADD_FORCE);
03772 
03773   for (CargoID j = 0; j < NUM_CARGO; j++) {
03774     st->goods[j].acceptance_pickup = 0;
03775     st->goods[j].days_since_pickup = 255;
03776     st->goods[j].rating = INITIAL_STATION_RATING;
03777     st->goods[j].last_speed = 0;
03778     st->goods[j].last_age = 255;
03779   }
03780 
03781   st->UpdateVirtCoord();
03782   UpdateStationAcceptance(st, false);
03783   st->RecomputeIndustriesNear();
03784 }
03785 
03786 void DeleteOilRig(TileIndex tile)
03787 {
03788   Station *st = Station::GetByTile(tile);
03789 
03790   MakeWaterKeepingClass(tile, OWNER_NONE);
03791 
03792   st->dock_tile = INVALID_TILE;
03793   st->airport.Clear();
03794   st->facilities &= ~(FACIL_AIRPORT | FACIL_DOCK);
03795   st->airport.flags = 0;
03796 
03797   st->rect.AfterRemoveTile(st, tile);
03798 
03799   st->UpdateVirtCoord();
03800   st->RecomputeIndustriesNear();
03801   if (!st->IsInUse()) delete st;
03802 }
03803 
03804 static void ChangeTileOwner_Station(TileIndex tile, Owner old_owner, Owner new_owner)
03805 {
03806   if (IsDriveThroughStopTile(tile)) {
03807     for (RoadType rt = ROADTYPE_ROAD; rt < ROADTYPE_END; rt++) {
03808       /* Update all roadtypes, no matter if they are present */
03809       if (GetRoadOwner(tile, rt) == old_owner) {
03810         if (HasTileRoadType(tile, rt)) {
03811           /* A drive-through road-stop has always two road bits. No need to dirty windows here, we'll redraw the whole screen anyway. */
03812           Company::Get(old_owner)->road_infrastructure[rt] -= 2;
03813           if (new_owner != INVALID_OWNER) Company::Get(new_owner)->road_infrastructure[rt] += 2;
03814         }
03815         SetRoadOwner(tile, rt, new_owner == INVALID_OWNER ? OWNER_NONE : new_owner);
03816       }
03817     }
03818   }
03819 
03820   if (!IsTileOwner(tile, old_owner)) return;
03821 
03822   if (new_owner != INVALID_OWNER) {
03823     /* Update company infrastructure counts. Only do it here
03824      * if the new owner is valid as otherwise the clear
03825      * command will do it for us. No need to dirty windows
03826      * here, we'll redraw the whole screen anyway.*/
03827     Company *old_company = Company::Get(old_owner);
03828     Company *new_company = Company::Get(new_owner);
03829 
03830     /* Update counts for underlying infrastructure. */
03831     switch (GetStationType(tile)) {
03832       case STATION_RAIL:
03833       case STATION_WAYPOINT:
03834         if (!IsStationTileBlocked(tile)) {
03835           old_company->rail_infrastructure[GetRailType(tile)]--;
03836           new_company->rail_infrastructure[GetRailType(tile)]++;
03837         }
03838         break;
03839 
03840       case STATION_BUS:
03841       case STATION_TRUCK:
03842         if (!IsDriveThroughStopTile(tile)) {
03843           /* Drive-through stops were already handled above. */
03844           old_company->road_infrastructure[FIND_FIRST_BIT(GetRoadTypes(tile))] -= 2;
03845           new_company->road_infrastructure[FIND_FIRST_BIT(GetRoadTypes(tile))] += 2;
03846         }
03847         break;
03848 
03849       case STATION_BUOY:
03850       case STATION_DOCK:
03851         if (GetWaterClass(tile) == WATER_CLASS_CANAL) {
03852           old_company->water_infrastructure--;
03853           new_company->water_infrastructure++;
03854         }
03855       break;
03856 
03857       default:
03858         break;
03859     }
03860 
03861     /* Update station tile count. */
03862     if (!IsBuoy(tile) && !IsAirport(tile)) {
03863       old_company->station_infrastructure--;
03864       new_company->station_infrastructure++;
03865     }
03866 
03867     /* for buoys, owner of tile is owner of water, st->owner == OWNER_NONE */
03868     SetTileOwner(tile, new_owner);
03869     InvalidateWindowClassesData(WC_STATION_LIST, 0);
03870   } else {
03871     if (IsDriveThroughStopTile(tile)) {
03872       /* Remove the drive-through road stop */
03873       DoCommand(tile, 1 | 1 << 8, (GetStationType(tile) == STATION_TRUCK) ? ROADSTOP_TRUCK : ROADSTOP_BUS, DC_EXEC | DC_BANKRUPT, CMD_REMOVE_ROAD_STOP);
03874       assert(IsTileType(tile, MP_ROAD));
03875       /* Change owner of tile and all roadtypes */
03876       ChangeTileOwner(tile, old_owner, new_owner);
03877     } else {
03878       DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
03879       /* Set tile owner of water under (now removed) buoy and dock to OWNER_NONE.
03880        * Update owner of buoy if it was not removed (was in orders).
03881        * Do not update when owned by OWNER_WATER (sea and rivers). */
03882       if ((IsTileType(tile, MP_WATER) || IsBuoyTile(tile)) && IsTileOwner(tile, old_owner)) SetTileOwner(tile, OWNER_NONE);
03883     }
03884   }
03885 }
03886 
03895 static bool CanRemoveRoadWithStop(TileIndex tile, DoCommandFlag flags)
03896 {
03897   /* Yeah... water can always remove stops, right? */
03898   if (_current_company == OWNER_WATER) return true;
03899 
03900   RoadTypes rts = GetRoadTypes(tile);
03901   if (HasBit(rts, ROADTYPE_TRAM)) {
03902     Owner tram_owner = GetRoadOwner(tile, ROADTYPE_TRAM);
03903     if (tram_owner != OWNER_NONE && CheckOwnership(tram_owner).Failed()) return false;
03904   }
03905   if (HasBit(rts, ROADTYPE_ROAD)) {
03906     Owner road_owner = GetRoadOwner(tile, ROADTYPE_ROAD);
03907     if (road_owner != OWNER_TOWN) {
03908       if (road_owner != OWNER_NONE && CheckOwnership(road_owner).Failed()) return false;
03909     } else {
03910       if (CheckAllowRemoveRoad(tile, GetAnyRoadBits(tile, ROADTYPE_ROAD), OWNER_TOWN, ROADTYPE_ROAD, flags).Failed()) return false;
03911     }
03912   }
03913 
03914   return true;
03915 }
03916 
03923 CommandCost ClearTile_Station(TileIndex tile, DoCommandFlag flags)
03924 {
03925   if (flags & DC_AUTO) {
03926     switch (GetStationType(tile)) {
03927       default: break;
03928       case STATION_RAIL:     return_cmd_error(STR_ERROR_MUST_DEMOLISH_RAILROAD);
03929       case STATION_WAYPOINT: return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
03930       case STATION_AIRPORT:  return_cmd_error(STR_ERROR_MUST_DEMOLISH_AIRPORT_FIRST);
03931       case STATION_TRUCK:    return_cmd_error(HasTileRoadType(tile, ROADTYPE_TRAM) ? STR_ERROR_MUST_DEMOLISH_CARGO_TRAM_STATION_FIRST : STR_ERROR_MUST_DEMOLISH_TRUCK_STATION_FIRST);
03932       case STATION_BUS:      return_cmd_error(HasTileRoadType(tile, ROADTYPE_TRAM) ? STR_ERROR_MUST_DEMOLISH_PASSENGER_TRAM_STATION_FIRST : STR_ERROR_MUST_DEMOLISH_BUS_STATION_FIRST);
03933       case STATION_BUOY:     return_cmd_error(STR_ERROR_BUOY_IN_THE_WAY);
03934       case STATION_DOCK:     return_cmd_error(STR_ERROR_MUST_DEMOLISH_DOCK_FIRST);
03935       case STATION_OILRIG:
03936         SetDParam(1, STR_INDUSTRY_NAME_OIL_RIG);
03937         return_cmd_error(STR_ERROR_GENERIC_OBJECT_IN_THE_WAY);
03938     }
03939   }
03940 
03941   switch (GetStationType(tile)) {
03942     case STATION_RAIL:     return RemoveRailStation(tile, flags);
03943     case STATION_WAYPOINT: return RemoveRailWaypoint(tile, flags);
03944     case STATION_AIRPORT:  return RemoveAirport(tile, flags);
03945     case STATION_TRUCK:
03946       if (IsDriveThroughStopTile(tile) && !CanRemoveRoadWithStop(tile, flags)) {
03947         return_cmd_error(STR_ERROR_MUST_DEMOLISH_TRUCK_STATION_FIRST);
03948       }
03949       return RemoveRoadStop(tile, flags);
03950     case STATION_BUS:
03951       if (IsDriveThroughStopTile(tile) && !CanRemoveRoadWithStop(tile, flags)) {
03952         return_cmd_error(STR_ERROR_MUST_DEMOLISH_BUS_STATION_FIRST);
03953       }
03954       return RemoveRoadStop(tile, flags);
03955     case STATION_BUOY:     return RemoveBuoy(tile, flags);
03956     case STATION_DOCK:     return RemoveDock(tile, flags);
03957     default: break;
03958   }
03959 
03960   return CMD_ERROR;
03961 }
03962 
03963 static CommandCost TerraformTile_Station(TileIndex tile, DoCommandFlag flags, uint z_new, Slope tileh_new)
03964 {
03965   if (_settings_game.construction.build_on_slopes && AutoslopeEnabled()) {
03966     /* TODO: If you implement newgrf callback 149 'land slope check', you have to decide what to do with it here.
03967      *       TTDP does not call it.
03968      */
03969     if (!IsSteepSlope(tileh_new) && (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new))) {
03970       switch (GetStationType(tile)) {
03971         case STATION_WAYPOINT:
03972         case STATION_RAIL: {
03973           DiagDirection direction = AxisToDiagDir(GetRailStationAxis(tile));
03974           if (!AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, direction)) break;
03975           if (!AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, ReverseDiagDir(direction))) break;
03976           return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
03977         }
03978 
03979         case STATION_AIRPORT:
03980           return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
03981 
03982         case STATION_TRUCK:
03983         case STATION_BUS: {
03984           DiagDirection direction = GetRoadStopDir(tile);
03985           if (!AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, direction)) break;
03986           if (IsDriveThroughStopTile(tile)) {
03987             if (!AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, ReverseDiagDir(direction))) break;
03988           }
03989           return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
03990         }
03991 
03992         default: break;
03993       }
03994     }
03995   }
03996   return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
03997 }
03998 
04005 void GoodsEntry::UpdateFlowStats(FlowStatSet &flow_stats, FlowStatSet::iterator flow_it, uint count)
04006 {
04007   FlowStat fs = *flow_it;
04008   fs.Increase(count);
04009   flow_stats.erase(flow_it);
04010   flow_stats.insert(fs);
04011 }
04012 
04019 void GoodsEntry::UpdateFlowStats(FlowStatSet &flow_stats, uint count, StationID next)
04020 {
04021   FlowStatSet::iterator flow_it = flow_stats.begin();
04022   while (flow_it != flow_stats.end()) {
04023     StationID via = flow_it->Via();
04024     if (via == next) { //usually the first one is the correct one
04025       this->UpdateFlowStats(flow_stats, flow_it, count);
04026       return;
04027     } else {
04028       ++flow_it;
04029     }
04030   }
04031 }
04032 
04039 void GoodsEntry::UpdateFlowStats(StationID source, uint count, StationID next)
04040 {
04041   if (source == INVALID_STATION || next == INVALID_STATION || this->flows.empty()) return;
04042   FlowStatSet &flow_stats = this->flows[source];
04043   this->UpdateFlowStats(flow_stats, count, next);
04044 }
04045 
04053 StationID GoodsEntry::UpdateFlowStatsTransfer(StationID source, uint count, StationID curr)
04054 {
04055   if (source == INVALID_STATION || this->flows.empty()) return INVALID_STATION;
04056   FlowStatSet &flow_stats = this->flows[source];
04057   FlowStatSet::iterator flow_it = flow_stats.begin();
04058   while (flow_it != flow_stats.end()) {
04059     StationID via = flow_it->Via();
04060     if (via != curr) {
04061       this->UpdateFlowStats(flow_stats, flow_it, count);
04062       return via;
04063     } else {
04064       ++flow_it;
04065     }
04066   }
04067   return INVALID_STATION;
04068 }
04069 
04075 FlowStat GoodsEntry::GetSumFlowVia(StationID via) const {
04076   FlowStat ret(1, via);
04077   for (FlowStatMap::const_iterator i = this->flows.begin(); i != this->flows.end(); ++i) {
04078     const FlowStatSet &flow_set = i->second;
04079     for (FlowStatSet::const_iterator j = flow_set.begin(); j != flow_set.end(); ++j) {
04080       const FlowStat &flow = *j;
04081       if (flow.Via() == via) {
04082         ret += flow;
04083       }
04084     }
04085   }
04086   return ret;
04087 }
04088 
04089 extern const TileTypeProcs _tile_type_station_procs = {
04090   DrawTile_Station,           // draw_tile_proc
04091   GetSlopeZ_Station,          // get_slope_z_proc
04092   ClearTile_Station,          // clear_tile_proc
04093   NULL,                       // add_accepted_cargo_proc
04094   GetTileDesc_Station,        // get_tile_desc_proc
04095   GetTileTrackStatus_Station, // get_tile_track_status_proc
04096   ClickTile_Station,          // click_tile_proc
04097   AnimateTile_Station,        // animate_tile_proc
04098   TileLoop_Station,           // tile_loop_clear
04099   ChangeTileOwner_Station,    // change_tile_owner_clear
04100   NULL,                       // add_produced_cargo_proc
04101   VehicleEnter_Station,       // vehicle_enter_tile_proc
04102   GetFoundation_Station,      // get_foundation_proc
04103   TerraformTile_Station,      // terraform_tile_proc
04104 };