rail_cmd.cpp

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

Generated on Fri Feb 4 20:53:45 2011 for OpenTTD by  doxygen 1.6.1