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 new (&rti->alternate_labels) RailTypeLabelList;
00105
00106
00107 rti->powered_railtypes = (RailTypes)(1 << rt);
00108 rti->compatible_railtypes = (RailTypes)(1 << rt);
00109
00110
00111 rti->introduces_railtypes = (RailTypes)(1 << rt);
00112
00113
00114
00115
00116
00117
00118
00119 rti->sorting_order = rt << 4 | 7;
00120 return rt;
00121 }
00122 }
00123
00124 return INVALID_RAILTYPE;
00125 }
00126
00127 static const byte _track_sloped_sprites[14] = {
00128 14, 15, 22, 13,
00129 0, 21, 17, 12,
00130 23, 0, 18, 20,
00131 19, 16
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
00163
00164
00165
00174 static CommandCost EnsureNoTrainOnTrack(TileIndex tile, Track track)
00175 {
00176 TrackBits rail_bits = TrackToTrackBits(track);
00177 return EnsureNoTrainOnTrackBits(tile, rail_bits);
00178 }
00179
00187 static CommandCost CheckTrackCombination(TileIndex tile, TrackBits to_build, uint flags)
00188 {
00189 if (!IsPlainRail(tile)) return_cmd_error(STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION);
00190
00191
00192
00193 TrackBits current = GetTrackBits(tile);
00194 TrackBits future = current | to_build;
00195
00196
00197 if (current == future) {
00198
00199 return_cmd_error(STR_ERROR_ALREADY_BUILT);
00200 }
00201
00202
00203 if ((flags & DC_NO_RAIL_OVERLAP) || HasSignals(tile)) {
00204
00205
00206 if (future != TRACK_BIT_HORZ && future != TRACK_BIT_VERT) {
00207 return_cmd_error((flags & DC_NO_RAIL_OVERLAP) ? STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION : STR_ERROR_MUST_REMOVE_SIGNALS_FIRST);
00208 }
00209 }
00210
00211 return CommandCost();
00212 }
00213
00214
00216 static const TrackBits _valid_tracks_without_foundation[15] = {
00217 TRACK_BIT_ALL,
00218 TRACK_BIT_RIGHT,
00219 TRACK_BIT_UPPER,
00220 TRACK_BIT_X,
00221
00222 TRACK_BIT_LEFT,
00223 TRACK_BIT_NONE,
00224 TRACK_BIT_Y,
00225 TRACK_BIT_LOWER,
00226
00227 TRACK_BIT_LOWER,
00228 TRACK_BIT_Y,
00229 TRACK_BIT_NONE,
00230 TRACK_BIT_LEFT,
00231
00232 TRACK_BIT_X,
00233 TRACK_BIT_UPPER,
00234 TRACK_BIT_RIGHT,
00235 };
00236
00238 static const TrackBits _valid_tracks_on_leveled_foundation[15] = {
00239 TRACK_BIT_NONE,
00240 TRACK_BIT_LEFT,
00241 TRACK_BIT_LOWER,
00242 TRACK_BIT_Y | TRACK_BIT_LOWER | TRACK_BIT_LEFT,
00243
00244 TRACK_BIT_RIGHT,
00245 TRACK_BIT_ALL,
00246 TRACK_BIT_X | TRACK_BIT_LOWER | TRACK_BIT_RIGHT,
00247 TRACK_BIT_ALL,
00248
00249 TRACK_BIT_UPPER,
00250 TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_LEFT,
00251 TRACK_BIT_ALL,
00252 TRACK_BIT_ALL,
00253
00254 TRACK_BIT_Y | TRACK_BIT_UPPER | TRACK_BIT_RIGHT,
00255 TRACK_BIT_ALL,
00256 TRACK_BIT_ALL
00257 };
00258
00266 Foundation GetRailFoundation(Slope tileh, TrackBits bits)
00267 {
00268 if (bits == TRACK_BIT_NONE) return FOUNDATION_NONE;
00269
00270 if (IsSteepSlope(tileh)) {
00271
00272 if (bits == TRACK_BIT_X) return FOUNDATION_INCLINED_X;
00273 if (bits == TRACK_BIT_Y) return FOUNDATION_INCLINED_Y;
00274
00275
00276 Corner highest_corner = GetHighestSlopeCorner(tileh);
00277 TrackBits higher_track = CornerToTrackBits(highest_corner);
00278
00279
00280 if (bits == higher_track) return HalftileFoundation(highest_corner);
00281
00282
00283 if (TracksOverlap(bits | higher_track)) return FOUNDATION_INVALID;
00284
00285
00286 return ((bits & higher_track) != 0 ? FOUNDATION_STEEP_BOTH : FOUNDATION_STEEP_LOWER);
00287 } else {
00288 if ((~_valid_tracks_without_foundation[tileh] & bits) == 0) return FOUNDATION_NONE;
00289
00290 bool valid_on_leveled = ((~_valid_tracks_on_leveled_foundation[tileh] & bits) == 0);
00291
00292 Corner track_corner;
00293 switch (bits) {
00294 case TRACK_BIT_LEFT: track_corner = CORNER_W; break;
00295 case TRACK_BIT_LOWER: track_corner = CORNER_S; break;
00296 case TRACK_BIT_RIGHT: track_corner = CORNER_E; break;
00297 case TRACK_BIT_UPPER: track_corner = CORNER_N; break;
00298
00299 case TRACK_BIT_HORZ:
00300 if (tileh == SLOPE_N) return HalftileFoundation(CORNER_N);
00301 if (tileh == SLOPE_S) return HalftileFoundation(CORNER_S);
00302 return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
00303
00304 case TRACK_BIT_VERT:
00305 if (tileh == SLOPE_W) return HalftileFoundation(CORNER_W);
00306 if (tileh == SLOPE_E) return HalftileFoundation(CORNER_E);
00307 return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
00308
00309 case TRACK_BIT_X:
00310 if (IsSlopeWithOneCornerRaised(tileh)) return FOUNDATION_INCLINED_X;
00311 return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
00312
00313 case TRACK_BIT_Y:
00314 if (IsSlopeWithOneCornerRaised(tileh)) return FOUNDATION_INCLINED_Y;
00315 return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
00316
00317 default:
00318 return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
00319 }
00320
00321
00322
00323 if (!valid_on_leveled) return FOUNDATION_INVALID;
00324
00325
00326 if (IsSlopeWithThreeCornersRaised(tileh)) return FOUNDATION_LEVELED;
00327
00328
00329 if ((tileh & SlopeWithThreeCornersRaised(OppositeCorner(track_corner))) == SlopeWithOneCornerRaised(track_corner)) return HalftileFoundation(track_corner);
00330
00331
00332 return SpecialRailFoundation(track_corner);
00333 }
00334 }
00335
00336
00346 static CommandCost CheckRailSlope(Slope tileh, TrackBits rail_bits, TrackBits existing, TileIndex tile)
00347 {
00348
00349 if (GetFloodingBehaviour(tile) != FLOOD_NONE) {
00350 if (!IsSteepSlope(tileh) && ((~_valid_tracks_on_leveled_foundation[tileh] & (rail_bits | existing)) != 0)) return_cmd_error(STR_ERROR_CAN_T_BUILD_ON_WATER);
00351 }
00352
00353 Foundation f_new = GetRailFoundation(tileh, rail_bits | existing);
00354
00355
00356 if ((f_new == FOUNDATION_INVALID) ||
00357 ((f_new != FOUNDATION_NONE) && (!_settings_game.construction.build_on_slopes))) {
00358 return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
00359 }
00360
00361 Foundation f_old = GetRailFoundation(tileh, existing);
00362 return CommandCost(EXPENSES_CONSTRUCTION, f_new != f_old ? _price[PR_BUILD_FOUNDATION] : (Money)0);
00363 }
00364
00365
00366 static inline bool ValParamTrackOrientation(Track track)
00367 {
00368 return IsValidTrack(track);
00369 }
00370
00380 CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00381 {
00382 RailType railtype = Extract<RailType, 0, 4>(p1);
00383 Track track = Extract<Track, 0, 3>(p2);
00384 CommandCost cost(EXPENSES_CONSTRUCTION);
00385
00386 if (!ValParamRailtype(railtype) || !ValParamTrackOrientation(track)) return CMD_ERROR;
00387
00388 Slope tileh = GetTileSlope(tile);
00389 TrackBits trackbit = TrackToTrackBits(track);
00390
00391 switch (GetTileType(tile)) {
00392 case MP_RAILWAY: {
00393 CommandCost ret = CheckTileOwnership(tile);
00394 if (ret.Failed()) return ret;
00395
00396 if (!IsPlainRail(tile)) return CMD_ERROR;
00397
00398 if (!IsCompatibleRail(GetRailType(tile), railtype)) return_cmd_error(STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION);
00399
00400 ret = CheckTrackCombination(tile, trackbit, flags);
00401 if (ret.Succeeded()) ret = EnsureNoTrainOnTrack(tile, track);
00402 if (ret.Failed()) return ret;
00403
00404 ret = CheckRailSlope(tileh, trackbit, GetTrackBits(tile), tile);
00405 if (ret.Failed()) return ret;
00406 cost.AddCost(ret);
00407
00408
00409
00410
00411 if (GetRailType(tile) != railtype && !HasPowerOnRail(railtype, GetRailType(tile))) {
00412 if (HasPowerOnRail(GetRailType(tile), railtype)) {
00413 ret = DoCommand(tile, tile, railtype, flags, CMD_CONVERT_RAIL);
00414 if (ret.Failed()) return ret;
00415 cost.AddCost(ret);
00416 } else {
00417 return CMD_ERROR;
00418 }
00419 }
00420
00421 if (flags & DC_EXEC) {
00422 SetRailGroundType(tile, RAIL_GROUND_BARREN);
00423 TrackBits bits = GetTrackBits(tile);
00424 SetTrackBits(tile, bits | trackbit);
00425
00426 uint pieces = CountBits(bits);
00427 if (TracksOverlap(bits)) pieces *= pieces;
00428 Company::Get(GetTileOwner(tile))->infrastructure.rail[GetRailType(tile)] -= pieces;
00429
00430 pieces = CountBits(bits | trackbit);
00431 if (TracksOverlap(bits | trackbit)) pieces *= pieces;
00432 Company::Get(GetTileOwner(tile))->infrastructure.rail[GetRailType(tile)] += pieces;
00433 DirtyCompanyInfrastructureWindows(GetTileOwner(tile));
00434 }
00435 break;
00436 }
00437
00438 case MP_ROAD: {
00439
00440 if (!HasBit(VALID_LEVEL_CROSSING_SLOPES, tileh)) return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
00441
00442 CommandCost ret = EnsureNoVehicleOnGround(tile);
00443 if (ret.Failed()) return ret;
00444
00445 if (IsNormalRoad(tile)) {
00446 if (HasRoadWorks(tile)) return_cmd_error(STR_ERROR_ROAD_WORKS_IN_PROGRESS);
00447
00448 if (GetDisallowedRoadDirections(tile) != DRD_NONE) return_cmd_error(STR_ERROR_CROSSING_ON_ONEWAY_ROAD);
00449
00450 if (RailNoLevelCrossings(railtype)) return_cmd_error(STR_ERROR_CROSSING_DISALLOWED);
00451
00452 RoadTypes roadtypes = GetRoadTypes(tile);
00453 RoadBits road = GetRoadBits(tile, ROADTYPE_ROAD);
00454 RoadBits tram = GetRoadBits(tile, ROADTYPE_TRAM);
00455 switch (roadtypes) {
00456 default: break;
00457 case ROADTYPES_TRAM:
00458
00459 if (flags & DC_EXEC) {
00460 SetRoadOwner(tile, ROADTYPE_ROAD, _current_company);
00461 Company *c = Company::GetIfValid(_current_company);
00462 if (c != NULL) {
00463
00464 c->infrastructure.road[ROADTYPE_ROAD] += 2;
00465 DirtyCompanyInfrastructureWindows(c->index);
00466 }
00467 }
00468 roadtypes |= ROADTYPES_ROAD;
00469 break;
00470
00471 case ROADTYPES_ALL:
00472 if (road != tram) return CMD_ERROR;
00473 break;
00474 }
00475
00476 road |= tram;
00477
00478 if ((track == TRACK_X && road == ROAD_Y) ||
00479 (track == TRACK_Y && road == ROAD_X)) {
00480 if (flags & DC_EXEC) {
00481 MakeRoadCrossing(tile, GetRoadOwner(tile, ROADTYPE_ROAD), GetRoadOwner(tile, ROADTYPE_TRAM), _current_company, (track == TRACK_X ? AXIS_Y : AXIS_X), railtype, roadtypes, GetTownIndex(tile));
00482 UpdateLevelCrossing(tile, false);
00483 Company::Get(_current_company)->infrastructure.rail[railtype] += LEVELCROSSING_TRACKBIT_FACTOR;
00484 DirtyCompanyInfrastructureWindows(_current_company);
00485 }
00486 break;
00487 }
00488 }
00489
00490 if (IsLevelCrossing(tile) && GetCrossingRailBits(tile) == trackbit) {
00491 return_cmd_error(STR_ERROR_ALREADY_BUILT);
00492 }
00493
00494 }
00495
00496 default: {
00497
00498 bool water_ground = IsTileType(tile, MP_WATER) && IsSlopeWithOneCornerRaised(tileh);
00499
00500 CommandCost ret = CheckRailSlope(tileh, trackbit, TRACK_BIT_NONE, tile);
00501 if (ret.Failed()) return ret;
00502 cost.AddCost(ret);
00503
00504 ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00505 if (ret.Failed()) return ret;
00506 cost.AddCost(ret);
00507
00508 if (water_ground) {
00509 cost.AddCost(-_price[PR_CLEAR_WATER]);
00510 cost.AddCost(_price[PR_CLEAR_ROUGH]);
00511 }
00512
00513 if (flags & DC_EXEC) {
00514 MakeRailNormal(tile, _current_company, trackbit, railtype);
00515 if (water_ground) SetRailGroundType(tile, RAIL_GROUND_WATER);
00516 Company::Get(_current_company)->infrastructure.rail[railtype]++;
00517 DirtyCompanyInfrastructureWindows(_current_company);
00518 }
00519 break;
00520 }
00521 }
00522
00523 if (flags & DC_EXEC) {
00524 MarkTileDirtyByTile(tile);
00525 AddTrackToSignalBuffer(tile, track, _current_company);
00526 YapfNotifyTrackLayoutChange(tile, track);
00527 }
00528
00529 cost.AddCost(RailBuildCost(railtype));
00530 return cost;
00531 }
00532
00542 CommandCost CmdRemoveSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00543 {
00544 Track track = Extract<Track, 0, 3>(p2);
00545 CommandCost cost(EXPENSES_CONSTRUCTION);
00546 bool crossing = false;
00547
00548 if (!ValParamTrackOrientation(track)) return CMD_ERROR;
00549 TrackBits trackbit = TrackToTrackBits(track);
00550
00551
00552
00553
00554
00555 Owner owner = INVALID_OWNER;
00556
00557 Train *v = NULL;
00558
00559 switch (GetTileType(tile)) {
00560 case MP_ROAD: {
00561 if (!IsLevelCrossing(tile) || GetCrossingRailBits(tile) != trackbit) return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
00562
00563 if (_current_company != OWNER_WATER) {
00564 CommandCost ret = CheckTileOwnership(tile);
00565 if (ret.Failed()) return ret;
00566 }
00567
00568 if (!(flags & DC_BANKRUPT)) {
00569 CommandCost ret = EnsureNoVehicleOnGround(tile);
00570 if (ret.Failed()) return ret;
00571 }
00572
00573 cost.AddCost(RailClearCost(GetRailType(tile)));
00574
00575 if (flags & DC_EXEC) {
00576 if (HasReservedTracks(tile, trackbit)) {
00577 v = GetTrainForReservation(tile, track);
00578 if (v != NULL) FreeTrainTrackReservation(v);
00579 }
00580 owner = GetTileOwner(tile);
00581 Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= LEVELCROSSING_TRACKBIT_FACTOR;
00582 DirtyCompanyInfrastructureWindows(owner);
00583 MakeRoadNormal(tile, GetCrossingRoadBits(tile), GetRoadTypes(tile), GetTownIndex(tile), GetRoadOwner(tile, ROADTYPE_ROAD), GetRoadOwner(tile, ROADTYPE_TRAM));
00584 DeleteNewGRFInspectWindow(GSF_RAILTYPES, tile);
00585 }
00586 break;
00587 }
00588
00589 case MP_RAILWAY: {
00590 TrackBits present;
00591
00592 if (!IsPlainRail(tile)) return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
00593
00594 if (_current_company != OWNER_WATER) {
00595 CommandCost ret = CheckTileOwnership(tile);
00596 if (ret.Failed()) return ret;
00597 }
00598
00599 CommandCost ret = EnsureNoTrainOnTrack(tile, track);
00600 if (ret.Failed()) return ret;
00601
00602 present = GetTrackBits(tile);
00603 if ((present & trackbit) == 0) return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
00604 if (present == (TRACK_BIT_X | TRACK_BIT_Y)) crossing = true;
00605
00606 cost.AddCost(RailClearCost(GetRailType(tile)));
00607
00608
00609 if (HasSignalOnTrack(tile, track)) {
00610 cost.AddCost(DoCommand(tile, track, 0, flags, CMD_REMOVE_SIGNALS));
00611 }
00612
00613 if (flags & DC_EXEC) {
00614 if (HasReservedTracks(tile, trackbit)) {
00615 v = GetTrainForReservation(tile, track);
00616 if (v != NULL) FreeTrainTrackReservation(v);
00617 }
00618
00619 owner = GetTileOwner(tile);
00620
00621
00622 uint pieces = CountBits(present);
00623 if (TracksOverlap(present)) pieces *= pieces;
00624 Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= pieces;
00625
00626 present ^= trackbit;
00627 pieces = CountBits(present);
00628 if (TracksOverlap(present)) pieces *= pieces;
00629 Company::Get(owner)->infrastructure.rail[GetRailType(tile)] += pieces;
00630 DirtyCompanyInfrastructureWindows(owner);
00631
00632 if (present == 0) {
00633 Slope tileh = GetTileSlope(tile);
00634
00635 if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh)) {
00636 MakeShore(tile);
00637 } else {
00638 DoClearSquare(tile);
00639 }
00640 DeleteNewGRFInspectWindow(GSF_RAILTYPES, tile);
00641 } else {
00642 SetTrackBits(tile, present);
00643 SetTrackReservation(tile, GetRailReservationTrackBits(tile) & present);
00644 }
00645 }
00646 break;
00647 }
00648
00649 default: return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
00650 }
00651
00652 if (flags & DC_EXEC) {
00653
00654 assert(Company::IsValidID(owner));
00655
00656 MarkTileDirtyByTile(tile);
00657 if (crossing) {
00658
00659
00660
00661
00662 AddTrackToSignalBuffer(tile, TRACK_X, owner);
00663 AddTrackToSignalBuffer(tile, TRACK_Y, owner);
00664 YapfNotifyTrackLayoutChange(tile, TRACK_X);
00665 YapfNotifyTrackLayoutChange(tile, TRACK_Y);
00666 } else {
00667 AddTrackToSignalBuffer(tile, track, owner);
00668 YapfNotifyTrackLayoutChange(tile, track);
00669 }
00670
00671 if (v != NULL) TryPathReserve(v, true);
00672 }
00673
00674 return cost;
00675 }
00676
00677
00685 bool FloodHalftile(TileIndex t)
00686 {
00687 assert(IsPlainRailTile(t));
00688
00689 bool flooded = false;
00690 if (GetRailGroundType(t) == RAIL_GROUND_WATER) return flooded;
00691
00692 Slope tileh = GetTileSlope(t);
00693 TrackBits rail_bits = GetTrackBits(t);
00694
00695 if (IsSlopeWithOneCornerRaised(tileh)) {
00696 TrackBits lower_track = CornerToTrackBits(OppositeCorner(GetHighestSlopeCorner(tileh)));
00697
00698 TrackBits to_remove = lower_track & rail_bits;
00699 if (to_remove != 0) {
00700 Backup<CompanyByte> cur_company(_current_company, OWNER_WATER, FILE_LINE);
00701 flooded = DoCommand(t, 0, FIND_FIRST_BIT(to_remove), DC_EXEC, CMD_REMOVE_SINGLE_RAIL).Succeeded();
00702 cur_company.Restore();
00703 if (!flooded) return flooded;
00704 rail_bits = rail_bits & ~to_remove;
00705 if (rail_bits == 0) {
00706 MakeShore(t);
00707 MarkTileDirtyByTile(t);
00708 return flooded;
00709 }
00710 }
00711
00712 if (IsNonContinuousFoundation(GetRailFoundation(tileh, rail_bits))) {
00713 flooded = true;
00714 SetRailGroundType(t, RAIL_GROUND_WATER);
00715 MarkTileDirtyByTile(t);
00716 }
00717 } else {
00718
00719 if (ApplyFoundationToSlope(GetRailFoundation(tileh, rail_bits), &tileh) == 0) {
00720 if (IsSteepSlope(tileh) || IsSlopeWithThreeCornersRaised(tileh)) {
00721 flooded = true;
00722 SetRailGroundType(t, RAIL_GROUND_WATER);
00723 MarkTileDirtyByTile(t);
00724 }
00725 }
00726 }
00727 return flooded;
00728 }
00729
00730 static const TileIndexDiffC _trackdelta[] = {
00731 { -1, 0 }, { 0, 1 }, { -1, 0 }, { 0, 1 }, { 1, 0 }, { 0, 1 },
00732 { 0, 0 },
00733 { 0, 0 },
00734 { 1, 0 }, { 0, -1 }, { 0, -1 }, { 1, 0 }, { 0, -1 }, { -1, 0 },
00735 { 0, 0 },
00736 { 0, 0 }
00737 };
00738
00739
00740 static CommandCost ValidateAutoDrag(Trackdir *trackdir, TileIndex start, TileIndex end)
00741 {
00742 int x = TileX(start);
00743 int y = TileY(start);
00744 int ex = TileX(end);
00745 int ey = TileY(end);
00746
00747 if (!ValParamTrackOrientation(TrackdirToTrack(*trackdir))) return CMD_ERROR;
00748
00749
00750 int dx = ex - x;
00751 int dy = ey - y;
00752
00753
00754 int trdx = _trackdelta[*trackdir].x;
00755 int trdy = _trackdelta[*trackdir].y;
00756
00757 if (!IsDiagonalTrackdir(*trackdir)) {
00758 trdx += _trackdelta[*trackdir ^ 1].x;
00759 trdy += _trackdelta[*trackdir ^ 1].y;
00760 }
00761
00762
00763 while ((trdx <= 0 && dx > 0) ||
00764 (trdx >= 0 && dx < 0) ||
00765 (trdy <= 0 && dy > 0) ||
00766 (trdy >= 0 && dy < 0)) {
00767 if (!HasBit(*trackdir, 3)) {
00768 SetBit(*trackdir, 3);
00769 trdx = -trdx;
00770 trdy = -trdy;
00771 } else {
00772 return CMD_ERROR;
00773 }
00774 }
00775
00776
00777
00778 if (!IsDiagonalTrackdir(*trackdir)) {
00779 trdx = _trackdelta[*trackdir].x;
00780 trdy = _trackdelta[*trackdir].y;
00781 if (abs(dx) != abs(dy) && abs(dx) + abs(trdy) != abs(dy) + abs(trdx)) return CMD_ERROR;
00782 }
00783
00784 return CommandCost();
00785 }
00786
00800 static CommandCost CmdRailTrackHelper(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00801 {
00802 CommandCost total_cost(EXPENSES_CONSTRUCTION);
00803 Track track = Extract<Track, 4, 3>(p2);
00804 bool remove = HasBit(p2, 7);
00805 RailType railtype = Extract<RailType, 0, 4>(p2);
00806
00807 if (!ValParamRailtype(railtype) || !ValParamTrackOrientation(track)) return CMD_ERROR;
00808 if (p1 >= MapSize()) return CMD_ERROR;
00809 TileIndex end_tile = p1;
00810 Trackdir trackdir = TrackToTrackdir(track);
00811
00812 CommandCost ret = ValidateAutoDrag(&trackdir, tile, end_tile);
00813 if (ret.Failed()) return ret;
00814
00815 if (flags & DC_EXEC) SndPlayTileFx(SND_20_SPLAT_2, tile);
00816
00817 bool had_success = false;
00818 CommandCost last_error = CMD_ERROR;
00819 for (;;) {
00820 CommandCost ret = DoCommand(tile, railtype, TrackdirToTrack(trackdir), flags, remove ? CMD_REMOVE_SINGLE_RAIL : CMD_BUILD_SINGLE_RAIL);
00821
00822 if (ret.Failed()) {
00823 last_error = ret;
00824 if (last_error.GetErrorMessage() != STR_ERROR_ALREADY_BUILT && !remove) {
00825 if (HasBit(p2, 8)) return last_error;
00826 break;
00827 }
00828
00829
00830 if (last_error.GetErrorMessage() == STR_ERROR_OWNED_BY && remove) break;
00831 } else {
00832 had_success = true;
00833 total_cost.AddCost(ret);
00834 }
00835
00836 if (tile == end_tile) break;
00837
00838 tile += ToTileIndexDiff(_trackdelta[trackdir]);
00839
00840
00841 if (!IsDiagonalTrackdir(trackdir)) ToggleBit(trackdir, 0);
00842 }
00843
00844 if (had_success) return total_cost;
00845 return last_error;
00846 }
00847
00862 CommandCost CmdBuildRailroadTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00863 {
00864 return CmdRailTrackHelper(tile, flags, p1, ClrBit(p2, 7), text);
00865 }
00866
00881 CommandCost CmdRemoveRailroadTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00882 {
00883 return CmdRailTrackHelper(tile, flags, p1, SetBit(p2, 7), text);
00884 }
00885
00898 CommandCost CmdBuildTrainDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00899 {
00900
00901 RailType railtype = Extract<RailType, 0, 4>(p1);
00902 if (!ValParamRailtype(railtype)) return CMD_ERROR;
00903
00904 Slope tileh = GetTileSlope(tile);
00905
00906 DiagDirection dir = Extract<DiagDirection, 0, 2>(p2);
00907
00908
00909
00910
00911
00912
00913
00914
00915 if (tileh != SLOPE_FLAT && (
00916 !_settings_game.construction.build_on_slopes ||
00917 !CanBuildDepotByTileh(dir, tileh)
00918 )) {
00919 return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
00920 }
00921
00922 CommandCost cost = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00923 if (cost.Failed()) return cost;
00924
00925 if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
00926
00927 if (!Depot::CanAllocateItem()) return CMD_ERROR;
00928
00929 if (flags & DC_EXEC) {
00930 Depot *d = new Depot(tile);
00931 d->build_date = _date;
00932
00933 MakeRailDepot(tile, _current_company, d->index, dir, railtype);
00934 MarkTileDirtyByTile(tile);
00935 MakeDefaultName(d);
00936
00937 Company::Get(_current_company)->infrastructure.rail[railtype]++;
00938 DirtyCompanyInfrastructureWindows(_current_company);
00939
00940 AddSideToSignalBuffer(tile, INVALID_DIAGDIR, _current_company);
00941 YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
00942 }
00943
00944 cost.AddCost(_price[PR_BUILD_DEPOT_TRAIN]);
00945 cost.AddCost(RailBuildCost(railtype));
00946 return cost;
00947 }
00948
00970 CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00971 {
00972 Track track = Extract<Track, 0, 3>(p1);
00973 bool ctrl_pressed = HasBit(p1, 3);
00974 SignalVariant sigvar = (ctrl_pressed ^ HasBit(p1, 4)) ? SIG_SEMAPHORE : SIG_ELECTRIC;
00975 SignalType sigtype = Extract<SignalType, 5, 3>(p1);
00976 bool convert_signal = HasBit(p1, 8);
00977 SignalType cycle_start = Extract<SignalType, 9, 3>(p1);
00978 SignalType cycle_stop = Extract<SignalType, 12, 3>(p1);
00979 uint num_dir_cycle = GB(p1, 15, 2);
00980
00981 if (sigtype > SIGTYPE_LAST) return CMD_ERROR;
00982 if (cycle_start > cycle_stop || cycle_stop > SIGTYPE_LAST) return CMD_ERROR;
00983
00984
00985 if (!ValParamTrackOrientation(track) || !IsPlainRailTile(tile) ||
00986 !HasTrack(tile, track)) {
00987 return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
00988 }
00989
00990 if (p2 != 0 && (p2 & SignalOnTrack(track)) == 0) return CMD_ERROR;
00991
00992 CommandCost 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
01203 static CommandCost CmdSignalTrackHelper(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01204 {
01205 CommandCost total_cost(EXPENSES_CONSTRUCTION);
01206 TileIndex start_tile = tile;
01207
01208 Track track = Extract<Track, 0, 3>(p2);
01209 bool mode = HasBit(p2, 3);
01210 bool semaphores = HasBit(p2, 4);
01211 bool remove = HasBit(p2, 5);
01212 bool autofill = HasBit(p2, 6);
01213 bool minimise_gaps = HasBit(p2, 10);
01214 byte signal_density = GB(p2, 24, 8);
01215
01216 if (p1 >= MapSize() || !ValParamTrackOrientation(track)) return CMD_ERROR;
01217 TileIndex end_tile = p1;
01218 if (signal_density == 0 || signal_density > 20) return CMD_ERROR;
01219
01220 if (!IsPlainRailTile(tile)) return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
01221
01222
01223
01224 signal_density *= 2;
01225
01226 Trackdir trackdir = TrackToTrackdir(track);
01227 CommandCost ret = ValidateAutoDrag(&trackdir, tile, end_tile);
01228 if (ret.Failed()) return ret;
01229
01230 track = TrackdirToTrack(trackdir);
01231 Trackdir start_trackdir = trackdir;
01232
01233
01234 if (!HasTrack(tile, track)) return CMD_ERROR;
01235
01236 SignalType sigtype = (SignalType)GB(p2, 7, 3);
01237 if (sigtype > SIGTYPE_LAST) return CMD_ERROR;
01238
01239 byte signals;
01240
01241 if (HasSignalOnTrack(tile, track)) {
01242 signals = GetPresentSignals(tile) & SignalOnTrack(track);
01243 assert(signals != 0);
01244
01245
01246 semaphores = GetSignalVariant(tile, track) != SIG_ELECTRIC;
01247
01248 sigtype = GetSignalType(tile, track);
01249
01250 if (sigtype == SIGTYPE_ENTRY || sigtype == SIGTYPE_EXIT) sigtype = SIGTYPE_NORMAL;
01251 } else {
01252 signals = IsPbsSignal(sigtype) ? SignalAlongTrackdir(trackdir) : SignalOnTrack(track);
01253 }
01254
01255 byte signal_dir = 0;
01256 if (signals & SignalAlongTrackdir(trackdir)) SetBit(signal_dir, 0);
01257 if (signals & SignalAgainstTrackdir(trackdir)) SetBit(signal_dir, 1);
01258
01259
01260
01261
01262
01263
01264
01265
01266
01267
01268
01269
01270
01271 int signal_ctr = 0;
01272 int last_used_ctr = INT_MIN;
01273 int last_suitable_ctr = 0;
01274 TileIndex last_suitable_tile = INVALID_TILE;
01275 Trackdir last_suitable_trackdir = INVALID_TRACKDIR;
01276 CommandCost last_error = CMD_ERROR;
01277 bool had_success = false;
01278 for (;;) {
01279
01280 if (remove || minimise_gaps || signal_ctr % signal_density == 0) {
01281 uint32 p1 = GB(TrackdirToTrack(trackdir), 0, 3);
01282 SB(p1, 3, 1, mode);
01283 SB(p1, 4, 1, semaphores);
01284 SB(p1, 5, 3, sigtype);
01285 if (!remove && signal_ctr == 0) SetBit(p1, 17);
01286
01287
01288 signals = 0;
01289 if (HasBit(signal_dir, 0)) signals |= SignalAlongTrackdir(trackdir);
01290 if (HasBit(signal_dir, 1)) signals |= SignalAgainstTrackdir(trackdir);
01291
01292
01293 bool test_only = minimise_gaps && signal_ctr < (last_used_ctr + signal_density);
01294 CommandCost ret = DoCommand(tile, p1, signals, test_only ? flags & ~DC_EXEC : flags, remove ? CMD_REMOVE_SIGNALS : CMD_BUILD_SIGNALS);
01295
01296 if (ret.Succeeded()) {
01297
01298 last_suitable_ctr = signal_ctr;
01299 last_suitable_tile = tile;
01300 last_suitable_trackdir = trackdir;
01301 } else if (!test_only && last_suitable_tile != INVALID_TILE) {
01302
01303 SB(p1, 0, 3, TrackdirToTrack(last_suitable_trackdir));
01304 ClrBit(p1, 17);
01305
01306
01307 signals = 0;
01308 if (HasBit(signal_dir, 0)) signals |= SignalAlongTrackdir(last_suitable_trackdir);
01309 if (HasBit(signal_dir, 1)) signals |= SignalAgainstTrackdir(last_suitable_trackdir);
01310
01311 ret = DoCommand(last_suitable_tile, p1, signals, flags, remove ? CMD_REMOVE_SIGNALS : CMD_BUILD_SIGNALS);
01312 }
01313
01314
01315 if (!test_only) {
01316
01317 if (ret.Succeeded()) {
01318 had_success = true;
01319 total_cost.AddCost(ret);
01320 last_used_ctr = last_suitable_ctr;
01321 last_suitable_tile = INVALID_TILE;
01322 } else {
01323
01324 if (ret.GetErrorMessage() != STR_ERROR_THERE_IS_NO_RAILROAD_TRACK ||
01325 last_error.GetErrorMessage() == INVALID_STRING_ID) {
01326 last_error = ret;
01327 }
01328 }
01329 }
01330 }
01331
01332 if (autofill) {
01333 if (!CheckSignalAutoFill(tile, trackdir, signal_ctr, remove)) break;
01334
01335
01336 if (tile == start_tile && trackdir == start_trackdir) break;
01337 } else {
01338 if (tile == end_tile) break;
01339
01340 tile += ToTileIndexDiff(_trackdelta[trackdir]);
01341 signal_ctr++;
01342
01343
01344 if (IsDiagonalTrackdir(trackdir)) {
01345 signal_ctr++;
01346 } else {
01347 ToggleBit(trackdir, 0);
01348 }
01349 }
01350 }
01351
01352 return had_success ? total_cost : last_error;
01353 }
01354
01373 CommandCost CmdBuildSignalTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01374 {
01375 return CmdSignalTrackHelper(tile, flags, p1, p2, text);
01376 }
01377
01390 CommandCost CmdRemoveSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01391 {
01392 Track track = Extract<Track, 0, 3>(p1);
01393
01394 if (!ValParamTrackOrientation(track) || !IsPlainRailTile(tile) || !HasTrack(tile, track)) {
01395 return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
01396 }
01397 if (!HasSignalOnTrack(tile, track)) {
01398 return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS);
01399 }
01400
01401
01402 if (_current_company != OWNER_WATER) {
01403 CommandCost ret = CheckTileOwnership(tile);
01404 if (ret.Failed()) return ret;
01405 }
01406
01407
01408 if (flags & DC_EXEC) {
01409 Train *v = NULL;
01410 if (HasReservedTracks(tile, TrackToTrackBits(track))) {
01411 v = GetTrainForReservation(tile, track);
01412 } else if (IsPbsSignal(GetSignalType(tile, track))) {
01413
01414 Trackdir td = TrackToTrackdir(track);
01415 for (int i = 0; v == NULL && i < 2; i++, td = ReverseTrackdir(td)) {
01416
01417 if (!HasSignalOnTrackdir(tile, ReverseTrackdir(td))) continue;
01418 TileIndex next = TileAddByDiagDir(tile, TrackdirToExitdir(td));
01419 TrackBits tracks = TrackdirBitsToTrackBits(TrackdirReachesTrackdirs(td));
01420 if (HasReservedTracks(next, tracks)) {
01421 v = GetTrainForReservation(next, TrackBitsToTrack(GetReservedTrackbits(next) & tracks));
01422 }
01423 }
01424 }
01425 Company::Get(GetTileOwner(tile))->infrastructure.signal -= CountBits(GetPresentSignals(tile));
01426 SetPresentSignals(tile, GetPresentSignals(tile) & ~SignalOnTrack(track));
01427 Company::Get(GetTileOwner(tile))->infrastructure.signal += CountBits(GetPresentSignals(tile));
01428 DirtyCompanyInfrastructureWindows(GetTileOwner(tile));
01429
01430
01431 if (GetPresentSignals(tile) == 0) {
01432 SetSignalStates(tile, 0);
01433 SetHasSignals(tile, false);
01434 SetSignalVariant(tile, INVALID_TRACK, SIG_ELECTRIC);
01435 }
01436
01437 AddTrackToSignalBuffer(tile, track, GetTileOwner(tile));
01438 YapfNotifyTrackLayoutChange(tile, track);
01439 if (v != NULL) TryPathReserve(v, false);
01440
01441 MarkTileDirtyByTile(tile);
01442 }
01443
01444 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_SIGNALS]);
01445 }
01446
01465 CommandCost CmdRemoveSignalTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01466 {
01467 return CmdSignalTrackHelper(tile, flags, p1, SetBit(p2, 5), text);
01468 }
01469
01471 static Vehicle *UpdateTrainPowerProc(Vehicle *v, void *data)
01472 {
01473 if (v->type != VEH_TRAIN) return NULL;
01474
01475 TrainList *affected_trains = static_cast<TrainList*>(data);
01476 affected_trains->Include(Train::From(v)->First());
01477
01478 return NULL;
01479 }
01480
01493 CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01494 {
01495 RailType totype = Extract<RailType, 0, 4>(p2);
01496
01497 if (!ValParamRailtype(totype)) return CMD_ERROR;
01498 if (p1 >= MapSize()) return CMD_ERROR;
01499
01500 TrainList affected_trains;
01501
01502 CommandCost cost(EXPENSES_CONSTRUCTION);
01503 CommandCost error = CommandCost(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK);
01504 TileArea ta(tile, p1);
01505 TileIterator *iter = HasBit(p2, 4) ? (TileIterator *)new DiagonalTileIterator(tile, p1) : new OrthogonalTileIterator(ta);
01506 for (; (tile = *iter) != INVALID_TILE; ++(*iter)) {
01507 TileType tt = GetTileType(tile);
01508
01509
01510 switch (tt) {
01511 case MP_RAILWAY:
01512 break;
01513 case MP_STATION:
01514 if (!HasStationRail(tile)) continue;
01515 break;
01516 case MP_ROAD:
01517 if (!IsLevelCrossing(tile)) continue;
01518 if (RailNoLevelCrossings(totype)) {
01519 error.MakeError(STR_ERROR_CROSSING_DISALLOWED);
01520 continue;
01521 }
01522 break;
01523 case MP_TUNNELBRIDGE:
01524 if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) continue;
01525 break;
01526 default: continue;
01527 }
01528
01529
01530 RailType type = GetRailType(tile);
01531
01532
01533 if (type == totype || (_settings_game.vehicle.disable_elrails && totype == RAILTYPE_RAIL && type == RAILTYPE_ELECTRIC)) continue;
01534
01535
01536 CommandCost ret = CheckTileOwnership(tile);
01537 if (ret.Failed()) {
01538 error = ret;
01539 continue;
01540 }
01541
01542 SmallVector<Train *, 2> vehicles_affected;
01543
01544
01545
01546 if (tt != MP_TUNNELBRIDGE) {
01547 if (!IsCompatibleRail(type, totype)) {
01548 CommandCost ret = EnsureNoVehicleOnGround(tile);
01549 if (ret.Failed()) {
01550 error = ret;
01551 continue;
01552 }
01553 }
01554 if (flags & DC_EXEC) {
01555 TrackBits reserved = GetReservedTrackbits(tile);
01556 Track track;
01557 while ((track = RemoveFirstTrack(&reserved)) != INVALID_TRACK) {
01558 Train *v = GetTrainForReservation(tile, track);
01559 if (v != NULL && !HasPowerOnRail(v->railtype, totype)) {
01560
01561 FreeTrainTrackReservation(v);
01562 *vehicles_affected.Append() = v;
01563 }
01564 }
01565
01566
01567 if (!IsRailStationTile(tile) || !IsStationTileBlocked(tile)) {
01568 Company *c = Company::Get(GetTileOwner(tile));
01569 uint num_pieces = IsLevelCrossingTile(tile) ? LEVELCROSSING_TRACKBIT_FACTOR : 1;
01570 if (IsPlainRailTile(tile)) {
01571 TrackBits bits = GetTrackBits(tile);
01572 num_pieces = CountBits(bits);
01573 if (TracksOverlap(bits)) num_pieces *= num_pieces;
01574 }
01575 c->infrastructure.rail[type] -= num_pieces;
01576 c->infrastructure.rail[totype] += num_pieces;
01577 DirtyCompanyInfrastructureWindows(c->index);
01578 }
01579
01580 SetRailType(tile, totype);
01581 MarkTileDirtyByTile(tile);
01582
01583 FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc);
01584 }
01585 }
01586
01587 switch (tt) {
01588 case MP_RAILWAY:
01589 switch (GetRailTileType(tile)) {
01590 case RAIL_TILE_DEPOT:
01591 if (flags & DC_EXEC) {
01592
01593 YapfNotifyTrackLayoutChange(tile, GetRailDepotTrack(tile));
01594
01595
01596 InvalidateWindowData(WC_VEHICLE_DEPOT, tile);
01597 InvalidateWindowData(WC_BUILD_VEHICLE, tile);
01598 }
01599 cost.AddCost(RailConvertCost(type, totype));
01600 break;
01601
01602 default:
01603 if (flags & DC_EXEC) {
01604
01605 TrackBits tracks = GetTrackBits(tile);
01606 while (tracks != TRACK_BIT_NONE) {
01607 YapfNotifyTrackLayoutChange(tile, RemoveFirstTrack(&tracks));
01608 }
01609 }
01610 cost.AddCost(RailConvertCost(type, totype) * CountBits(GetTrackBits(tile)));
01611 break;
01612 }
01613 break;
01614
01615 case MP_TUNNELBRIDGE: {
01616 TileIndex endtile = GetOtherTunnelBridgeEnd(tile);
01617
01618
01619
01620 if (endtile < tile && TileX(endtile) >= TileX(ta.tile) && TileX(endtile) < TileX(ta.tile) + ta.w &&
01621 TileY(endtile) >= TileY(ta.tile) && TileY(endtile) < TileY(ta.tile) + ta.h) continue;
01622
01623
01624 if (!IsCompatibleRail(GetRailType(tile), totype)) {
01625 CommandCost ret = TunnelBridgeIsFree(tile, endtile);
01626 if (ret.Failed()) {
01627 error = ret;
01628 continue;
01629 }
01630 }
01631
01632 if (flags & DC_EXEC) {
01633 Track track = DiagDirToDiagTrack(GetTunnelBridgeDirection(tile));
01634 if (HasTunnelBridgeReservation(tile)) {
01635 Train *v = GetTrainForReservation(tile, track);
01636 if (v != NULL && !HasPowerOnRail(v->railtype, totype)) {
01637
01638 FreeTrainTrackReservation(v);
01639 *vehicles_affected.Append() = v;
01640 }
01641 }
01642
01643
01644 uint num_pieces = (GetTunnelBridgeLength(tile, endtile) + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR;
01645 Company *c = Company::Get(GetTileOwner(tile));
01646 c->infrastructure.rail[GetRailType(tile)] -= num_pieces;
01647 c->infrastructure.rail[totype] += num_pieces;
01648 DirtyCompanyInfrastructureWindows(c->index);
01649
01650 SetRailType(tile, totype);
01651 SetRailType(endtile, totype);
01652
01653 FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc);
01654 FindVehicleOnPos(endtile, &affected_trains, &UpdateTrainPowerProc);
01655
01656 YapfNotifyTrackLayoutChange(tile, track);
01657 YapfNotifyTrackLayoutChange(endtile, track);
01658
01659 MarkTileDirtyByTile(tile);
01660 MarkTileDirtyByTile(endtile);
01661
01662 if (IsBridge(tile)) {
01663 TileIndexDiff delta = TileOffsByDiagDir(GetTunnelBridgeDirection(tile));
01664 TileIndex t = tile + delta;
01665 for (; t != endtile; t += delta) MarkTileDirtyByTile(t);
01666 }
01667 }
01668
01669 cost.AddCost((GetTunnelBridgeLength(tile, endtile) + 2) * RailConvertCost(type, totype));
01670 break;
01671 }
01672
01673 default:
01674 if (flags & DC_EXEC) {
01675 Track track = ((tt == MP_STATION) ? GetRailStationTrack(tile) : GetCrossingRailTrack(tile));
01676 YapfNotifyTrackLayoutChange(tile, track);
01677 }
01678
01679 cost.AddCost(RailConvertCost(type, totype));
01680 break;
01681 }
01682
01683 for (uint i = 0; i < vehicles_affected.Length(); ++i) {
01684 TryPathReserve(vehicles_affected[i], true);
01685 }
01686 }
01687
01688 if (flags & DC_EXEC) {
01689
01690 for (Train **v = affected_trains.Begin(); v != affected_trains.End(); v++) {
01691 (*v)->ConsistChanged(true);
01692 }
01693 }
01694
01695 delete iter;
01696 return (cost.GetCost() == 0) ? error : cost;
01697 }
01698
01699 static CommandCost RemoveTrainDepot(TileIndex tile, DoCommandFlag flags)
01700 {
01701 if (_current_company != OWNER_WATER) {
01702 CommandCost ret = CheckTileOwnership(tile);
01703 if (ret.Failed()) return ret;
01704 }
01705
01706 CommandCost ret = EnsureNoVehicleOnGround(tile);
01707 if (ret.Failed()) return ret;
01708
01709 if (flags & DC_EXEC) {
01710
01711 DiagDirection dir = GetRailDepotDirection(tile);
01712 Owner owner = GetTileOwner(tile);
01713 Train *v = NULL;
01714
01715 if (HasDepotReservation(tile)) {
01716 v = GetTrainForReservation(tile, DiagDirToDiagTrack(dir));
01717 if (v != NULL) FreeTrainTrackReservation(v);
01718 }
01719
01720 Company::Get(owner)->infrastructure.rail[GetRailType(tile)]--;
01721 DirtyCompanyInfrastructureWindows(owner);
01722
01723 delete Depot::GetByTile(tile);
01724 DoClearSquare(tile);
01725 AddSideToSignalBuffer(tile, dir, owner);
01726 YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
01727 if (v != NULL) TryPathReserve(v, true);
01728 }
01729
01730 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_TRAIN]);
01731 }
01732
01733 static CommandCost ClearTile_Track(TileIndex tile, DoCommandFlag flags)
01734 {
01735 CommandCost cost(EXPENSES_CONSTRUCTION);
01736
01737 if (flags & DC_AUTO) {
01738 if (!IsTileOwner(tile, _current_company)) {
01739 return_cmd_error(STR_ERROR_AREA_IS_OWNED_BY_ANOTHER);
01740 }
01741
01742 if (IsPlainRail(tile)) {
01743 return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
01744 } else {
01745 return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
01746 }
01747 }
01748
01749 switch (GetRailTileType(tile)) {
01750 case RAIL_TILE_SIGNALS:
01751 case RAIL_TILE_NORMAL: {
01752 Slope tileh = GetTileSlope(tile);
01753
01754 bool water_ground = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh));
01755
01756 TrackBits tracks = GetTrackBits(tile);
01757 while (tracks != TRACK_BIT_NONE) {
01758 Track track = RemoveFirstTrack(&tracks);
01759 CommandCost ret = DoCommand(tile, 0, track, flags, CMD_REMOVE_SINGLE_RAIL);
01760 if (ret.Failed()) return ret;
01761 cost.AddCost(ret);
01762 }
01763
01764
01765 if (water_ground && !(flags & DC_BANKRUPT)) {
01766 CommandCost ret = EnsureNoVehicleOnGround(tile);
01767 if (ret.Failed()) return ret;
01768
01769
01770 if (flags & DC_EXEC) DoClearSquare(tile);
01771 cost.AddCost(_price[PR_CLEAR_WATER]);
01772 }
01773
01774 return cost;
01775 }
01776
01777 case RAIL_TILE_DEPOT:
01778 return RemoveTrainDepot(tile, flags);
01779
01780 default:
01781 return CMD_ERROR;
01782 }
01783 }
01784
01789 static uint GetSaveSlopeZ(uint x, uint y, Track track)
01790 {
01791 switch (track) {
01792 case TRACK_UPPER: x &= ~0xF; y &= ~0xF; break;
01793 case TRACK_LOWER: x |= 0xF; y |= 0xF; break;
01794 case TRACK_LEFT: x |= 0xF; y &= ~0xF; break;
01795 case TRACK_RIGHT: x &= ~0xF; y |= 0xF; break;
01796 default: break;
01797 }
01798 return GetSlopePixelZ(x, y);
01799 }
01800
01801 static void DrawSingleSignal(TileIndex tile, Track track, byte condition, uint image, uint pos)
01802 {
01803 bool side;
01804 switch (_settings_game.construction.train_signal_side) {
01805 case 0: side = false; break;
01806 case 2: side = true; break;
01807 default: side = _settings_game.vehicle.road_side != 0; break;
01808 }
01809 static const Point SignalPositions[2][12] = {
01810 {
01811
01812 { 8, 5}, {14, 1}, { 1, 14}, { 9, 11}, { 1, 0}, { 3, 10},
01813
01814 {11, 4}, {14, 14}, {11, 3}, { 4, 13}, { 3, 4}, {11, 13}
01815 }, {
01816
01817 {14, 1}, {12, 10}, { 4, 6}, { 1, 14}, {10, 4}, { 0, 1},
01818
01819 {14, 14}, { 5, 12}, {11, 13}, { 4, 3}, {13, 4}, { 3, 11}
01820 }
01821 };
01822
01823 uint x = TileX(tile) * TILE_SIZE + SignalPositions[side][pos].x;
01824 uint y = TileY(tile) * TILE_SIZE + SignalPositions[side][pos].y;
01825
01826 SpriteID sprite;
01827
01828 SignalType type = GetSignalType(tile, track);
01829 SignalVariant variant = GetSignalVariant(tile, track);
01830
01831 if (type == SIGTYPE_NORMAL && variant == SIG_ELECTRIC) {
01832
01833 sprite = SPR_ORIGINAL_SIGNALS_BASE + image + condition;
01834 } else {
01835
01836 sprite = SPR_SIGNALS_BASE + (type - 1) * 16 + variant * 64 + image + condition + (type > SIGTYPE_LAST_NOPBS ? 64 : 0);
01837 }
01838
01839 AddSortableSpriteToDraw(sprite, PAL_NONE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, GetSaveSlopeZ(x, y, track));
01840 }
01841
01842 static uint32 _drawtile_track_palette;
01843
01844
01845 static void DrawTrackFence_NW(const TileInfo *ti, SpriteID base_image)
01846 {
01847 RailFenceOffset rfo = RFO_FLAT_X;
01848 if (ti->tileh & SLOPE_NW) rfo = (ti->tileh & SLOPE_W) ? RFO_SLOPE_SW : RFO_SLOPE_NE;
01849 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01850 ti->x, ti->y + 1, 16, 1, 4, ti->z);
01851 }
01852
01853 static void DrawTrackFence_SE(const TileInfo *ti, SpriteID base_image)
01854 {
01855 RailFenceOffset rfo = RFO_FLAT_X;
01856 if (ti->tileh & SLOPE_SE) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SW : RFO_SLOPE_NE;
01857 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01858 ti->x, ti->y + TILE_SIZE - 1, 16, 1, 4, ti->z);
01859 }
01860
01861 static void DrawTrackFence_NW_SE(const TileInfo *ti, SpriteID base_image)
01862 {
01863 DrawTrackFence_NW(ti, base_image);
01864 DrawTrackFence_SE(ti, base_image);
01865 }
01866
01867 static void DrawTrackFence_NE(const TileInfo *ti, SpriteID base_image)
01868 {
01869 RailFenceOffset rfo = RFO_FLAT_Y;
01870 if (ti->tileh & SLOPE_NE) rfo = (ti->tileh & SLOPE_E) ? RFO_SLOPE_SE : RFO_SLOPE_NW;
01871 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01872 ti->x + 1, ti->y, 1, 16, 4, ti->z);
01873 }
01874
01875 static void DrawTrackFence_SW(const TileInfo *ti, SpriteID base_image)
01876 {
01877 RailFenceOffset rfo = RFO_FLAT_Y;
01878 if (ti->tileh & SLOPE_SW) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SE : RFO_SLOPE_NW;
01879 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01880 ti->x + TILE_SIZE - 1, ti->y, 1, 16, 4, ti->z);
01881 }
01882
01883 static void DrawTrackFence_NE_SW(const TileInfo *ti, SpriteID base_image)
01884 {
01885 DrawTrackFence_NE(ti, base_image);
01886 DrawTrackFence_SW(ti, base_image);
01887 }
01888
01892 static void DrawTrackFence_NS_1(const TileInfo *ti, SpriteID base_image)
01893 {
01894 int z = ti->z + GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_W);
01895 AddSortableSpriteToDraw(base_image + RFO_FLAT_VERT, _drawtile_track_palette,
01896 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01897 }
01898
01902 static void DrawTrackFence_NS_2(const TileInfo *ti, SpriteID base_image)
01903 {
01904 int z = ti->z + GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_E);
01905 AddSortableSpriteToDraw(base_image + RFO_FLAT_VERT, _drawtile_track_palette,
01906 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01907 }
01908
01912 static void DrawTrackFence_WE_1(const TileInfo *ti, SpriteID base_image)
01913 {
01914 int z = ti->z + GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_N);
01915 AddSortableSpriteToDraw(base_image + RFO_FLAT_HORZ, _drawtile_track_palette,
01916 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01917 }
01918
01922 static void DrawTrackFence_WE_2(const TileInfo *ti, SpriteID base_image)
01923 {
01924 int z = ti->z + GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_S);
01925 AddSortableSpriteToDraw(base_image + RFO_FLAT_HORZ, _drawtile_track_palette,
01926 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01927 }
01928
01929
01930 static void DrawTrackDetails(const TileInfo *ti, const RailtypeInfo *rti)
01931 {
01932
01933
01934 SpriteID base_image = GetCustomRailSprite(rti, ti->tile, RTSG_FENCES, IsHalftileSlope(ti->tileh) ? TCX_UPPER_HALFTILE : TCX_NORMAL);
01935 if (base_image == 0) base_image = SPR_TRACK_FENCE_FLAT_X;
01936
01937 switch (GetRailGroundType(ti->tile)) {
01938 case RAIL_GROUND_FENCE_NW: DrawTrackFence_NW(ti, base_image); break;
01939 case RAIL_GROUND_FENCE_SE: DrawTrackFence_SE(ti, base_image); break;
01940 case RAIL_GROUND_FENCE_SENW: DrawTrackFence_NW_SE(ti, base_image); break;
01941 case RAIL_GROUND_FENCE_NE: DrawTrackFence_NE(ti, base_image); break;
01942 case RAIL_GROUND_FENCE_SW: DrawTrackFence_SW(ti, base_image); break;
01943 case RAIL_GROUND_FENCE_NESW: DrawTrackFence_NE_SW(ti, base_image); break;
01944 case RAIL_GROUND_FENCE_VERT1: DrawTrackFence_NS_1(ti, base_image); break;
01945 case RAIL_GROUND_FENCE_VERT2: DrawTrackFence_NS_2(ti, base_image); break;
01946 case RAIL_GROUND_FENCE_HORIZ1: DrawTrackFence_WE_1(ti, base_image); break;
01947 case RAIL_GROUND_FENCE_HORIZ2: DrawTrackFence_WE_2(ti, base_image); break;
01948 case RAIL_GROUND_WATER: {
01949 Corner track_corner;
01950 if (IsHalftileSlope(ti->tileh)) {
01951
01952 track_corner = GetHalftileSlopeCorner(ti->tileh);
01953 } else {
01954
01955 track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh)));
01956 }
01957 switch (track_corner) {
01958 case CORNER_W: DrawTrackFence_NS_1(ti, base_image); break;
01959 case CORNER_S: DrawTrackFence_WE_2(ti, base_image); break;
01960 case CORNER_E: DrawTrackFence_NS_2(ti, base_image); break;
01961 case CORNER_N: DrawTrackFence_WE_1(ti, base_image); break;
01962 default: NOT_REACHED();
01963 }
01964 break;
01965 }
01966 default: break;
01967 }
01968 }
01969
01970
01971 static const int INF = 1000;
01972 static const SubSprite _halftile_sub_sprite[4] = {
01973 { -INF , -INF , 32 - 33, INF },
01974 { -INF , 0 + 7, INF , INF },
01975 { -31 + 33, -INF , INF , INF },
01976 { -INF , -INF , INF , 30 - 23 }
01977 };
01978
01979 static inline void DrawTrackSprite(SpriteID sprite, PaletteID pal, const TileInfo *ti, Slope s)
01980 {
01981 DrawGroundSprite(sprite, pal, NULL, 0, (ti->tileh & s) ? -8 : 0);
01982 }
01983
01984 static void DrawTrackBitsOverlay(TileInfo *ti, TrackBits track, const RailtypeInfo *rti)
01985 {
01986 RailGroundType rgt = GetRailGroundType(ti->tile);
01987 Foundation f = GetRailFoundation(ti->tileh, track);
01988 Corner halftile_corner = CORNER_INVALID;
01989
01990 if (IsNonContinuousFoundation(f)) {
01991
01992 halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f));
01993
01994 track &= ~CornerToTrackBits(halftile_corner);
01995 f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE);
01996 }
01997
01998 DrawFoundation(ti, f);
01999
02000
02001
02002 if (rgt == RAIL_GROUND_WATER) {
02003 if (track != TRACK_BIT_NONE || IsSteepSlope(ti->tileh)) {
02004
02005 DrawShoreTile(ti->tileh);
02006 } else {
02007
02008 DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
02009 }
02010 } else {
02011 SpriteID image;
02012
02013 switch (rgt) {
02014 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
02015 case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOW_DESERT_TILE; break;
02016 default: image = SPR_FLAT_GRASS_TILE; break;
02017 }
02018
02019 image += SlopeToSpriteOffset(ti->tileh);
02020
02021 DrawGroundSprite(image, PAL_NONE);
02022 }
02023
02024 SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
02025 SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
02026 TrackBits pbs = _settings_client.gui.show_track_reservation ? GetRailReservationTrackBits(ti->tile) : TRACK_BIT_NONE;
02027
02028 if (track == TRACK_BIT_NONE) {
02029
02030 } else if (ti->tileh == SLOPE_NW && track == TRACK_BIT_Y) {
02031 DrawGroundSprite(ground + RTO_SLOPE_NW, PAL_NONE);
02032 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 9, PALETTE_CRASH);
02033 } else if (ti->tileh == SLOPE_NE && track == TRACK_BIT_X) {
02034 DrawGroundSprite(ground + RTO_SLOPE_NE, PAL_NONE);
02035 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 6, PALETTE_CRASH);
02036 } else if (ti->tileh == SLOPE_SE && track == TRACK_BIT_Y) {
02037 DrawGroundSprite(ground + RTO_SLOPE_SE, PAL_NONE);
02038 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 7, PALETTE_CRASH);
02039 } else if (ti->tileh == SLOPE_SW && track == TRACK_BIT_X) {
02040 DrawGroundSprite(ground + RTO_SLOPE_SW, PAL_NONE);
02041 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 8, PALETTE_CRASH);
02042 } else {
02043 switch (track) {
02044
02045
02046 case TRACK_BIT_X: DrawGroundSprite(ground + RTO_X, PAL_NONE); break;
02047 case TRACK_BIT_Y: DrawGroundSprite(ground + RTO_Y, PAL_NONE); break;
02048 case TRACK_BIT_UPPER: DrawTrackSprite(ground + RTO_N, PAL_NONE, ti, SLOPE_N); break;
02049 case TRACK_BIT_LOWER: DrawTrackSprite(ground + RTO_S, PAL_NONE, ti, SLOPE_S); break;
02050 case TRACK_BIT_RIGHT: DrawTrackSprite(ground + RTO_E, PAL_NONE, ti, SLOPE_E); break;
02051 case TRACK_BIT_LEFT: DrawTrackSprite(ground + RTO_W, PAL_NONE, ti, SLOPE_W); break;
02052 case TRACK_BIT_CROSS: DrawGroundSprite(ground + RTO_CROSSING_XY, PAL_NONE); break;
02053 case TRACK_BIT_HORZ: DrawTrackSprite(ground + RTO_N, PAL_NONE, ti, SLOPE_N);
02054 DrawTrackSprite(ground + RTO_S, PAL_NONE, ti, SLOPE_S); break;
02055 case TRACK_BIT_VERT: DrawTrackSprite(ground + RTO_E, PAL_NONE, ti, SLOPE_E);
02056 DrawTrackSprite(ground + RTO_W, PAL_NONE, ti, SLOPE_W); break;
02057
02058 default:
02059
02060 if ((track & TRACK_BIT_3WAY_NE) == 0) {
02061 DrawGroundSprite(ground + RTO_JUNCTION_SW, PAL_NONE);
02062 } else if ((track & TRACK_BIT_3WAY_SW) == 0) {
02063 DrawGroundSprite(ground + RTO_JUNCTION_NE, PAL_NONE);
02064 } else if ((track & TRACK_BIT_3WAY_NW) == 0) {
02065 DrawGroundSprite(ground + RTO_JUNCTION_SE, PAL_NONE);
02066 } else if ((track & TRACK_BIT_3WAY_SE) == 0) {
02067 DrawGroundSprite(ground + RTO_JUNCTION_NW, PAL_NONE);
02068 } else {
02069 DrawGroundSprite(ground + RTO_JUNCTION_NSEW, PAL_NONE);
02070 }
02071
02072
02073 track &= ~pbs;
02074
02075
02076 if (track & TRACK_BIT_X) DrawGroundSprite(overlay + RTO_X, PAL_NONE);
02077 if (track & TRACK_BIT_Y) DrawGroundSprite(overlay + RTO_Y, PAL_NONE);
02078 if (track & TRACK_BIT_UPPER) DrawGroundSprite(overlay + RTO_N, PAL_NONE);
02079 if (track & TRACK_BIT_LOWER) DrawGroundSprite(overlay + RTO_S, PAL_NONE);
02080 if (track & TRACK_BIT_RIGHT) DrawGroundSprite(overlay + RTO_E, PAL_NONE);
02081 if (track & TRACK_BIT_LEFT) DrawGroundSprite(overlay + RTO_W, PAL_NONE);
02082 }
02083
02084
02085 if (pbs & TRACK_BIT_X) DrawGroundSprite(overlay + RTO_X, PALETTE_CRASH);
02086 if (pbs & TRACK_BIT_Y) DrawGroundSprite(overlay + RTO_Y, PALETTE_CRASH);
02087 if (pbs & TRACK_BIT_UPPER) DrawTrackSprite(overlay + RTO_N, PALETTE_CRASH, ti, SLOPE_N);
02088 if (pbs & TRACK_BIT_LOWER) DrawTrackSprite(overlay + RTO_S, PALETTE_CRASH, ti, SLOPE_S);
02089 if (pbs & TRACK_BIT_RIGHT) DrawTrackSprite(overlay + RTO_E, PALETTE_CRASH, ti, SLOPE_E);
02090 if (pbs & TRACK_BIT_LEFT) DrawTrackSprite(overlay + RTO_W, PALETTE_CRASH, ti, SLOPE_W);
02091 }
02092
02093 if (IsValidCorner(halftile_corner)) {
02094 DrawFoundation(ti, HalftileFoundation(halftile_corner));
02095 overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY, TCX_UPPER_HALFTILE);
02096 ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND, TCX_UPPER_HALFTILE);
02097
02098
02099 Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
02100
02101 SpriteID image;
02102 switch (rgt) {
02103 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
02104 case RAIL_GROUND_ICE_DESERT:
02105 case RAIL_GROUND_HALF_SNOW: image = SPR_FLAT_SNOW_DESERT_TILE; break;
02106 default: image = SPR_FLAT_GRASS_TILE; break;
02107 }
02108
02109 image += SlopeToSpriteOffset(fake_slope);
02110
02111 DrawGroundSprite(image, PAL_NONE, &(_halftile_sub_sprite[halftile_corner]));
02112
02113 track = CornerToTrackBits(halftile_corner);
02114
02115 int offset;
02116 switch (track) {
02117 default: NOT_REACHED();
02118 case TRACK_BIT_UPPER: offset = RTO_N; break;
02119 case TRACK_BIT_LOWER: offset = RTO_S; break;
02120 case TRACK_BIT_RIGHT: offset = RTO_E; break;
02121 case TRACK_BIT_LEFT: offset = RTO_W; break;
02122 }
02123
02124 DrawTrackSprite(ground + offset, PAL_NONE, ti, fake_slope);
02125 if (_settings_client.gui.show_track_reservation && HasReservedTracks(ti->tile, track)) {
02126 DrawTrackSprite(overlay + offset, PALETTE_CRASH, ti, fake_slope);
02127 }
02128 }
02129 }
02130
02136 static void DrawTrackBits(TileInfo *ti, TrackBits track)
02137 {
02138 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
02139
02140 if (rti->UsesOverlay()) {
02141 DrawTrackBitsOverlay(ti, track, rti);
02142 return;
02143 }
02144
02145 RailGroundType rgt = GetRailGroundType(ti->tile);
02146 Foundation f = GetRailFoundation(ti->tileh, track);
02147 Corner halftile_corner = CORNER_INVALID;
02148
02149 if (IsNonContinuousFoundation(f)) {
02150
02151 halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f));
02152
02153 track &= ~CornerToTrackBits(halftile_corner);
02154 f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE);
02155 }
02156
02157 DrawFoundation(ti, f);
02158
02159
02160 SpriteID image;
02161 PaletteID pal = PAL_NONE;
02162 const SubSprite *sub = NULL;
02163 bool junction = false;
02164
02165
02166 if (track == 0) {
02167
02168 if (rgt == RAIL_GROUND_WATER) {
02169 if (IsSteepSlope(ti->tileh)) {
02170 DrawShoreTile(ti->tileh);
02171 image = 0;
02172 } else {
02173 image = SPR_FLAT_WATER_TILE;
02174 }
02175 } else {
02176 switch (rgt) {
02177 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
02178 case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOW_DESERT_TILE; break;
02179 default: image = SPR_FLAT_GRASS_TILE; break;
02180 }
02181 image += SlopeToSpriteOffset(ti->tileh);
02182 }
02183 } else {
02184 if (ti->tileh != SLOPE_FLAT) {
02185
02186 image = _track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.track_y;
02187 } else {
02188
02189 (image = rti->base_sprites.track_y, track == TRACK_BIT_Y) ||
02190 (image++, track == TRACK_BIT_X) ||
02191 (image++, track == TRACK_BIT_UPPER) ||
02192 (image++, track == TRACK_BIT_LOWER) ||
02193 (image++, track == TRACK_BIT_RIGHT) ||
02194 (image++, track == TRACK_BIT_LEFT) ||
02195 (image++, track == TRACK_BIT_CROSS) ||
02196
02197 (image = rti->base_sprites.track_ns, track == TRACK_BIT_HORZ) ||
02198 (image++, track == TRACK_BIT_VERT) ||
02199
02200 (junction = true, false) ||
02201 (image = rti->base_sprites.ground, (track & TRACK_BIT_3WAY_NE) == 0) ||
02202 (image++, (track & TRACK_BIT_3WAY_SW) == 0) ||
02203 (image++, (track & TRACK_BIT_3WAY_NW) == 0) ||
02204 (image++, (track & TRACK_BIT_3WAY_SE) == 0) ||
02205 (image++, true);
02206 }
02207
02208 switch (rgt) {
02209 case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
02210 case RAIL_GROUND_ICE_DESERT: image += rti->snow_offset; break;
02211 case RAIL_GROUND_WATER: {
02212
02213 DrawShoreTile(ti->tileh);
02214 Corner track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh)));
02215 sub = &(_halftile_sub_sprite[track_corner]);
02216 break;
02217 }
02218 default: break;
02219 }
02220 }
02221
02222 if (image != 0) DrawGroundSprite(image, pal, sub);
02223
02224
02225 if (junction) {
02226 if (track & TRACK_BIT_X) DrawGroundSprite(rti->base_sprites.single_x, PAL_NONE);
02227 if (track & TRACK_BIT_Y) DrawGroundSprite(rti->base_sprites.single_y, PAL_NONE);
02228 if (track & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PAL_NONE);
02229 if (track & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PAL_NONE);
02230 if (track & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PAL_NONE);
02231 if (track & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PAL_NONE);
02232 }
02233
02234
02235 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation) {
02236
02237 TrackBits pbs = GetRailReservationTrackBits(ti->tile) & track;
02238 if (pbs & TRACK_BIT_X) {
02239 if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
02240 DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH);
02241 } else {
02242 DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
02243 }
02244 }
02245 if (pbs & TRACK_BIT_Y) {
02246 if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
02247 DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH);
02248 } else {
02249 DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
02250 }
02251 }
02252 if (pbs & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_N ? -(int)TILE_HEIGHT : 0);
02253 if (pbs & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_S ? -(int)TILE_HEIGHT : 0);
02254 if (pbs & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_W ? -(int)TILE_HEIGHT : 0);
02255 if (pbs & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_E ? -(int)TILE_HEIGHT : 0);
02256 }
02257
02258 if (IsValidCorner(halftile_corner)) {
02259 DrawFoundation(ti, HalftileFoundation(halftile_corner));
02260
02261
02262 Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
02263 image = _track_sloped_sprites[fake_slope - 1] + rti->base_sprites.track_y;
02264 pal = PAL_NONE;
02265 switch (rgt) {
02266 case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
02267 case RAIL_GROUND_ICE_DESERT:
02268 case RAIL_GROUND_HALF_SNOW: image += rti->snow_offset; break;
02269 default: break;
02270 }
02271 DrawGroundSprite(image, pal, &(_halftile_sub_sprite[halftile_corner]));
02272
02273 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasReservedTracks(ti->tile, CornerToTrackBits(halftile_corner))) {
02274 static const byte _corner_to_track_sprite[] = {3, 1, 2, 0};
02275 DrawGroundSprite(_corner_to_track_sprite[halftile_corner] + rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, -(int)TILE_HEIGHT);
02276 }
02277 }
02278 }
02279
02287 enum SignalOffsets {
02288 SIGNAL_TO_SOUTHWEST = 0,
02289 SIGNAL_TO_NORTHEAST = 2,
02290 SIGNAL_TO_SOUTHEAST = 4,
02291 SIGNAL_TO_NORTHWEST = 6,
02292 SIGNAL_TO_EAST = 8,
02293 SIGNAL_TO_WEST = 10,
02294 SIGNAL_TO_SOUTH = 12,
02295 SIGNAL_TO_NORTH = 14,
02296 };
02297
02298 static void DrawSignals(TileIndex tile, TrackBits rails)
02299 {
02300 #define MAYBE_DRAW_SIGNAL(x, y, z, t) if (IsSignalPresent(tile, x)) DrawSingleSignal(tile, t, GetSingleSignalState(tile, x), y, z)
02301
02302 if (!(rails & TRACK_BIT_Y)) {
02303 if (!(rails & TRACK_BIT_X)) {
02304 if (rails & TRACK_BIT_LEFT) {
02305 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTH, 0, TRACK_LEFT);
02306 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTH, 1, TRACK_LEFT);
02307 }
02308 if (rails & TRACK_BIT_RIGHT) {
02309 MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_NORTH, 2, TRACK_RIGHT);
02310 MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_SOUTH, 3, TRACK_RIGHT);
02311 }
02312 if (rails & TRACK_BIT_UPPER) {
02313 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_WEST, 4, TRACK_UPPER);
02314 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_EAST, 5, TRACK_UPPER);
02315 }
02316 if (rails & TRACK_BIT_LOWER) {
02317 MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_WEST, 6, TRACK_LOWER);
02318 MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_EAST, 7, TRACK_LOWER);
02319 }
02320 } else {
02321 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHWEST, 8, TRACK_X);
02322 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHEAST, 9, TRACK_X);
02323 }
02324 } else {
02325 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHEAST, 10, TRACK_Y);
02326 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHWEST, 11, TRACK_Y);
02327 }
02328 }
02329
02330 static void DrawTile_Track(TileInfo *ti)
02331 {
02332 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
02333
02334 _drawtile_track_palette = COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile));
02335
02336 if (IsPlainRail(ti->tile)) {
02337 TrackBits rails = GetTrackBits(ti->tile);
02338
02339 DrawTrackBits(ti, rails);
02340
02341 if (HasBit(_display_opt, DO_FULL_DETAIL)) DrawTrackDetails(ti, rti);
02342
02343 if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
02344
02345 if (HasSignals(ti->tile)) DrawSignals(ti->tile, rails);
02346 } else {
02347
02348 const DrawTileSprites *dts;
02349 PaletteID pal = PAL_NONE;
02350 SpriteID relocation;
02351
02352 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
02353
02354 if (IsInvisibilitySet(TO_BUILDINGS)) {
02355
02356 dts = &_depot_invisible_gfx_table[GetRailDepotDirection(ti->tile)];
02357 } else {
02358 dts = &_depot_gfx_table[GetRailDepotDirection(ti->tile)];
02359 }
02360
02361 SpriteID image;
02362 if (rti->UsesOverlay()) {
02363 image = SPR_FLAT_GRASS_TILE;
02364 } else {
02365 image = dts->ground.sprite;
02366 if (image != SPR_FLAT_GRASS_TILE) image += rti->GetRailtypeSpriteOffset();
02367 }
02368
02369
02370
02371 if (IsSnowRailGround(ti->tile) && _settings_game.game_creation.landscape == LT_TROPIC) {
02372 if (image != SPR_FLAT_GRASS_TILE) {
02373 image += rti->snow_offset;
02374 } else {
02375 image = SPR_FLAT_SNOW_DESERT_TILE;
02376 }
02377 }
02378
02379 DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, _drawtile_track_palette));
02380
02381 if (rti->UsesOverlay()) {
02382 SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
02383
02384 switch (GetRailDepotDirection(ti->tile)) {
02385 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02386 case DIAGDIR_SW: DrawGroundSprite(ground + RTO_X, PAL_NONE); break;
02387 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02388 case DIAGDIR_SE: DrawGroundSprite(ground + RTO_Y, PAL_NONE); break;
02389 default: break;
02390 }
02391
02392 if (_settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile)) {
02393 SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
02394
02395 switch (GetRailDepotDirection(ti->tile)) {
02396 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02397 case DIAGDIR_SW: DrawGroundSprite(overlay + RTO_X, PALETTE_CRASH); break;
02398 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02399 case DIAGDIR_SE: DrawGroundSprite(overlay + RTO_Y, PALETTE_CRASH); break;
02400 default: break;
02401 }
02402 }
02403 } else {
02404
02405 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile)) {
02406 switch (GetRailDepotDirection(ti->tile)) {
02407 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02408 case DIAGDIR_SW: DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH); break;
02409 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02410 case DIAGDIR_SE: DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH); break;
02411 default: break;
02412 }
02413 }
02414 }
02415 int depot_sprite = GetCustomRailSprite(rti, ti->tile, RTSG_DEPOT);
02416 relocation = depot_sprite != 0 ? depot_sprite - SPR_RAIL_DEPOT_SE_1 : rti->GetRailtypeSpriteOffset();
02417
02418 if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
02419
02420 DrawRailTileSeq(ti, dts, TO_BUILDINGS, relocation, 0, _drawtile_track_palette);
02421 }
02422 DrawBridgeMiddle(ti);
02423 }
02424
02425 void DrawTrainDepotSprite(int x, int y, int dir, RailType railtype)
02426 {
02427 const DrawTileSprites *dts = &_depot_gfx_table[dir];
02428 const RailtypeInfo *rti = GetRailTypeInfo(railtype);
02429 SpriteID image = rti->UsesOverlay() ? SPR_FLAT_GRASS_TILE : dts->ground.sprite;
02430 uint32 offset = rti->GetRailtypeSpriteOffset();
02431
02432 x += 33;
02433 y += 17;
02434
02435 if (image != SPR_FLAT_GRASS_TILE) image += offset;
02436 PaletteID palette = COMPANY_SPRITE_COLOUR(_local_company);
02437
02438 DrawSprite(image, PAL_NONE, x, y);
02439
02440 if (rti->UsesOverlay()) {
02441 SpriteID ground = GetCustomRailSprite(rti, INVALID_TILE, RTSG_GROUND);
02442
02443 switch (dir) {
02444 case DIAGDIR_SW: DrawSprite(ground + RTO_X, PAL_NONE, x, y); break;
02445 case DIAGDIR_SE: DrawSprite(ground + RTO_Y, PAL_NONE, x, y); break;
02446 default: break;
02447 }
02448 }
02449 int depot_sprite = GetCustomRailSprite(rti, INVALID_TILE, RTSG_DEPOT);
02450 if (depot_sprite != 0) offset = depot_sprite - SPR_RAIL_DEPOT_SE_1;
02451
02452 DrawRailTileSeqInGUI(x, y, dts, offset, 0, palette);
02453 }
02454
02455 static int GetSlopePixelZ_Track(TileIndex tile, uint x, uint y)
02456 {
02457 if (IsPlainRail(tile)) {
02458 int z;
02459 Slope tileh = GetTilePixelSlope(tile, &z);
02460 if (tileh == SLOPE_FLAT) return z;
02461
02462 z += ApplyPixelFoundationToSlope(GetRailFoundation(tileh, GetTrackBits(tile)), &tileh);
02463 return z + GetPartialPixelZ(x & 0xF, y & 0xF, tileh);
02464 } else {
02465 return GetTileMaxPixelZ(tile);
02466 }
02467 }
02468
02469 static Foundation GetFoundation_Track(TileIndex tile, Slope tileh)
02470 {
02471 return IsPlainRail(tile) ? GetRailFoundation(tileh, GetTrackBits(tile)) : FlatteningFoundation(tileh);
02472 }
02473
02474 static void TileLoop_Track(TileIndex tile)
02475 {
02476 RailGroundType old_ground = GetRailGroundType(tile);
02477 RailGroundType new_ground;
02478
02479 if (old_ground == RAIL_GROUND_WATER) {
02480 TileLoop_Water(tile);
02481 return;
02482 }
02483
02484 switch (_settings_game.game_creation.landscape) {
02485 case LT_ARCTIC: {
02486 int z;
02487 Slope slope = GetTileSlope(tile, &z);
02488 bool half = false;
02489
02490
02491
02492 if (IsPlainRail(tile)) {
02493 TrackBits track = GetTrackBits(tile);
02494 Foundation f = GetRailFoundation(slope, track);
02495
02496 switch (f) {
02497 case FOUNDATION_NONE:
02498
02499 if (IsSlopeWithThreeCornersRaised(slope)) z++;
02500 break;
02501
02502 case FOUNDATION_INCLINED_X:
02503 case FOUNDATION_INCLINED_Y:
02504
02505 if (IsSteepSlope(slope)) z++;
02506 break;
02507
02508 case FOUNDATION_STEEP_LOWER:
02509
02510 z++;
02511 break;
02512
02513 default:
02514
02515 if (IsSteepSlope(slope)) z++;
02516 z++;
02517 break;
02518 }
02519
02520 half = IsInsideMM(f, FOUNDATION_STEEP_BOTH, FOUNDATION_HALFTILE_N + 1);
02521 } else {
02522
02523 if (slope != SLOPE_FLAT) z++;
02524 }
02525
02526
02527
02528
02529
02530 if (z > GetSnowLine()) {
02531 if (half && z - GetSnowLine() == 1) {
02532
02533 new_ground = RAIL_GROUND_HALF_SNOW;
02534 } else {
02535 new_ground = RAIL_GROUND_ICE_DESERT;
02536 }
02537 goto set_ground;
02538 }
02539 break;
02540 }
02541
02542 case LT_TROPIC:
02543 if (GetTropicZone(tile) == TROPICZONE_DESERT) {
02544 new_ground = RAIL_GROUND_ICE_DESERT;
02545 goto set_ground;
02546 }
02547 break;
02548 }
02549
02550 new_ground = RAIL_GROUND_GRASS;
02551
02552 if (IsPlainRail(tile) && old_ground != RAIL_GROUND_BARREN) {
02553
02554 TrackBits rail = GetTrackBits(tile);
02555
02556 Owner owner = GetTileOwner(tile);
02557 byte fences = 0;
02558
02559 for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
02560 static const TrackBits dir_to_trackbits[DIAGDIR_END] = {TRACK_BIT_3WAY_NE, TRACK_BIT_3WAY_SE, TRACK_BIT_3WAY_SW, TRACK_BIT_3WAY_NW};
02561
02562
02563 if ((rail & dir_to_trackbits[d]) != TRACK_BIT_NONE) continue;
02564
02565 TileIndex tile2 = tile + TileOffsByDiagDir(d);
02566
02567
02568 if (!IsValidTile(tile2) || IsTileType(tile2, MP_HOUSE) || IsTileType(tile2, MP_INDUSTRY) ||
02569 IsTileType(tile2, MP_ROAD) || IsTileType(tile2, MP_TUNNELBRIDGE) || !IsTileOwner(tile2, owner)) {
02570 fences |= 1 << d;
02571 }
02572 }
02573
02574 switch (fences) {
02575 case 0: break;
02576 case (1 << DIAGDIR_NE): new_ground = RAIL_GROUND_FENCE_NE; break;
02577 case (1 << DIAGDIR_SE): new_ground = RAIL_GROUND_FENCE_SE; break;
02578 case (1 << DIAGDIR_SW): new_ground = RAIL_GROUND_FENCE_SW; break;
02579 case (1 << DIAGDIR_NW): new_ground = RAIL_GROUND_FENCE_NW; break;
02580 case (1 << DIAGDIR_NE) | (1 << DIAGDIR_SW): new_ground = RAIL_GROUND_FENCE_NESW; break;
02581 case (1 << DIAGDIR_SE) | (1 << DIAGDIR_NW): new_ground = RAIL_GROUND_FENCE_SENW; break;
02582 case (1 << DIAGDIR_NE) | (1 << DIAGDIR_SE): new_ground = RAIL_GROUND_FENCE_VERT1; break;
02583 case (1 << DIAGDIR_NE) | (1 << DIAGDIR_NW): new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
02584 case (1 << DIAGDIR_SE) | (1 << DIAGDIR_SW): new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
02585 case (1 << DIAGDIR_SW) | (1 << DIAGDIR_NW): new_ground = RAIL_GROUND_FENCE_VERT2; break;
02586 default: NOT_REACHED();
02587 }
02588 }
02589
02590 set_ground:
02591 if (old_ground != new_ground) {
02592 SetRailGroundType(tile, new_ground);
02593 MarkTileDirtyByTile(tile);
02594 }
02595 }
02596
02597
02598 static TrackStatus GetTileTrackStatus_Track(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
02599 {
02600
02601 if (mode == TRANSPORT_WATER && IsPlainRail(tile) && GetRailGroundType(tile) == RAIL_GROUND_WATER) {
02602 TrackBits tb = GetTrackBits(tile);
02603 switch (tb) {
02604 default: NOT_REACHED();
02605 case TRACK_BIT_UPPER: tb = TRACK_BIT_LOWER; break;
02606 case TRACK_BIT_LOWER: tb = TRACK_BIT_UPPER; break;
02607 case TRACK_BIT_LEFT: tb = TRACK_BIT_RIGHT; break;
02608 case TRACK_BIT_RIGHT: tb = TRACK_BIT_LEFT; break;
02609 }
02610 return CombineTrackStatus(TrackBitsToTrackdirBits(tb), TRACKDIR_BIT_NONE);
02611 }
02612
02613 if (mode != TRANSPORT_RAIL) return 0;
02614
02615 TrackBits trackbits = TRACK_BIT_NONE;
02616 TrackdirBits red_signals = TRACKDIR_BIT_NONE;
02617
02618 switch (GetRailTileType(tile)) {
02619 default: NOT_REACHED();
02620 case RAIL_TILE_NORMAL:
02621 trackbits = GetTrackBits(tile);
02622 break;
02623
02624 case RAIL_TILE_SIGNALS: {
02625 trackbits = GetTrackBits(tile);
02626 byte a = GetPresentSignals(tile);
02627 uint b = GetSignalStates(tile);
02628
02629 b &= a;
02630
02631
02632
02633
02634
02635
02636 if (!IsOnewaySignal(tile, TRACK_UPPER) || (a & SignalOnTrack(TRACK_UPPER)) == 0) b |= ~a & SignalOnTrack(TRACK_UPPER);
02637 if (!IsOnewaySignal(tile, TRACK_LOWER) || (a & SignalOnTrack(TRACK_LOWER)) == 0) b |= ~a & SignalOnTrack(TRACK_LOWER);
02638
02639 if ((b & 0x8) == 0) red_signals |= (TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_X_NE | TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_UPPER_E);
02640 if ((b & 0x4) == 0) red_signals |= (TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_X_SW | TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_UPPER_W);
02641 if ((b & 0x2) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_LOWER_E);
02642 if ((b & 0x1) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_S | TRACKDIR_BIT_LOWER_W);
02643
02644 break;
02645 }
02646
02647 case RAIL_TILE_DEPOT: {
02648 DiagDirection dir = GetRailDepotDirection(tile);
02649
02650 if (side != INVALID_DIAGDIR && side != dir) break;
02651
02652 trackbits = DiagDirToDiagTrackBits(dir);
02653 break;
02654 }
02655 }
02656
02657 return CombineTrackStatus(TrackBitsToTrackdirBits(trackbits), red_signals);
02658 }
02659
02660 static bool ClickTile_Track(TileIndex tile)
02661 {
02662 if (!IsRailDepot(tile)) return false;
02663
02664 ShowDepotWindow(tile, VEH_TRAIN);
02665 return true;
02666 }
02667
02668 static void GetTileDesc_Track(TileIndex tile, TileDesc *td)
02669 {
02670 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(tile));
02671 td->rail_speed = rti->max_speed;
02672 td->owner[0] = GetTileOwner(tile);
02673 SetDParamX(td->dparam, 0, rti->strings.name);
02674 switch (GetRailTileType(tile)) {
02675 case RAIL_TILE_NORMAL:
02676 td->str = STR_LAI_RAIL_DESCRIPTION_TRACK;
02677 break;
02678
02679 case RAIL_TILE_SIGNALS: {
02680 static const StringID signal_type[6][6] = {
02681 {
02682 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS,
02683 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS,
02684 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS,
02685 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS,
02686 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS,
02687 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS
02688 },
02689 {
02690 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS,
02691 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRESIGNALS,
02692 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS,
02693 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS,
02694 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS,
02695 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS
02696 },
02697 {
02698 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS,
02699 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS,
02700 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXITSIGNALS,
02701 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS,
02702 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS,
02703 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS
02704 },
02705 {
02706 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS,
02707 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS,
02708 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS,
02709 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBOSIGNALS,
02710 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS,
02711 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS
02712 },
02713 {
02714 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS,
02715 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS,
02716 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS,
02717 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS,
02718 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBSSIGNALS,
02719 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS
02720 },
02721 {
02722 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS,
02723 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS,
02724 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS,
02725 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS,
02726 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS,
02727 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRYSIGNALS
02728 }
02729 };
02730
02731 SignalType primary_signal;
02732 SignalType secondary_signal;
02733 if (HasSignalOnTrack(tile, TRACK_UPPER)) {
02734 primary_signal = GetSignalType(tile, TRACK_UPPER);
02735 secondary_signal = HasSignalOnTrack(tile, TRACK_LOWER) ? GetSignalType(tile, TRACK_LOWER) : primary_signal;
02736 } else {
02737 secondary_signal = primary_signal = GetSignalType(tile, TRACK_LOWER);
02738 }
02739
02740 td->str = signal_type[secondary_signal][primary_signal];
02741 break;
02742 }
02743
02744 case RAIL_TILE_DEPOT:
02745 td->str = STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT;
02746 if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL) {
02747 if (td->rail_speed > 0) {
02748 td->rail_speed = min(td->rail_speed, 61);
02749 } else {
02750 td->rail_speed = 61;
02751 }
02752 }
02753 td->build_date = Depot::GetByTile(tile)->build_date;
02754 break;
02755
02756 default:
02757 NOT_REACHED();
02758 }
02759 }
02760
02761 static void ChangeTileOwner_Track(TileIndex tile, Owner old_owner, Owner new_owner)
02762 {
02763 if (!IsTileOwner(tile, old_owner)) return;
02764
02765 if (new_owner != INVALID_OWNER) {
02766
02767 uint num_pieces = 1;
02768 if (IsPlainRail(tile)) {
02769 TrackBits bits = GetTrackBits(tile);
02770 num_pieces = CountBits(bits);
02771 if (TracksOverlap(bits)) num_pieces *= num_pieces;
02772 }
02773 RailType rt = GetRailType(tile);
02774 Company::Get(old_owner)->infrastructure.rail[rt] -= num_pieces;
02775 Company::Get(new_owner)->infrastructure.rail[rt] += num_pieces;
02776
02777 if (HasSignals(tile)) {
02778 uint num_sigs = CountBits(GetPresentSignals(tile));
02779 Company::Get(old_owner)->infrastructure.signal -= num_sigs;
02780 Company::Get(new_owner)->infrastructure.signal += num_sigs;
02781 }
02782
02783 SetTileOwner(tile, new_owner);
02784 } else {
02785 DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
02786 }
02787 }
02788
02789 static const byte _fractcoords_behind[4] = { 0x8F, 0x8, 0x80, 0xF8 };
02790 static const byte _fractcoords_enter[4] = { 0x8A, 0x48, 0x84, 0xA8 };
02791 static const int8 _deltacoord_leaveoffset[8] = {
02792 -1, 0, 1, 0,
02793 0, 1, 0, -1
02794 };
02795
02796
02803 int TicksToLeaveDepot(const Train *v)
02804 {
02805 DiagDirection dir = GetRailDepotDirection(v->tile);
02806 int length = v->CalcNextVehicleOffset();
02807
02808 switch (dir) {
02809 case DIAGDIR_NE: return ((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) - (length + 1)));
02810 case DIAGDIR_SE: return -((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) + (length + 1)));
02811 case DIAGDIR_SW: return -((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) + (length + 1)));
02812 default:
02813 case DIAGDIR_NW: return ((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) - (length + 1)));
02814 }
02815
02816 return 0;
02817 }
02818
02823 static VehicleEnterTileStatus VehicleEnter_Track(Vehicle *u, TileIndex tile, int x, int y)
02824 {
02825
02826 if (u->type != VEH_TRAIN || !IsRailDepotTile(tile)) return VETSB_CONTINUE;
02827
02828 Train *v = Train::From(u);
02829
02830
02831 DiagDirection dir = GetRailDepotDirection(tile);
02832
02833
02834 int length = v->CalcNextVehicleOffset();
02835
02836 byte fract_coord_leave =
02837 ((_fractcoords_enter[dir] & 0x0F) +
02838 (length + 1) * _deltacoord_leaveoffset[dir]) +
02839 (((_fractcoords_enter[dir] >> 4) +
02840 ((length + 1) * _deltacoord_leaveoffset[dir + 4])) << 4);
02841
02842 byte fract_coord = (x & 0xF) + ((y & 0xF) << 4);
02843
02844 if (_fractcoords_behind[dir] == fract_coord) {
02845
02846 return VETSB_CANNOT_ENTER;
02847 } else if (_fractcoords_enter[dir] == fract_coord) {
02848 if (DiagDirToDir(ReverseDiagDir(dir)) == v->direction) {
02849
02850 v->track = TRACK_BIT_DEPOT,
02851 v->vehstatus |= VS_HIDDEN;
02852 v->direction = ReverseDir(v->direction);
02853 if (v->Next() == NULL) VehicleEnterDepot(v->First());
02854 v->tile = tile;
02855
02856 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
02857 return VETSB_ENTERED_WORMHOLE;
02858 }
02859 } else if (fract_coord_leave == fract_coord) {
02860 if (DiagDirToDir(dir) == v->direction) {
02861
02862 if ((v = v->Next()) != NULL) {
02863 v->vehstatus &= ~VS_HIDDEN;
02864 v->track = (DiagDirToAxis(dir) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y);
02865 }
02866 }
02867 }
02868
02869 return VETSB_CONTINUE;
02870 }
02871
02883 static CommandCost TestAutoslopeOnRailTile(TileIndex tile, uint flags, int z_old, Slope tileh_old, int z_new, Slope tileh_new, TrackBits rail_bits)
02884 {
02885 if (!_settings_game.construction.build_on_slopes || !AutoslopeEnabled()) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02886
02887
02888 if (CheckRailSlope(tileh_new, rail_bits, TRACK_BIT_NONE, tile).Failed()) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02889
02890
02891 z_old += ApplyFoundationToSlope(GetRailFoundation(tileh_old, rail_bits), &tileh_old);
02892 z_new += ApplyFoundationToSlope(GetRailFoundation(tileh_new, rail_bits), &tileh_new);
02893
02894 Corner track_corner;
02895 switch (rail_bits) {
02896 case TRACK_BIT_LEFT: track_corner = CORNER_W; break;
02897 case TRACK_BIT_LOWER: track_corner = CORNER_S; break;
02898 case TRACK_BIT_RIGHT: track_corner = CORNER_E; break;
02899 case TRACK_BIT_UPPER: track_corner = CORNER_N; break;
02900
02901
02902 default:
02903 if (z_old != z_new || tileh_old != tileh_new) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02904 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02905 }
02906
02907
02908 z_old += GetSlopeZInCorner(RemoveHalftileSlope(tileh_old), track_corner);
02909 z_new += GetSlopeZInCorner(RemoveHalftileSlope(tileh_new), track_corner);
02910 if (z_old != z_new) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02911
02912 CommandCost cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02913
02914 if (tileh_old != tileh_new) {
02915
02916 if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old)) cost.AddCost(_price[PR_CLEAR_WATER]);
02917 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
02918 }
02919 return cost;
02920 }
02921
02922 static CommandCost TerraformTile_Track(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new)
02923 {
02924 int z_old;
02925 Slope tileh_old = GetTileSlope(tile, &z_old);
02926 if (IsPlainRail(tile)) {
02927 TrackBits rail_bits = GetTrackBits(tile);
02928
02929 bool was_water = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old));
02930
02931
02932 CommandCost autoslope_result = TestAutoslopeOnRailTile(tile, flags, z_old, tileh_old, z_new, tileh_new, rail_bits);
02933
02934
02935 Corner allowed_corner;
02936 switch (rail_bits) {
02937 case TRACK_BIT_RIGHT: allowed_corner = CORNER_W; break;
02938 case TRACK_BIT_UPPER: allowed_corner = CORNER_S; break;
02939 case TRACK_BIT_LEFT: allowed_corner = CORNER_E; break;
02940 case TRACK_BIT_LOWER: allowed_corner = CORNER_N; break;
02941 default: return autoslope_result;
02942 }
02943
02944 Foundation f_old = GetRailFoundation(tileh_old, rail_bits);
02945
02946
02947 if (tileh_old != SLOPE_NS && tileh_old != SLOPE_EW && IsSpecialRailFoundation(f_old)) return autoslope_result;
02948
02949
02950 for (Corner corner = (Corner)0; corner < CORNER_END; corner = (Corner)(corner + 1)) {
02951 if (allowed_corner == corner) continue;
02952 if (z_old + GetSlopeZInCorner(tileh_old, corner) != z_new + GetSlopeZInCorner(tileh_new, corner)) return autoslope_result;
02953 }
02954
02955
02956 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
02957
02958
02959 return CommandCost(EXPENSES_CONSTRUCTION, was_water ? _price[PR_CLEAR_WATER] : (Money)0);
02960 } else if (_settings_game.construction.build_on_slopes && AutoslopeEnabled() &&
02961 AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetRailDepotDirection(tile))) {
02962 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02963 }
02964 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
02965 }
02966
02967
02968 extern const TileTypeProcs _tile_type_rail_procs = {
02969 DrawTile_Track,
02970 GetSlopePixelZ_Track,
02971 ClearTile_Track,
02972 NULL,
02973 GetTileDesc_Track,
02974 GetTileTrackStatus_Track,
02975 ClickTile_Track,
02976 NULL,
02977 TileLoop_Track,
02978 ChangeTileOwner_Track,
02979 NULL,
02980 VehicleEnter_Track,
02981 GetFoundation_Track,
02982 TerraformTile_Track,
02983 };