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