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 "vehicle_func.h"
00025 #include "sound_func.h"
00026 #include "tunnelbridge.h"
00027 #include "elrail_func.h"
00028 #include "town.h"
00029 #include "pbs.h"
00030 #include "company_base.h"
00031 #include "core/backup_type.hpp"
00032 #include "date_func.h"
00033 #include "strings_func.h"
00034 #include "company_gui.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);
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 TrackBits bits = GetTrackBits(tile);
00421 SetTrackBits(tile, bits | trackbit);
00422
00423 uint pieces = CountBits(bits);
00424 if (TracksOverlap(bits)) pieces *= pieces;
00425 Company::Get(GetTileOwner(tile))->infrastructure.rail[GetRailType(tile)] -= pieces;
00426
00427 pieces = CountBits(bits | trackbit);
00428 if (TracksOverlap(bits | trackbit)) pieces *= pieces;
00429 Company::Get(GetTileOwner(tile))->infrastructure.rail[GetRailType(tile)] += pieces;
00430 DirtyCompanyInfrastructureWindows(GetTileOwner(tile));
00431 }
00432 break;
00433 }
00434
00435 case MP_ROAD: {
00436
00437 if (!HasBit(VALID_LEVEL_CROSSING_SLOPES, tileh)) return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
00438
00439 CommandCost ret = EnsureNoVehicleOnGround(tile);
00440 if (ret.Failed()) return ret;
00441
00442 if (IsNormalRoad(tile)) {
00443 if (HasRoadWorks(tile)) return_cmd_error(STR_ERROR_ROAD_WORKS_IN_PROGRESS);
00444
00445 if (GetDisallowedRoadDirections(tile) != DRD_NONE) return_cmd_error(STR_ERROR_CROSSING_ON_ONEWAY_ROAD);
00446
00447 if (RailNoLevelCrossings(railtype)) return_cmd_error(STR_ERROR_CROSSING_DISALLOWED);
00448
00449 RoadTypes roadtypes = GetRoadTypes(tile);
00450 RoadBits road = GetRoadBits(tile, ROADTYPE_ROAD);
00451 RoadBits tram = GetRoadBits(tile, ROADTYPE_TRAM);
00452 switch (roadtypes) {
00453 default: break;
00454 case ROADTYPES_TRAM:
00455
00456 if (flags & DC_EXEC) {
00457 SetRoadOwner(tile, ROADTYPE_ROAD, _current_company);
00458 Company *c = Company::GetIfValid(_current_company);
00459 if (c != NULL) {
00460
00461 c->infrastructure.road[ROADTYPE_ROAD] += 2;
00462 DirtyCompanyInfrastructureWindows(c->index);
00463 }
00464 }
00465 roadtypes |= ROADTYPES_ROAD;
00466 break;
00467
00468 case ROADTYPES_ALL:
00469 if (road != tram) return CMD_ERROR;
00470 break;
00471 }
00472
00473 road |= tram;
00474
00475 if ((track == TRACK_X && road == ROAD_Y) ||
00476 (track == TRACK_Y && road == ROAD_X)) {
00477 if (flags & DC_EXEC) {
00478 MakeRoadCrossing(tile, GetRoadOwner(tile, ROADTYPE_ROAD), GetRoadOwner(tile, ROADTYPE_TRAM), _current_company, (track == TRACK_X ? AXIS_Y : AXIS_X), railtype, roadtypes, GetTownIndex(tile));
00479 UpdateLevelCrossing(tile, false);
00480 Company::Get(_current_company)->infrastructure.rail[railtype] += LEVELCROSSING_TRACKBIT_FACTOR;
00481 DirtyCompanyInfrastructureWindows(_current_company);
00482 }
00483 break;
00484 }
00485 }
00486
00487 if (IsLevelCrossing(tile) && GetCrossingRailBits(tile) == trackbit) {
00488 return_cmd_error(STR_ERROR_ALREADY_BUILT);
00489 }
00490
00491 }
00492
00493 default: {
00494
00495 bool water_ground = IsTileType(tile, MP_WATER) && IsSlopeWithOneCornerRaised(tileh);
00496
00497 CommandCost ret = CheckRailSlope(tileh, trackbit, TRACK_BIT_NONE, tile);
00498 if (ret.Failed()) return ret;
00499 cost.AddCost(ret);
00500
00501 ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00502 if (ret.Failed()) return ret;
00503 cost.AddCost(ret);
00504
00505 if (water_ground) {
00506 cost.AddCost(-_price[PR_CLEAR_WATER]);
00507 cost.AddCost(_price[PR_CLEAR_ROUGH]);
00508 }
00509
00510 if (flags & DC_EXEC) {
00511 MakeRailNormal(tile, _current_company, trackbit, railtype);
00512 if (water_ground) SetRailGroundType(tile, RAIL_GROUND_WATER);
00513 Company::Get(_current_company)->infrastructure.rail[railtype]++;
00514 DirtyCompanyInfrastructureWindows(_current_company);
00515 }
00516 break;
00517 }
00518 }
00519
00520 if (flags & DC_EXEC) {
00521 MarkTileDirtyByTile(tile);
00522 AddTrackToSignalBuffer(tile, track, _current_company);
00523 YapfNotifyTrackLayoutChange(tile, track);
00524 }
00525
00526 cost.AddCost(RailBuildCost(railtype));
00527 return cost;
00528 }
00529
00539 CommandCost CmdRemoveSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00540 {
00541 Track track = Extract<Track, 0, 3>(p2);
00542 CommandCost cost(EXPENSES_CONSTRUCTION);
00543 bool crossing = false;
00544
00545 if (!ValParamTrackOrientation(track)) return CMD_ERROR;
00546 TrackBits trackbit = TrackToTrackBits(track);
00547
00548
00549
00550
00551
00552 Owner owner = INVALID_OWNER;
00553
00554 Train *v = NULL;
00555
00556 switch (GetTileType(tile)) {
00557 case MP_ROAD: {
00558 if (!IsLevelCrossing(tile) || GetCrossingRailBits(tile) != trackbit) return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
00559
00560 if (_current_company != OWNER_WATER) {
00561 CommandCost ret = CheckTileOwnership(tile);
00562 if (ret.Failed()) return ret;
00563 }
00564
00565 if (!(flags & DC_BANKRUPT)) {
00566 CommandCost ret = EnsureNoVehicleOnGround(tile);
00567 if (ret.Failed()) return ret;
00568 }
00569
00570 cost.AddCost(RailClearCost(GetRailType(tile)));
00571
00572 if (flags & DC_EXEC) {
00573 if (HasReservedTracks(tile, trackbit)) {
00574 v = GetTrainForReservation(tile, track);
00575 if (v != NULL) FreeTrainTrackReservation(v);
00576 }
00577 owner = GetTileOwner(tile);
00578 Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= LEVELCROSSING_TRACKBIT_FACTOR;
00579 DirtyCompanyInfrastructureWindows(owner);
00580 MakeRoadNormal(tile, GetCrossingRoadBits(tile), GetRoadTypes(tile), GetTownIndex(tile), GetRoadOwner(tile, ROADTYPE_ROAD), GetRoadOwner(tile, ROADTYPE_TRAM));
00581 DeleteNewGRFInspectWindow(GSF_RAILTYPES, tile);
00582 }
00583 break;
00584 }
00585
00586 case MP_RAILWAY: {
00587 TrackBits present;
00588
00589 if (!IsPlainRail(tile)) return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
00590
00591 if (_current_company != OWNER_WATER) {
00592 CommandCost ret = CheckTileOwnership(tile);
00593 if (ret.Failed()) return ret;
00594 }
00595
00596 CommandCost ret = EnsureNoTrainOnTrack(tile, track);
00597 if (ret.Failed()) return ret;
00598
00599 present = GetTrackBits(tile);
00600 if ((present & trackbit) == 0) return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
00601 if (present == (TRACK_BIT_X | TRACK_BIT_Y)) crossing = true;
00602
00603 cost.AddCost(RailClearCost(GetRailType(tile)));
00604
00605
00606 if (HasSignalOnTrack(tile, track)) {
00607 cost.AddCost(DoCommand(tile, track, 0, flags, CMD_REMOVE_SIGNALS));
00608 }
00609
00610 if (flags & DC_EXEC) {
00611 if (HasReservedTracks(tile, trackbit)) {
00612 v = GetTrainForReservation(tile, track);
00613 if (v != NULL) FreeTrainTrackReservation(v);
00614 }
00615
00616 owner = GetTileOwner(tile);
00617
00618
00619 uint pieces = CountBits(present);
00620 if (TracksOverlap(present)) pieces *= pieces;
00621 Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= pieces;
00622
00623 present ^= trackbit;
00624 pieces = CountBits(present);
00625 if (TracksOverlap(present)) pieces *= pieces;
00626 Company::Get(owner)->infrastructure.rail[GetRailType(tile)] += pieces;
00627 DirtyCompanyInfrastructureWindows(owner);
00628
00629 if (present == 0) {
00630 Slope tileh = GetTileSlope(tile);
00631
00632 if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh)) {
00633 MakeShore(tile);
00634 } else {
00635 DoClearSquare(tile);
00636 }
00637 DeleteNewGRFInspectWindow(GSF_RAILTYPES, tile);
00638 } else {
00639 SetTrackBits(tile, present);
00640 SetTrackReservation(tile, GetRailReservationTrackBits(tile) & present);
00641 }
00642 }
00643 break;
00644 }
00645
00646 default: return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
00647 }
00648
00649 if (flags & DC_EXEC) {
00650
00651 assert(Company::IsValidID(owner));
00652
00653 MarkTileDirtyByTile(tile);
00654 if (crossing) {
00655
00656
00657
00658
00659 AddTrackToSignalBuffer(tile, TRACK_X, owner);
00660 AddTrackToSignalBuffer(tile, TRACK_Y, owner);
00661 YapfNotifyTrackLayoutChange(tile, TRACK_X);
00662 YapfNotifyTrackLayoutChange(tile, TRACK_Y);
00663 } else {
00664 AddTrackToSignalBuffer(tile, track, owner);
00665 YapfNotifyTrackLayoutChange(tile, track);
00666 }
00667
00668 if (v != NULL) TryPathReserve(v, true);
00669 }
00670
00671 return cost;
00672 }
00673
00674
00682 bool FloodHalftile(TileIndex t)
00683 {
00684 assert(IsPlainRailTile(t));
00685
00686 bool flooded = false;
00687 if (GetRailGroundType(t) == RAIL_GROUND_WATER) return flooded;
00688
00689 Slope tileh = GetTileSlope(t);
00690 TrackBits rail_bits = GetTrackBits(t);
00691
00692 if (IsSlopeWithOneCornerRaised(tileh)) {
00693 TrackBits lower_track = CornerToTrackBits(OppositeCorner(GetHighestSlopeCorner(tileh)));
00694
00695 TrackBits to_remove = lower_track & rail_bits;
00696 if (to_remove != 0) {
00697 Backup<CompanyByte> cur_company(_current_company, OWNER_WATER, FILE_LINE);
00698 flooded = DoCommand(t, 0, FIND_FIRST_BIT(to_remove), DC_EXEC, CMD_REMOVE_SINGLE_RAIL).Succeeded();
00699 cur_company.Restore();
00700 if (!flooded) return flooded;
00701 rail_bits = rail_bits & ~to_remove;
00702 if (rail_bits == 0) {
00703 MakeShore(t);
00704 MarkTileDirtyByTile(t);
00705 return flooded;
00706 }
00707 }
00708
00709 if (IsNonContinuousFoundation(GetRailFoundation(tileh, rail_bits))) {
00710 flooded = true;
00711 SetRailGroundType(t, RAIL_GROUND_WATER);
00712 MarkTileDirtyByTile(t);
00713 }
00714 } else {
00715
00716 if (ApplyFoundationToSlope(GetRailFoundation(tileh, rail_bits), &tileh) == 0) {
00717 if (IsSteepSlope(tileh) || IsSlopeWithThreeCornersRaised(tileh)) {
00718 flooded = true;
00719 SetRailGroundType(t, RAIL_GROUND_WATER);
00720 MarkTileDirtyByTile(t);
00721 }
00722 }
00723 }
00724 return flooded;
00725 }
00726
00727 static const TileIndexDiffC _trackdelta[] = {
00728 { -1, 0 }, { 0, 1 }, { -1, 0 }, { 0, 1 }, { 1, 0 }, { 0, 1 },
00729 { 0, 0 },
00730 { 0, 0 },
00731 { 1, 0 }, { 0, -1 }, { 0, -1 }, { 1, 0 }, { 0, -1 }, { -1, 0 },
00732 { 0, 0 },
00733 { 0, 0 }
00734 };
00735
00736
00737 static CommandCost ValidateAutoDrag(Trackdir *trackdir, TileIndex start, TileIndex end)
00738 {
00739 int x = TileX(start);
00740 int y = TileY(start);
00741 int ex = TileX(end);
00742 int ey = TileY(end);
00743
00744 if (!ValParamTrackOrientation(TrackdirToTrack(*trackdir))) return CMD_ERROR;
00745
00746
00747 int dx = ex - x;
00748 int dy = ey - y;
00749
00750
00751 int trdx = _trackdelta[*trackdir].x;
00752 int trdy = _trackdelta[*trackdir].y;
00753
00754 if (!IsDiagonalTrackdir(*trackdir)) {
00755 trdx += _trackdelta[*trackdir ^ 1].x;
00756 trdy += _trackdelta[*trackdir ^ 1].y;
00757 }
00758
00759
00760 while ((trdx <= 0 && dx > 0) ||
00761 (trdx >= 0 && dx < 0) ||
00762 (trdy <= 0 && dy > 0) ||
00763 (trdy >= 0 && dy < 0)) {
00764 if (!HasBit(*trackdir, 3)) {
00765 SetBit(*trackdir, 3);
00766 trdx = -trdx;
00767 trdy = -trdy;
00768 } else {
00769 return CMD_ERROR;
00770 }
00771 }
00772
00773
00774
00775 if (!IsDiagonalTrackdir(*trackdir)) {
00776 trdx = _trackdelta[*trackdir].x;
00777 trdy = _trackdelta[*trackdir].y;
00778 if (abs(dx) != abs(dy) && abs(dx) + abs(trdy) != abs(dy) + abs(trdx)) return CMD_ERROR;
00779 }
00780
00781 return CommandCost();
00782 }
00783
00797 static CommandCost CmdRailTrackHelper(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00798 {
00799 CommandCost total_cost(EXPENSES_CONSTRUCTION);
00800 Track track = Extract<Track, 4, 3>(p2);
00801 bool remove = HasBit(p2, 7);
00802 RailType railtype = Extract<RailType, 0, 4>(p2);
00803
00804 if (!ValParamRailtype(railtype) || !ValParamTrackOrientation(track)) return CMD_ERROR;
00805 if (p1 >= MapSize()) return CMD_ERROR;
00806 TileIndex end_tile = p1;
00807 Trackdir trackdir = TrackToTrackdir(track);
00808
00809 CommandCost ret = ValidateAutoDrag(&trackdir, tile, end_tile);
00810 if (ret.Failed()) return ret;
00811
00812 if (flags & DC_EXEC) SndPlayTileFx(SND_20_SPLAT_2, tile);
00813
00814 bool had_success = false;
00815 CommandCost last_error = CMD_ERROR;
00816 for (;;) {
00817 CommandCost ret = DoCommand(tile, railtype, TrackdirToTrack(trackdir), flags, remove ? CMD_REMOVE_SINGLE_RAIL : CMD_BUILD_SINGLE_RAIL);
00818
00819 if (ret.Failed()) {
00820 last_error = ret;
00821 if (last_error.GetErrorMessage() != STR_ERROR_ALREADY_BUILT && !remove) {
00822 if (HasBit(p2, 8)) return last_error;
00823 break;
00824 }
00825
00826
00827 if (last_error.GetErrorMessage() == STR_ERROR_OWNED_BY && remove) break;
00828 } else {
00829 had_success = true;
00830 total_cost.AddCost(ret);
00831 }
00832
00833 if (tile == end_tile) break;
00834
00835 tile += ToTileIndexDiff(_trackdelta[trackdir]);
00836
00837
00838 if (!IsDiagonalTrackdir(trackdir)) ToggleBit(trackdir, 0);
00839 }
00840
00841 if (had_success) return total_cost;
00842 return last_error;
00843 }
00844
00859 CommandCost CmdBuildRailroadTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00860 {
00861 return CmdRailTrackHelper(tile, flags, p1, ClrBit(p2, 7), text);
00862 }
00863
00878 CommandCost CmdRemoveRailroadTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00879 {
00880 return CmdRailTrackHelper(tile, flags, p1, SetBit(p2, 7), text);
00881 }
00882
00895 CommandCost CmdBuildTrainDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00896 {
00897
00898 RailType railtype = Extract<RailType, 0, 4>(p1);
00899 if (!ValParamRailtype(railtype)) return CMD_ERROR;
00900
00901 Slope tileh = GetTileSlope(tile);
00902
00903 DiagDirection dir = Extract<DiagDirection, 0, 2>(p2);
00904
00905
00906
00907
00908
00909
00910
00911
00912 if (tileh != SLOPE_FLAT && (
00913 !_settings_game.construction.build_on_slopes ||
00914 !CanBuildDepotByTileh(dir, tileh)
00915 )) {
00916 return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
00917 }
00918
00919 CommandCost cost = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00920 if (cost.Failed()) return cost;
00921
00922 if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
00923
00924 if (!Depot::CanAllocateItem()) return CMD_ERROR;
00925
00926 if (flags & DC_EXEC) {
00927 Depot *d = new Depot(tile);
00928 d->build_date = _date;
00929
00930 MakeRailDepot(tile, _current_company, d->index, dir, railtype);
00931 MarkTileDirtyByTile(tile);
00932 MakeDefaultName(d);
00933
00934 Company::Get(_current_company)->infrastructure.rail[railtype]++;
00935 DirtyCompanyInfrastructureWindows(_current_company);
00936
00937 AddSideToSignalBuffer(tile, INVALID_DIAGDIR, _current_company);
00938 YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
00939 }
00940
00941 cost.AddCost(_price[PR_BUILD_DEPOT_TRAIN]);
00942 cost.AddCost(RailBuildCost(railtype));
00943 return cost;
00944 }
00945
00967 CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00968 {
00969 Track track = Extract<Track, 0, 3>(p1);
00970 bool ctrl_pressed = HasBit(p1, 3);
00971 SignalVariant sigvar = (ctrl_pressed ^ HasBit(p1, 4)) ? SIG_SEMAPHORE : SIG_ELECTRIC;
00972 SignalType sigtype = Extract<SignalType, 5, 3>(p1);
00973 bool convert_signal = HasBit(p1, 8);
00974 SignalType cycle_start = Extract<SignalType, 9, 3>(p1);
00975 SignalType cycle_stop = Extract<SignalType, 12, 3>(p1);
00976 uint num_dir_cycle = GB(p1, 15, 2);
00977
00978 if (sigtype > SIGTYPE_LAST) return CMD_ERROR;
00979 if (cycle_start > cycle_stop || cycle_stop > SIGTYPE_LAST) return CMD_ERROR;
00980
00981
00982 if (!ValParamTrackOrientation(track) || !IsPlainRailTile(tile) ||
00983 !HasTrack(tile, track)) {
00984 return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
00985 }
00986 CommandCost ret = EnsureNoTrainOnTrack(tile, track);
00987 if (ret.Failed()) return ret;
00988
00989
00990 if (p2 != 0 && (p2 & SignalOnTrack(track)) == 0) return CMD_ERROR;
00991
00992 ret = CheckTileOwnership(tile);
00993 if (ret.Failed()) return ret;
00994
00995 {
00996
00997 TrackBits trackbits = GetTrackBits(tile);
00998 if (KillFirstBit(trackbits) != TRACK_BIT_NONE &&
00999 trackbits != TRACK_BIT_HORZ &&
01000 trackbits != TRACK_BIT_VERT) {
01001 return_cmd_error(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK);
01002 }
01003 }
01004
01005
01006 if (HasBit(p1, 17) && HasSignalOnTrack(tile, track)) return CommandCost();
01007
01008
01009 if (convert_signal && !HasSignalOnTrack(tile, track)) return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS);
01010
01011 CommandCost cost;
01012 if (!HasSignalOnTrack(tile, track)) {
01013
01014 cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS]);
01015 } else {
01016 if (p2 != 0 && sigvar != GetSignalVariant(tile, track)) {
01017
01018 cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] + _price[PR_CLEAR_SIGNALS]);
01019
01020 } else if (convert_signal) {
01021
01022 if (ctrl_pressed || GetSignalVariant(tile, track) != sigvar) {
01023
01024 cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] + _price[PR_CLEAR_SIGNALS]);
01025 } else {
01026
01027 cost = CommandCost();
01028 }
01029
01030 } else {
01031
01032 cost = CommandCost();
01033 }
01034 }
01035
01036 if (flags & DC_EXEC) {
01037 Train *v = NULL;
01038
01039
01040
01041 if (HasReservedTracks(tile, TrackToTrackBits(track))) {
01042 v = GetTrainForReservation(tile, track);
01043 if (v != NULL) FreeTrainTrackReservation(v);
01044 }
01045
01046 if (!HasSignals(tile)) {
01047
01048 SetHasSignals(tile, true);
01049 SetSignalStates(tile, 0xF);
01050 SetPresentSignals(tile, 0);
01051 SetSignalType(tile, track, sigtype);
01052 SetSignalVariant(tile, track, sigvar);
01053 }
01054
01055
01056 Company::Get(GetTileOwner(tile))->infrastructure.signal -= CountBits(GetPresentSignals(tile));
01057
01058 if (p2 == 0) {
01059 if (!HasSignalOnTrack(tile, track)) {
01060
01061 SetPresentSignals(tile, GetPresentSignals(tile) | (IsPbsSignal(sigtype) ? KillFirstBit(SignalOnTrack(track)) : SignalOnTrack(track)));
01062 SetSignalType(tile, track, sigtype);
01063 SetSignalVariant(tile, track, sigvar);
01064 while (num_dir_cycle-- > 0) CycleSignalSide(tile, track);
01065 } else {
01066 if (convert_signal) {
01067
01068 if (ctrl_pressed) {
01069
01070 SetSignalVariant(tile, track, (GetSignalVariant(tile, track) == SIG_ELECTRIC) ? SIG_SEMAPHORE : SIG_ELECTRIC);
01071
01072 sigtype = GetSignalType(tile, track);
01073 } else {
01074
01075 SetSignalType(tile, track, sigtype);
01076 SetSignalVariant(tile, track, sigvar);
01077 if (IsPbsSignal(sigtype) && (GetPresentSignals(tile) & SignalOnTrack(track)) == SignalOnTrack(track)) {
01078 SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | KillFirstBit(SignalOnTrack(track)));
01079 }
01080 }
01081
01082 } else if (ctrl_pressed) {
01083
01084 sigtype = (SignalType)(GetSignalType(tile, track) + 1);
01085
01086 if (sigtype < cycle_start || sigtype > cycle_stop) sigtype = cycle_start;
01087
01088 SetSignalType(tile, track, sigtype);
01089 if (IsPbsSignal(sigtype) && (GetPresentSignals(tile) & SignalOnTrack(track)) == SignalOnTrack(track)) {
01090 SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | KillFirstBit(SignalOnTrack(track)));
01091 }
01092 } else {
01093
01094 CycleSignalSide(tile, track);
01095
01096 sigtype = GetSignalType(tile, track);
01097 }
01098 }
01099 } else {
01100
01101
01102 SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | (p2 & SignalOnTrack(track)));
01103 SetSignalVariant(tile, track, sigvar);
01104 SetSignalType(tile, track, sigtype);
01105 }
01106
01107
01108 Company::Get(GetTileOwner(tile))->infrastructure.signal += CountBits(GetPresentSignals(tile));
01109 DirtyCompanyInfrastructureWindows(GetTileOwner(tile));
01110
01111 if (IsPbsSignal(sigtype)) {
01112
01113 uint mask = GetPresentSignals(tile) & SignalOnTrack(track);
01114 SetSignalStates(tile, (GetSignalStates(tile) & ~mask) | ((HasBit(GetRailReservationTrackBits(tile), track) ? UINT_MAX : 0) & mask));
01115 }
01116 MarkTileDirtyByTile(tile);
01117 AddTrackToSignalBuffer(tile, track, _current_company);
01118 YapfNotifyTrackLayoutChange(tile, track);
01119 if (v != NULL) {
01120
01121 if (!(((v->vehstatus & VS_STOPPED) && v->cur_speed == 0) || v->current_order.IsType(OT_LOADING)) ||
01122 !IsSafeWaitingPosition(v, v->tile, v->GetVehicleTrackdir(), true, _settings_game.pf.forbid_90_deg)) {
01123 TryPathReserve(v, true);
01124 }
01125 }
01126 }
01127
01128 return cost;
01129 }
01130
01131 static bool CheckSignalAutoFill(TileIndex &tile, Trackdir &trackdir, int &signal_ctr, bool remove)
01132 {
01133 tile = AddTileIndexDiffCWrap(tile, _trackdelta[trackdir]);
01134 if (tile == INVALID_TILE) return false;
01135
01136
01137 TrackdirBits trackdirbits = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0));
01138
01139 if (TracksOverlap(TrackdirBitsToTrackBits(trackdirbits))) return false;
01140 trackdirbits &= TrackdirReachesTrackdirs(trackdir);
01141
01142
01143 if (trackdirbits == TRACKDIR_BIT_NONE) return false;
01144
01145
01146 trackdir = RemoveFirstTrackdir(&trackdirbits);
01147
01148
01149 if (trackdirbits != TRACKDIR_BIT_NONE) return false;
01150
01151 switch (GetTileType(tile)) {
01152 case MP_RAILWAY:
01153 if (IsRailDepot(tile)) return false;
01154 if (!remove && HasSignalOnTrack(tile, TrackdirToTrack(trackdir))) return false;
01155 signal_ctr++;
01156 if (IsDiagonalTrackdir(trackdir)) {
01157 signal_ctr++;
01158
01159 ClrBit(signal_ctr, 0);
01160 }
01161 return true;
01162
01163 case MP_ROAD:
01164 if (!IsLevelCrossing(tile)) return false;
01165 signal_ctr += 2;
01166 return true;
01167
01168 case MP_TUNNELBRIDGE: {
01169 TileIndex orig_tile = tile;
01170
01171 if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) return false;
01172 if (GetTunnelBridgeDirection(tile) != TrackdirToExitdir(trackdir)) return false;
01173
01174
01175
01176 tile = GetOtherTunnelBridgeEnd(tile);
01177
01178 signal_ctr += (GetTunnelBridgeLength(orig_tile, tile) + 2) * 2;
01179 return true;
01180 }
01181
01182 default: return false;
01183 }
01184 }
01185
01202 static CommandCost CmdSignalTrackHelper(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01203 {
01204 CommandCost total_cost(EXPENSES_CONSTRUCTION);
01205 TileIndex start_tile = tile;
01206
01207 Track track = Extract<Track, 0, 3>(p2);
01208 bool mode = HasBit(p2, 3);
01209 bool semaphores = HasBit(p2, 4);
01210 bool remove = HasBit(p2, 5);
01211 bool autofill = HasBit(p2, 6);
01212 byte signal_density = GB(p2, 24, 8);
01213
01214 if (p1 >= MapSize() || !ValParamTrackOrientation(track)) return CMD_ERROR;
01215 TileIndex end_tile = p1;
01216 if (signal_density == 0 || signal_density > 20) return CMD_ERROR;
01217
01218 if (!IsPlainRailTile(tile)) return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
01219
01220
01221
01222 signal_density *= 2;
01223
01224 Trackdir trackdir = TrackToTrackdir(track);
01225 CommandCost ret = ValidateAutoDrag(&trackdir, tile, end_tile);
01226 if (ret.Failed()) return ret;
01227
01228 track = TrackdirToTrack(trackdir);
01229 Trackdir start_trackdir = trackdir;
01230
01231
01232 if (!HasTrack(tile, track)) return CMD_ERROR;
01233
01234 SignalType sigtype = (SignalType)GB(p2, 7, 3);
01235 if (sigtype > SIGTYPE_LAST) return CMD_ERROR;
01236
01237 byte signals;
01238
01239 if (HasSignalOnTrack(tile, track)) {
01240 signals = GetPresentSignals(tile) & SignalOnTrack(track);
01241 assert(signals != 0);
01242
01243
01244 semaphores = GetSignalVariant(tile, track) != SIG_ELECTRIC;
01245
01246 sigtype = GetSignalType(tile, track);
01247
01248 if (sigtype == SIGTYPE_ENTRY || sigtype == SIGTYPE_EXIT) sigtype = SIGTYPE_NORMAL;
01249 } else {
01250 signals = IsPbsSignal(sigtype) ? SignalAlongTrackdir(trackdir) : SignalOnTrack(track);
01251 }
01252
01253 byte signal_dir = 0;
01254 if (signals & SignalAlongTrackdir(trackdir)) SetBit(signal_dir, 0);
01255 if (signals & SignalAgainstTrackdir(trackdir)) SetBit(signal_dir, 1);
01256
01257
01258
01259
01260
01261
01262
01263
01264
01265 int signal_ctr = 0;
01266 CommandCost last_error = CMD_ERROR;
01267 bool had_success = false;
01268 for (;;) {
01269
01270 if (remove || signal_ctr % signal_density == 0) {
01271 uint32 p1 = GB(TrackdirToTrack(trackdir), 0, 3);
01272 SB(p1, 3, 1, mode);
01273 SB(p1, 4, 1, semaphores);
01274 SB(p1, 5, 3, sigtype);
01275 if (!remove && signal_ctr == 0) SetBit(p1, 17);
01276
01277
01278 signals = 0;
01279 if (HasBit(signal_dir, 0)) signals |= SignalAlongTrackdir(trackdir);
01280 if (HasBit(signal_dir, 1)) signals |= SignalAgainstTrackdir(trackdir);
01281
01282 CommandCost ret = DoCommand(tile, p1, signals, flags, remove ? CMD_REMOVE_SIGNALS : CMD_BUILD_SIGNALS);
01283
01284
01285 if (ret.Succeeded()) {
01286 had_success = true;
01287 total_cost.AddCost(ret);
01288 } else {
01289
01290 if (ret.GetErrorMessage() != STR_ERROR_THERE_IS_NO_RAILROAD_TRACK ||
01291 last_error.GetErrorMessage() == INVALID_STRING_ID) {
01292 last_error = ret;
01293 }
01294 }
01295 }
01296
01297 if (autofill) {
01298 if (!CheckSignalAutoFill(tile, trackdir, signal_ctr, remove)) break;
01299
01300
01301 if (tile == start_tile && trackdir == start_trackdir) break;
01302 } else {
01303 if (tile == end_tile) break;
01304
01305 tile += ToTileIndexDiff(_trackdelta[trackdir]);
01306 signal_ctr++;
01307
01308
01309 if (IsDiagonalTrackdir(trackdir)) {
01310 signal_ctr++;
01311 } else {
01312 ToggleBit(trackdir, 0);
01313 }
01314 }
01315 }
01316
01317 return had_success ? total_cost : last_error;
01318 }
01319
01338 CommandCost CmdBuildSignalTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01339 {
01340 return CmdSignalTrackHelper(tile, flags, p1, p2, text);
01341 }
01342
01355 CommandCost CmdRemoveSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01356 {
01357 Track track = Extract<Track, 0, 3>(p1);
01358
01359 if (!ValParamTrackOrientation(track) || !IsPlainRailTile(tile) || !HasTrack(tile, track)) {
01360 return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
01361 }
01362 if (!HasSignalOnTrack(tile, track)) {
01363 return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS);
01364 }
01365 CommandCost ret = EnsureNoTrainOnTrack(tile, track);
01366 if (ret.Failed()) return ret;
01367
01368
01369 if (_current_company != OWNER_WATER) {
01370 CommandCost ret = CheckTileOwnership(tile);
01371 if (ret.Failed()) return ret;
01372 }
01373
01374
01375 if (flags & DC_EXEC) {
01376 Train *v = NULL;
01377 if (HasReservedTracks(tile, TrackToTrackBits(track))) {
01378 v = GetTrainForReservation(tile, track);
01379 } else if (IsPbsSignal(GetSignalType(tile, track))) {
01380
01381 Trackdir td = TrackToTrackdir(track);
01382 for (int i = 0; v == NULL && i < 2; i++, td = ReverseTrackdir(td)) {
01383
01384 if (!HasSignalOnTrackdir(tile, ReverseTrackdir(td))) continue;
01385 TileIndex next = TileAddByDiagDir(tile, TrackdirToExitdir(td));
01386 TrackBits tracks = TrackdirBitsToTrackBits(TrackdirReachesTrackdirs(td));
01387 if (HasReservedTracks(next, tracks)) {
01388 v = GetTrainForReservation(next, TrackBitsToTrack(GetReservedTrackbits(next) & tracks));
01389 }
01390 }
01391 }
01392 Company::Get(GetTileOwner(tile))->infrastructure.signal -= CountBits(GetPresentSignals(tile));
01393 SetPresentSignals(tile, GetPresentSignals(tile) & ~SignalOnTrack(track));
01394 Company::Get(GetTileOwner(tile))->infrastructure.signal += CountBits(GetPresentSignals(tile));
01395 DirtyCompanyInfrastructureWindows(GetTileOwner(tile));
01396
01397
01398 if (GetPresentSignals(tile) == 0) {
01399 SetSignalStates(tile, 0);
01400 SetHasSignals(tile, false);
01401 SetSignalVariant(tile, INVALID_TRACK, SIG_ELECTRIC);
01402 }
01403
01404 AddTrackToSignalBuffer(tile, track, GetTileOwner(tile));
01405 YapfNotifyTrackLayoutChange(tile, track);
01406 if (v != NULL) TryPathReserve(v, false);
01407
01408 MarkTileDirtyByTile(tile);
01409 }
01410
01411 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_SIGNALS]);
01412 }
01413
01432 CommandCost CmdRemoveSignalTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01433 {
01434 return CmdSignalTrackHelper(tile, flags, p1, SetBit(p2, 5), text);
01435 }
01436
01438 static Vehicle *UpdateTrainPowerProc(Vehicle *v, void *data)
01439 {
01440 if (v->type != VEH_TRAIN) return NULL;
01441
01442 TrainList *affected_trains = static_cast<TrainList*>(data);
01443 affected_trains->Include(Train::From(v)->First());
01444
01445 return NULL;
01446 }
01447
01460 CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01461 {
01462 RailType totype = Extract<RailType, 0, 4>(p2);
01463
01464 if (!ValParamRailtype(totype)) return CMD_ERROR;
01465 if (p1 >= MapSize()) return CMD_ERROR;
01466
01467 TrainList affected_trains;
01468
01469 CommandCost cost(EXPENSES_CONSTRUCTION);
01470 CommandCost error = CommandCost(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK);
01471 TileArea ta(tile, p1);
01472 TileIterator *iter = HasBit(p2, 4) ? (TileIterator *)new DiagonalTileIterator(tile, p1) : new OrthogonalTileIterator(ta);
01473 for (; (tile = *iter) != INVALID_TILE; ++(*iter)) {
01474 TileType tt = GetTileType(tile);
01475
01476
01477 switch (tt) {
01478 case MP_RAILWAY:
01479 break;
01480 case MP_STATION:
01481 if (!HasStationRail(tile)) continue;
01482 break;
01483 case MP_ROAD:
01484 if (!IsLevelCrossing(tile)) continue;
01485 if (RailNoLevelCrossings(totype)) {
01486 error.MakeError(STR_ERROR_CROSSING_DISALLOWED);
01487 continue;
01488 }
01489 break;
01490 case MP_TUNNELBRIDGE:
01491 if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) continue;
01492 break;
01493 default: continue;
01494 }
01495
01496
01497 RailType type = GetRailType(tile);
01498
01499
01500 if (type == totype || (_settings_game.vehicle.disable_elrails && totype == RAILTYPE_RAIL && type == RAILTYPE_ELECTRIC)) continue;
01501
01502
01503 CommandCost ret = CheckTileOwnership(tile);
01504 if (ret.Failed()) {
01505 error = ret;
01506 continue;
01507 }
01508
01509 SmallVector<Train *, 2> vehicles_affected;
01510
01511
01512
01513 if (tt != MP_TUNNELBRIDGE) {
01514 if (!IsCompatibleRail(type, totype)) {
01515 CommandCost ret = EnsureNoVehicleOnGround(tile);
01516 if (ret.Failed()) {
01517 error = ret;
01518 continue;
01519 }
01520 }
01521 if (flags & DC_EXEC) {
01522 TrackBits reserved = GetReservedTrackbits(tile);
01523 Track track;
01524 while ((track = RemoveFirstTrack(&reserved)) != INVALID_TRACK) {
01525 Train *v = GetTrainForReservation(tile, track);
01526 if (v != NULL && !HasPowerOnRail(v->railtype, totype)) {
01527
01528 FreeTrainTrackReservation(v);
01529 *vehicles_affected.Append() = v;
01530 }
01531 }
01532
01533
01534 if (!IsRailStationTile(tile) || !IsStationTileBlocked(tile)) {
01535 Company *c = Company::Get(GetTileOwner(tile));
01536 uint num_pieces = IsLevelCrossingTile(tile) ? LEVELCROSSING_TRACKBIT_FACTOR : 1;
01537 if (IsPlainRailTile(tile)) {
01538 TrackBits bits = GetTrackBits(tile);
01539 num_pieces = CountBits(bits);
01540 if (TracksOverlap(bits)) num_pieces *= num_pieces;
01541 }
01542 c->infrastructure.rail[type] -= num_pieces;
01543 c->infrastructure.rail[totype] += num_pieces;
01544 DirtyCompanyInfrastructureWindows(c->index);
01545 }
01546
01547 SetRailType(tile, totype);
01548 MarkTileDirtyByTile(tile);
01549
01550 FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc);
01551 }
01552 }
01553
01554 switch (tt) {
01555 case MP_RAILWAY:
01556 switch (GetRailTileType(tile)) {
01557 case RAIL_TILE_DEPOT:
01558 if (flags & DC_EXEC) {
01559
01560 YapfNotifyTrackLayoutChange(tile, GetRailDepotTrack(tile));
01561
01562
01563 InvalidateWindowData(WC_VEHICLE_DEPOT, tile);
01564 InvalidateWindowData(WC_BUILD_VEHICLE, tile);
01565 }
01566 cost.AddCost(RailConvertCost(type, totype));
01567 break;
01568
01569 default:
01570 if (flags & DC_EXEC) {
01571
01572 TrackBits tracks = GetTrackBits(tile);
01573 while (tracks != TRACK_BIT_NONE) {
01574 YapfNotifyTrackLayoutChange(tile, RemoveFirstTrack(&tracks));
01575 }
01576 }
01577 cost.AddCost(RailConvertCost(type, totype) * CountBits(GetTrackBits(tile)));
01578 break;
01579 }
01580 break;
01581
01582 case MP_TUNNELBRIDGE: {
01583 TileIndex endtile = GetOtherTunnelBridgeEnd(tile);
01584
01585
01586
01587 if (endtile < tile && TileX(endtile) >= TileX(ta.tile) && TileX(endtile) < TileX(ta.tile) + ta.w &&
01588 TileY(endtile) >= TileY(ta.tile) && TileY(endtile) < TileY(ta.tile) + ta.h) continue;
01589
01590
01591 if (!IsCompatibleRail(GetRailType(tile), totype)) {
01592 CommandCost ret = TunnelBridgeIsFree(tile, endtile);
01593 if (ret.Failed()) {
01594 error = ret;
01595 continue;
01596 }
01597 }
01598
01599 if (flags & DC_EXEC) {
01600 Track track = DiagDirToDiagTrack(GetTunnelBridgeDirection(tile));
01601 if (HasTunnelBridgeReservation(tile)) {
01602 Train *v = GetTrainForReservation(tile, track);
01603 if (v != NULL && !HasPowerOnRail(v->railtype, totype)) {
01604
01605 FreeTrainTrackReservation(v);
01606 *vehicles_affected.Append() = v;
01607 }
01608 }
01609
01610
01611 uint num_pieces = (GetTunnelBridgeLength(tile, endtile) + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR;
01612 Company *c = Company::Get(GetTileOwner(tile));
01613 c->infrastructure.rail[GetRailType(tile)] -= num_pieces;
01614 c->infrastructure.rail[totype] += num_pieces;
01615 DirtyCompanyInfrastructureWindows(c->index);
01616
01617 SetRailType(tile, totype);
01618 SetRailType(endtile, totype);
01619
01620 FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc);
01621 FindVehicleOnPos(endtile, &affected_trains, &UpdateTrainPowerProc);
01622
01623 YapfNotifyTrackLayoutChange(tile, track);
01624 YapfNotifyTrackLayoutChange(endtile, track);
01625
01626 MarkTileDirtyByTile(tile);
01627 MarkTileDirtyByTile(endtile);
01628
01629 if (IsBridge(tile)) {
01630 TileIndexDiff delta = TileOffsByDiagDir(GetTunnelBridgeDirection(tile));
01631 TileIndex t = tile + delta;
01632 for (; t != endtile; t += delta) MarkTileDirtyByTile(t);
01633 }
01634 }
01635
01636 cost.AddCost((GetTunnelBridgeLength(tile, endtile) + 2) * RailConvertCost(type, totype));
01637 break;
01638 }
01639
01640 default:
01641 if (flags & DC_EXEC) {
01642 Track track = ((tt == MP_STATION) ? GetRailStationTrack(tile) : GetCrossingRailTrack(tile));
01643 YapfNotifyTrackLayoutChange(tile, track);
01644 }
01645
01646 cost.AddCost(RailConvertCost(type, totype));
01647 break;
01648 }
01649
01650 for (uint i = 0; i < vehicles_affected.Length(); ++i) {
01651 TryPathReserve(vehicles_affected[i], true);
01652 }
01653 }
01654
01655 if (flags & DC_EXEC) {
01656
01657 for (Train **v = affected_trains.Begin(); v != affected_trains.End(); v++) {
01658 (*v)->RailtypeChanged();
01659 }
01660 }
01661
01662 delete iter;
01663 return (cost.GetCost() == 0) ? error : cost;
01664 }
01665
01666 static CommandCost RemoveTrainDepot(TileIndex tile, DoCommandFlag flags)
01667 {
01668 if (_current_company != OWNER_WATER) {
01669 CommandCost ret = CheckTileOwnership(tile);
01670 if (ret.Failed()) return ret;
01671 }
01672
01673 CommandCost ret = EnsureNoVehicleOnGround(tile);
01674 if (ret.Failed()) return ret;
01675
01676 if (flags & DC_EXEC) {
01677
01678 DiagDirection dir = GetRailDepotDirection(tile);
01679 Owner owner = GetTileOwner(tile);
01680 Train *v = NULL;
01681
01682 if (HasDepotReservation(tile)) {
01683 v = GetTrainForReservation(tile, DiagDirToDiagTrack(dir));
01684 if (v != NULL) FreeTrainTrackReservation(v);
01685 }
01686
01687 Company::Get(owner)->infrastructure.rail[GetRailType(tile)]--;
01688 DirtyCompanyInfrastructureWindows(owner);
01689
01690 delete Depot::GetByTile(tile);
01691 DoClearSquare(tile);
01692 AddSideToSignalBuffer(tile, dir, owner);
01693 YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
01694 if (v != NULL) TryPathReserve(v, true);
01695 }
01696
01697 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_TRAIN]);
01698 }
01699
01700 static CommandCost ClearTile_Track(TileIndex tile, DoCommandFlag flags)
01701 {
01702 CommandCost cost(EXPENSES_CONSTRUCTION);
01703
01704 if (flags & DC_AUTO) {
01705 if (!IsTileOwner(tile, _current_company)) {
01706 return_cmd_error(STR_ERROR_AREA_IS_OWNED_BY_ANOTHER);
01707 }
01708
01709 if (IsPlainRail(tile)) {
01710 return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
01711 } else {
01712 return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
01713 }
01714 }
01715
01716 switch (GetRailTileType(tile)) {
01717 case RAIL_TILE_SIGNALS:
01718 case RAIL_TILE_NORMAL: {
01719 Slope tileh = GetTileSlope(tile);
01720
01721 bool water_ground = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh));
01722
01723 TrackBits tracks = GetTrackBits(tile);
01724 while (tracks != TRACK_BIT_NONE) {
01725 Track track = RemoveFirstTrack(&tracks);
01726 CommandCost ret = DoCommand(tile, 0, track, flags, CMD_REMOVE_SINGLE_RAIL);
01727 if (ret.Failed()) return ret;
01728 cost.AddCost(ret);
01729 }
01730
01731
01732 if (water_ground && !(flags & DC_BANKRUPT)) {
01733 CommandCost ret = EnsureNoVehicleOnGround(tile);
01734 if (ret.Failed()) return ret;
01735
01736
01737 if (flags & DC_EXEC) DoClearSquare(tile);
01738 cost.AddCost(_price[PR_CLEAR_WATER]);
01739 }
01740
01741 return cost;
01742 }
01743
01744 case RAIL_TILE_DEPOT:
01745 return RemoveTrainDepot(tile, flags);
01746
01747 default:
01748 return CMD_ERROR;
01749 }
01750 }
01751
01756 static uint GetSaveSlopeZ(uint x, uint y, Track track)
01757 {
01758 switch (track) {
01759 case TRACK_UPPER: x &= ~0xF; y &= ~0xF; break;
01760 case TRACK_LOWER: x |= 0xF; y |= 0xF; break;
01761 case TRACK_LEFT: x |= 0xF; y &= ~0xF; break;
01762 case TRACK_RIGHT: x &= ~0xF; y |= 0xF; break;
01763 default: break;
01764 }
01765 return GetSlopePixelZ(x, y);
01766 }
01767
01768 static void DrawSingleSignal(TileIndex tile, Track track, byte condition, uint image, uint pos)
01769 {
01770 bool side = (_settings_game.vehicle.road_side != 0) && _settings_game.construction.signal_side;
01771 static const Point SignalPositions[2][12] = {
01772 {
01773
01774 { 8, 5}, {14, 1}, { 1, 14}, { 9, 11}, { 1, 0}, { 3, 10},
01775
01776 {11, 4}, {14, 14}, {11, 3}, { 4, 13}, { 3, 4}, {11, 13}
01777 }, {
01778
01779 {14, 1}, {12, 10}, { 4, 6}, { 1, 14}, {10, 4}, { 0, 1},
01780
01781 {14, 14}, { 5, 12}, {11, 13}, { 4, 3}, {13, 4}, { 3, 11}
01782 }
01783 };
01784
01785 uint x = TileX(tile) * TILE_SIZE + SignalPositions[side][pos].x;
01786 uint y = TileY(tile) * TILE_SIZE + SignalPositions[side][pos].y;
01787
01788 SpriteID sprite;
01789
01790 SignalType type = GetSignalType(tile, track);
01791 SignalVariant variant = GetSignalVariant(tile, track);
01792
01793 if (type == SIGTYPE_NORMAL && variant == SIG_ELECTRIC) {
01794
01795 sprite = SPR_ORIGINAL_SIGNALS_BASE + image + condition;
01796 } else {
01797
01798 sprite = SPR_SIGNALS_BASE + (type - 1) * 16 + variant * 64 + image + condition + (type > SIGTYPE_LAST_NOPBS ? 64 : 0);
01799 }
01800
01801 AddSortableSpriteToDraw(sprite, PAL_NONE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, GetSaveSlopeZ(x, y, track));
01802 }
01803
01804 static uint32 _drawtile_track_palette;
01805
01806
01807 static void DrawTrackFence_NW(const TileInfo *ti, SpriteID base_image)
01808 {
01809 RailFenceOffset rfo = RFO_FLAT_X;
01810 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SW : RFO_SLOPE_NE;
01811 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01812 ti->x, ti->y + 1, 16, 1, 4, ti->z);
01813 }
01814
01815 static void DrawTrackFence_SE(const TileInfo *ti, SpriteID base_image)
01816 {
01817 RailFenceOffset rfo = RFO_FLAT_X;
01818 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SW : RFO_SLOPE_NE;
01819 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01820 ti->x, ti->y + TILE_SIZE - 1, 16, 1, 4, ti->z);
01821 }
01822
01823 static void DrawTrackFence_NW_SE(const TileInfo *ti, SpriteID base_image)
01824 {
01825 DrawTrackFence_NW(ti, base_image);
01826 DrawTrackFence_SE(ti, base_image);
01827 }
01828
01829 static void DrawTrackFence_NE(const TileInfo *ti, SpriteID base_image)
01830 {
01831 RailFenceOffset rfo = RFO_FLAT_Y;
01832 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SE : RFO_SLOPE_NW;
01833 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01834 ti->x + 1, ti->y, 1, 16, 4, ti->z);
01835 }
01836
01837 static void DrawTrackFence_SW(const TileInfo *ti, SpriteID base_image)
01838 {
01839 RailFenceOffset rfo = RFO_FLAT_Y;
01840 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SE : RFO_SLOPE_NW;
01841 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01842 ti->x + TILE_SIZE - 1, ti->y, 1, 16, 4, ti->z);
01843 }
01844
01845 static void DrawTrackFence_NE_SW(const TileInfo *ti, SpriteID base_image)
01846 {
01847 DrawTrackFence_NE(ti, base_image);
01848 DrawTrackFence_SW(ti, base_image);
01849 }
01850
01854 static void DrawTrackFence_NS_1(const TileInfo *ti, SpriteID base_image)
01855 {
01856 int z = ti->z + GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_W);
01857 AddSortableSpriteToDraw(base_image + RFO_FLAT_VERT, _drawtile_track_palette,
01858 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01859 }
01860
01864 static void DrawTrackFence_NS_2(const TileInfo *ti, SpriteID base_image)
01865 {
01866 int z = ti->z + GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_E);
01867 AddSortableSpriteToDraw(base_image + RFO_FLAT_VERT, _drawtile_track_palette,
01868 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01869 }
01870
01874 static void DrawTrackFence_WE_1(const TileInfo *ti, SpriteID base_image)
01875 {
01876 int z = ti->z + GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_N);
01877 AddSortableSpriteToDraw(base_image + RFO_FLAT_HORZ, _drawtile_track_palette,
01878 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01879 }
01880
01884 static void DrawTrackFence_WE_2(const TileInfo *ti, SpriteID base_image)
01885 {
01886 int z = ti->z + GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_S);
01887 AddSortableSpriteToDraw(base_image + RFO_FLAT_HORZ, _drawtile_track_palette,
01888 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01889 }
01890
01891
01892 static void DrawTrackDetails(const TileInfo *ti, const RailtypeInfo *rti)
01893 {
01894
01895
01896 SpriteID base_image = GetCustomRailSprite(rti, ti->tile, RTSG_FENCES, IsHalftileSlope(ti->tileh) ? TCX_UPPER_HALFTILE : TCX_NORMAL);
01897 if (base_image == 0) base_image = SPR_TRACK_FENCE_FLAT_X;
01898
01899 switch (GetRailGroundType(ti->tile)) {
01900 case RAIL_GROUND_FENCE_NW: DrawTrackFence_NW(ti, base_image); break;
01901 case RAIL_GROUND_FENCE_SE: DrawTrackFence_SE(ti, base_image); break;
01902 case RAIL_GROUND_FENCE_SENW: DrawTrackFence_NW_SE(ti, base_image); break;
01903 case RAIL_GROUND_FENCE_NE: DrawTrackFence_NE(ti, base_image); break;
01904 case RAIL_GROUND_FENCE_SW: DrawTrackFence_SW(ti, base_image); break;
01905 case RAIL_GROUND_FENCE_NESW: DrawTrackFence_NE_SW(ti, base_image); break;
01906 case RAIL_GROUND_FENCE_VERT1: DrawTrackFence_NS_1(ti, base_image); break;
01907 case RAIL_GROUND_FENCE_VERT2: DrawTrackFence_NS_2(ti, base_image); break;
01908 case RAIL_GROUND_FENCE_HORIZ1: DrawTrackFence_WE_1(ti, base_image); break;
01909 case RAIL_GROUND_FENCE_HORIZ2: DrawTrackFence_WE_2(ti, base_image); break;
01910 case RAIL_GROUND_WATER: {
01911 Corner track_corner;
01912 if (IsHalftileSlope(ti->tileh)) {
01913
01914 track_corner = GetHalftileSlopeCorner(ti->tileh);
01915 } else {
01916
01917 track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh)));
01918 }
01919 switch (track_corner) {
01920 case CORNER_W: DrawTrackFence_NS_1(ti, base_image); break;
01921 case CORNER_S: DrawTrackFence_WE_2(ti, base_image); break;
01922 case CORNER_E: DrawTrackFence_NS_2(ti, base_image); break;
01923 case CORNER_N: DrawTrackFence_WE_1(ti, base_image); break;
01924 default: NOT_REACHED();
01925 }
01926 break;
01927 }
01928 default: break;
01929 }
01930 }
01931
01932
01933 static const int INF = 1000;
01934 static const SubSprite _halftile_sub_sprite[4] = {
01935 { -INF , -INF , 32 - 33, INF },
01936 { -INF , 0 + 7, INF , INF },
01937 { -31 + 33, -INF , INF , INF },
01938 { -INF , -INF , INF , 30 - 23 }
01939 };
01940
01941 static inline void DrawTrackSprite(SpriteID sprite, PaletteID pal, const TileInfo *ti, Slope s)
01942 {
01943 DrawGroundSprite(sprite, pal, NULL, 0, (ti->tileh & s) ? -8 : 0);
01944 }
01945
01946 static void DrawTrackBitsOverlay(TileInfo *ti, TrackBits track, const RailtypeInfo *rti)
01947 {
01948 RailGroundType rgt = GetRailGroundType(ti->tile);
01949 Foundation f = GetRailFoundation(ti->tileh, track);
01950 Corner halftile_corner = CORNER_INVALID;
01951
01952 if (IsNonContinuousFoundation(f)) {
01953
01954 halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f));
01955
01956 track &= ~CornerToTrackBits(halftile_corner);
01957 f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE);
01958 }
01959
01960 DrawFoundation(ti, f);
01961
01962
01963
01964 if (rgt == RAIL_GROUND_WATER) {
01965 if (track != TRACK_BIT_NONE || IsSteepSlope(ti->tileh)) {
01966
01967 DrawShoreTile(ti->tileh);
01968 } else {
01969
01970 DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
01971 }
01972 } else {
01973 SpriteID image;
01974
01975 switch (rgt) {
01976 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
01977 case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOW_DESERT_TILE; break;
01978 default: image = SPR_FLAT_GRASS_TILE; break;
01979 }
01980
01981 image += SlopeToSpriteOffset(ti->tileh);
01982
01983 DrawGroundSprite(image, PAL_NONE);
01984 }
01985
01986 SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
01987 SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
01988 TrackBits pbs = _settings_client.gui.show_track_reservation ? GetRailReservationTrackBits(ti->tile) : TRACK_BIT_NONE;
01989
01990 if (track == TRACK_BIT_NONE) {
01991
01992 } else if (ti->tileh == SLOPE_NW && track == TRACK_BIT_Y) {
01993 DrawGroundSprite(ground + RTO_SLOPE_NW, PAL_NONE);
01994 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 9, PALETTE_CRASH);
01995 } else if (ti->tileh == SLOPE_NE && track == TRACK_BIT_X) {
01996 DrawGroundSprite(ground + RTO_SLOPE_NE, PAL_NONE);
01997 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 6, PALETTE_CRASH);
01998 } else if (ti->tileh == SLOPE_SE && track == TRACK_BIT_Y) {
01999 DrawGroundSprite(ground + RTO_SLOPE_SE, PAL_NONE);
02000 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 7, PALETTE_CRASH);
02001 } else if (ti->tileh == SLOPE_SW && track == TRACK_BIT_X) {
02002 DrawGroundSprite(ground + RTO_SLOPE_SW, PAL_NONE);
02003 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 8, PALETTE_CRASH);
02004 } else {
02005 switch (track) {
02006
02007
02008 case TRACK_BIT_X: DrawGroundSprite(ground + RTO_X, PAL_NONE); break;
02009 case TRACK_BIT_Y: DrawGroundSprite(ground + RTO_Y, PAL_NONE); break;
02010 case TRACK_BIT_UPPER: DrawTrackSprite(ground + RTO_N, PAL_NONE, ti, SLOPE_N); break;
02011 case TRACK_BIT_LOWER: DrawTrackSprite(ground + RTO_S, PAL_NONE, ti, SLOPE_S); break;
02012 case TRACK_BIT_RIGHT: DrawTrackSprite(ground + RTO_E, PAL_NONE, ti, SLOPE_E); break;
02013 case TRACK_BIT_LEFT: DrawTrackSprite(ground + RTO_W, PAL_NONE, ti, SLOPE_W); break;
02014 case TRACK_BIT_CROSS: DrawGroundSprite(ground + RTO_CROSSING_XY, PAL_NONE); break;
02015 case TRACK_BIT_HORZ: DrawTrackSprite(ground + RTO_N, PAL_NONE, ti, SLOPE_N);
02016 DrawTrackSprite(ground + RTO_S, PAL_NONE, ti, SLOPE_S); break;
02017 case TRACK_BIT_VERT: DrawTrackSprite(ground + RTO_E, PAL_NONE, ti, SLOPE_E);
02018 DrawTrackSprite(ground + RTO_W, PAL_NONE, ti, SLOPE_W); break;
02019
02020 default:
02021
02022 if ((track & TRACK_BIT_3WAY_NE) == 0) {
02023 DrawGroundSprite(ground + RTO_JUNCTION_SW, PAL_NONE);
02024 } else if ((track & TRACK_BIT_3WAY_SW) == 0) {
02025 DrawGroundSprite(ground + RTO_JUNCTION_NE, PAL_NONE);
02026 } else if ((track & TRACK_BIT_3WAY_NW) == 0) {
02027 DrawGroundSprite(ground + RTO_JUNCTION_SE, PAL_NONE);
02028 } else if ((track & TRACK_BIT_3WAY_SE) == 0) {
02029 DrawGroundSprite(ground + RTO_JUNCTION_NW, PAL_NONE);
02030 } else {
02031 DrawGroundSprite(ground + RTO_JUNCTION_NSEW, PAL_NONE);
02032 }
02033
02034
02035 track &= ~pbs;
02036
02037
02038 if (track & TRACK_BIT_X) DrawGroundSprite(overlay + RTO_X, PAL_NONE);
02039 if (track & TRACK_BIT_Y) DrawGroundSprite(overlay + RTO_Y, PAL_NONE);
02040 if (track & TRACK_BIT_UPPER) DrawGroundSprite(overlay + RTO_N, PAL_NONE);
02041 if (track & TRACK_BIT_LOWER) DrawGroundSprite(overlay + RTO_S, PAL_NONE);
02042 if (track & TRACK_BIT_RIGHT) DrawGroundSprite(overlay + RTO_E, PAL_NONE);
02043 if (track & TRACK_BIT_LEFT) DrawGroundSprite(overlay + RTO_W, PAL_NONE);
02044 }
02045
02046
02047 if (pbs & TRACK_BIT_X) DrawGroundSprite(overlay + RTO_X, PALETTE_CRASH);
02048 if (pbs & TRACK_BIT_Y) DrawGroundSprite(overlay + RTO_Y, PALETTE_CRASH);
02049 if (pbs & TRACK_BIT_UPPER) DrawTrackSprite(overlay + RTO_N, PALETTE_CRASH, ti, SLOPE_N);
02050 if (pbs & TRACK_BIT_LOWER) DrawTrackSprite(overlay + RTO_S, PALETTE_CRASH, ti, SLOPE_S);
02051 if (pbs & TRACK_BIT_RIGHT) DrawTrackSprite(overlay + RTO_E, PALETTE_CRASH, ti, SLOPE_E);
02052 if (pbs & TRACK_BIT_LEFT) DrawTrackSprite(overlay + RTO_W, PALETTE_CRASH, ti, SLOPE_W);
02053 }
02054
02055 if (IsValidCorner(halftile_corner)) {
02056 DrawFoundation(ti, HalftileFoundation(halftile_corner));
02057 overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY, TCX_UPPER_HALFTILE);
02058 ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND, TCX_UPPER_HALFTILE);
02059
02060
02061 Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
02062
02063 SpriteID image;
02064 switch (rgt) {
02065 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
02066 case RAIL_GROUND_ICE_DESERT:
02067 case RAIL_GROUND_HALF_SNOW: image = SPR_FLAT_SNOW_DESERT_TILE; break;
02068 default: image = SPR_FLAT_GRASS_TILE; break;
02069 }
02070
02071 image += SlopeToSpriteOffset(fake_slope);
02072
02073 DrawGroundSprite(image, PAL_NONE, &(_halftile_sub_sprite[halftile_corner]));
02074
02075 track = CornerToTrackBits(halftile_corner);
02076
02077 int offset;
02078 switch (track) {
02079 default: NOT_REACHED();
02080 case TRACK_BIT_UPPER: offset = RTO_N; break;
02081 case TRACK_BIT_LOWER: offset = RTO_S; break;
02082 case TRACK_BIT_RIGHT: offset = RTO_E; break;
02083 case TRACK_BIT_LEFT: offset = RTO_W; break;
02084 }
02085
02086 DrawTrackSprite(ground + offset, PAL_NONE, ti, fake_slope);
02087 if (_settings_client.gui.show_track_reservation && HasReservedTracks(ti->tile, track)) {
02088 DrawTrackSprite(overlay + offset, PALETTE_CRASH, ti, fake_slope);
02089 }
02090 }
02091 }
02092
02098 static void DrawTrackBits(TileInfo *ti, TrackBits track)
02099 {
02100 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
02101
02102 if (rti->UsesOverlay()) {
02103 DrawTrackBitsOverlay(ti, track, rti);
02104 return;
02105 }
02106
02107 RailGroundType rgt = GetRailGroundType(ti->tile);
02108 Foundation f = GetRailFoundation(ti->tileh, track);
02109 Corner halftile_corner = CORNER_INVALID;
02110
02111 if (IsNonContinuousFoundation(f)) {
02112
02113 halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f));
02114
02115 track &= ~CornerToTrackBits(halftile_corner);
02116 f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE);
02117 }
02118
02119 DrawFoundation(ti, f);
02120
02121
02122 SpriteID image;
02123 PaletteID pal = PAL_NONE;
02124 const SubSprite *sub = NULL;
02125 bool junction = false;
02126
02127
02128 if (track == 0) {
02129
02130 if (rgt == RAIL_GROUND_WATER) {
02131 if (IsSteepSlope(ti->tileh)) {
02132 DrawShoreTile(ti->tileh);
02133 image = 0;
02134 } else {
02135 image = SPR_FLAT_WATER_TILE;
02136 }
02137 } else {
02138 switch (rgt) {
02139 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
02140 case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOW_DESERT_TILE; break;
02141 default: image = SPR_FLAT_GRASS_TILE; break;
02142 }
02143 image += SlopeToSpriteOffset(ti->tileh);
02144 }
02145 } else {
02146 if (ti->tileh != SLOPE_FLAT) {
02147
02148 image = _track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.track_y;
02149 } else {
02150
02151 (image = rti->base_sprites.track_y, track == TRACK_BIT_Y) ||
02152 (image++, track == TRACK_BIT_X) ||
02153 (image++, track == TRACK_BIT_UPPER) ||
02154 (image++, track == TRACK_BIT_LOWER) ||
02155 (image++, track == TRACK_BIT_RIGHT) ||
02156 (image++, track == TRACK_BIT_LEFT) ||
02157 (image++, track == TRACK_BIT_CROSS) ||
02158
02159 (image = rti->base_sprites.track_ns, track == TRACK_BIT_HORZ) ||
02160 (image++, track == TRACK_BIT_VERT) ||
02161
02162 (junction = true, false) ||
02163 (image = rti->base_sprites.ground, (track & TRACK_BIT_3WAY_NE) == 0) ||
02164 (image++, (track & TRACK_BIT_3WAY_SW) == 0) ||
02165 (image++, (track & TRACK_BIT_3WAY_NW) == 0) ||
02166 (image++, (track & TRACK_BIT_3WAY_SE) == 0) ||
02167 (image++, true);
02168 }
02169
02170 switch (rgt) {
02171 case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
02172 case RAIL_GROUND_ICE_DESERT: image += rti->snow_offset; break;
02173 case RAIL_GROUND_WATER: {
02174
02175 DrawShoreTile(ti->tileh);
02176 Corner track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh)));
02177 sub = &(_halftile_sub_sprite[track_corner]);
02178 break;
02179 }
02180 default: break;
02181 }
02182 }
02183
02184 if (image != 0) DrawGroundSprite(image, pal, sub);
02185
02186
02187 if (junction) {
02188 if (track & TRACK_BIT_X) DrawGroundSprite(rti->base_sprites.single_x, PAL_NONE);
02189 if (track & TRACK_BIT_Y) DrawGroundSprite(rti->base_sprites.single_y, PAL_NONE);
02190 if (track & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PAL_NONE);
02191 if (track & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PAL_NONE);
02192 if (track & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PAL_NONE);
02193 if (track & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PAL_NONE);
02194 }
02195
02196
02197 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation) {
02198
02199 TrackBits pbs = GetRailReservationTrackBits(ti->tile) & track;
02200 if (pbs & TRACK_BIT_X) {
02201 if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
02202 DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH);
02203 } else {
02204 DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
02205 }
02206 }
02207 if (pbs & TRACK_BIT_Y) {
02208 if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
02209 DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH);
02210 } else {
02211 DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
02212 }
02213 }
02214 if (pbs & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_N ? -(int)TILE_HEIGHT : 0);
02215 if (pbs & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_S ? -(int)TILE_HEIGHT : 0);
02216 if (pbs & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_W ? -(int)TILE_HEIGHT : 0);
02217 if (pbs & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_E ? -(int)TILE_HEIGHT : 0);
02218 }
02219
02220 if (IsValidCorner(halftile_corner)) {
02221 DrawFoundation(ti, HalftileFoundation(halftile_corner));
02222
02223
02224 Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
02225 image = _track_sloped_sprites[fake_slope - 1] + rti->base_sprites.track_y;
02226 pal = PAL_NONE;
02227 switch (rgt) {
02228 case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
02229 case RAIL_GROUND_ICE_DESERT:
02230 case RAIL_GROUND_HALF_SNOW: image += rti->snow_offset; break;
02231 default: break;
02232 }
02233 DrawGroundSprite(image, pal, &(_halftile_sub_sprite[halftile_corner]));
02234
02235 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasReservedTracks(ti->tile, CornerToTrackBits(halftile_corner))) {
02236 static const byte _corner_to_track_sprite[] = {3, 1, 2, 0};
02237 DrawGroundSprite(_corner_to_track_sprite[halftile_corner] + rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, -(int)TILE_HEIGHT);
02238 }
02239 }
02240 }
02241
02249 enum SignalOffsets {
02250 SIGNAL_TO_SOUTHWEST = 0,
02251 SIGNAL_TO_NORTHEAST = 2,
02252 SIGNAL_TO_SOUTHEAST = 4,
02253 SIGNAL_TO_NORTHWEST = 6,
02254 SIGNAL_TO_EAST = 8,
02255 SIGNAL_TO_WEST = 10,
02256 SIGNAL_TO_SOUTH = 12,
02257 SIGNAL_TO_NORTH = 14,
02258 };
02259
02260 static void DrawSignals(TileIndex tile, TrackBits rails)
02261 {
02262 #define MAYBE_DRAW_SIGNAL(x, y, z, t) if (IsSignalPresent(tile, x)) DrawSingleSignal(tile, t, GetSingleSignalState(tile, x), y, z)
02263
02264 if (!(rails & TRACK_BIT_Y)) {
02265 if (!(rails & TRACK_BIT_X)) {
02266 if (rails & TRACK_BIT_LEFT) {
02267 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTH, 0, TRACK_LEFT);
02268 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTH, 1, TRACK_LEFT);
02269 }
02270 if (rails & TRACK_BIT_RIGHT) {
02271 MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_NORTH, 2, TRACK_RIGHT);
02272 MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_SOUTH, 3, TRACK_RIGHT);
02273 }
02274 if (rails & TRACK_BIT_UPPER) {
02275 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_WEST, 4, TRACK_UPPER);
02276 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_EAST, 5, TRACK_UPPER);
02277 }
02278 if (rails & TRACK_BIT_LOWER) {
02279 MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_WEST, 6, TRACK_LOWER);
02280 MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_EAST, 7, TRACK_LOWER);
02281 }
02282 } else {
02283 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHWEST, 8, TRACK_X);
02284 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHEAST, 9, TRACK_X);
02285 }
02286 } else {
02287 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHEAST, 10, TRACK_Y);
02288 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHWEST, 11, TRACK_Y);
02289 }
02290 }
02291
02292 static void DrawTile_Track(TileInfo *ti)
02293 {
02294 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
02295
02296 _drawtile_track_palette = COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile));
02297
02298 if (IsPlainRail(ti->tile)) {
02299 TrackBits rails = GetTrackBits(ti->tile);
02300
02301 DrawTrackBits(ti, rails);
02302
02303 if (HasBit(_display_opt, DO_FULL_DETAIL)) DrawTrackDetails(ti, rti);
02304
02305 if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
02306
02307 if (HasSignals(ti->tile)) DrawSignals(ti->tile, rails);
02308 } else {
02309
02310 const DrawTileSprites *dts;
02311 PaletteID pal = PAL_NONE;
02312 SpriteID relocation;
02313
02314 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
02315
02316 if (IsInvisibilitySet(TO_BUILDINGS)) {
02317
02318 dts = &_depot_invisible_gfx_table[GetRailDepotDirection(ti->tile)];
02319 } else {
02320 dts = &_depot_gfx_table[GetRailDepotDirection(ti->tile)];
02321 }
02322
02323 SpriteID image;
02324 if (rti->UsesOverlay()) {
02325 image = SPR_FLAT_GRASS_TILE;
02326 } else {
02327 image = dts->ground.sprite;
02328 if (image != SPR_FLAT_GRASS_TILE) image += rti->GetRailtypeSpriteOffset();
02329 }
02330
02331
02332
02333 if (IsSnowRailGround(ti->tile) && _settings_game.game_creation.landscape == LT_TROPIC) {
02334 if (image != SPR_FLAT_GRASS_TILE) {
02335 image += rti->snow_offset;
02336 } else {
02337 image = SPR_FLAT_SNOW_DESERT_TILE;
02338 }
02339 }
02340
02341 DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, _drawtile_track_palette));
02342
02343 if (rti->UsesOverlay()) {
02344 SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
02345
02346 switch (GetRailDepotDirection(ti->tile)) {
02347 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02348 case DIAGDIR_SW: DrawGroundSprite(ground + RTO_X, PAL_NONE); break;
02349 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02350 case DIAGDIR_SE: DrawGroundSprite(ground + RTO_Y, PAL_NONE); break;
02351 default: break;
02352 }
02353
02354 if (_settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile)) {
02355 SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
02356
02357 switch (GetRailDepotDirection(ti->tile)) {
02358 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02359 case DIAGDIR_SW: DrawGroundSprite(overlay + RTO_X, PALETTE_CRASH); break;
02360 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02361 case DIAGDIR_SE: DrawGroundSprite(overlay + RTO_Y, PALETTE_CRASH); break;
02362 default: break;
02363 }
02364 }
02365 } else {
02366
02367 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile)) {
02368 switch (GetRailDepotDirection(ti->tile)) {
02369 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02370 case DIAGDIR_SW: DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH); break;
02371 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02372 case DIAGDIR_SE: DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH); break;
02373 default: break;
02374 }
02375 }
02376 }
02377 int depot_sprite = GetCustomRailSprite(rti, ti->tile, RTSG_DEPOT);
02378 relocation = depot_sprite != 0 ? depot_sprite - SPR_RAIL_DEPOT_SE_1 : rti->GetRailtypeSpriteOffset();
02379
02380 if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
02381
02382 DrawRailTileSeq(ti, dts, TO_BUILDINGS, relocation, 0, _drawtile_track_palette);
02383 }
02384 DrawBridgeMiddle(ti);
02385 }
02386
02387 void DrawTrainDepotSprite(int x, int y, int dir, RailType railtype)
02388 {
02389 const DrawTileSprites *dts = &_depot_gfx_table[dir];
02390 const RailtypeInfo *rti = GetRailTypeInfo(railtype);
02391 SpriteID image = rti->UsesOverlay() ? SPR_FLAT_GRASS_TILE : dts->ground.sprite;
02392 uint32 offset = rti->GetRailtypeSpriteOffset();
02393
02394 x += 33;
02395 y += 17;
02396
02397 if (image != SPR_FLAT_GRASS_TILE) image += offset;
02398 PaletteID palette = COMPANY_SPRITE_COLOUR(_local_company);
02399
02400 DrawSprite(image, PAL_NONE, x, y);
02401
02402 if (rti->UsesOverlay()) {
02403 SpriteID ground = GetCustomRailSprite(rti, INVALID_TILE, RTSG_GROUND);
02404
02405 switch (dir) {
02406 case DIAGDIR_SW: DrawSprite(ground + RTO_X, PAL_NONE, x, y); break;
02407 case DIAGDIR_SE: DrawSprite(ground + RTO_Y, PAL_NONE, x, y); break;
02408 default: break;
02409 }
02410 }
02411 int depot_sprite = GetCustomRailSprite(rti, INVALID_TILE, RTSG_DEPOT);
02412 if (depot_sprite != 0) offset = depot_sprite - SPR_RAIL_DEPOT_SE_1;
02413
02414 DrawRailTileSeqInGUI(x, y, dts, offset, 0, palette);
02415 }
02416
02417 static int GetSlopePixelZ_Track(TileIndex tile, uint x, uint y)
02418 {
02419 if (IsPlainRail(tile)) {
02420 int z;
02421 Slope tileh = GetTilePixelSlope(tile, &z);
02422 if (tileh == SLOPE_FLAT) return z;
02423
02424 z += ApplyPixelFoundationToSlope(GetRailFoundation(tileh, GetTrackBits(tile)), &tileh);
02425 return z + GetPartialPixelZ(x & 0xF, y & 0xF, tileh);
02426 } else {
02427 return GetTileMaxPixelZ(tile);
02428 }
02429 }
02430
02431 static Foundation GetFoundation_Track(TileIndex tile, Slope tileh)
02432 {
02433 return IsPlainRail(tile) ? GetRailFoundation(tileh, GetTrackBits(tile)) : FlatteningFoundation(tileh);
02434 }
02435
02436 static void TileLoop_Track(TileIndex tile)
02437 {
02438 RailGroundType old_ground = GetRailGroundType(tile);
02439 RailGroundType new_ground;
02440
02441 if (old_ground == RAIL_GROUND_WATER) {
02442 TileLoop_Water(tile);
02443 return;
02444 }
02445
02446 switch (_settings_game.game_creation.landscape) {
02447 case LT_ARCTIC: {
02448 int z;
02449 Slope slope = GetTileSlope(tile, &z);
02450 bool half = false;
02451
02452
02453
02454 if (IsPlainRail(tile)) {
02455 TrackBits track = GetTrackBits(tile);
02456 Foundation f = GetRailFoundation(slope, track);
02457
02458 switch (f) {
02459 case FOUNDATION_NONE:
02460
02461 if (IsSlopeWithThreeCornersRaised(slope)) z++;
02462 break;
02463
02464 case FOUNDATION_INCLINED_X:
02465 case FOUNDATION_INCLINED_Y:
02466
02467 if (IsSteepSlope(slope)) z++;
02468 break;
02469
02470 case FOUNDATION_STEEP_LOWER:
02471
02472 z++;
02473 break;
02474
02475 default:
02476
02477 if (IsSteepSlope(slope)) z++;
02478 z++;
02479 break;
02480 }
02481
02482 half = IsInsideMM(f, FOUNDATION_STEEP_BOTH, FOUNDATION_HALFTILE_N + 1);
02483 } else {
02484
02485 if (slope != SLOPE_FLAT) z++;
02486 }
02487
02488
02489
02490
02491
02492 if (z > GetSnowLine()) {
02493 if (half && z - GetSnowLine() == 1) {
02494
02495 new_ground = RAIL_GROUND_HALF_SNOW;
02496 } else {
02497 new_ground = RAIL_GROUND_ICE_DESERT;
02498 }
02499 goto set_ground;
02500 }
02501 break;
02502 }
02503
02504 case LT_TROPIC:
02505 if (GetTropicZone(tile) == TROPICZONE_DESERT) {
02506 new_ground = RAIL_GROUND_ICE_DESERT;
02507 goto set_ground;
02508 }
02509 break;
02510 }
02511
02512 new_ground = RAIL_GROUND_GRASS;
02513
02514 if (IsPlainRail(tile) && old_ground != RAIL_GROUND_BARREN) {
02515
02516 TrackBits rail = GetTrackBits(tile);
02517
02518 switch (rail) {
02519 case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
02520 case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
02521 case TRACK_BIT_LEFT: new_ground = RAIL_GROUND_FENCE_VERT1; break;
02522 case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2; break;
02523
02524 default: {
02525 Owner owner = GetTileOwner(tile);
02526
02527 if (rail == (TRACK_BIT_LOWER | TRACK_BIT_RIGHT) || (
02528 (rail & TRACK_BIT_3WAY_NW) == 0 &&
02529 (rail & TRACK_BIT_X)
02530 )) {
02531 TileIndex n = tile + TileDiffXY(0, -1);
02532 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02533
02534 if ((!IsTileType(n, MP_RAILWAY) && !IsRailWaypointTile(n)) ||
02535 !IsTileOwner(n, owner) ||
02536 nrail == TRACK_BIT_UPPER ||
02537 nrail == TRACK_BIT_LEFT) {
02538 new_ground = RAIL_GROUND_FENCE_NW;
02539 }
02540 }
02541
02542 if (rail == (TRACK_BIT_UPPER | TRACK_BIT_LEFT) || (
02543 (rail & TRACK_BIT_3WAY_SE) == 0 &&
02544 (rail & TRACK_BIT_X)
02545 )) {
02546 TileIndex n = tile + TileDiffXY(0, 1);
02547 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02548
02549 if ((!IsTileType(n, MP_RAILWAY) && !IsRailWaypointTile(n)) ||
02550 !IsTileOwner(n, owner) ||
02551 nrail == TRACK_BIT_LOWER ||
02552 nrail == TRACK_BIT_RIGHT) {
02553 new_ground = (new_ground == RAIL_GROUND_FENCE_NW) ?
02554 RAIL_GROUND_FENCE_SENW : RAIL_GROUND_FENCE_SE;
02555 }
02556 }
02557
02558 if (rail == (TRACK_BIT_LOWER | TRACK_BIT_LEFT) || (
02559 (rail & TRACK_BIT_3WAY_NE) == 0 &&
02560 (rail & TRACK_BIT_Y)
02561 )) {
02562 TileIndex n = tile + TileDiffXY(-1, 0);
02563 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02564
02565 if ((!IsTileType(n, MP_RAILWAY) && !IsRailWaypointTile(n)) ||
02566 !IsTileOwner(n, owner) ||
02567 nrail == TRACK_BIT_UPPER ||
02568 nrail == TRACK_BIT_RIGHT) {
02569 new_ground = RAIL_GROUND_FENCE_NE;
02570 }
02571 }
02572
02573 if (rail == (TRACK_BIT_UPPER | TRACK_BIT_RIGHT) || (
02574 (rail & TRACK_BIT_3WAY_SW) == 0 &&
02575 (rail & TRACK_BIT_Y)
02576 )) {
02577 TileIndex n = tile + TileDiffXY(1, 0);
02578 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02579
02580 if ((!IsTileType(n, MP_RAILWAY) && !IsRailWaypointTile(n)) ||
02581 !IsTileOwner(n, owner) ||
02582 nrail == TRACK_BIT_LOWER ||
02583 nrail == TRACK_BIT_LEFT) {
02584 new_ground = (new_ground == RAIL_GROUND_FENCE_NE) ?
02585 RAIL_GROUND_FENCE_NESW : RAIL_GROUND_FENCE_SW;
02586 }
02587 }
02588 break;
02589 }
02590 }
02591 }
02592
02593 set_ground:
02594 if (old_ground != new_ground) {
02595 SetRailGroundType(tile, new_ground);
02596 MarkTileDirtyByTile(tile);
02597 }
02598 }
02599
02600
02601 static TrackStatus GetTileTrackStatus_Track(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
02602 {
02603
02604 if (mode == TRANSPORT_WATER && IsPlainRail(tile) && GetRailGroundType(tile) == RAIL_GROUND_WATER) {
02605 TrackBits tb = GetTrackBits(tile);
02606 switch (tb) {
02607 default: NOT_REACHED();
02608 case TRACK_BIT_UPPER: tb = TRACK_BIT_LOWER; break;
02609 case TRACK_BIT_LOWER: tb = TRACK_BIT_UPPER; break;
02610 case TRACK_BIT_LEFT: tb = TRACK_BIT_RIGHT; break;
02611 case TRACK_BIT_RIGHT: tb = TRACK_BIT_LEFT; break;
02612 }
02613 return CombineTrackStatus(TrackBitsToTrackdirBits(tb), TRACKDIR_BIT_NONE);
02614 }
02615
02616 if (mode != TRANSPORT_RAIL) return 0;
02617
02618 TrackBits trackbits = TRACK_BIT_NONE;
02619 TrackdirBits red_signals = TRACKDIR_BIT_NONE;
02620
02621 switch (GetRailTileType(tile)) {
02622 default: NOT_REACHED();
02623 case RAIL_TILE_NORMAL:
02624 trackbits = GetTrackBits(tile);
02625 break;
02626
02627 case RAIL_TILE_SIGNALS: {
02628 trackbits = GetTrackBits(tile);
02629 byte a = GetPresentSignals(tile);
02630 uint b = GetSignalStates(tile);
02631
02632 b &= a;
02633
02634
02635
02636
02637
02638
02639 if (!IsOnewaySignal(tile, TRACK_UPPER) || (a & SignalOnTrack(TRACK_UPPER)) == 0) b |= ~a & SignalOnTrack(TRACK_UPPER);
02640 if (!IsOnewaySignal(tile, TRACK_LOWER) || (a & SignalOnTrack(TRACK_LOWER)) == 0) b |= ~a & SignalOnTrack(TRACK_LOWER);
02641
02642 if ((b & 0x8) == 0) red_signals |= (TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_X_NE | TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_UPPER_E);
02643 if ((b & 0x4) == 0) red_signals |= (TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_X_SW | TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_UPPER_W);
02644 if ((b & 0x2) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_LOWER_E);
02645 if ((b & 0x1) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_S | TRACKDIR_BIT_LOWER_W);
02646
02647 break;
02648 }
02649
02650 case RAIL_TILE_DEPOT: {
02651 DiagDirection dir = GetRailDepotDirection(tile);
02652
02653 if (side != INVALID_DIAGDIR && side != dir) break;
02654
02655 trackbits = DiagDirToDiagTrackBits(dir);
02656 break;
02657 }
02658 }
02659
02660 return CombineTrackStatus(TrackBitsToTrackdirBits(trackbits), red_signals);
02661 }
02662
02663 static bool ClickTile_Track(TileIndex tile)
02664 {
02665 if (!IsRailDepot(tile)) return false;
02666
02667 ShowDepotWindow(tile, VEH_TRAIN);
02668 return true;
02669 }
02670
02671 static void GetTileDesc_Track(TileIndex tile, TileDesc *td)
02672 {
02673 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(tile));
02674 td->rail_speed = rti->max_speed;
02675 td->owner[0] = GetTileOwner(tile);
02676 SetDParamX(td->dparam, 0, rti->strings.name);
02677 switch (GetRailTileType(tile)) {
02678 case RAIL_TILE_NORMAL:
02679 td->str = STR_LAI_RAIL_DESCRIPTION_TRACK;
02680 break;
02681
02682 case RAIL_TILE_SIGNALS: {
02683 static const StringID signal_type[6][6] = {
02684 {
02685 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS,
02686 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS,
02687 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS,
02688 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS,
02689 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS,
02690 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS
02691 },
02692 {
02693 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS,
02694 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRESIGNALS,
02695 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS,
02696 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS,
02697 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS,
02698 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS
02699 },
02700 {
02701 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS,
02702 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS,
02703 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXITSIGNALS,
02704 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS,
02705 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS,
02706 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS
02707 },
02708 {
02709 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS,
02710 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS,
02711 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS,
02712 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBOSIGNALS,
02713 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS,
02714 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS
02715 },
02716 {
02717 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS,
02718 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS,
02719 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS,
02720 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS,
02721 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBSSIGNALS,
02722 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS
02723 },
02724 {
02725 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS,
02726 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS,
02727 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS,
02728 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS,
02729 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS,
02730 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRYSIGNALS
02731 }
02732 };
02733
02734 SignalType primary_signal;
02735 SignalType secondary_signal;
02736 if (HasSignalOnTrack(tile, TRACK_UPPER)) {
02737 primary_signal = GetSignalType(tile, TRACK_UPPER);
02738 secondary_signal = HasSignalOnTrack(tile, TRACK_LOWER) ? GetSignalType(tile, TRACK_LOWER) : primary_signal;
02739 } else {
02740 secondary_signal = primary_signal = GetSignalType(tile, TRACK_LOWER);
02741 }
02742
02743 td->str = signal_type[secondary_signal][primary_signal];
02744 break;
02745 }
02746
02747 case RAIL_TILE_DEPOT:
02748 td->str = STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT;
02749 if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL) {
02750 if (td->rail_speed > 0) {
02751 td->rail_speed = min(td->rail_speed, 61);
02752 } else {
02753 td->rail_speed = 61;
02754 }
02755 }
02756 td->build_date = Depot::GetByTile(tile)->build_date;
02757 break;
02758
02759 default:
02760 NOT_REACHED();
02761 }
02762 }
02763
02764 static void ChangeTileOwner_Track(TileIndex tile, Owner old_owner, Owner new_owner)
02765 {
02766 if (!IsTileOwner(tile, old_owner)) return;
02767
02768 if (new_owner != INVALID_OWNER) {
02769
02770 uint num_pieces = 1;
02771 if (IsPlainRail(tile)) {
02772 TrackBits bits = GetTrackBits(tile);
02773 num_pieces = CountBits(bits);
02774 if (TracksOverlap(bits)) num_pieces *= num_pieces;
02775 }
02776 RailType rt = GetRailType(tile);
02777 Company::Get(old_owner)->infrastructure.rail[rt] -= num_pieces;
02778 Company::Get(new_owner)->infrastructure.rail[rt] += num_pieces;
02779
02780 if (HasSignals(tile)) {
02781 uint num_sigs = CountBits(GetPresentSignals(tile));
02782 Company::Get(old_owner)->infrastructure.signal -= num_sigs;
02783 Company::Get(new_owner)->infrastructure.signal += num_sigs;
02784 }
02785
02786 SetTileOwner(tile, new_owner);
02787 } else {
02788 DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
02789 }
02790 }
02791
02792 static const byte _fractcoords_behind[4] = { 0x8F, 0x8, 0x80, 0xF8 };
02793 static const byte _fractcoords_enter[4] = { 0x8A, 0x48, 0x84, 0xA8 };
02794 static const int8 _deltacoord_leaveoffset[8] = {
02795 -1, 0, 1, 0,
02796 0, 1, 0, -1
02797 };
02798
02799
02806 int TicksToLeaveDepot(const Train *v)
02807 {
02808 DiagDirection dir = GetRailDepotDirection(v->tile);
02809 int length = v->CalcNextVehicleOffset();
02810
02811 switch (dir) {
02812 case DIAGDIR_NE: return ((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) - (length + 1)));
02813 case DIAGDIR_SE: return -((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) + (length + 1)));
02814 case DIAGDIR_SW: return -((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) + (length + 1)));
02815 default:
02816 case DIAGDIR_NW: return ((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) - (length + 1)));
02817 }
02818
02819 return 0;
02820 }
02821
02826 static VehicleEnterTileStatus VehicleEnter_Track(Vehicle *u, TileIndex tile, int x, int y)
02827 {
02828
02829 if (u->type != VEH_TRAIN || !IsRailDepotTile(tile)) return VETSB_CONTINUE;
02830
02831 Train *v = Train::From(u);
02832
02833
02834 DiagDirection dir = GetRailDepotDirection(tile);
02835
02836
02837 int length = v->CalcNextVehicleOffset();
02838
02839 byte fract_coord_leave =
02840 ((_fractcoords_enter[dir] & 0x0F) +
02841 (length + 1) * _deltacoord_leaveoffset[dir]) +
02842 (((_fractcoords_enter[dir] >> 4) +
02843 ((length + 1) * _deltacoord_leaveoffset[dir + 4])) << 4);
02844
02845 byte fract_coord = (x & 0xF) + ((y & 0xF) << 4);
02846
02847 if (_fractcoords_behind[dir] == fract_coord) {
02848
02849 return VETSB_CANNOT_ENTER;
02850 } else if (_fractcoords_enter[dir] == fract_coord) {
02851 if (DiagDirToDir(ReverseDiagDir(dir)) == v->direction) {
02852
02853 v->track = TRACK_BIT_DEPOT,
02854 v->vehstatus |= VS_HIDDEN;
02855 v->direction = ReverseDir(v->direction);
02856 if (v->Next() == NULL) VehicleEnterDepot(v->First());
02857 v->tile = tile;
02858
02859 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
02860 return VETSB_ENTERED_WORMHOLE;
02861 }
02862 } else if (fract_coord_leave == fract_coord) {
02863 if (DiagDirToDir(dir) == v->direction) {
02864
02865 if ((v = v->Next()) != NULL) {
02866 v->vehstatus &= ~VS_HIDDEN;
02867 v->track = (DiagDirToAxis(dir) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y);
02868 }
02869 }
02870 }
02871
02872 return VETSB_CONTINUE;
02873 }
02874
02886 static CommandCost TestAutoslopeOnRailTile(TileIndex tile, uint flags, int z_old, Slope tileh_old, int z_new, Slope tileh_new, TrackBits rail_bits)
02887 {
02888 if (!_settings_game.construction.build_on_slopes || !AutoslopeEnabled()) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02889
02890
02891 if (CheckRailSlope(tileh_new, rail_bits, TRACK_BIT_NONE, tile).Failed()) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02892
02893
02894 z_old += ApplyFoundationToSlope(GetRailFoundation(tileh_old, rail_bits), &tileh_old);
02895 z_new += ApplyFoundationToSlope(GetRailFoundation(tileh_new, rail_bits), &tileh_new);
02896
02897 Corner track_corner;
02898 switch (rail_bits) {
02899 case TRACK_BIT_LEFT: track_corner = CORNER_W; break;
02900 case TRACK_BIT_LOWER: track_corner = CORNER_S; break;
02901 case TRACK_BIT_RIGHT: track_corner = CORNER_E; break;
02902 case TRACK_BIT_UPPER: track_corner = CORNER_N; break;
02903
02904
02905 default:
02906 if (z_old != z_new || tileh_old != tileh_new) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02907 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02908 }
02909
02910
02911 z_old += GetSlopeZInCorner(RemoveHalftileSlope(tileh_old), track_corner);
02912 z_new += GetSlopeZInCorner(RemoveHalftileSlope(tileh_new), track_corner);
02913 if (z_old != z_new) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02914
02915 CommandCost cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02916
02917 if (tileh_old != tileh_new) {
02918
02919 if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old)) cost.AddCost(_price[PR_CLEAR_WATER]);
02920 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
02921 }
02922 return cost;
02923 }
02924
02925 static CommandCost TerraformTile_Track(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new)
02926 {
02927 int z_old;
02928 Slope tileh_old = GetTileSlope(tile, &z_old);
02929 if (IsPlainRail(tile)) {
02930 TrackBits rail_bits = GetTrackBits(tile);
02931
02932 bool was_water = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old));
02933
02934
02935 CommandCost autoslope_result = TestAutoslopeOnRailTile(tile, flags, z_old, tileh_old, z_new, tileh_new, rail_bits);
02936
02937
02938 Corner allowed_corner;
02939 switch (rail_bits) {
02940 case TRACK_BIT_RIGHT: allowed_corner = CORNER_W; break;
02941 case TRACK_BIT_UPPER: allowed_corner = CORNER_S; break;
02942 case TRACK_BIT_LEFT: allowed_corner = CORNER_E; break;
02943 case TRACK_BIT_LOWER: allowed_corner = CORNER_N; break;
02944 default: return autoslope_result;
02945 }
02946
02947 Foundation f_old = GetRailFoundation(tileh_old, rail_bits);
02948
02949
02950 if (tileh_old != SLOPE_NS && tileh_old != SLOPE_EW && IsSpecialRailFoundation(f_old)) return autoslope_result;
02951
02952
02953 for (Corner corner = (Corner)0; corner < CORNER_END; corner = (Corner)(corner + 1)) {
02954 if (allowed_corner == corner) continue;
02955 if (z_old + GetSlopeZInCorner(tileh_old, corner) != z_new + GetSlopeZInCorner(tileh_new, corner)) return autoslope_result;
02956 }
02957
02958
02959 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
02960
02961
02962 return CommandCost(EXPENSES_CONSTRUCTION, was_water ? _price[PR_CLEAR_WATER] : (Money)0);
02963 } else if (_settings_game.construction.build_on_slopes && AutoslopeEnabled() &&
02964 AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetRailDepotDirection(tile))) {
02965 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02966 }
02967 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
02968 }
02969
02970
02971 extern const TileTypeProcs _tile_type_rail_procs = {
02972 DrawTile_Track,
02973 GetSlopePixelZ_Track,
02974 ClearTile_Track,
02975 NULL,
02976 GetTileDesc_Track,
02977 GetTileTrackStatus_Track,
02978 ClickTile_Track,
02979 NULL,
02980 TileLoop_Track,
02981 ChangeTileOwner_Track,
02982 NULL,
02983 VehicleEnter_Track,
02984 GetFoundation_Track,
02985 TerraformTile_Track,
02986 };