rail_cmd.cpp

Go to the documentation of this file.
00001 /* $Id: rail_cmd.cpp 23593 2011-12-19 14:24:12Z michi_cc $ */
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 "cmd_helper.h"
00014 #include "viewport_func.h"
00015 #include "command_func.h"
00016 #include "depot_base.h"
00017 #include "pathfinder/yapf/yapf_cache.h"
00018 #include "newgrf_debug.h"
00019 #include "newgrf_railtype.h"
00020 #include "train.h"
00021 #include "autoslope.h"
00022 #include "water.h"
00023 #include "tunnelbridge_map.h"
00024 #include "window_func.h"
00025 #include "vehicle_func.h"
00026 #include "sound_func.h"
00027 #include "tunnelbridge.h"
00028 #include "elrail_func.h"
00029 #include "town.h"
00030 #include "pbs.h"
00031 #include "company_base.h"
00032 #include "core/backup_type.hpp"
00033 #include "date_func.h"
00034 #include "strings_func.h"
00035 #include "company_gui.h"
00036 
00037 #include "table/strings.h"
00038 #include "table/railtypes.h"
00039 #include "table/track_land.h"
00040 
00042 typedef SmallVector<Train *, 16> TrainList;
00043 
00044 RailtypeInfo _railtypes[RAILTYPE_END];
00045 
00046 assert_compile(sizeof(_original_railtypes) <= sizeof(_railtypes));
00047 
00051 void ResetRailTypes()
00052 {
00053   memset(_railtypes, 0, sizeof(_railtypes));
00054   memcpy(_railtypes, _original_railtypes, sizeof(_original_railtypes));
00055 }
00056 
00057 void ResolveRailTypeGUISprites(RailtypeInfo *rti)
00058 {
00059   SpriteID cursors_base = GetCustomRailSprite(rti, INVALID_TILE, RTSG_CURSORS);
00060   if (cursors_base != 0) {
00061     rti->gui_sprites.build_ns_rail = cursors_base +  0;
00062     rti->gui_sprites.build_x_rail  = cursors_base +  1;
00063     rti->gui_sprites.build_ew_rail = cursors_base +  2;
00064     rti->gui_sprites.build_y_rail  = cursors_base +  3;
00065     rti->gui_sprites.auto_rail     = cursors_base +  4;
00066     rti->gui_sprites.build_depot   = cursors_base +  5;
00067     rti->gui_sprites.build_tunnel  = cursors_base +  6;
00068     rti->gui_sprites.convert_rail  = cursors_base +  7;
00069     rti->cursor.rail_ns   = cursors_base +  8;
00070     rti->cursor.rail_swne = cursors_base +  9;
00071     rti->cursor.rail_ew   = cursors_base + 10;
00072     rti->cursor.rail_nwse = cursors_base + 11;
00073     rti->cursor.autorail  = cursors_base + 12;
00074     rti->cursor.depot     = cursors_base + 13;
00075     rti->cursor.tunnel    = cursors_base + 14;
00076     rti->cursor.convert   = cursors_base + 15;
00077   }
00078 }
00079 
00083 void InitRailTypes()
00084 {
00085   for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
00086     RailtypeInfo *rti = &_railtypes[rt];
00087     ResolveRailTypeGUISprites(rti);
00088   }
00089 }
00090 
00094 RailType AllocateRailType(RailTypeLabel label)
00095 {
00096   for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
00097     RailtypeInfo *rti = &_railtypes[rt];
00098 
00099     if (rti->label == 0) {
00100       /* Set up new rail type */
00101       memcpy(rti, &_railtypes[RAILTYPE_RAIL], sizeof(*rti));
00102       rti->label = label;
00103 
00104       /* Make us compatible with ourself. */
00105       rti->powered_railtypes    = (RailTypes)(1 << rt);
00106       rti->compatible_railtypes = (RailTypes)(1 << rt);
00107 
00108       /* We also introduce ourself. */
00109       rti->introduces_railtypes = (RailTypes)(1 << rt);
00110 
00111       /* Default sort order; order of allocation, but with some
00112        * offsets so it's easier for NewGRF to pick a spot without
00113        * changing the order of other (original) rail types.
00114        * The << is so you can place other railtypes in between the
00115        * other railtypes, the 7 is to be able to place something
00116        * before the first (default) rail type. */
00117       rti->sorting_order = rt << 4 | 7;
00118       return rt;
00119     }
00120   }
00121 
00122   return INVALID_RAILTYPE;
00123 }
00124 
00125 static const byte _track_sloped_sprites[14] = {
00126   14, 15, 22, 13,
00127    0, 21, 17, 12,
00128   23,  0, 18, 20,
00129   19, 16
00130 };
00131 
00132 
00133 /*         4
00134  *     ---------
00135  *    |\       /|
00136  *    | \    1/ |
00137  *    |  \   /  |
00138  *    |   \ /   |
00139  *  16|    \    |32
00140  *    |   / \2  |
00141  *    |  /   \  |
00142  *    | /     \ |
00143  *    |/       \|
00144  *     ---------
00145  *         8
00146  */
00147 
00148 
00149 
00150 /* MAP2 byte:    abcd???? => Signal On? Same coding as map3lo
00151  * MAP3LO byte:  abcd???? => Signal Exists?
00152  *               a and b are for diagonals, upper and left,
00153  *               one for each direction. (ie a == NE->SW, b ==
00154  *               SW->NE, or v.v., I don't know. b and c are
00155  *               similar for lower and right.
00156  * MAP2 byte:    ????abcd => Type of ground.
00157  * MAP3LO byte:  ????abcd => Type of rail.
00158  * MAP5:         00abcdef => rail
00159  *               01abcdef => rail w/ signals
00160  *               10uuuuuu => unused
00161  *               11uuuudd => rail depot
00162  */
00163 
00172 static CommandCost EnsureNoTrainOnTrack(TileIndex tile, Track track)
00173 {
00174   TrackBits rail_bits = TrackToTrackBits(track);
00175   return EnsureNoTrainOnTrackBits(tile, rail_bits);
00176 }
00177 
00185 static CommandCost CheckTrackCombination(TileIndex tile, TrackBits to_build, uint flags)
00186 {
00187   if (!IsPlainRail(tile)) return_cmd_error(STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION);
00188 
00189   /* So, we have a tile with tracks on it (and possibly signals). Let's see
00190    * what tracks first */
00191   TrackBits current = GetTrackBits(tile); // The current track layout.
00192   TrackBits future = current | to_build;  // The track layout we want to build.
00193 
00194   /* Are we really building something new? */
00195   if (current == future) {
00196     /* Nothing new is being built */
00197     return_cmd_error(STR_ERROR_ALREADY_BUILT);
00198   }
00199 
00200   /* Let's see if we may build this */
00201   if ((flags & DC_NO_RAIL_OVERLAP) || HasSignals(tile)) {
00202     /* If we are not allowed to overlap (flag is on for ai companies or we have
00203      * signals on the tile), check that */
00204     if (future != TRACK_BIT_HORZ && future != TRACK_BIT_VERT) {
00205       return_cmd_error((flags & DC_NO_RAIL_OVERLAP) ? STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION : STR_ERROR_MUST_REMOVE_SIGNALS_FIRST);
00206     }
00207   }
00208   /* Normally, we may overlap and any combination is valid */
00209   return CommandCost();
00210 }
00211 
00212 
00214 static const TrackBits _valid_tracks_without_foundation[15] = {
00215   TRACK_BIT_ALL,
00216   TRACK_BIT_RIGHT,
00217   TRACK_BIT_UPPER,
00218   TRACK_BIT_X,
00219 
00220   TRACK_BIT_LEFT,
00221   TRACK_BIT_NONE,
00222   TRACK_BIT_Y,
00223   TRACK_BIT_LOWER,
00224 
00225   TRACK_BIT_LOWER,
00226   TRACK_BIT_Y,
00227   TRACK_BIT_NONE,
00228   TRACK_BIT_LEFT,
00229 
00230   TRACK_BIT_X,
00231   TRACK_BIT_UPPER,
00232   TRACK_BIT_RIGHT,
00233 };
00234 
00236 static const TrackBits _valid_tracks_on_leveled_foundation[15] = {
00237   TRACK_BIT_NONE,
00238   TRACK_BIT_LEFT,
00239   TRACK_BIT_LOWER,
00240   TRACK_BIT_Y | TRACK_BIT_LOWER | TRACK_BIT_LEFT,
00241 
00242   TRACK_BIT_RIGHT,
00243   TRACK_BIT_ALL,
00244   TRACK_BIT_X | TRACK_BIT_LOWER | TRACK_BIT_RIGHT,
00245   TRACK_BIT_ALL,
00246 
00247   TRACK_BIT_UPPER,
00248   TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_LEFT,
00249   TRACK_BIT_ALL,
00250   TRACK_BIT_ALL,
00251 
00252   TRACK_BIT_Y | TRACK_BIT_UPPER | TRACK_BIT_RIGHT,
00253   TRACK_BIT_ALL,
00254   TRACK_BIT_ALL
00255 };
00256 
00264 Foundation GetRailFoundation(Slope tileh, TrackBits bits)
00265 {
00266   if (bits == TRACK_BIT_NONE) return FOUNDATION_NONE;
00267 
00268   if (IsSteepSlope(tileh)) {
00269     /* Test for inclined foundations */
00270     if (bits == TRACK_BIT_X) return FOUNDATION_INCLINED_X;
00271     if (bits == TRACK_BIT_Y) return FOUNDATION_INCLINED_Y;
00272 
00273     /* Get higher track */
00274     Corner highest_corner = GetHighestSlopeCorner(tileh);
00275     TrackBits higher_track = CornerToTrackBits(highest_corner);
00276 
00277     /* Only higher track? */
00278     if (bits == higher_track) return HalftileFoundation(highest_corner);
00279 
00280     /* Overlap with higher track? */
00281     if (TracksOverlap(bits | higher_track)) return FOUNDATION_INVALID;
00282 
00283     /* either lower track or both higher and lower track */
00284     return ((bits & higher_track) != 0 ? FOUNDATION_STEEP_BOTH : FOUNDATION_STEEP_LOWER);
00285   } else {
00286     if ((~_valid_tracks_without_foundation[tileh] & bits) == 0) return FOUNDATION_NONE;
00287 
00288     bool valid_on_leveled = ((~_valid_tracks_on_leveled_foundation[tileh] & bits) == 0);
00289 
00290     Corner track_corner;
00291     switch (bits) {
00292       case TRACK_BIT_LEFT:  track_corner = CORNER_W; break;
00293       case TRACK_BIT_LOWER: track_corner = CORNER_S; break;
00294       case TRACK_BIT_RIGHT: track_corner = CORNER_E; break;
00295       case TRACK_BIT_UPPER: track_corner = CORNER_N; break;
00296 
00297       case TRACK_BIT_HORZ:
00298         if (tileh == SLOPE_N) return HalftileFoundation(CORNER_N);
00299         if (tileh == SLOPE_S) return HalftileFoundation(CORNER_S);
00300         return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
00301 
00302       case TRACK_BIT_VERT:
00303         if (tileh == SLOPE_W) return HalftileFoundation(CORNER_W);
00304         if (tileh == SLOPE_E) return HalftileFoundation(CORNER_E);
00305         return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
00306 
00307       case TRACK_BIT_X:
00308         if (IsSlopeWithOneCornerRaised(tileh)) return FOUNDATION_INCLINED_X;
00309         return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
00310 
00311       case TRACK_BIT_Y:
00312         if (IsSlopeWithOneCornerRaised(tileh)) return FOUNDATION_INCLINED_Y;
00313         return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
00314 
00315       default:
00316         return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
00317     }
00318     /* Single diagonal track */
00319 
00320     /* Track must be at least valid on leveled foundation */
00321     if (!valid_on_leveled) return FOUNDATION_INVALID;
00322 
00323     /* If slope has three raised corners, build leveled foundation */
00324     if (IsSlopeWithThreeCornersRaised(tileh)) return FOUNDATION_LEVELED;
00325 
00326     /* If neighboured corners of track_corner are lowered, build halftile foundation */
00327     if ((tileh & SlopeWithThreeCornersRaised(OppositeCorner(track_corner))) == SlopeWithOneCornerRaised(track_corner)) return HalftileFoundation(track_corner);
00328 
00329     /* else special anti-zig-zag foundation */
00330     return SpecialRailFoundation(track_corner);
00331   }
00332 }
00333 
00334 
00344 static CommandCost CheckRailSlope(Slope tileh, TrackBits rail_bits, TrackBits existing, TileIndex tile)
00345 {
00346   /* don't allow building on the lower side of a coast */
00347   if (GetFloodingBehaviour(tile) != FLOOD_NONE) {
00348     if (!IsSteepSlope(tileh) && ((~_valid_tracks_on_leveled_foundation[tileh] & (rail_bits | existing)) != 0)) return_cmd_error(STR_ERROR_CAN_T_BUILD_ON_WATER);
00349   }
00350 
00351   Foundation f_new = GetRailFoundation(tileh, rail_bits | existing);
00352 
00353   /* check track/slope combination */
00354   if ((f_new == FOUNDATION_INVALID) ||
00355       ((f_new != FOUNDATION_NONE) && (!_settings_game.construction.build_on_slopes))) {
00356     return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
00357   }
00358 
00359   Foundation f_old = GetRailFoundation(tileh, existing);
00360   return CommandCost(EXPENSES_CONSTRUCTION, f_new != f_old ? _price[PR_BUILD_FOUNDATION] : (Money)0);
00361 }
00362 
00363 /* Validate functions for rail building */
00364 static inline bool ValParamTrackOrientation(Track track)
00365 {
00366   return IsValidTrack(track);
00367 }
00368 
00378 CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00379 {
00380   RailType railtype = Extract<RailType, 0, 4>(p1);
00381   Track track = Extract<Track, 0, 3>(p2);
00382   CommandCost cost(EXPENSES_CONSTRUCTION);
00383 
00384   if (!ValParamRailtype(railtype) || !ValParamTrackOrientation(track)) return CMD_ERROR;
00385 
00386   Slope tileh = GetTileSlope(tile);
00387   TrackBits trackbit = TrackToTrackBits(track);
00388 
00389   switch (GetTileType(tile)) {
00390     case MP_RAILWAY: {
00391       CommandCost ret = CheckTileOwnership(tile);
00392       if (ret.Failed()) return ret;
00393 
00394       if (!IsPlainRail(tile)) return CMD_ERROR;
00395 
00396       if (!IsCompatibleRail(GetRailType(tile), railtype)) return_cmd_error(STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION);
00397 
00398       ret = CheckTrackCombination(tile, trackbit, flags);
00399       if (ret.Succeeded()) ret = EnsureNoTrainOnTrack(tile, track);
00400       if (ret.Failed()) return ret;
00401 
00402       ret = CheckRailSlope(tileh, trackbit, GetTrackBits(tile), tile);
00403       if (ret.Failed()) return ret;
00404       cost.AddCost(ret);
00405 
00406       /* If the rail types don't match, try to convert only if engines of
00407        * the new rail type are not powered on the present rail type and engines of
00408        * the present rail type are powered on the new rail type. */
00409       if (GetRailType(tile) != railtype && !HasPowerOnRail(railtype, GetRailType(tile))) {
00410         if (HasPowerOnRail(GetRailType(tile), railtype)) {
00411           ret = DoCommand(tile, tile, railtype, flags, CMD_CONVERT_RAIL);
00412           if (ret.Failed()) return ret;
00413           cost.AddCost(ret);
00414         } else {
00415           return CMD_ERROR;
00416         }
00417       }
00418 
00419       if (flags & DC_EXEC) {
00420         SetRailGroundType(tile, RAIL_GROUND_BARREN);
00421         TrackBits bits = GetTrackBits(tile);
00422         SetTrackBits(tile, bits | trackbit);
00423         /* Subtract old infrastructure count. */
00424         uint pieces = CountBits(bits);
00425         if (TracksOverlap(bits)) pieces *= pieces;
00426         Company::Get(GetTileOwner(tile))->infrastructure.rail[GetRailType(tile)] -= pieces;
00427         /* Add new infrastructure count. */
00428         pieces = CountBits(bits | trackbit);
00429         if (TracksOverlap(bits | trackbit)) pieces *= pieces;
00430         Company::Get(GetTileOwner(tile))->infrastructure.rail[GetRailType(tile)] += pieces;
00431         DirtyCompanyInfrastructureWindows(GetTileOwner(tile));
00432       }
00433       break;
00434     }
00435 
00436     case MP_ROAD: {
00437       /* Level crossings may only be built on these slopes */
00438       if (!HasBit(VALID_LEVEL_CROSSING_SLOPES, tileh)) return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
00439 
00440       CommandCost ret = EnsureNoVehicleOnGround(tile);
00441       if (ret.Failed()) return ret;
00442 
00443       if (IsNormalRoad(tile)) {
00444         if (HasRoadWorks(tile)) return_cmd_error(STR_ERROR_ROAD_WORKS_IN_PROGRESS);
00445 
00446         if (GetDisallowedRoadDirections(tile) != DRD_NONE) return_cmd_error(STR_ERROR_CROSSING_ON_ONEWAY_ROAD);
00447 
00448         if (RailNoLevelCrossings(railtype)) return_cmd_error(STR_ERROR_CROSSING_DISALLOWED);
00449 
00450         RoadTypes roadtypes = GetRoadTypes(tile);
00451         RoadBits road = GetRoadBits(tile, ROADTYPE_ROAD);
00452         RoadBits tram = GetRoadBits(tile, ROADTYPE_TRAM);
00453         switch (roadtypes) {
00454           default: break;
00455           case ROADTYPES_TRAM:
00456             /* Tram crossings must always have road. */
00457             if (flags & DC_EXEC) {
00458               SetRoadOwner(tile, ROADTYPE_ROAD, _current_company);
00459               Company *c = Company::GetIfValid(_current_company);
00460               if (c != NULL) {
00461                 /* A full diagonal tile has two road bits. */
00462                 c->infrastructure.road[ROADTYPE_ROAD] += 2;
00463                 DirtyCompanyInfrastructureWindows(c->index);
00464               }
00465             }
00466             roadtypes |= ROADTYPES_ROAD;
00467             break;
00468 
00469           case ROADTYPES_ALL:
00470             if (road != tram) return CMD_ERROR;
00471             break;
00472         }
00473 
00474         road |= tram;
00475 
00476         if ((track == TRACK_X && road == ROAD_Y) ||
00477             (track == TRACK_Y && road == ROAD_X)) {
00478           if (flags & DC_EXEC) {
00479             MakeRoadCrossing(tile, GetRoadOwner(tile, ROADTYPE_ROAD), GetRoadOwner(tile, ROADTYPE_TRAM), _current_company, (track == TRACK_X ? AXIS_Y : AXIS_X), railtype, roadtypes, GetTownIndex(tile));
00480             UpdateLevelCrossing(tile, false);
00481             Company::Get(_current_company)->infrastructure.rail[railtype] += LEVELCROSSING_TRACKBIT_FACTOR;
00482             DirtyCompanyInfrastructureWindows(_current_company);
00483           }
00484           break;
00485         }
00486       }
00487 
00488       if (IsLevelCrossing(tile) && GetCrossingRailBits(tile) == trackbit) {
00489         return_cmd_error(STR_ERROR_ALREADY_BUILT);
00490       }
00491       /* FALL THROUGH */
00492     }
00493 
00494     default: {
00495       /* Will there be flat water on the lower halftile? */
00496       bool water_ground = IsTileType(tile, MP_WATER) && IsSlopeWithOneCornerRaised(tileh);
00497 
00498       CommandCost ret = CheckRailSlope(tileh, trackbit, TRACK_BIT_NONE, tile);
00499       if (ret.Failed()) return ret;
00500       cost.AddCost(ret);
00501 
00502       ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00503       if (ret.Failed()) return ret;
00504       cost.AddCost(ret);
00505 
00506       if (water_ground) {
00507         cost.AddCost(-_price[PR_CLEAR_WATER]);
00508         cost.AddCost(_price[PR_CLEAR_ROUGH]);
00509       }
00510 
00511       if (flags & DC_EXEC) {
00512         MakeRailNormal(tile, _current_company, trackbit, railtype);
00513         if (water_ground) SetRailGroundType(tile, RAIL_GROUND_WATER);
00514         Company::Get(_current_company)->infrastructure.rail[railtype]++;
00515         DirtyCompanyInfrastructureWindows(_current_company);
00516       }
00517       break;
00518     }
00519   }
00520 
00521   if (flags & DC_EXEC) {
00522     MarkTileDirtyByTile(tile);
00523     AddTrackToSignalBuffer(tile, track, _current_company);
00524     YapfNotifyTrackLayoutChange(tile, track);
00525   }
00526 
00527   cost.AddCost(RailBuildCost(railtype));
00528   return cost;
00529 }
00530 
00540 CommandCost CmdRemoveSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00541 {
00542   Track track = Extract<Track, 0, 3>(p2);
00543   CommandCost cost(EXPENSES_CONSTRUCTION);
00544   bool crossing = false;
00545 
00546   if (!ValParamTrackOrientation(track)) return CMD_ERROR;
00547   TrackBits trackbit = TrackToTrackBits(track);
00548 
00549   /* Need to read tile owner now because it may change when the rail is removed
00550    * Also, in case of floods, _current_company != owner
00551    * There may be invalid tiletype even in exec run (when removing long track),
00552    * so do not call GetTileOwner(tile) in any case here */
00553   Owner owner = INVALID_OWNER;
00554 
00555   Train *v = NULL;
00556 
00557   switch (GetTileType(tile)) {
00558     case MP_ROAD: {
00559       if (!IsLevelCrossing(tile) || GetCrossingRailBits(tile) != trackbit) return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
00560 
00561       if (_current_company != OWNER_WATER) {
00562         CommandCost ret = CheckTileOwnership(tile);
00563         if (ret.Failed()) return ret;
00564       }
00565 
00566       if (!(flags & DC_BANKRUPT)) {
00567         CommandCost ret = EnsureNoVehicleOnGround(tile);
00568         if (ret.Failed()) return ret;
00569       }
00570 
00571       cost.AddCost(RailClearCost(GetRailType(tile)));
00572 
00573       if (flags & DC_EXEC) {
00574         if (HasReservedTracks(tile, trackbit)) {
00575           v = GetTrainForReservation(tile, track);
00576           if (v != NULL) FreeTrainTrackReservation(v);
00577         }
00578         owner = GetTileOwner(tile);
00579         Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= LEVELCROSSING_TRACKBIT_FACTOR;
00580         DirtyCompanyInfrastructureWindows(owner);
00581         MakeRoadNormal(tile, GetCrossingRoadBits(tile), GetRoadTypes(tile), GetTownIndex(tile), GetRoadOwner(tile, ROADTYPE_ROAD), GetRoadOwner(tile, ROADTYPE_TRAM));
00582         DeleteNewGRFInspectWindow(GSF_RAILTYPES, tile);
00583       }
00584       break;
00585     }
00586 
00587     case MP_RAILWAY: {
00588       TrackBits present;
00589       /* There are no rails present at depots. */
00590       if (!IsPlainRail(tile)) return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
00591 
00592       if (_current_company != OWNER_WATER) {
00593         CommandCost ret = CheckTileOwnership(tile);
00594         if (ret.Failed()) return ret;
00595       }
00596 
00597       CommandCost ret = EnsureNoTrainOnTrack(tile, track);
00598       if (ret.Failed()) return ret;
00599 
00600       present = GetTrackBits(tile);
00601       if ((present & trackbit) == 0) return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
00602       if (present == (TRACK_BIT_X | TRACK_BIT_Y)) crossing = true;
00603 
00604       cost.AddCost(RailClearCost(GetRailType(tile)));
00605 
00606       /* Charge extra to remove signals on the track, if they are there */
00607       if (HasSignalOnTrack(tile, track)) {
00608         cost.AddCost(DoCommand(tile, track, 0, flags, CMD_REMOVE_SIGNALS));
00609       }
00610 
00611       if (flags & DC_EXEC) {
00612         if (HasReservedTracks(tile, trackbit)) {
00613           v = GetTrainForReservation(tile, track);
00614           if (v != NULL) FreeTrainTrackReservation(v);
00615         }
00616 
00617         owner = GetTileOwner(tile);
00618 
00619         /* Subtract old infrastructure count. */
00620         uint pieces = CountBits(present);
00621         if (TracksOverlap(present)) pieces *= pieces;
00622         Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= pieces;
00623         /* Add new infrastructure count. */
00624         present ^= trackbit;
00625         pieces = CountBits(present);
00626         if (TracksOverlap(present)) pieces *= pieces;
00627         Company::Get(owner)->infrastructure.rail[GetRailType(tile)] += pieces;
00628         DirtyCompanyInfrastructureWindows(owner);
00629 
00630         if (present == 0) {
00631           Slope tileh = GetTileSlope(tile);
00632           /* If there is flat water on the lower halftile, convert the tile to shore so the water remains */
00633           if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh)) {
00634             MakeShore(tile);
00635           } else {
00636             DoClearSquare(tile);
00637           }
00638           DeleteNewGRFInspectWindow(GSF_RAILTYPES, tile);
00639         } else {
00640           SetTrackBits(tile, present);
00641           SetTrackReservation(tile, GetRailReservationTrackBits(tile) & present);
00642         }
00643       }
00644       break;
00645     }
00646 
00647     default: return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
00648   }
00649 
00650   if (flags & DC_EXEC) {
00651     /* if we got that far, 'owner' variable is set correctly */
00652     assert(Company::IsValidID(owner));
00653 
00654     MarkTileDirtyByTile(tile);
00655     if (crossing) {
00656       /* crossing is set when only TRACK_BIT_X and TRACK_BIT_Y are set. As we
00657        * are removing one of these pieces, we'll need to update signals for
00658        * both directions explicitly, as after the track is removed it won't
00659        * 'connect' with the other piece. */
00660       AddTrackToSignalBuffer(tile, TRACK_X, owner);
00661       AddTrackToSignalBuffer(tile, TRACK_Y, owner);
00662       YapfNotifyTrackLayoutChange(tile, TRACK_X);
00663       YapfNotifyTrackLayoutChange(tile, TRACK_Y);
00664     } else {
00665       AddTrackToSignalBuffer(tile, track, owner);
00666       YapfNotifyTrackLayoutChange(tile, track);
00667     }
00668 
00669     if (v != NULL) TryPathReserve(v, true);
00670   }
00671 
00672   return cost;
00673 }
00674 
00675 
00683 bool FloodHalftile(TileIndex t)
00684 {
00685   assert(IsPlainRailTile(t));
00686 
00687   bool flooded = false;
00688   if (GetRailGroundType(t) == RAIL_GROUND_WATER) return flooded;
00689 
00690   Slope tileh = GetTileSlope(t);
00691   TrackBits rail_bits = GetTrackBits(t);
00692 
00693   if (IsSlopeWithOneCornerRaised(tileh)) {
00694     TrackBits lower_track = CornerToTrackBits(OppositeCorner(GetHighestSlopeCorner(tileh)));
00695 
00696     TrackBits to_remove = lower_track & rail_bits;
00697     if (to_remove != 0) {
00698       Backup<CompanyByte> cur_company(_current_company, OWNER_WATER, FILE_LINE);
00699       flooded = DoCommand(t, 0, FIND_FIRST_BIT(to_remove), DC_EXEC, CMD_REMOVE_SINGLE_RAIL).Succeeded();
00700       cur_company.Restore();
00701       if (!flooded) return flooded; // not yet floodable
00702       rail_bits = rail_bits & ~to_remove;
00703       if (rail_bits == 0) {
00704         MakeShore(t);
00705         MarkTileDirtyByTile(t);
00706         return flooded;
00707       }
00708     }
00709 
00710     if (IsNonContinuousFoundation(GetRailFoundation(tileh, rail_bits))) {
00711       flooded = true;
00712       SetRailGroundType(t, RAIL_GROUND_WATER);
00713       MarkTileDirtyByTile(t);
00714     }
00715   } else {
00716     /* Make shore on steep slopes and 'three-corners-raised'-slopes. */
00717     if (ApplyFoundationToSlope(GetRailFoundation(tileh, rail_bits), &tileh) == 0) {
00718       if (IsSteepSlope(tileh) || IsSlopeWithThreeCornersRaised(tileh)) {
00719         flooded = true;
00720         SetRailGroundType(t, RAIL_GROUND_WATER);
00721         MarkTileDirtyByTile(t);
00722       }
00723     }
00724   }
00725   return flooded;
00726 }
00727 
00728 static const TileIndexDiffC _trackdelta[] = {
00729   { -1,  0 }, {  0,  1 }, { -1,  0 }, {  0,  1 }, {  1,  0 }, {  0,  1 },
00730   {  0,  0 },
00731   {  0,  0 },
00732   {  1,  0 }, {  0, -1 }, {  0, -1 }, {  1,  0 }, {  0, -1 }, { -1,  0 },
00733   {  0,  0 },
00734   {  0,  0 }
00735 };
00736 
00737 
00738 static CommandCost ValidateAutoDrag(Trackdir *trackdir, TileIndex start, TileIndex end)
00739 {
00740   int x = TileX(start);
00741   int y = TileY(start);
00742   int ex = TileX(end);
00743   int ey = TileY(end);
00744 
00745   if (!ValParamTrackOrientation(TrackdirToTrack(*trackdir))) return CMD_ERROR;
00746 
00747   /* calculate delta x,y from start to end tile */
00748   int dx = ex - x;
00749   int dy = ey - y;
00750 
00751   /* calculate delta x,y for the first direction */
00752   int trdx = _trackdelta[*trackdir].x;
00753   int trdy = _trackdelta[*trackdir].y;
00754 
00755   if (!IsDiagonalTrackdir(*trackdir)) {
00756     trdx += _trackdelta[*trackdir ^ 1].x;
00757     trdy += _trackdelta[*trackdir ^ 1].y;
00758   }
00759 
00760   /* validate the direction */
00761   while ((trdx <= 0 && dx > 0) ||
00762       (trdx >= 0 && dx < 0) ||
00763       (trdy <= 0 && dy > 0) ||
00764       (trdy >= 0 && dy < 0)) {
00765     if (!HasBit(*trackdir, 3)) { // first direction is invalid, try the other
00766       SetBit(*trackdir, 3); // reverse the direction
00767       trdx = -trdx;
00768       trdy = -trdy;
00769     } else { // other direction is invalid too, invalid drag
00770       return CMD_ERROR;
00771     }
00772   }
00773 
00774   /* (for diagonal tracks, this is already made sure of by above test), but:
00775    * for non-diagonal tracks, check if the start and end tile are on 1 line */
00776   if (!IsDiagonalTrackdir(*trackdir)) {
00777     trdx = _trackdelta[*trackdir].x;
00778     trdy = _trackdelta[*trackdir].y;
00779     if (abs(dx) != abs(dy) && abs(dx) + abs(trdy) != abs(dy) + abs(trdx)) return CMD_ERROR;
00780   }
00781 
00782   return CommandCost();
00783 }
00784 
00798 static CommandCost CmdRailTrackHelper(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00799 {
00800   CommandCost total_cost(EXPENSES_CONSTRUCTION);
00801   Track track = Extract<Track, 4, 3>(p2);
00802   bool remove = HasBit(p2, 7);
00803   RailType railtype = Extract<RailType, 0, 4>(p2);
00804 
00805   if (!ValParamRailtype(railtype) || !ValParamTrackOrientation(track)) return CMD_ERROR;
00806   if (p1 >= MapSize()) return CMD_ERROR;
00807   TileIndex end_tile = p1;
00808   Trackdir trackdir = TrackToTrackdir(track);
00809 
00810   CommandCost ret = ValidateAutoDrag(&trackdir, tile, end_tile);
00811   if (ret.Failed()) return ret;
00812 
00813   if (flags & DC_EXEC) SndPlayTileFx(SND_20_SPLAT_2, tile);
00814 
00815   bool had_success = false;
00816   CommandCost last_error = CMD_ERROR;
00817   for (;;) {
00818     CommandCost ret = DoCommand(tile, railtype, TrackdirToTrack(trackdir), flags, remove ? CMD_REMOVE_SINGLE_RAIL : CMD_BUILD_SINGLE_RAIL);
00819 
00820     if (ret.Failed()) {
00821       last_error = ret;
00822       if (last_error.GetErrorMessage() != STR_ERROR_ALREADY_BUILT && !remove) {
00823         if (HasBit(p2, 8)) return last_error;
00824         break;
00825       }
00826 
00827       /* Ownership errors are more important. */
00828       if (last_error.GetErrorMessage() == STR_ERROR_OWNED_BY && remove) break;
00829     } else {
00830       had_success = true;
00831       total_cost.AddCost(ret);
00832     }
00833 
00834     if (tile == end_tile) break;
00835 
00836     tile += ToTileIndexDiff(_trackdelta[trackdir]);
00837 
00838     /* toggle railbit for the non-diagonal tracks */
00839     if (!IsDiagonalTrackdir(trackdir)) ToggleBit(trackdir, 0);
00840   }
00841 
00842   if (had_success) return total_cost;
00843   return last_error;
00844 }
00845 
00860 CommandCost CmdBuildRailroadTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00861 {
00862   return CmdRailTrackHelper(tile, flags, p1, ClrBit(p2, 7), text);
00863 }
00864 
00879 CommandCost CmdRemoveRailroadTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00880 {
00881   return CmdRailTrackHelper(tile, flags, p1, SetBit(p2, 7), text);
00882 }
00883 
00896 CommandCost CmdBuildTrainDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00897 {
00898   /* check railtype and valid direction for depot (0 through 3), 4 in total */
00899   RailType railtype = Extract<RailType, 0, 4>(p1);
00900   if (!ValParamRailtype(railtype)) return CMD_ERROR;
00901 
00902   Slope tileh = GetTileSlope(tile);
00903 
00904   DiagDirection dir = Extract<DiagDirection, 0, 2>(p2);
00905 
00906   /* Prohibit construction if
00907    * The tile is non-flat AND
00908    * 1) build-on-slopes is disabled
00909    * 2) the tile is steep i.e. spans two height levels
00910    * 3) the exit points in the wrong direction
00911    */
00912 
00913   if (tileh != SLOPE_FLAT && (
00914         !_settings_game.construction.build_on_slopes ||
00915         !CanBuildDepotByTileh(dir, tileh)
00916       )) {
00917     return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
00918   }
00919 
00920   CommandCost cost = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00921   if (cost.Failed()) return cost;
00922 
00923   if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
00924 
00925   if (!Depot::CanAllocateItem()) return CMD_ERROR;
00926 
00927   if (flags & DC_EXEC) {
00928     Depot *d = new Depot(tile);
00929     d->build_date = _date;
00930 
00931     MakeRailDepot(tile, _current_company, d->index, dir, railtype);
00932     MarkTileDirtyByTile(tile);
00933     MakeDefaultName(d);
00934 
00935     Company::Get(_current_company)->infrastructure.rail[railtype]++;
00936     DirtyCompanyInfrastructureWindows(_current_company);
00937 
00938     AddSideToSignalBuffer(tile, INVALID_DIAGDIR, _current_company);
00939     YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
00940   }
00941 
00942   cost.AddCost(_price[PR_BUILD_DEPOT_TRAIN]);
00943   cost.AddCost(RailBuildCost(railtype));
00944   return cost;
00945 }
00946 
00968 CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00969 {
00970   Track track = Extract<Track, 0, 3>(p1);
00971   bool ctrl_pressed = HasBit(p1, 3); // was the CTRL button pressed
00972   SignalVariant sigvar = (ctrl_pressed ^ HasBit(p1, 4)) ? SIG_SEMAPHORE : SIG_ELECTRIC; // the signal variant of the new signal
00973   SignalType sigtype = Extract<SignalType, 5, 3>(p1); // the signal type of the new signal
00974   bool convert_signal = HasBit(p1, 8); // convert button pressed
00975   SignalType cycle_start = Extract<SignalType, 9, 3>(p1);
00976   SignalType cycle_stop = Extract<SignalType, 12, 3>(p1);
00977   uint num_dir_cycle = GB(p1, 15, 2);
00978 
00979   if (sigtype > SIGTYPE_LAST) return CMD_ERROR;
00980   if (cycle_start > cycle_stop || cycle_stop > SIGTYPE_LAST) return CMD_ERROR;
00981 
00982   /* You can only build signals on plain rail tiles, and the selected track must exist */
00983   if (!ValParamTrackOrientation(track) || !IsPlainRailTile(tile) ||
00984       !HasTrack(tile, track)) {
00985     return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
00986   }
00987   CommandCost ret = EnsureNoTrainOnTrack(tile, track);
00988   if (ret.Failed()) return ret;
00989 
00990   /* Protect against invalid signal copying */
00991   if (p2 != 0 && (p2 & SignalOnTrack(track)) == 0) return CMD_ERROR;
00992 
00993   ret = CheckTileOwnership(tile);
00994   if (ret.Failed()) return ret;
00995 
00996   {
00997     /* See if this is a valid track combination for signals, (ie, no overlap) */
00998     TrackBits trackbits = GetTrackBits(tile);
00999     if (KillFirstBit(trackbits) != TRACK_BIT_NONE && // More than one track present
01000         trackbits != TRACK_BIT_HORZ &&
01001         trackbits != TRACK_BIT_VERT) {
01002       return_cmd_error(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK);
01003     }
01004   }
01005 
01006   /* In case we don't want to change an existing signal, return without error. */
01007   if (HasBit(p1, 17) && HasSignalOnTrack(tile, track)) return CommandCost();
01008 
01009   /* you can not convert a signal if no signal is on track */
01010   if (convert_signal && !HasSignalOnTrack(tile, track)) return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS);
01011 
01012   CommandCost cost;
01013   if (!HasSignalOnTrack(tile, track)) {
01014     /* build new signals */
01015     cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS]);
01016   } else {
01017     if (p2 != 0 && sigvar != GetSignalVariant(tile, track)) {
01018       /* convert signals <-> semaphores */
01019       cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] + _price[PR_CLEAR_SIGNALS]);
01020 
01021     } else if (convert_signal) {
01022       /* convert button pressed */
01023       if (ctrl_pressed || GetSignalVariant(tile, track) != sigvar) {
01024         /* convert electric <-> semaphore */
01025         cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] + _price[PR_CLEAR_SIGNALS]);
01026       } else {
01027         /* it is free to change signal type: normal-pre-exit-combo */
01028         cost = CommandCost();
01029       }
01030 
01031     } else {
01032       /* it is free to change orientation/pre-exit-combo signals */
01033       cost = CommandCost();
01034     }
01035   }
01036 
01037   if (flags & DC_EXEC) {
01038     Train *v = NULL;
01039     /* The new/changed signal could block our path. As this can lead to
01040      * stale reservations, we clear the path reservation here and try
01041      * to redo it later on. */
01042     if (HasReservedTracks(tile, TrackToTrackBits(track))) {
01043       v = GetTrainForReservation(tile, track);
01044       if (v != NULL) FreeTrainTrackReservation(v);
01045     }
01046 
01047     if (!HasSignals(tile)) {
01048       /* there are no signals at all on this tile yet */
01049       SetHasSignals(tile, true);
01050       SetSignalStates(tile, 0xF); // all signals are on
01051       SetPresentSignals(tile, 0); // no signals built by default
01052       SetSignalType(tile, track, sigtype);
01053       SetSignalVariant(tile, track, sigvar);
01054     }
01055 
01056     /* Subtract old signal infrastructure count. */
01057     Company::Get(GetTileOwner(tile))->infrastructure.signal -= CountBits(GetPresentSignals(tile));
01058 
01059     if (p2 == 0) {
01060       if (!HasSignalOnTrack(tile, track)) {
01061         /* build new signals */
01062         SetPresentSignals(tile, GetPresentSignals(tile) | (IsPbsSignal(sigtype) ? KillFirstBit(SignalOnTrack(track)) : SignalOnTrack(track)));
01063         SetSignalType(tile, track, sigtype);
01064         SetSignalVariant(tile, track, sigvar);
01065         while (num_dir_cycle-- > 0) CycleSignalSide(tile, track);
01066       } else {
01067         if (convert_signal) {
01068           /* convert signal button pressed */
01069           if (ctrl_pressed) {
01070             /* toggle the pressent signal variant: SIG_ELECTRIC <-> SIG_SEMAPHORE */
01071             SetSignalVariant(tile, track, (GetSignalVariant(tile, track) == SIG_ELECTRIC) ? SIG_SEMAPHORE : SIG_ELECTRIC);
01072             /* Query current signal type so the check for PBS signals below works. */
01073             sigtype = GetSignalType(tile, track);
01074           } else {
01075             /* convert the present signal to the chosen type and variant */
01076             SetSignalType(tile, track, sigtype);
01077             SetSignalVariant(tile, track, sigvar);
01078             if (IsPbsSignal(sigtype) && (GetPresentSignals(tile) & SignalOnTrack(track)) == SignalOnTrack(track)) {
01079               SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | KillFirstBit(SignalOnTrack(track)));
01080             }
01081           }
01082 
01083         } else if (ctrl_pressed) {
01084           /* cycle between cycle_start and cycle_end */
01085           sigtype = (SignalType)(GetSignalType(tile, track) + 1);
01086 
01087           if (sigtype < cycle_start || sigtype > cycle_stop) sigtype = cycle_start;
01088 
01089           SetSignalType(tile, track, sigtype);
01090           if (IsPbsSignal(sigtype) && (GetPresentSignals(tile) & SignalOnTrack(track)) == SignalOnTrack(track)) {
01091             SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | KillFirstBit(SignalOnTrack(track)));
01092           }
01093         } else {
01094           /* cycle the signal side: both -> left -> right -> both -> ... */
01095           CycleSignalSide(tile, track);
01096           /* Query current signal type so the check for PBS signals below works. */
01097           sigtype = GetSignalType(tile, track);
01098         }
01099       }
01100     } else {
01101       /* If CmdBuildManySignals is called with copying signals, just copy the
01102        * direction of the first signal given as parameter by CmdBuildManySignals */
01103       SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | (p2 & SignalOnTrack(track)));
01104       SetSignalVariant(tile, track, sigvar);
01105       SetSignalType(tile, track, sigtype);
01106     }
01107 
01108     /* Add new signal infrastructure count. */
01109     Company::Get(GetTileOwner(tile))->infrastructure.signal += CountBits(GetPresentSignals(tile));
01110     DirtyCompanyInfrastructureWindows(GetTileOwner(tile));
01111 
01112     if (IsPbsSignal(sigtype)) {
01113       /* PBS signals should show red unless they are on a reservation. */
01114       uint mask = GetPresentSignals(tile) & SignalOnTrack(track);
01115       SetSignalStates(tile, (GetSignalStates(tile) & ~mask) | ((HasBit(GetRailReservationTrackBits(tile), track) ? UINT_MAX : 0) & mask));
01116     }
01117     MarkTileDirtyByTile(tile);
01118     AddTrackToSignalBuffer(tile, track, _current_company);
01119     YapfNotifyTrackLayoutChange(tile, track);
01120     if (v != NULL) {
01121       /* Extend the train's path if it's not stopped or loading, or not at a safe position. */
01122       if (!(((v->vehstatus & VS_STOPPED) && v->cur_speed == 0) || v->current_order.IsType(OT_LOADING)) ||
01123           !IsSafeWaitingPosition(v, v->tile, v->GetVehicleTrackdir(), true, _settings_game.pf.forbid_90_deg)) {
01124         TryPathReserve(v, true);
01125       }
01126     }
01127   }
01128 
01129   return cost;
01130 }
01131 
01132 static bool CheckSignalAutoFill(TileIndex &tile, Trackdir &trackdir, int &signal_ctr, bool remove)
01133 {
01134   tile = AddTileIndexDiffCWrap(tile, _trackdelta[trackdir]);
01135   if (tile == INVALID_TILE) return false;
01136 
01137   /* Check for track bits on the new tile */
01138   TrackdirBits trackdirbits = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0));
01139 
01140   if (TracksOverlap(TrackdirBitsToTrackBits(trackdirbits))) return false;
01141   trackdirbits &= TrackdirReachesTrackdirs(trackdir);
01142 
01143   /* No track bits, must stop */
01144   if (trackdirbits == TRACKDIR_BIT_NONE) return false;
01145 
01146   /* Get the first track dir */
01147   trackdir = RemoveFirstTrackdir(&trackdirbits);
01148 
01149   /* Any left? It's a junction so we stop */
01150   if (trackdirbits != TRACKDIR_BIT_NONE) return false;
01151 
01152   switch (GetTileType(tile)) {
01153     case MP_RAILWAY:
01154       if (IsRailDepot(tile)) return false;
01155       if (!remove && HasSignalOnTrack(tile, TrackdirToTrack(trackdir))) return false;
01156       signal_ctr++;
01157       if (IsDiagonalTrackdir(trackdir)) {
01158         signal_ctr++;
01159         /* Ensure signal_ctr even so X and Y pieces get signals */
01160         ClrBit(signal_ctr, 0);
01161       }
01162       return true;
01163 
01164     case MP_ROAD:
01165       if (!IsLevelCrossing(tile)) return false;
01166       signal_ctr += 2;
01167       return true;
01168 
01169     case MP_TUNNELBRIDGE: {
01170       TileIndex orig_tile = tile; // backup old value
01171 
01172       if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) return false;
01173       if (GetTunnelBridgeDirection(tile) != TrackdirToExitdir(trackdir)) return false;
01174 
01175       /* Skip to end of tunnel or bridge
01176        * note that tile is a parameter by reference, so it must be updated */
01177       tile = GetOtherTunnelBridgeEnd(tile);
01178 
01179       signal_ctr += (GetTunnelBridgeLength(orig_tile, tile) + 2) * 2;
01180       return true;
01181     }
01182 
01183     default: return false;
01184   }
01185 }
01186 
01203 static CommandCost CmdSignalTrackHelper(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01204 {
01205   CommandCost total_cost(EXPENSES_CONSTRUCTION);
01206   TileIndex start_tile = tile;
01207 
01208   Track track = Extract<Track, 0, 3>(p2);
01209   bool mode = HasBit(p2, 3);
01210   bool semaphores = HasBit(p2, 4);
01211   bool remove = HasBit(p2, 5);
01212   bool autofill = HasBit(p2, 6);
01213   byte signal_density = GB(p2, 24, 8);
01214 
01215   if (p1 >= MapSize() || !ValParamTrackOrientation(track)) return CMD_ERROR;
01216   TileIndex end_tile = p1;
01217   if (signal_density == 0 || signal_density > 20) return CMD_ERROR;
01218 
01219   if (!IsPlainRailTile(tile)) return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
01220 
01221   /* for vertical/horizontal tracks, double the given signals density
01222    * since the original amount will be too dense (shorter tracks) */
01223   signal_density *= 2;
01224 
01225   Trackdir trackdir = TrackToTrackdir(track);
01226   CommandCost ret = ValidateAutoDrag(&trackdir, tile, end_tile);
01227   if (ret.Failed()) return ret;
01228 
01229   track = TrackdirToTrack(trackdir); // trackdir might have changed, keep track in sync
01230   Trackdir start_trackdir = trackdir;
01231 
01232   /* Must start on a valid track to be able to avoid loops */
01233   if (!HasTrack(tile, track)) return CMD_ERROR;
01234 
01235   SignalType sigtype = (SignalType)GB(p2, 7, 3);
01236   if (sigtype > SIGTYPE_LAST) return CMD_ERROR;
01237 
01238   byte signals;
01239   /* copy the signal-style of the first rail-piece if existing */
01240   if (HasSignalOnTrack(tile, track)) {
01241     signals = GetPresentSignals(tile) & SignalOnTrack(track);
01242     assert(signals != 0);
01243 
01244     /* copy signal/semaphores style (independent of CTRL) */
01245     semaphores = GetSignalVariant(tile, track) != SIG_ELECTRIC;
01246 
01247     sigtype = GetSignalType(tile, track);
01248     /* Don't but copy entry or exit-signal type */
01249     if (sigtype == SIGTYPE_ENTRY || sigtype == SIGTYPE_EXIT) sigtype = SIGTYPE_NORMAL;
01250   } else { // no signals exist, drag a two-way signal stretch
01251     signals = IsPbsSignal(sigtype) ? SignalAlongTrackdir(trackdir) : SignalOnTrack(track);
01252   }
01253 
01254   byte signal_dir = 0;
01255   if (signals & SignalAlongTrackdir(trackdir))   SetBit(signal_dir, 0);
01256   if (signals & SignalAgainstTrackdir(trackdir)) SetBit(signal_dir, 1);
01257 
01258   /* signal_ctr         - amount of tiles already processed
01259    * signals_density    - setting to put signal on every Nth tile (double space on |, -- tracks)
01260    **********
01261    * trackdir   - trackdir to build with autorail
01262    * semaphores - semaphores or signals
01263    * signals    - is there a signal/semaphore on the first tile, copy its style (two-way/single-way)
01264    *              and convert all others to semaphore/signal
01265    * remove     - 1 remove signals, 0 build signals */
01266   int signal_ctr = 0;
01267   CommandCost last_error = CMD_ERROR;
01268   bool had_success = false;
01269   for (;;) {
01270     /* only build/remove signals with the specified density */
01271     if (remove || signal_ctr % signal_density == 0) {
01272       uint32 p1 = GB(TrackdirToTrack(trackdir), 0, 3);
01273       SB(p1, 3, 1, mode);
01274       SB(p1, 4, 1, semaphores);
01275       SB(p1, 5, 3, sigtype);
01276       if (!remove && signal_ctr == 0) SetBit(p1, 17);
01277 
01278       /* Pick the correct orientation for the track direction */
01279       signals = 0;
01280       if (HasBit(signal_dir, 0)) signals |= SignalAlongTrackdir(trackdir);
01281       if (HasBit(signal_dir, 1)) signals |= SignalAgainstTrackdir(trackdir);
01282 
01283       CommandCost ret = DoCommand(tile, p1, signals, flags, remove ? CMD_REMOVE_SIGNALS : CMD_BUILD_SIGNALS);
01284 
01285       /* Be user-friendly and try placing signals as much as possible */
01286       if (ret.Succeeded()) {
01287         had_success = true;
01288         total_cost.AddCost(ret);
01289       } else {
01290         /* The "No railway" error is the least important one. */
01291         if (ret.GetErrorMessage() != STR_ERROR_THERE_IS_NO_RAILROAD_TRACK ||
01292             last_error.GetErrorMessage() == INVALID_STRING_ID) {
01293           last_error = ret;
01294         }
01295       }
01296     }
01297 
01298     if (autofill) {
01299       if (!CheckSignalAutoFill(tile, trackdir, signal_ctr, remove)) break;
01300 
01301       /* Prevent possible loops */
01302       if (tile == start_tile && trackdir == start_trackdir) break;
01303     } else {
01304       if (tile == end_tile) break;
01305 
01306       tile += ToTileIndexDiff(_trackdelta[trackdir]);
01307       signal_ctr++;
01308 
01309       /* toggle railbit for the non-diagonal tracks (|, -- tracks) */
01310       if (IsDiagonalTrackdir(trackdir)) {
01311         signal_ctr++;
01312       } else {
01313         ToggleBit(trackdir, 0);
01314       }
01315     }
01316   }
01317 
01318   return had_success ? total_cost : last_error;
01319 }
01320 
01339 CommandCost CmdBuildSignalTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01340 {
01341   return CmdSignalTrackHelper(tile, flags, p1, p2, text);
01342 }
01343 
01356 CommandCost CmdRemoveSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01357 {
01358   Track track = Extract<Track, 0, 3>(p1);
01359 
01360   if (!ValParamTrackOrientation(track) || !IsPlainRailTile(tile) || !HasTrack(tile, track)) {
01361     return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
01362   }
01363   if (!HasSignalOnTrack(tile, track)) {
01364     return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS);
01365   }
01366   CommandCost ret = EnsureNoTrainOnTrack(tile, track);
01367   if (ret.Failed()) return ret;
01368 
01369   /* Only water can remove signals from anyone */
01370   if (_current_company != OWNER_WATER) {
01371     CommandCost ret = CheckTileOwnership(tile);
01372     if (ret.Failed()) return ret;
01373   }
01374 
01375   /* Do it? */
01376   if (flags & DC_EXEC) {
01377     Train *v = NULL;
01378     if (HasReservedTracks(tile, TrackToTrackBits(track))) {
01379       v = GetTrainForReservation(tile, track);
01380     } else if (IsPbsSignal(GetSignalType(tile, track))) {
01381       /* PBS signal, might be the end of a path reservation. */
01382       Trackdir td = TrackToTrackdir(track);
01383       for (int i = 0; v == NULL && i < 2; i++, td = ReverseTrackdir(td)) {
01384         /* Only test the active signal side. */
01385         if (!HasSignalOnTrackdir(tile, ReverseTrackdir(td))) continue;
01386         TileIndex next = TileAddByDiagDir(tile, TrackdirToExitdir(td));
01387         TrackBits tracks = TrackdirBitsToTrackBits(TrackdirReachesTrackdirs(td));
01388         if (HasReservedTracks(next, tracks)) {
01389           v = GetTrainForReservation(next, TrackBitsToTrack(GetReservedTrackbits(next) & tracks));
01390         }
01391       }
01392     }
01393     Company::Get(GetTileOwner(tile))->infrastructure.signal -= CountBits(GetPresentSignals(tile));
01394     SetPresentSignals(tile, GetPresentSignals(tile) & ~SignalOnTrack(track));
01395     Company::Get(GetTileOwner(tile))->infrastructure.signal += CountBits(GetPresentSignals(tile));
01396     DirtyCompanyInfrastructureWindows(GetTileOwner(tile));
01397 
01398     /* removed last signal from tile? */
01399     if (GetPresentSignals(tile) == 0) {
01400       SetSignalStates(tile, 0);
01401       SetHasSignals(tile, false);
01402       SetSignalVariant(tile, INVALID_TRACK, SIG_ELECTRIC); // remove any possible semaphores
01403     }
01404 
01405     AddTrackToSignalBuffer(tile, track, GetTileOwner(tile));
01406     YapfNotifyTrackLayoutChange(tile, track);
01407     if (v != NULL) TryPathReserve(v, false);
01408 
01409     MarkTileDirtyByTile(tile);
01410   }
01411 
01412   return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_SIGNALS]);
01413 }
01414 
01433 CommandCost CmdRemoveSignalTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01434 {
01435   return CmdSignalTrackHelper(tile, flags, p1, SetBit(p2, 5), text); // bit 5 is remove bit
01436 }
01437 
01439 static Vehicle *UpdateTrainPowerProc(Vehicle *v, void *data)
01440 {
01441   if (v->type != VEH_TRAIN) return NULL;
01442 
01443   TrainList *affected_trains = static_cast<TrainList*>(data);
01444   affected_trains->Include(Train::From(v)->First());
01445 
01446   return NULL;
01447 }
01448 
01461 CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01462 {
01463   RailType totype = Extract<RailType, 0, 4>(p2);
01464 
01465   if (!ValParamRailtype(totype)) return CMD_ERROR;
01466   if (p1 >= MapSize()) return CMD_ERROR;
01467 
01468   TrainList affected_trains;
01469 
01470   CommandCost cost(EXPENSES_CONSTRUCTION);
01471   CommandCost error = CommandCost(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK); // by default, there is no track to convert.
01472   TileArea ta(tile, p1);
01473   TileIterator *iter = HasBit(p2, 4) ? (TileIterator *)new DiagonalTileIterator(tile, p1) : new OrthogonalTileIterator(ta);
01474   for (; (tile = *iter) != INVALID_TILE; ++(*iter)) {
01475     TileType tt = GetTileType(tile);
01476 
01477     /* Check if there is any track on tile */
01478     switch (tt) {
01479       case MP_RAILWAY:
01480         break;
01481       case MP_STATION:
01482         if (!HasStationRail(tile)) continue;
01483         break;
01484       case MP_ROAD:
01485         if (!IsLevelCrossing(tile)) continue;
01486         if (RailNoLevelCrossings(totype)) {
01487           error.MakeError(STR_ERROR_CROSSING_DISALLOWED);
01488           continue;
01489         }
01490         break;
01491       case MP_TUNNELBRIDGE:
01492         if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) continue;
01493         break;
01494       default: continue;
01495     }
01496 
01497     /* Original railtype we are converting from */
01498     RailType type = GetRailType(tile);
01499 
01500     /* Converting to the same type or converting 'hidden' elrail -> rail */
01501     if (type == totype || (_settings_game.vehicle.disable_elrails && totype == RAILTYPE_RAIL && type == RAILTYPE_ELECTRIC)) continue;
01502 
01503     /* Trying to convert other's rail */
01504     CommandCost ret = CheckTileOwnership(tile);
01505     if (ret.Failed()) {
01506       error = ret;
01507       continue;
01508     }
01509 
01510     SmallVector<Train *, 2> vehicles_affected;
01511 
01512     /* Vehicle on the tile when not converting Rail <-> ElRail
01513      * Tunnels and bridges have special check later */
01514     if (tt != MP_TUNNELBRIDGE) {
01515       if (!IsCompatibleRail(type, totype)) {
01516         CommandCost ret = EnsureNoVehicleOnGround(tile);
01517         if (ret.Failed()) {
01518           error = ret;
01519           continue;
01520         }
01521       }
01522       if (flags & DC_EXEC) { // we can safely convert, too
01523         TrackBits reserved = GetReservedTrackbits(tile);
01524         Track     track;
01525         while ((track = RemoveFirstTrack(&reserved)) != INVALID_TRACK) {
01526           Train *v = GetTrainForReservation(tile, track);
01527           if (v != NULL && !HasPowerOnRail(v->railtype, totype)) {
01528             /* No power on new rail type, reroute. */
01529             FreeTrainTrackReservation(v);
01530             *vehicles_affected.Append() = v;
01531           }
01532         }
01533 
01534         /* Update the company infrastructure counters. */
01535         if (!IsRailStationTile(tile) || !IsStationTileBlocked(tile)) {
01536           Company *c = Company::Get(GetTileOwner(tile));
01537           uint num_pieces = IsLevelCrossingTile(tile) ? LEVELCROSSING_TRACKBIT_FACTOR : 1;
01538           if (IsPlainRailTile(tile)) {
01539             TrackBits bits = GetTrackBits(tile);
01540             num_pieces = CountBits(bits);
01541             if (TracksOverlap(bits)) num_pieces *= num_pieces;
01542           }
01543           c->infrastructure.rail[type] -= num_pieces;
01544           c->infrastructure.rail[totype] += num_pieces;
01545           DirtyCompanyInfrastructureWindows(c->index);
01546         }
01547 
01548         SetRailType(tile, totype);
01549         MarkTileDirtyByTile(tile);
01550         /* update power of train on this tile */
01551         FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc);
01552       }
01553     }
01554 
01555     switch (tt) {
01556       case MP_RAILWAY:
01557         switch (GetRailTileType(tile)) {
01558           case RAIL_TILE_DEPOT:
01559             if (flags & DC_EXEC) {
01560               /* notify YAPF about the track layout change */
01561               YapfNotifyTrackLayoutChange(tile, GetRailDepotTrack(tile));
01562 
01563               /* Update build vehicle window related to this depot */
01564               InvalidateWindowData(WC_VEHICLE_DEPOT, tile);
01565               InvalidateWindowData(WC_BUILD_VEHICLE, tile);
01566             }
01567             cost.AddCost(RailConvertCost(type, totype));
01568             break;
01569 
01570           default: // RAIL_TILE_NORMAL, RAIL_TILE_SIGNALS
01571             if (flags & DC_EXEC) {
01572               /* notify YAPF about the track layout change */
01573               TrackBits tracks = GetTrackBits(tile);
01574               while (tracks != TRACK_BIT_NONE) {
01575                 YapfNotifyTrackLayoutChange(tile, RemoveFirstTrack(&tracks));
01576               }
01577             }
01578             cost.AddCost(RailConvertCost(type, totype) * CountBits(GetTrackBits(tile)));
01579             break;
01580         }
01581         break;
01582 
01583       case MP_TUNNELBRIDGE: {
01584         TileIndex endtile = GetOtherTunnelBridgeEnd(tile);
01585 
01586         /* If both ends of tunnel/bridge are in the range, do not try to convert twice -
01587          * it would cause assert because of different test and exec runs */
01588         if (endtile < tile && TileX(endtile) >= TileX(ta.tile) && TileX(endtile) < TileX(ta.tile) + ta.w &&
01589             TileY(endtile) >= TileY(ta.tile) && TileY(endtile) < TileY(ta.tile) + ta.h) continue;
01590 
01591         /* When not coverting rail <-> el. rail, any vehicle cannot be in tunnel/bridge */
01592         if (!IsCompatibleRail(GetRailType(tile), totype)) {
01593           CommandCost ret = TunnelBridgeIsFree(tile, endtile);
01594           if (ret.Failed()) {
01595             error = ret;
01596             continue;
01597           }
01598         }
01599 
01600         if (flags & DC_EXEC) {
01601           Track track = DiagDirToDiagTrack(GetTunnelBridgeDirection(tile));
01602           if (HasTunnelBridgeReservation(tile)) {
01603             Train *v = GetTrainForReservation(tile, track);
01604             if (v != NULL && !HasPowerOnRail(v->railtype, totype)) {
01605               /* No power on new rail type, reroute. */
01606               FreeTrainTrackReservation(v);
01607               *vehicles_affected.Append() = v;
01608             }
01609           }
01610 
01611           /* Update the company infrastructure counters. */
01612           uint num_pieces = (GetTunnelBridgeLength(tile, endtile) + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR;
01613           Company *c = Company::Get(GetTileOwner(tile));
01614           c->infrastructure.rail[GetRailType(tile)] -= num_pieces;
01615           c->infrastructure.rail[totype] += num_pieces;
01616           DirtyCompanyInfrastructureWindows(c->index);
01617 
01618           SetRailType(tile, totype);
01619           SetRailType(endtile, totype);
01620 
01621           FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc);
01622           FindVehicleOnPos(endtile, &affected_trains, &UpdateTrainPowerProc);
01623 
01624           YapfNotifyTrackLayoutChange(tile, track);
01625           YapfNotifyTrackLayoutChange(endtile, track);
01626 
01627           MarkTileDirtyByTile(tile);
01628           MarkTileDirtyByTile(endtile);
01629 
01630           if (IsBridge(tile)) {
01631             TileIndexDiff delta = TileOffsByDiagDir(GetTunnelBridgeDirection(tile));
01632             TileIndex t = tile + delta;
01633             for (; t != endtile; t += delta) MarkTileDirtyByTile(t); // TODO encapsulate this into a function
01634           }
01635         }
01636 
01637         cost.AddCost((GetTunnelBridgeLength(tile, endtile) + 2) * RailConvertCost(type, totype));
01638         break;
01639       }
01640 
01641       default: // MP_STATION, MP_ROAD
01642         if (flags & DC_EXEC) {
01643           Track track = ((tt == MP_STATION) ? GetRailStationTrack(tile) : GetCrossingRailTrack(tile));
01644           YapfNotifyTrackLayoutChange(tile, track);
01645         }
01646 
01647         cost.AddCost(RailConvertCost(type, totype));
01648         break;
01649     }
01650 
01651     for (uint i = 0; i < vehicles_affected.Length(); ++i) {
01652       TryPathReserve(vehicles_affected[i], true);
01653     }
01654   }
01655 
01656   if (flags & DC_EXEC) {
01657     /* Railtype changed, update trains as when entering different track */
01658     for (Train **v = affected_trains.Begin(); v != affected_trains.End(); v++) {
01659       (*v)->RailtypeChanged();
01660     }
01661   }
01662 
01663   delete iter;
01664   return (cost.GetCost() == 0) ? error : cost;
01665 }
01666 
01667 static CommandCost RemoveTrainDepot(TileIndex tile, DoCommandFlag flags)
01668 {
01669   if (_current_company != OWNER_WATER) {
01670     CommandCost ret = CheckTileOwnership(tile);
01671     if (ret.Failed()) return ret;
01672   }
01673 
01674   CommandCost ret = EnsureNoVehicleOnGround(tile);
01675   if (ret.Failed()) return ret;
01676 
01677   if (flags & DC_EXEC) {
01678     /* read variables before the depot is removed */
01679     DiagDirection dir = GetRailDepotDirection(tile);
01680     Owner owner = GetTileOwner(tile);
01681     Train *v = NULL;
01682 
01683     if (HasDepotReservation(tile)) {
01684       v = GetTrainForReservation(tile, DiagDirToDiagTrack(dir));
01685       if (v != NULL) FreeTrainTrackReservation(v);
01686     }
01687 
01688     Company::Get(owner)->infrastructure.rail[GetRailType(tile)]--;
01689     DirtyCompanyInfrastructureWindows(owner);
01690 
01691     delete Depot::GetByTile(tile);
01692     DoClearSquare(tile);
01693     AddSideToSignalBuffer(tile, dir, owner);
01694     YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
01695     if (v != NULL) TryPathReserve(v, true);
01696   }
01697 
01698   return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_TRAIN]);
01699 }
01700 
01701 static CommandCost ClearTile_Track(TileIndex tile, DoCommandFlag flags)
01702 {
01703   CommandCost cost(EXPENSES_CONSTRUCTION);
01704 
01705   if (flags & DC_AUTO) {
01706     if (!IsTileOwner(tile, _current_company)) {
01707       return_cmd_error(STR_ERROR_AREA_IS_OWNED_BY_ANOTHER);
01708     }
01709 
01710     if (IsPlainRail(tile)) {
01711       return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
01712     } else {
01713       return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
01714     }
01715   }
01716 
01717   switch (GetRailTileType(tile)) {
01718     case RAIL_TILE_SIGNALS:
01719     case RAIL_TILE_NORMAL: {
01720       Slope tileh = GetTileSlope(tile);
01721       /* Is there flat water on the lower halftile that gets cleared expensively? */
01722       bool water_ground = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh));
01723 
01724       TrackBits tracks = GetTrackBits(tile);
01725       while (tracks != TRACK_BIT_NONE) {
01726         Track track = RemoveFirstTrack(&tracks);
01727         CommandCost ret = DoCommand(tile, 0, track, flags, CMD_REMOVE_SINGLE_RAIL);
01728         if (ret.Failed()) return ret;
01729         cost.AddCost(ret);
01730       }
01731 
01732       /* when bankrupting, don't make water dirty, there could be a ship on lower halftile */
01733       if (water_ground && !(flags & DC_BANKRUPT)) {
01734         CommandCost ret = EnsureNoVehicleOnGround(tile);
01735         if (ret.Failed()) return ret;
01736 
01737         /* The track was removed, and left a coast tile. Now also clear the water. */
01738         if (flags & DC_EXEC) DoClearSquare(tile);
01739         cost.AddCost(_price[PR_CLEAR_WATER]);
01740       }
01741 
01742       return cost;
01743     }
01744 
01745     case RAIL_TILE_DEPOT:
01746       return RemoveTrainDepot(tile, flags);
01747 
01748     default:
01749       return CMD_ERROR;
01750   }
01751 }
01752 
01757 static uint GetSaveSlopeZ(uint x, uint y, Track track)
01758 {
01759   switch (track) {
01760     case TRACK_UPPER: x &= ~0xF; y &= ~0xF; break;
01761     case TRACK_LOWER: x |=  0xF; y |=  0xF; break;
01762     case TRACK_LEFT:  x |=  0xF; y &= ~0xF; break;
01763     case TRACK_RIGHT: x &= ~0xF; y |=  0xF; break;
01764     default: break;
01765   }
01766   return GetSlopePixelZ(x, y);
01767 }
01768 
01769 static void DrawSingleSignal(TileIndex tile, Track track, byte condition, uint image, uint pos)
01770 {
01771   bool side = (_settings_game.vehicle.road_side != 0) && _settings_game.construction.signal_side;
01772   static const Point SignalPositions[2][12] = {
01773     { // Signals on the left side
01774     /*  LEFT      LEFT      RIGHT     RIGHT     UPPER     UPPER */
01775       { 8,  5}, {14,  1}, { 1, 14}, { 9, 11}, { 1,  0}, { 3, 10},
01776     /*  LOWER     LOWER     X         X         Y         Y     */
01777       {11,  4}, {14, 14}, {11,  3}, { 4, 13}, { 3,  4}, {11, 13}
01778     }, { // Signals on the right side
01779     /*  LEFT      LEFT      RIGHT     RIGHT     UPPER     UPPER */
01780       {14,  1}, {12, 10}, { 4,  6}, { 1, 14}, {10,  4}, { 0,  1},
01781     /*  LOWER     LOWER     X         X         Y         Y     */
01782       {14, 14}, { 5, 12}, {11, 13}, { 4,  3}, {13,  4}, { 3, 11}
01783     }
01784   };
01785 
01786   uint x = TileX(tile) * TILE_SIZE + SignalPositions[side][pos].x;
01787   uint y = TileY(tile) * TILE_SIZE + SignalPositions[side][pos].y;
01788 
01789   SpriteID sprite;
01790 
01791   SignalType type       = GetSignalType(tile, track);
01792   SignalVariant variant = GetSignalVariant(tile, track);
01793 
01794   if (type == SIGTYPE_NORMAL && variant == SIG_ELECTRIC) {
01795     /* Normal electric signals are picked from original sprites. */
01796     sprite = SPR_ORIGINAL_SIGNALS_BASE + image + condition;
01797   } else {
01798     /* All other signals are picked from add on sprites. */
01799     sprite = SPR_SIGNALS_BASE + (type - 1) * 16 + variant * 64 + image + condition + (type > SIGTYPE_LAST_NOPBS ? 64 : 0);
01800   }
01801 
01802   AddSortableSpriteToDraw(sprite, PAL_NONE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, GetSaveSlopeZ(x, y, track));
01803 }
01804 
01805 static uint32 _drawtile_track_palette;
01806 
01807 
01808 static void DrawTrackFence_NW(const TileInfo *ti, SpriteID base_image)
01809 {
01810   RailFenceOffset rfo = RFO_FLAT_X;
01811   if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SW : RFO_SLOPE_NE;
01812   AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01813     ti->x, ti->y + 1, 16, 1, 4, ti->z);
01814 }
01815 
01816 static void DrawTrackFence_SE(const TileInfo *ti, SpriteID base_image)
01817 {
01818   RailFenceOffset rfo = RFO_FLAT_X;
01819   if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SW : RFO_SLOPE_NE;
01820   AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01821     ti->x, ti->y + TILE_SIZE - 1, 16, 1, 4, ti->z);
01822 }
01823 
01824 static void DrawTrackFence_NW_SE(const TileInfo *ti, SpriteID base_image)
01825 {
01826   DrawTrackFence_NW(ti, base_image);
01827   DrawTrackFence_SE(ti, base_image);
01828 }
01829 
01830 static void DrawTrackFence_NE(const TileInfo *ti, SpriteID base_image)
01831 {
01832   RailFenceOffset rfo = RFO_FLAT_Y;
01833   if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SE : RFO_SLOPE_NW;
01834   AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01835     ti->x + 1, ti->y, 1, 16, 4, ti->z);
01836 }
01837 
01838 static void DrawTrackFence_SW(const TileInfo *ti, SpriteID base_image)
01839 {
01840   RailFenceOffset rfo = RFO_FLAT_Y;
01841   if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SE : RFO_SLOPE_NW;
01842   AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01843     ti->x + TILE_SIZE - 1, ti->y, 1, 16, 4, ti->z);
01844 }
01845 
01846 static void DrawTrackFence_NE_SW(const TileInfo *ti, SpriteID base_image)
01847 {
01848   DrawTrackFence_NE(ti, base_image);
01849   DrawTrackFence_SW(ti, base_image);
01850 }
01851 
01855 static void DrawTrackFence_NS_1(const TileInfo *ti, SpriteID base_image)
01856 {
01857   int z = ti->z + GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_W);
01858   AddSortableSpriteToDraw(base_image + RFO_FLAT_VERT, _drawtile_track_palette,
01859     ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01860 }
01861 
01865 static void DrawTrackFence_NS_2(const TileInfo *ti, SpriteID base_image)
01866 {
01867   int z = ti->z + GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_E);
01868   AddSortableSpriteToDraw(base_image + RFO_FLAT_VERT, _drawtile_track_palette,
01869     ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01870 }
01871 
01875 static void DrawTrackFence_WE_1(const TileInfo *ti, SpriteID base_image)
01876 {
01877   int z = ti->z + GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_N);
01878   AddSortableSpriteToDraw(base_image + RFO_FLAT_HORZ, _drawtile_track_palette,
01879     ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01880 }
01881 
01885 static void DrawTrackFence_WE_2(const TileInfo *ti, SpriteID base_image)
01886 {
01887   int z = ti->z + GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_S);
01888   AddSortableSpriteToDraw(base_image + RFO_FLAT_HORZ, _drawtile_track_palette,
01889     ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01890 }
01891 
01892 
01893 static void DrawTrackDetails(const TileInfo *ti, const RailtypeInfo *rti)
01894 {
01895   /* Base sprite for track fences.
01896    * Note: Halftile slopes only have fences on the upper part. */
01897   SpriteID base_image = GetCustomRailSprite(rti, ti->tile, RTSG_FENCES, IsHalftileSlope(ti->tileh) ? TCX_UPPER_HALFTILE : TCX_NORMAL);
01898   if (base_image == 0) base_image = SPR_TRACK_FENCE_FLAT_X;
01899 
01900   switch (GetRailGroundType(ti->tile)) {
01901     case RAIL_GROUND_FENCE_NW:     DrawTrackFence_NW(ti, base_image);    break;
01902     case RAIL_GROUND_FENCE_SE:     DrawTrackFence_SE(ti, base_image);    break;
01903     case RAIL_GROUND_FENCE_SENW:   DrawTrackFence_NW_SE(ti, base_image); break;
01904     case RAIL_GROUND_FENCE_NE:     DrawTrackFence_NE(ti, base_image);    break;
01905     case RAIL_GROUND_FENCE_SW:     DrawTrackFence_SW(ti, base_image);    break;
01906     case RAIL_GROUND_FENCE_NESW:   DrawTrackFence_NE_SW(ti, base_image); break;
01907     case RAIL_GROUND_FENCE_VERT1:  DrawTrackFence_NS_1(ti, base_image);  break;
01908     case RAIL_GROUND_FENCE_VERT2:  DrawTrackFence_NS_2(ti, base_image);  break;
01909     case RAIL_GROUND_FENCE_HORIZ1: DrawTrackFence_WE_1(ti, base_image);  break;
01910     case RAIL_GROUND_FENCE_HORIZ2: DrawTrackFence_WE_2(ti, base_image);  break;
01911     case RAIL_GROUND_WATER: {
01912       Corner track_corner;
01913       if (IsHalftileSlope(ti->tileh)) {
01914         /* Steep slope or one-corner-raised slope with halftile foundation */
01915         track_corner = GetHalftileSlopeCorner(ti->tileh);
01916       } else {
01917         /* Three-corner-raised slope */
01918         track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh)));
01919       }
01920       switch (track_corner) {
01921         case CORNER_W: DrawTrackFence_NS_1(ti, base_image); break;
01922         case CORNER_S: DrawTrackFence_WE_2(ti, base_image); break;
01923         case CORNER_E: DrawTrackFence_NS_2(ti, base_image); break;
01924         case CORNER_N: DrawTrackFence_WE_1(ti, base_image); break;
01925         default: NOT_REACHED();
01926       }
01927       break;
01928     }
01929     default: break;
01930   }
01931 }
01932 
01933 /* SubSprite for drawing the track halftile of 'three-corners-raised'-sloped rail sprites. */
01934 static const int INF = 1000; // big number compared to tilesprite size
01935 static const SubSprite _halftile_sub_sprite[4] = {
01936   { -INF    , -INF  , 32 - 33, INF     }, // CORNER_W, clip 33 pixels from right
01937   { -INF    ,  0 + 7, INF    , INF     }, // CORNER_S, clip 7 pixels from top
01938   { -31 + 33, -INF  , INF    , INF     }, // CORNER_E, clip 33 pixels from left
01939   { -INF    , -INF  , INF    , 30 - 23 }  // CORNER_N, clip 23 pixels from bottom
01940 };
01941 
01942 static inline void DrawTrackSprite(SpriteID sprite, PaletteID pal, const TileInfo *ti, Slope s)
01943 {
01944   DrawGroundSprite(sprite, pal, NULL, 0, (ti->tileh & s) ? -8 : 0);
01945 }
01946 
01947 static void DrawTrackBitsOverlay(TileInfo *ti, TrackBits track, const RailtypeInfo *rti)
01948 {
01949   RailGroundType rgt = GetRailGroundType(ti->tile);
01950   Foundation f = GetRailFoundation(ti->tileh, track);
01951   Corner halftile_corner = CORNER_INVALID;
01952 
01953   if (IsNonContinuousFoundation(f)) {
01954     /* Save halftile corner */
01955     halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f));
01956     /* Draw lower part first */
01957     track &= ~CornerToTrackBits(halftile_corner);
01958     f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE);
01959   }
01960 
01961   DrawFoundation(ti, f);
01962   /* DrawFoundation modifies ti */
01963 
01964   /* Draw ground */
01965   if (rgt == RAIL_GROUND_WATER) {
01966     if (track != TRACK_BIT_NONE || IsSteepSlope(ti->tileh)) {
01967       /* three-corner-raised slope or steep slope with track on upper part */
01968       DrawShoreTile(ti->tileh);
01969     } else {
01970       /* single-corner-raised slope with track on upper part */
01971       DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
01972     }
01973   } else {
01974     SpriteID image;
01975 
01976     switch (rgt) {
01977       case RAIL_GROUND_BARREN:     image = SPR_FLAT_BARE_LAND;  break;
01978       case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOW_DESERT_TILE; break;
01979       default:                     image = SPR_FLAT_GRASS_TILE; break;
01980     }
01981 
01982     image += SlopeToSpriteOffset(ti->tileh);
01983 
01984     DrawGroundSprite(image, PAL_NONE);
01985   }
01986 
01987   SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
01988   SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
01989   TrackBits pbs = _settings_client.gui.show_track_reservation ? GetRailReservationTrackBits(ti->tile) : TRACK_BIT_NONE;
01990 
01991   if (track == TRACK_BIT_NONE) {
01992     /* Half-tile foundation, no track here? */
01993   } else if (ti->tileh == SLOPE_NW && track == TRACK_BIT_Y) {
01994     DrawGroundSprite(ground + RTO_SLOPE_NW, PAL_NONE);
01995     if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 9, PALETTE_CRASH);
01996   } else if (ti->tileh == SLOPE_NE && track == TRACK_BIT_X) {
01997     DrawGroundSprite(ground + RTO_SLOPE_NE, PAL_NONE);
01998     if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 6, PALETTE_CRASH);
01999   } else if (ti->tileh == SLOPE_SE && track == TRACK_BIT_Y) {
02000     DrawGroundSprite(ground + RTO_SLOPE_SE, PAL_NONE);
02001     if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 7, PALETTE_CRASH);
02002   } else if (ti->tileh == SLOPE_SW && track == TRACK_BIT_X) {
02003     DrawGroundSprite(ground + RTO_SLOPE_SW, PAL_NONE);
02004     if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 8, PALETTE_CRASH);
02005   } else {
02006     switch (track) {
02007       /* Draw single ground sprite when not overlapping. No track overlay
02008        * is necessary for these sprites. */
02009       case TRACK_BIT_X:     DrawGroundSprite(ground + RTO_X, PAL_NONE); break;
02010       case TRACK_BIT_Y:     DrawGroundSprite(ground + RTO_Y, PAL_NONE); break;
02011       case TRACK_BIT_UPPER: DrawTrackSprite(ground + RTO_N, PAL_NONE, ti, SLOPE_N); break;
02012       case TRACK_BIT_LOWER: DrawTrackSprite(ground + RTO_S, PAL_NONE, ti, SLOPE_S); break;
02013       case TRACK_BIT_RIGHT: DrawTrackSprite(ground + RTO_E, PAL_NONE, ti, SLOPE_E); break;
02014       case TRACK_BIT_LEFT:  DrawTrackSprite(ground + RTO_W, PAL_NONE, ti, SLOPE_W); break;
02015       case TRACK_BIT_CROSS: DrawGroundSprite(ground + RTO_CROSSING_XY, PAL_NONE); break;
02016       case TRACK_BIT_HORZ:  DrawTrackSprite(ground + RTO_N, PAL_NONE, ti, SLOPE_N);
02017                             DrawTrackSprite(ground + RTO_S, PAL_NONE, ti, SLOPE_S); break;
02018       case TRACK_BIT_VERT:  DrawTrackSprite(ground + RTO_E, PAL_NONE, ti, SLOPE_E);
02019                             DrawTrackSprite(ground + RTO_W, PAL_NONE, ti, SLOPE_W); break;
02020 
02021       default:
02022         /* We're drawing a junction tile */
02023         if ((track & TRACK_BIT_3WAY_NE) == 0) {
02024           DrawGroundSprite(ground + RTO_JUNCTION_SW, PAL_NONE);
02025         } else if ((track & TRACK_BIT_3WAY_SW) == 0) {
02026           DrawGroundSprite(ground + RTO_JUNCTION_NE, PAL_NONE);
02027         } else if ((track & TRACK_BIT_3WAY_NW) == 0) {
02028           DrawGroundSprite(ground + RTO_JUNCTION_SE, PAL_NONE);
02029         } else if ((track & TRACK_BIT_3WAY_SE) == 0) {
02030           DrawGroundSprite(ground + RTO_JUNCTION_NW, PAL_NONE);
02031         } else {
02032           DrawGroundSprite(ground + RTO_JUNCTION_NSEW, PAL_NONE);
02033         }
02034 
02035         /* Mask out PBS bits as we shall draw them afterwards anyway. */
02036         track &= ~pbs;
02037 
02038         /* Draw regular track bits */
02039         if (track & TRACK_BIT_X)     DrawGroundSprite(overlay + RTO_X, PAL_NONE);
02040         if (track & TRACK_BIT_Y)     DrawGroundSprite(overlay + RTO_Y, PAL_NONE);
02041         if (track & TRACK_BIT_UPPER) DrawGroundSprite(overlay + RTO_N, PAL_NONE);
02042         if (track & TRACK_BIT_LOWER) DrawGroundSprite(overlay + RTO_S, PAL_NONE);
02043         if (track & TRACK_BIT_RIGHT) DrawGroundSprite(overlay + RTO_E, PAL_NONE);
02044         if (track & TRACK_BIT_LEFT)  DrawGroundSprite(overlay + RTO_W, PAL_NONE);
02045     }
02046 
02047     /* Draw reserved track bits */
02048     if (pbs & TRACK_BIT_X)     DrawGroundSprite(overlay + RTO_X, PALETTE_CRASH);
02049     if (pbs & TRACK_BIT_Y)     DrawGroundSprite(overlay + RTO_Y, PALETTE_CRASH);
02050     if (pbs & TRACK_BIT_UPPER) DrawTrackSprite(overlay + RTO_N, PALETTE_CRASH, ti, SLOPE_N);
02051     if (pbs & TRACK_BIT_LOWER) DrawTrackSprite(overlay + RTO_S, PALETTE_CRASH, ti, SLOPE_S);
02052     if (pbs & TRACK_BIT_RIGHT) DrawTrackSprite(overlay + RTO_E, PALETTE_CRASH, ti, SLOPE_E);
02053     if (pbs & TRACK_BIT_LEFT)  DrawTrackSprite(overlay + RTO_W, PALETTE_CRASH, ti, SLOPE_W);
02054   }
02055 
02056   if (IsValidCorner(halftile_corner)) {
02057     DrawFoundation(ti, HalftileFoundation(halftile_corner));
02058     overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY, TCX_UPPER_HALFTILE);
02059     ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND, TCX_UPPER_HALFTILE);
02060 
02061     /* Draw higher halftile-overlay: Use the sloped sprites with three corners raised. They probably best fit the lightning. */
02062     Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
02063 
02064     SpriteID image;
02065     switch (rgt) {
02066       case RAIL_GROUND_BARREN:     image = SPR_FLAT_BARE_LAND;  break;
02067       case RAIL_GROUND_ICE_DESERT:
02068       case RAIL_GROUND_HALF_SNOW:  image = SPR_FLAT_SNOW_DESERT_TILE; break;
02069       default:                     image = SPR_FLAT_GRASS_TILE; break;
02070     }
02071 
02072     image += SlopeToSpriteOffset(fake_slope);
02073 
02074     DrawGroundSprite(image, PAL_NONE, &(_halftile_sub_sprite[halftile_corner]));
02075 
02076     track = CornerToTrackBits(halftile_corner);
02077 
02078     int offset;
02079     switch (track) {
02080       default: NOT_REACHED();
02081       case TRACK_BIT_UPPER: offset = RTO_N; break;
02082       case TRACK_BIT_LOWER: offset = RTO_S; break;
02083       case TRACK_BIT_RIGHT: offset = RTO_E; break;
02084       case TRACK_BIT_LEFT:  offset = RTO_W; break;
02085     }
02086 
02087     DrawTrackSprite(ground + offset, PAL_NONE, ti, fake_slope);
02088     if (_settings_client.gui.show_track_reservation && HasReservedTracks(ti->tile, track)) {
02089       DrawTrackSprite(overlay + offset, PALETTE_CRASH, ti, fake_slope);
02090     }
02091   }
02092 }
02093 
02099 static void DrawTrackBits(TileInfo *ti, TrackBits track)
02100 {
02101   const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
02102 
02103   if (rti->UsesOverlay()) {
02104     DrawTrackBitsOverlay(ti, track, rti);
02105     return;
02106   }
02107 
02108   RailGroundType rgt = GetRailGroundType(ti->tile);
02109   Foundation f = GetRailFoundation(ti->tileh, track);
02110   Corner halftile_corner = CORNER_INVALID;
02111 
02112   if (IsNonContinuousFoundation(f)) {
02113     /* Save halftile corner */
02114     halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f));
02115     /* Draw lower part first */
02116     track &= ~CornerToTrackBits(halftile_corner);
02117     f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE);
02118   }
02119 
02120   DrawFoundation(ti, f);
02121   /* DrawFoundation modifies ti */
02122 
02123   SpriteID image;
02124   PaletteID pal = PAL_NONE;
02125   const SubSprite *sub = NULL;
02126   bool junction = false;
02127 
02128   /* Select the sprite to use. */
02129   if (track == 0) {
02130     /* Clear ground (only track on halftile foundation) */
02131     if (rgt == RAIL_GROUND_WATER) {
02132       if (IsSteepSlope(ti->tileh)) {
02133         DrawShoreTile(ti->tileh);
02134         image = 0;
02135       } else {
02136         image = SPR_FLAT_WATER_TILE;
02137       }
02138     } else {
02139       switch (rgt) {
02140         case RAIL_GROUND_BARREN:     image = SPR_FLAT_BARE_LAND;  break;
02141         case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOW_DESERT_TILE; break;
02142         default:                     image = SPR_FLAT_GRASS_TILE; break;
02143       }
02144       image += SlopeToSpriteOffset(ti->tileh);
02145     }
02146   } else {
02147     if (ti->tileh != SLOPE_FLAT) {
02148       /* track on non-flat ground */
02149       image = _track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.track_y;
02150     } else {
02151       /* track on flat ground */
02152       (image = rti->base_sprites.track_y, track == TRACK_BIT_Y) ||
02153       (image++,                           track == TRACK_BIT_X) ||
02154       (image++,                           track == TRACK_BIT_UPPER) ||
02155       (image++,                           track == TRACK_BIT_LOWER) ||
02156       (image++,                           track == TRACK_BIT_RIGHT) ||
02157       (image++,                           track == TRACK_BIT_LEFT) ||
02158       (image++,                           track == TRACK_BIT_CROSS) ||
02159 
02160       (image = rti->base_sprites.track_ns, track == TRACK_BIT_HORZ) ||
02161       (image++,                            track == TRACK_BIT_VERT) ||
02162 
02163       (junction = true, false) ||
02164       (image = rti->base_sprites.ground, (track & TRACK_BIT_3WAY_NE) == 0) ||
02165       (image++,                          (track & TRACK_BIT_3WAY_SW) == 0) ||
02166       (image++,                          (track & TRACK_BIT_3WAY_NW) == 0) ||
02167       (image++,                          (track & TRACK_BIT_3WAY_SE) == 0) ||
02168       (image++, true);
02169     }
02170 
02171     switch (rgt) {
02172       case RAIL_GROUND_BARREN:     pal = PALETTE_TO_BARE_LAND; break;
02173       case RAIL_GROUND_ICE_DESERT: image += rti->snow_offset;  break;
02174       case RAIL_GROUND_WATER: {
02175         /* three-corner-raised slope */
02176         DrawShoreTile(ti->tileh);
02177         Corner track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh)));
02178         sub = &(_halftile_sub_sprite[track_corner]);
02179         break;
02180       }
02181       default: break;
02182     }
02183   }
02184 
02185   if (image != 0) DrawGroundSprite(image, pal, sub);
02186 
02187   /* Draw track pieces individually for junction tiles */
02188   if (junction) {
02189     if (track & TRACK_BIT_X)     DrawGroundSprite(rti->base_sprites.single_x, PAL_NONE);
02190     if (track & TRACK_BIT_Y)     DrawGroundSprite(rti->base_sprites.single_y, PAL_NONE);
02191     if (track & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PAL_NONE);
02192     if (track & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PAL_NONE);
02193     if (track & TRACK_BIT_LEFT)  DrawGroundSprite(rti->base_sprites.single_w, PAL_NONE);
02194     if (track & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PAL_NONE);
02195   }
02196 
02197   /* PBS debugging, draw reserved tracks darker */
02198   if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation) {
02199     /* Get reservation, but mask track on halftile slope */
02200     TrackBits pbs = GetRailReservationTrackBits(ti->tile) & track;
02201     if (pbs & TRACK_BIT_X) {
02202       if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
02203         DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH);
02204       } else {
02205         DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
02206       }
02207     }
02208     if (pbs & TRACK_BIT_Y) {
02209       if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
02210         DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH);
02211       } else {
02212         DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
02213       }
02214     }
02215     if (pbs & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_N ? -(int)TILE_HEIGHT : 0);
02216     if (pbs & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_S ? -(int)TILE_HEIGHT : 0);
02217     if (pbs & TRACK_BIT_LEFT)  DrawGroundSprite(rti->base_sprites.single_w, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_W ? -(int)TILE_HEIGHT : 0);
02218     if (pbs & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_E ? -(int)TILE_HEIGHT : 0);
02219   }
02220 
02221   if (IsValidCorner(halftile_corner)) {
02222     DrawFoundation(ti, HalftileFoundation(halftile_corner));
02223 
02224     /* Draw higher halftile-overlay: Use the sloped sprites with three corners raised. They probably best fit the lightning. */
02225     Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
02226     image = _track_sloped_sprites[fake_slope - 1] + rti->base_sprites.track_y;
02227     pal = PAL_NONE;
02228     switch (rgt) {
02229       case RAIL_GROUND_BARREN:     pal = PALETTE_TO_BARE_LAND; break;
02230       case RAIL_GROUND_ICE_DESERT:
02231       case RAIL_GROUND_HALF_SNOW:  image += rti->snow_offset;  break; // higher part has snow in this case too
02232       default: break;
02233     }
02234     DrawGroundSprite(image, pal, &(_halftile_sub_sprite[halftile_corner]));
02235 
02236     if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasReservedTracks(ti->tile, CornerToTrackBits(halftile_corner))) {
02237       static const byte _corner_to_track_sprite[] = {3, 1, 2, 0};
02238       DrawGroundSprite(_corner_to_track_sprite[halftile_corner] + rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, -(int)TILE_HEIGHT);
02239     }
02240   }
02241 }
02242 
02250 enum SignalOffsets {
02251   SIGNAL_TO_SOUTHWEST =  0,
02252   SIGNAL_TO_NORTHEAST =  2,
02253   SIGNAL_TO_SOUTHEAST =  4,
02254   SIGNAL_TO_NORTHWEST =  6,
02255   SIGNAL_TO_EAST      =  8,
02256   SIGNAL_TO_WEST      = 10,
02257   SIGNAL_TO_SOUTH     = 12,
02258   SIGNAL_TO_NORTH     = 14,
02259 };
02260 
02261 static void DrawSignals(TileIndex tile, TrackBits rails)
02262 {
02263 #define MAYBE_DRAW_SIGNAL(x, y, z, t) if (IsSignalPresent(tile, x)) DrawSingleSignal(tile, t, GetSingleSignalState(tile, x), y, z)
02264 
02265   if (!(rails & TRACK_BIT_Y)) {
02266     if (!(rails & TRACK_BIT_X)) {
02267       if (rails & TRACK_BIT_LEFT) {
02268         MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTH, 0, TRACK_LEFT);
02269         MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTH, 1, TRACK_LEFT);
02270       }
02271       if (rails & TRACK_BIT_RIGHT) {
02272         MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_NORTH, 2, TRACK_RIGHT);
02273         MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_SOUTH, 3, TRACK_RIGHT);
02274       }
02275       if (rails & TRACK_BIT_UPPER) {
02276         MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_WEST, 4, TRACK_UPPER);
02277         MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_EAST, 5, TRACK_UPPER);
02278       }
02279       if (rails & TRACK_BIT_LOWER) {
02280         MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_WEST, 6, TRACK_LOWER);
02281         MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_EAST, 7, TRACK_LOWER);
02282       }
02283     } else {
02284       MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHWEST, 8, TRACK_X);
02285       MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHEAST, 9, TRACK_X);
02286     }
02287   } else {
02288     MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHEAST, 10, TRACK_Y);
02289     MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHWEST, 11, TRACK_Y);
02290   }
02291 }
02292 
02293 static void DrawTile_Track(TileInfo *ti)
02294 {
02295   const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
02296 
02297   _drawtile_track_palette = COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile));
02298 
02299   if (IsPlainRail(ti->tile)) {
02300     TrackBits rails = GetTrackBits(ti->tile);
02301 
02302     DrawTrackBits(ti, rails);
02303 
02304     if (HasBit(_display_opt, DO_FULL_DETAIL)) DrawTrackDetails(ti, rti);
02305 
02306     if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
02307 
02308     if (HasSignals(ti->tile)) DrawSignals(ti->tile, rails);
02309   } else {
02310     /* draw depot */
02311     const DrawTileSprites *dts;
02312     PaletteID pal = PAL_NONE;
02313     SpriteID relocation;
02314 
02315     if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
02316 
02317     if (IsInvisibilitySet(TO_BUILDINGS)) {
02318       /* Draw rail instead of depot */
02319       dts = &_depot_invisible_gfx_table[GetRailDepotDirection(ti->tile)];
02320     } else {
02321       dts = &_depot_gfx_table[GetRailDepotDirection(ti->tile)];
02322     }
02323 
02324     SpriteID image;
02325     if (rti->UsesOverlay()) {
02326       image = SPR_FLAT_GRASS_TILE;
02327     } else {
02328       image = dts->ground.sprite;
02329       if (image != SPR_FLAT_GRASS_TILE) image += rti->GetRailtypeSpriteOffset();
02330     }
02331 
02332     /* adjust ground tile for desert
02333      * don't adjust for snow, because snow in depots looks weird */
02334     if (IsSnowRailGround(ti->tile) && _settings_game.game_creation.landscape == LT_TROPIC) {
02335       if (image != SPR_FLAT_GRASS_TILE) {
02336         image += rti->snow_offset; // tile with tracks
02337       } else {
02338         image = SPR_FLAT_SNOW_DESERT_TILE; // flat ground
02339       }
02340     }
02341 
02342     DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, _drawtile_track_palette));
02343 
02344     if (rti->UsesOverlay()) {
02345       SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
02346 
02347       switch (GetRailDepotDirection(ti->tile)) {
02348         case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break; // else FALL THROUGH
02349         case DIAGDIR_SW: DrawGroundSprite(ground + RTO_X, PAL_NONE); break;
02350         case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break; // else FALL THROUGH
02351         case DIAGDIR_SE: DrawGroundSprite(ground + RTO_Y, PAL_NONE); break;
02352         default: break;
02353       }
02354 
02355       if (_settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile)) {
02356         SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
02357 
02358         switch (GetRailDepotDirection(ti->tile)) {
02359           case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break; // else FALL THROUGH
02360           case DIAGDIR_SW: DrawGroundSprite(overlay + RTO_X, PALETTE_CRASH); break;
02361           case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break; // else FALL THROUGH
02362           case DIAGDIR_SE: DrawGroundSprite(overlay + RTO_Y, PALETTE_CRASH); break;
02363           default: break;
02364         }
02365       }
02366     } else {
02367       /* PBS debugging, draw reserved tracks darker */
02368       if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile)) {
02369         switch (GetRailDepotDirection(ti->tile)) {
02370           case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break; // else FALL THROUGH
02371           case DIAGDIR_SW: DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH); break;
02372           case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break; // else FALL THROUGH
02373           case DIAGDIR_SE: DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH); break;
02374           default: break;
02375         }
02376       }
02377     }
02378     int depot_sprite = GetCustomRailSprite(rti, ti->tile, RTSG_DEPOT);
02379     relocation = depot_sprite != 0 ? depot_sprite - SPR_RAIL_DEPOT_SE_1 : rti->GetRailtypeSpriteOffset();
02380 
02381     if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
02382 
02383     DrawRailTileSeq(ti, dts, TO_BUILDINGS, relocation, 0, _drawtile_track_palette);
02384   }
02385   DrawBridgeMiddle(ti);
02386 }
02387 
02388 void DrawTrainDepotSprite(int x, int y, int dir, RailType railtype)
02389 {
02390   const DrawTileSprites *dts = &_depot_gfx_table[dir];
02391   const RailtypeInfo *rti = GetRailTypeInfo(railtype);
02392   SpriteID image = rti->UsesOverlay() ? SPR_FLAT_GRASS_TILE : dts->ground.sprite;
02393   uint32 offset = rti->GetRailtypeSpriteOffset();
02394 
02395   x += 33;
02396   y += 17;
02397 
02398   if (image != SPR_FLAT_GRASS_TILE) image += offset;
02399   PaletteID palette = COMPANY_SPRITE_COLOUR(_local_company);
02400 
02401   DrawSprite(image, PAL_NONE, x, y);
02402 
02403   if (rti->UsesOverlay()) {
02404     SpriteID ground = GetCustomRailSprite(rti, INVALID_TILE, RTSG_GROUND);
02405 
02406     switch (dir) {
02407       case DIAGDIR_SW: DrawSprite(ground + RTO_X, PAL_NONE, x, y); break;
02408       case DIAGDIR_SE: DrawSprite(ground + RTO_Y, PAL_NONE, x, y); break;
02409       default: break;
02410     }
02411   }
02412   int depot_sprite = GetCustomRailSprite(rti, INVALID_TILE, RTSG_DEPOT);
02413   if (depot_sprite != 0) offset = depot_sprite - SPR_RAIL_DEPOT_SE_1;
02414 
02415   DrawRailTileSeqInGUI(x, y, dts, offset, 0, palette);
02416 }
02417 
02418 static int GetSlopePixelZ_Track(TileIndex tile, uint x, uint y)
02419 {
02420   if (IsPlainRail(tile)) {
02421     int z;
02422     Slope tileh = GetTilePixelSlope(tile, &z);
02423     if (tileh == SLOPE_FLAT) return z;
02424 
02425     z += ApplyPixelFoundationToSlope(GetRailFoundation(tileh, GetTrackBits(tile)), &tileh);
02426     return z + GetPartialPixelZ(x & 0xF, y & 0xF, tileh);
02427   } else {
02428     return GetTileMaxPixelZ(tile);
02429   }
02430 }
02431 
02432 static Foundation GetFoundation_Track(TileIndex tile, Slope tileh)
02433 {
02434   return IsPlainRail(tile) ? GetRailFoundation(tileh, GetTrackBits(tile)) : FlatteningFoundation(tileh);
02435 }
02436 
02437 static void TileLoop_Track(TileIndex tile)
02438 {
02439   RailGroundType old_ground = GetRailGroundType(tile);
02440   RailGroundType new_ground;
02441 
02442   if (old_ground == RAIL_GROUND_WATER) {
02443     TileLoop_Water(tile);
02444     return;
02445   }
02446 
02447   switch (_settings_game.game_creation.landscape) {
02448     case LT_ARCTIC: {
02449       int z;
02450       Slope slope = GetTileSlope(tile, &z);
02451       bool half = false;
02452 
02453       /* for non-flat track, use lower part of track
02454        * in other cases, use the highest part with track */
02455       if (IsPlainRail(tile)) {
02456         TrackBits track = GetTrackBits(tile);
02457         Foundation f = GetRailFoundation(slope, track);
02458 
02459         switch (f) {
02460           case FOUNDATION_NONE:
02461             /* no foundation - is the track on the upper side of three corners raised tile? */
02462             if (IsSlopeWithThreeCornersRaised(slope)) z++;
02463             break;
02464 
02465           case FOUNDATION_INCLINED_X:
02466           case FOUNDATION_INCLINED_Y:
02467             /* sloped track - is it on a steep slope? */
02468             if (IsSteepSlope(slope)) z++;
02469             break;
02470 
02471           case FOUNDATION_STEEP_LOWER:
02472             /* only lower part of steep slope */
02473             z++;
02474             break;
02475 
02476           default:
02477             /* if it is a steep slope, then there is a track on higher part */
02478             if (IsSteepSlope(slope)) z++;
02479             z++;
02480             break;
02481         }
02482 
02483         half = IsInsideMM(f, FOUNDATION_STEEP_BOTH, FOUNDATION_HALFTILE_N + 1);
02484       } else {
02485         /* is the depot on a non-flat tile? */
02486         if (slope != SLOPE_FLAT) z++;
02487       }
02488 
02489       /* 'z' is now the lowest part of the highest track bit -
02490        * for sloped track, it is 'z' of lower part
02491        * for two track bits, it is 'z' of higher track bit
02492        * For non-continuous foundations (and STEEP_BOTH), 'half' is set */
02493       if (z > GetSnowLine()) {
02494         if (half && z - GetSnowLine() == 1) {
02495           /* track on non-continuous foundation, lower part is not under snow */
02496           new_ground = RAIL_GROUND_HALF_SNOW;
02497         } else {
02498           new_ground = RAIL_GROUND_ICE_DESERT;
02499         }
02500         goto set_ground;
02501       }
02502       break;
02503       }
02504 
02505     case LT_TROPIC:
02506       if (GetTropicZone(tile) == TROPICZONE_DESERT) {
02507         new_ground = RAIL_GROUND_ICE_DESERT;
02508         goto set_ground;
02509       }
02510       break;
02511   }
02512 
02513   new_ground = RAIL_GROUND_GRASS;
02514 
02515   if (IsPlainRail(tile) && old_ground != RAIL_GROUND_BARREN) { // wait until bottom is green
02516     /* determine direction of fence */
02517     TrackBits rail = GetTrackBits(tile);
02518 
02519     switch (rail) {
02520       case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
02521       case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
02522       case TRACK_BIT_LEFT:  new_ground = RAIL_GROUND_FENCE_VERT1;  break;
02523       case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2;  break;
02524 
02525       default: {
02526         Owner owner = GetTileOwner(tile);
02527 
02528         if (rail == (TRACK_BIT_LOWER | TRACK_BIT_RIGHT) || (
02529               (rail & TRACK_BIT_3WAY_NW) == 0 &&
02530               (rail & TRACK_BIT_X)
02531             )) {
02532           TileIndex n = tile + TileDiffXY(0, -1);
02533           TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02534 
02535           if ((!IsTileType(n, MP_RAILWAY) && !IsRailWaypointTile(n)) ||
02536               !IsTileOwner(n, owner) ||
02537               nrail == TRACK_BIT_UPPER ||
02538               nrail == TRACK_BIT_LEFT) {
02539             new_ground = RAIL_GROUND_FENCE_NW;
02540           }
02541         }
02542 
02543         if (rail == (TRACK_BIT_UPPER | TRACK_BIT_LEFT) || (
02544               (rail & TRACK_BIT_3WAY_SE) == 0 &&
02545               (rail & TRACK_BIT_X)
02546             )) {
02547           TileIndex n = tile + TileDiffXY(0, 1);
02548           TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02549 
02550           if ((!IsTileType(n, MP_RAILWAY) && !IsRailWaypointTile(n)) ||
02551               !IsTileOwner(n, owner) ||
02552               nrail == TRACK_BIT_LOWER ||
02553               nrail == TRACK_BIT_RIGHT) {
02554             new_ground = (new_ground == RAIL_GROUND_FENCE_NW) ?
02555               RAIL_GROUND_FENCE_SENW : RAIL_GROUND_FENCE_SE;
02556           }
02557         }
02558 
02559         if (rail == (TRACK_BIT_LOWER | TRACK_BIT_LEFT) || (
02560               (rail & TRACK_BIT_3WAY_NE) == 0 &&
02561               (rail & TRACK_BIT_Y)
02562             )) {
02563           TileIndex n = tile + TileDiffXY(-1, 0);
02564           TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02565 
02566           if ((!IsTileType(n, MP_RAILWAY) && !IsRailWaypointTile(n)) ||
02567               !IsTileOwner(n, owner) ||
02568               nrail == TRACK_BIT_UPPER ||
02569               nrail == TRACK_BIT_RIGHT) {
02570             new_ground = RAIL_GROUND_FENCE_NE;
02571           }
02572         }
02573 
02574         if (rail == (TRACK_BIT_UPPER | TRACK_BIT_RIGHT) || (
02575               (rail & TRACK_BIT_3WAY_SW) == 0 &&
02576               (rail & TRACK_BIT_Y)
02577             )) {
02578           TileIndex n = tile + TileDiffXY(1, 0);
02579           TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02580 
02581           if ((!IsTileType(n, MP_RAILWAY) && !IsRailWaypointTile(n)) ||
02582               !IsTileOwner(n, owner) ||
02583               nrail == TRACK_BIT_LOWER ||
02584               nrail == TRACK_BIT_LEFT) {
02585             new_ground = (new_ground == RAIL_GROUND_FENCE_NE) ?
02586               RAIL_GROUND_FENCE_NESW : RAIL_GROUND_FENCE_SW;
02587           }
02588         }
02589         break;
02590       }
02591     }
02592   }
02593 
02594 set_ground:
02595   if (old_ground != new_ground) {
02596     SetRailGroundType(tile, new_ground);
02597     MarkTileDirtyByTile(tile);
02598   }
02599 }
02600 
02601 
02602 static TrackStatus GetTileTrackStatus_Track(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
02603 {
02604   /* Case of half tile slope with water. */
02605   if (mode == TRANSPORT_WATER && IsPlainRail(tile) && GetRailGroundType(tile) == RAIL_GROUND_WATER) {
02606     TrackBits tb = GetTrackBits(tile);
02607     switch (tb) {
02608       default: NOT_REACHED();
02609       case TRACK_BIT_UPPER: tb = TRACK_BIT_LOWER; break;
02610       case TRACK_BIT_LOWER: tb = TRACK_BIT_UPPER; break;
02611       case TRACK_BIT_LEFT:  tb = TRACK_BIT_RIGHT; break;
02612       case TRACK_BIT_RIGHT: tb = TRACK_BIT_LEFT;  break;
02613     }
02614     return CombineTrackStatus(TrackBitsToTrackdirBits(tb), TRACKDIR_BIT_NONE);
02615   }
02616 
02617   if (mode != TRANSPORT_RAIL) return 0;
02618 
02619   TrackBits trackbits = TRACK_BIT_NONE;
02620   TrackdirBits red_signals = TRACKDIR_BIT_NONE;
02621 
02622   switch (GetRailTileType(tile)) {
02623     default: NOT_REACHED();
02624     case RAIL_TILE_NORMAL:
02625       trackbits = GetTrackBits(tile);
02626       break;
02627 
02628     case RAIL_TILE_SIGNALS: {
02629       trackbits = GetTrackBits(tile);
02630       byte a = GetPresentSignals(tile);
02631       uint b = GetSignalStates(tile);
02632 
02633       b &= a;
02634 
02635       /* When signals are not present (in neither direction),
02636        * we pretend them to be green. Otherwise, it depends on
02637        * the signal type. For signals that are only active from
02638        * one side, we set the missing signals explicitely to
02639        * `green'. Otherwise, they implicitely become `red'. */
02640       if (!IsOnewaySignal(tile, TRACK_UPPER) || (a & SignalOnTrack(TRACK_UPPER)) == 0) b |= ~a & SignalOnTrack(TRACK_UPPER);
02641       if (!IsOnewaySignal(tile, TRACK_LOWER) || (a & SignalOnTrack(TRACK_LOWER)) == 0) b |= ~a & SignalOnTrack(TRACK_LOWER);
02642 
02643       if ((b & 0x8) == 0) red_signals |= (TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_X_NE | TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_UPPER_E);
02644       if ((b & 0x4) == 0) red_signals |= (TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_X_SW | TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_UPPER_W);
02645       if ((b & 0x2) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_LOWER_E);
02646       if ((b & 0x1) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_S | TRACKDIR_BIT_LOWER_W);
02647 
02648       break;
02649     }
02650 
02651     case RAIL_TILE_DEPOT: {
02652       DiagDirection dir = GetRailDepotDirection(tile);
02653 
02654       if (side != INVALID_DIAGDIR && side != dir) break;
02655 
02656       trackbits = DiagDirToDiagTrackBits(dir);
02657       break;
02658     }
02659   }
02660 
02661   return CombineTrackStatus(TrackBitsToTrackdirBits(trackbits), red_signals);
02662 }
02663 
02664 static bool ClickTile_Track(TileIndex tile)
02665 {
02666   if (!IsRailDepot(tile)) return false;
02667 
02668   ShowDepotWindow(tile, VEH_TRAIN);
02669   return true;
02670 }
02671 
02672 static void GetTileDesc_Track(TileIndex tile, TileDesc *td)
02673 {
02674   const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(tile));
02675   td->rail_speed = rti->max_speed;
02676   td->owner[0] = GetTileOwner(tile);
02677   SetDParamX(td->dparam, 0, rti->strings.name);
02678   switch (GetRailTileType(tile)) {
02679     case RAIL_TILE_NORMAL:
02680       td->str = STR_LAI_RAIL_DESCRIPTION_TRACK;
02681       break;
02682 
02683     case RAIL_TILE_SIGNALS: {
02684       static const StringID signal_type[6][6] = {
02685         {
02686           STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS,
02687           STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS,
02688           STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS,
02689           STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS,
02690           STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS,
02691           STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS
02692         },
02693         {
02694           STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS,
02695           STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRESIGNALS,
02696           STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS,
02697           STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS,
02698           STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS,
02699           STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS
02700         },
02701         {
02702           STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS,
02703           STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS,
02704           STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXITSIGNALS,
02705           STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS,
02706           STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS,
02707           STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS
02708         },
02709         {
02710           STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS,
02711           STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS,
02712           STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS,
02713           STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBOSIGNALS,
02714           STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS,
02715           STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS
02716         },
02717         {
02718           STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS,
02719           STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS,
02720           STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS,
02721           STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS,
02722           STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBSSIGNALS,
02723           STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS
02724         },
02725         {
02726           STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS,
02727           STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS,
02728           STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS,
02729           STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS,
02730           STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS,
02731           STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRYSIGNALS
02732         }
02733       };
02734 
02735       SignalType primary_signal;
02736       SignalType secondary_signal;
02737       if (HasSignalOnTrack(tile, TRACK_UPPER)) {
02738         primary_signal = GetSignalType(tile, TRACK_UPPER);
02739         secondary_signal = HasSignalOnTrack(tile, TRACK_LOWER) ? GetSignalType(tile, TRACK_LOWER) : primary_signal;
02740       } else {
02741         secondary_signal = primary_signal = GetSignalType(tile, TRACK_LOWER);
02742       }
02743 
02744       td->str = signal_type[secondary_signal][primary_signal];
02745       break;
02746     }
02747 
02748     case RAIL_TILE_DEPOT:
02749       td->str = STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT;
02750       if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL) {
02751         if (td->rail_speed > 0) {
02752           td->rail_speed = min(td->rail_speed, 61);
02753         } else {
02754           td->rail_speed = 61;
02755         }
02756       }
02757       td->build_date = Depot::GetByTile(tile)->build_date;
02758       break;
02759 
02760     default:
02761       NOT_REACHED();
02762   }
02763 }
02764 
02765 static void ChangeTileOwner_Track(TileIndex tile, Owner old_owner, Owner new_owner)
02766 {
02767   if (!IsTileOwner(tile, old_owner)) return;
02768 
02769   if (new_owner != INVALID_OWNER) {
02770     /* Update company infrastructure counts. No need to dirty windows here, we'll redraw the whole screen anyway. */
02771     uint num_pieces = 1;
02772     if (IsPlainRail(tile)) {
02773       TrackBits bits = GetTrackBits(tile);
02774       num_pieces = CountBits(bits);
02775       if (TracksOverlap(bits)) num_pieces *= num_pieces;
02776     }
02777     RailType rt = GetRailType(tile);
02778     Company::Get(old_owner)->infrastructure.rail[rt] -= num_pieces;
02779     Company::Get(new_owner)->infrastructure.rail[rt] += num_pieces;
02780 
02781     if (HasSignals(tile)) {
02782       uint num_sigs = CountBits(GetPresentSignals(tile));
02783       Company::Get(old_owner)->infrastructure.signal -= num_sigs;
02784       Company::Get(new_owner)->infrastructure.signal += num_sigs;
02785     }
02786 
02787     SetTileOwner(tile, new_owner);
02788   } else {
02789     DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
02790   }
02791 }
02792 
02793 static const byte _fractcoords_behind[4] = { 0x8F, 0x8, 0x80, 0xF8 };
02794 static const byte _fractcoords_enter[4] = { 0x8A, 0x48, 0x84, 0xA8 };
02795 static const int8 _deltacoord_leaveoffset[8] = {
02796   -1,  0,  1,  0, /* x */
02797    0,  1,  0, -1  /* y */
02798 };
02799 
02800 
02807 int TicksToLeaveDepot(const Train *v)
02808 {
02809   DiagDirection dir = GetRailDepotDirection(v->tile);
02810   int length = v->CalcNextVehicleOffset();
02811 
02812   switch (dir) {
02813     case DIAGDIR_NE: return  ((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) - (length + 1)));
02814     case DIAGDIR_SE: return -((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4)   + (length + 1)));
02815     case DIAGDIR_SW: return -((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) + (length + 1)));
02816     default:
02817     case DIAGDIR_NW: return  ((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4)   - (length + 1)));
02818   }
02819 
02820   return 0; // make compilers happy
02821 }
02822 
02827 static VehicleEnterTileStatus VehicleEnter_Track(Vehicle *u, TileIndex tile, int x, int y)
02828 {
02829   /* this routine applies only to trains in depot tiles */
02830   if (u->type != VEH_TRAIN || !IsRailDepotTile(tile)) return VETSB_CONTINUE;
02831 
02832   Train *v = Train::From(u);
02833 
02834   /* depot direction */
02835   DiagDirection dir = GetRailDepotDirection(tile);
02836 
02837   /* Calculate the point where the following wagon should be activated. */
02838   int length = v->CalcNextVehicleOffset();
02839 
02840   byte fract_coord_leave =
02841     ((_fractcoords_enter[dir] & 0x0F) + // x
02842       (length + 1) * _deltacoord_leaveoffset[dir]) +
02843     (((_fractcoords_enter[dir] >> 4) +  // y
02844       ((length + 1) * _deltacoord_leaveoffset[dir + 4])) << 4);
02845 
02846   byte fract_coord = (x & 0xF) + ((y & 0xF) << 4);
02847 
02848   if (_fractcoords_behind[dir] == fract_coord) {
02849     /* make sure a train is not entering the tile from behind */
02850     return VETSB_CANNOT_ENTER;
02851   } else if (_fractcoords_enter[dir] == fract_coord) {
02852     if (DiagDirToDir(ReverseDiagDir(dir)) == v->direction) {
02853       /* enter the depot */
02854       v->track = TRACK_BIT_DEPOT,
02855       v->vehstatus |= VS_HIDDEN; // hide it
02856       v->direction = ReverseDir(v->direction);
02857       if (v->Next() == NULL) VehicleEnterDepot(v->First());
02858       v->tile = tile;
02859 
02860       InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
02861       return VETSB_ENTERED_WORMHOLE;
02862     }
02863   } else if (fract_coord_leave == fract_coord) {
02864     if (DiagDirToDir(dir) == v->direction) {
02865       /* leave the depot? */
02866       if ((v = v->Next()) != NULL) {
02867         v->vehstatus &= ~VS_HIDDEN;
02868         v->track = (DiagDirToAxis(dir) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y);
02869       }
02870     }
02871   }
02872 
02873   return VETSB_CONTINUE;
02874 }
02875 
02887 static CommandCost TestAutoslopeOnRailTile(TileIndex tile, uint flags, int z_old, Slope tileh_old, int z_new, Slope tileh_new, TrackBits rail_bits)
02888 {
02889   if (!_settings_game.construction.build_on_slopes || !AutoslopeEnabled()) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02890 
02891   /* Is the slope-rail_bits combination valid in general? I.e. is it safe to call GetRailFoundation() ? */
02892   if (CheckRailSlope(tileh_new, rail_bits, TRACK_BIT_NONE, tile).Failed()) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02893 
02894   /* Get the slopes on top of the foundations */
02895   z_old += ApplyFoundationToSlope(GetRailFoundation(tileh_old, rail_bits), &tileh_old);
02896   z_new += ApplyFoundationToSlope(GetRailFoundation(tileh_new, rail_bits), &tileh_new);
02897 
02898   Corner track_corner;
02899   switch (rail_bits) {
02900     case TRACK_BIT_LEFT:  track_corner = CORNER_W; break;
02901     case TRACK_BIT_LOWER: track_corner = CORNER_S; break;
02902     case TRACK_BIT_RIGHT: track_corner = CORNER_E; break;
02903     case TRACK_BIT_UPPER: track_corner = CORNER_N; break;
02904 
02905     /* Surface slope must not be changed */
02906     default:
02907       if (z_old != z_new || tileh_old != tileh_new) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02908       return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02909   }
02910 
02911   /* The height of the track_corner must not be changed. The rest ensures GetRailFoundation() already. */
02912   z_old += GetSlopeZInCorner(RemoveHalftileSlope(tileh_old), track_corner);
02913   z_new += GetSlopeZInCorner(RemoveHalftileSlope(tileh_new), track_corner);
02914   if (z_old != z_new) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02915 
02916   CommandCost cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02917   /* Make the ground dirty, if surface slope has changed */
02918   if (tileh_old != tileh_new) {
02919     /* If there is flat water on the lower halftile add the cost for clearing it */
02920     if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old)) cost.AddCost(_price[PR_CLEAR_WATER]);
02921     if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
02922   }
02923   return  cost;
02924 }
02925 
02926 static CommandCost TerraformTile_Track(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new)
02927 {
02928   int z_old;
02929   Slope tileh_old = GetTileSlope(tile, &z_old);
02930   if (IsPlainRail(tile)) {
02931     TrackBits rail_bits = GetTrackBits(tile);
02932     /* Is there flat water on the lower halftile that must be cleared expensively? */
02933     bool was_water = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old));
02934 
02935     /* First test autoslope. However if it succeeds we still have to test the rest, because non-autoslope terraforming is cheaper. */
02936     CommandCost autoslope_result = TestAutoslopeOnRailTile(tile, flags, z_old, tileh_old, z_new, tileh_new, rail_bits);
02937 
02938     /* When there is only a single horizontal/vertical track, one corner can be terraformed. */
02939     Corner allowed_corner;
02940     switch (rail_bits) {
02941       case TRACK_BIT_RIGHT: allowed_corner = CORNER_W; break;
02942       case TRACK_BIT_UPPER: allowed_corner = CORNER_S; break;
02943       case TRACK_BIT_LEFT:  allowed_corner = CORNER_E; break;
02944       case TRACK_BIT_LOWER: allowed_corner = CORNER_N; break;
02945       default: return autoslope_result;
02946     }
02947 
02948     Foundation f_old = GetRailFoundation(tileh_old, rail_bits);
02949 
02950     /* Do not allow terraforming if allowed_corner is part of anti-zig-zag foundations */
02951     if (tileh_old != SLOPE_NS && tileh_old != SLOPE_EW && IsSpecialRailFoundation(f_old)) return autoslope_result;
02952 
02953     /* Everything is valid, which only changes allowed_corner */
02954     for (Corner corner = (Corner)0; corner < CORNER_END; corner = (Corner)(corner + 1)) {
02955       if (allowed_corner == corner) continue;
02956       if (z_old + GetSlopeZInCorner(tileh_old, corner) != z_new + GetSlopeZInCorner(tileh_new, corner)) return autoslope_result;
02957     }
02958 
02959     /* Make the ground dirty */
02960     if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
02961 
02962     /* allow terraforming */
02963     return CommandCost(EXPENSES_CONSTRUCTION, was_water ? _price[PR_CLEAR_WATER] : (Money)0);
02964   } else if (_settings_game.construction.build_on_slopes && AutoslopeEnabled() &&
02965       AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetRailDepotDirection(tile))) {
02966     return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02967   }
02968   return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
02969 }
02970 
02971 
02972 extern const TileTypeProcs _tile_type_rail_procs = {
02973   DrawTile_Track,           // draw_tile_proc
02974   GetSlopePixelZ_Track,     // get_slope_z_proc
02975   ClearTile_Track,          // clear_tile_proc
02976   NULL,                     // add_accepted_cargo_proc
02977   GetTileDesc_Track,        // get_tile_desc_proc
02978   GetTileTrackStatus_Track, // get_tile_track_status_proc
02979   ClickTile_Track,          // click_tile_proc
02980   NULL,                     // animate_tile_proc
02981   TileLoop_Track,           // tile_loop_proc
02982   ChangeTileOwner_Track,    // change_tile_owner_proc
02983   NULL,                     // add_produced_cargo_proc
02984   VehicleEnter_Track,       // vehicle_enter_tile_proc
02985   GetFoundation_Track,      // get_foundation_proc
02986   TerraformTile_Track,      // terraform_tile_proc
02987 };