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 "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
00100 memcpy(rti, &_railtypes[RAILTYPE_RAIL], sizeof(*rti));
00101 rti->label = label;
00102
00103
00104 rti->powered_railtypes = (RailTypes)(1 << rt);
00105 rti->compatible_railtypes = (RailTypes)(1 << rt);
00106
00107
00108 rti->introduces_railtypes = (RailTypes)(1 << rt);
00109
00110
00111
00112
00113
00114
00115
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
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
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
00189
00190 TrackBits current = GetTrackBits(tile);
00191 TrackBits future = current | to_build;
00192
00193
00194 if (current == future) {
00195
00196 return_cmd_error(STR_ERROR_ALREADY_BUILT);
00197 }
00198
00199
00200 if ((flags & DC_NO_RAIL_OVERLAP) || HasSignals(tile)) {
00201
00202
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
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
00269 if (bits == TRACK_BIT_X) return FOUNDATION_INCLINED_X;
00270 if (bits == TRACK_BIT_Y) return FOUNDATION_INCLINED_Y;
00271
00272
00273 Corner highest_corner = GetHighestSlopeCorner(tileh);
00274 TrackBits higher_track = CornerToTrackBits(highest_corner);
00275
00276
00277 if (bits == higher_track) return HalftileFoundation(highest_corner);
00278
00279
00280 if (TracksOverlap(bits | higher_track)) return FOUNDATION_INVALID;
00281
00282
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
00318
00319
00320 if (!valid_on_leveled) return FOUNDATION_INVALID;
00321
00322
00323 if (IsSlopeWithThreeCornersRaised(tileh)) return FOUNDATION_LEVELED;
00324
00325
00326 if ((tileh & SlopeWithThreeCornersRaised(OppositeCorner(track_corner))) == SlopeWithOneCornerRaised(track_corner)) return HalftileFoundation(track_corner);
00327
00328
00329 return SpecialRailFoundation(track_corner);
00330 }
00331 }
00332
00333
00343 static CommandCost CheckRailSlope(Slope tileh, TrackBits rail_bits, TrackBits existing, TileIndex tile)
00344 {
00345
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
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
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
00406
00407
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
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
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
00471 }
00472
00473 default: {
00474
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
00527
00528
00529
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
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
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
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
00615 assert(Company::IsValidID(owner));
00616
00617 MarkTileDirtyByTile(tile);
00618 if (crossing) {
00619
00620
00621
00622
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;
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
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
00711 int dx = ex - x;
00712 int dy = ey - y;
00713
00714
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
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)) {
00729 SetBit(*trackdir, 3);
00730 trdx = -trdx;
00731 trdy = -trdy;
00732 } else {
00733 return CMD_ERROR;
00734 }
00735 }
00736
00737
00738
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
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
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
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
00870
00871
00872
00873
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);
00933 SignalVariant sigvar = (ctrl_pressed ^ HasBit(p1, 4)) ? SIG_SEMAPHORE : SIG_ELECTRIC;
00934 SignalType sigtype = Extract<SignalType, 5, 3>(p1);
00935 bool convert_signal = HasBit(p1, 8);
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
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
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
00959 TrackBits trackbits = GetTrackBits(tile);
00960 if (KillFirstBit(trackbits) != TRACK_BIT_NONE &&
00961 trackbits != TRACK_BIT_HORZ &&
00962 trackbits != TRACK_BIT_VERT) {
00963 return_cmd_error(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK);
00964 }
00965 }
00966
00967
00968 if (HasBit(p1, 17) && HasSignalOnTrack(tile, track)) return CommandCost();
00969
00970
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
00976 cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS]);
00977 } else {
00978 if (p2 != 0 && sigvar != GetSignalVariant(tile, track)) {
00979
00980 cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] + _price[PR_CLEAR_SIGNALS]);
00981
00982 } else if (convert_signal) {
00983
00984 if (ctrl_pressed || GetSignalVariant(tile, track) != sigvar) {
00985
00986 cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] + _price[PR_CLEAR_SIGNALS]);
00987 } else {
00988
00989 cost = CommandCost();
00990 }
00991
00992 } else {
00993
00994 cost = CommandCost();
00995 }
00996 }
00997
00998 if (flags & DC_EXEC) {
00999 Train *v = NULL;
01000
01001
01002
01003 if (HasReservedTracks(tile, TrackToTrackBits(track))) {
01004 v = GetTrainForReservation(tile, track);
01005 if (v != NULL) FreeTrainTrackReservation(v);
01006 }
01007
01008 if (!HasSignals(tile)) {
01009
01010 SetHasSignals(tile, true);
01011 SetSignalStates(tile, 0xF);
01012 SetPresentSignals(tile, 0);
01013 SetSignalType(tile, track, sigtype);
01014 SetSignalVariant(tile, track, sigvar);
01015 }
01016
01017 if (p2 == 0) {
01018 if (!HasSignalOnTrack(tile, track)) {
01019
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
01027 if (ctrl_pressed) {
01028
01029 SetSignalVariant(tile, track, (GetSignalVariant(tile, track) == SIG_ELECTRIC) ? SIG_SEMAPHORE : SIG_ELECTRIC);
01030
01031 sigtype = GetSignalType(tile, track);
01032 } else {
01033
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
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
01053 CycleSignalSide(tile, track);
01054
01055 sigtype = GetSignalType(tile, track);
01056 }
01057 }
01058 } else {
01059
01060
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
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
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
01092 TrackdirBits trackdirbits = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0));
01093
01094 if (TracksOverlap(TrackdirBitsToTrackBits(trackdirbits))) return false;
01095 trackdirbits &= TrackdirReachesTrackdirs(trackdir);
01096
01097
01098 if (trackdirbits == TRACKDIR_BIT_NONE) return false;
01099
01100
01101 trackdir = RemoveFirstTrackdir(&trackdirbits);
01102
01103
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
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;
01125
01126 if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) return false;
01127 if (GetTunnelBridgeDirection(tile) != TrackdirToExitdir(trackdir)) return false;
01128
01129
01130
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
01176
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);
01184 Trackdir start_trackdir = trackdir;
01185
01186
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
01194 if (HasSignalOnTrack(tile, track)) {
01195 signals = GetPresentSignals(tile) & SignalOnTrack(track);
01196 assert(signals != 0);
01197
01198
01199 semaphores = GetSignalVariant(tile, track) != SIG_ELECTRIC;
01200
01201 sigtype = GetSignalType(tile, track);
01202
01203 if (sigtype == SIGTYPE_ENTRY || sigtype == SIGTYPE_EXIT) sigtype = SIGTYPE_NORMAL;
01204 } else {
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
01213
01214
01215
01216
01217
01218
01219
01220 int signal_ctr = 0;
01221 CommandCost last_error = CMD_ERROR;
01222 bool had_success = false;
01223 for (;;) {
01224
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
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
01240 if (ret.Succeeded()) {
01241 had_success = true;
01242 total_cost.AddCost(ret);
01243 } else {
01244
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
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
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
01324 if (_current_company != OWNER_WATER) {
01325 CommandCost ret = CheckTileOwnership(tile);
01326 if (ret.Failed()) return ret;
01327 }
01328
01329
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
01336 Trackdir td = TrackToTrackdir(track);
01337 for (int i = 0; v == NULL && i < 2; i++, td = ReverseTrackdir(td)) {
01338
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
01350 if (GetPresentSignals(tile) == 0) {
01351 SetSignalStates(tile, 0);
01352 SetHasSignals(tile, false);
01353 SetSignalVariant(tile, INVALID_TRACK, SIG_ELECTRIC);
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);
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);
01421 TileArea ta(tile, p1);
01422 TILE_AREA_LOOP(tile, ta) {
01423 TileType tt = GetTileType(tile);
01424
01425
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
01446 RailType type = GetRailType(tile);
01447
01448
01449 if (type == totype || (_settings_game.vehicle.disable_elrails && totype == RAILTYPE_RAIL && type == RAILTYPE_ELECTRIC)) continue;
01450
01451
01452 CommandCost ret = CheckTileOwnership(tile);
01453 if (ret.Failed()) {
01454 error = ret;
01455 continue;
01456 }
01457
01458 SmallVector<Train *, 2> vehicles_affected;
01459
01460
01461
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) {
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
01477 FreeTrainTrackReservation(v);
01478 *vehicles_affected.Append() = v;
01479 }
01480 }
01481
01482 SetRailType(tile, totype);
01483 MarkTileDirtyByTile(tile);
01484
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
01495 YapfNotifyTrackLayoutChange(tile, GetRailDepotTrack(tile));
01496
01497
01498 InvalidateWindowData(WC_VEHICLE_DEPOT, tile);
01499 InvalidateWindowData(WC_BUILD_VEHICLE, tile);
01500 }
01501 cost.AddCost(RailConvertCost(type, totype));
01502 break;
01503
01504 default:
01505 if (flags & DC_EXEC) {
01506
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
01521
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
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
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);
01560 }
01561 }
01562
01563 cost.AddCost((GetTunnelBridgeLength(tile, endtile) + 2) * RailConvertCost(type, totype));
01564 break;
01565 }
01566
01567 default:
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
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
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
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
01655 if (water_ground && !(flags & DC_BANKRUPT)) {
01656 CommandCost ret = EnsureNoVehicleOnGround(tile);
01657 if (ret.Failed()) return ret;
01658
01659
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 {
01696
01697 { 8, 5}, {14, 1}, { 1, 14}, { 9, 11}, { 1, 0}, { 3, 10},
01698
01699 {11, 4}, {14, 14}, {11, 3}, { 4, 13}, { 3, 4}, {11, 13}
01700 }, {
01701
01702 {14, 1}, {12, 10}, { 4, 6}, { 1, 14}, {10, 4}, { 0, 1},
01703
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
01718 sprite = SPR_ORIGINAL_SIGNALS_BASE + image + condition;
01719 } else {
01720
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
01818
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
01837 track_corner = GetHalftileSlopeCorner(ti->tileh);
01838 } else {
01839
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
01856 static const int INF = 1000;
01857 static const SubSprite _halftile_sub_sprite[4] = {
01858 { -INF , -INF , 32 - 33, INF },
01859 { -INF , 0 + 7, INF , INF },
01860 { -31 + 33, -INF , INF , INF },
01861 { -INF , -INF , INF , 30 - 23 }
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
01877 halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f));
01878
01879 track &= ~CornerToTrackBits(halftile_corner);
01880 f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE);
01881 }
01882
01883 DrawFoundation(ti, f);
01884
01885
01886
01887 if (rgt == RAIL_GROUND_WATER) {
01888 if (track != TRACK_BIT_NONE || IsSteepSlope(ti->tileh)) {
01889
01890 DrawShoreTile(ti->tileh);
01891 } else {
01892
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
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
01930
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
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
01958 track &= ~pbs;
01959
01960
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
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
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
02036 halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f));
02037
02038 track &= ~CornerToTrackBits(halftile_corner);
02039 f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE);
02040 }
02041
02042 DrawFoundation(ti, f);
02043
02044
02045 SpriteID image;
02046 PaletteID pal = PAL_NONE;
02047 const SubSprite *sub = NULL;
02048 bool junction = false;
02049
02050
02051 if (track == 0) {
02052
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
02071 image = _track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.track_y;
02072 } else {
02073
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
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
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
02120 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation) {
02121
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
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;
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
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
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
02255
02256 if (IsSnowRailGround(ti->tile) && _settings_game.game_creation.landscape == LT_TROPIC) {
02257 if (image != SPR_FLAT_GRASS_TILE) {
02258 image += rti->snow_offset;
02259 } else {
02260 image = SPR_FLAT_SNOW_DESERT_TILE;
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;
02271 case DIAGDIR_SW: DrawGroundSprite(ground + RTO_X, PAL_NONE); break;
02272 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
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;
02282 case DIAGDIR_SW: DrawGroundSprite(overlay + RTO_X, PALETTE_CRASH); break;
02283 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
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
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;
02296 case DIAGDIR_SW: DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH); break;
02297 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
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
02380
02381 if (IsPlainRail(tile)) {
02382 TrackBits track = GetTrackBits(tile);
02383 Foundation f = GetRailFoundation(slope, track);
02384
02385 switch (f) {
02386 case FOUNDATION_NONE:
02387
02388 if (IsSlopeWithThreeCornersRaised(slope)) z += TILE_HEIGHT;
02389 break;
02390
02391 case FOUNDATION_INCLINED_X:
02392 case FOUNDATION_INCLINED_Y:
02393
02394 if (IsSteepSlope(slope)) z += TILE_HEIGHT;
02395 break;
02396
02397 case FOUNDATION_STEEP_LOWER:
02398
02399 z += TILE_HEIGHT;
02400 break;
02401
02402 default:
02403
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
02412 if (slope != SLOPE_FLAT) z += TILE_HEIGHT;
02413 }
02414
02415
02416
02417
02418
02419 if (z > GetSnowLine()) {
02420 if (half && z - GetSnowLine() == TILE_HEIGHT) {
02421
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) {
02442
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
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
02562
02563
02564
02565
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,
02705 0, 1, 0, -1
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;
02729 }
02730
02735 static VehicleEnterTileStatus VehicleEnter_Track(Vehicle *u, TileIndex tile, int x, int y)
02736 {
02737
02738 if (u->type != VEH_TRAIN || !IsRailDepotTile(tile)) return VETSB_CONTINUE;
02739
02740 Train *v = Train::From(u);
02741
02742
02743 DiagDirection dir = GetRailDepotDirection(tile);
02744
02745
02746
02747 int length = v->gcache.cached_veh_length;
02748
02749 byte fract_coord_leave =
02750 ((_fractcoords_enter[dir] & 0x0F) +
02751 (length + 1) * _deltacoord_leaveoffset[dir]) +
02752 (((_fractcoords_enter[dir] >> 4) +
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
02759 return VETSB_CANNOT_ENTER;
02760 } else if (_fractcoords_enter[dir] == fract_coord) {
02761 if (DiagDirToDir(ReverseDiagDir(dir)) == v->direction) {
02762
02763 v->track = TRACK_BIT_DEPOT,
02764 v->vehstatus |= VS_HIDDEN;
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
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
02801 if (CheckRailSlope(tileh_new, rail_bits, TRACK_BIT_NONE, tile).Failed()) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02802
02803
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
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
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
02827 if (tileh_old != tileh_new) {
02828
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
02842 bool was_water = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old));
02843
02844
02845 CommandCost autoslope_result = TestAutoslopeOnRailTile(tile, flags, z_old, tileh_old, z_new, tileh_new, rail_bits);
02846
02847
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
02860 if (tileh_old != SLOPE_NS && tileh_old != SLOPE_EW && IsSpecialRailFoundation(f_old)) return autoslope_result;
02861
02862
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
02869 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
02870
02871
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,
02883 GetSlopeZ_Track,
02884 ClearTile_Track,
02885 NULL,
02886 GetTileDesc_Track,
02887 GetTileTrackStatus_Track,
02888 ClickTile_Track,
02889 NULL,
02890 TileLoop_Track,
02891 ChangeTileOwner_Track,
02892 NULL,
02893 VehicleEnter_Track,
02894 GetFoundation_Track,
02895 TerraformTile_Track,
02896 };