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 CommandCost ret = EnsureNoTrainOnTrack(tile, track);
00990 if (ret.Failed()) return ret;
00991
00992
00993 if (p2 != 0 && (p2 & SignalOnTrack(track)) == 0) return CMD_ERROR;
00994
00995 ret = CheckTileOwnership(tile);
00996 if (ret.Failed()) return ret;
00997
00998 {
00999
01000 TrackBits trackbits = GetTrackBits(tile);
01001 if (KillFirstBit(trackbits) != TRACK_BIT_NONE &&
01002 trackbits != TRACK_BIT_HORZ &&
01003 trackbits != TRACK_BIT_VERT) {
01004 return_cmd_error(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK);
01005 }
01006 }
01007
01008
01009 if (HasBit(p1, 17) && HasSignalOnTrack(tile, track)) return CommandCost();
01010
01011
01012 if (convert_signal && !HasSignalOnTrack(tile, track)) return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS);
01013
01014 CommandCost cost;
01015 if (!HasSignalOnTrack(tile, track)) {
01016
01017 cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS]);
01018 } else {
01019 if (p2 != 0 && sigvar != GetSignalVariant(tile, track)) {
01020
01021 cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] + _price[PR_CLEAR_SIGNALS]);
01022
01023 } else if (convert_signal) {
01024
01025 if (ctrl_pressed || GetSignalVariant(tile, track) != sigvar) {
01026
01027 cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] + _price[PR_CLEAR_SIGNALS]);
01028 } else {
01029
01030 cost = CommandCost();
01031 }
01032
01033 } else {
01034
01035 cost = CommandCost();
01036 }
01037 }
01038
01039 if (flags & DC_EXEC) {
01040 Train *v = NULL;
01041
01042
01043
01044 if (HasReservedTracks(tile, TrackToTrackBits(track))) {
01045 v = GetTrainForReservation(tile, track);
01046 if (v != NULL) FreeTrainTrackReservation(v);
01047 }
01048
01049 if (!HasSignals(tile)) {
01050
01051 SetHasSignals(tile, true);
01052 SetSignalStates(tile, 0xF);
01053 SetPresentSignals(tile, 0);
01054 SetSignalType(tile, track, sigtype);
01055 SetSignalVariant(tile, track, sigvar);
01056 }
01057
01058
01059 Company::Get(GetTileOwner(tile))->infrastructure.signal -= CountBits(GetPresentSignals(tile));
01060
01061 if (p2 == 0) {
01062 if (!HasSignalOnTrack(tile, track)) {
01063
01064 SetPresentSignals(tile, GetPresentSignals(tile) | (IsPbsSignal(sigtype) ? KillFirstBit(SignalOnTrack(track)) : SignalOnTrack(track)));
01065 SetSignalType(tile, track, sigtype);
01066 SetSignalVariant(tile, track, sigvar);
01067 while (num_dir_cycle-- > 0) CycleSignalSide(tile, track);
01068 } else {
01069 if (convert_signal) {
01070
01071 if (ctrl_pressed) {
01072
01073 SetSignalVariant(tile, track, (GetSignalVariant(tile, track) == SIG_ELECTRIC) ? SIG_SEMAPHORE : SIG_ELECTRIC);
01074
01075 sigtype = GetSignalType(tile, track);
01076 } else {
01077
01078 SetSignalType(tile, track, sigtype);
01079 SetSignalVariant(tile, track, sigvar);
01080 if (IsPbsSignal(sigtype) && (GetPresentSignals(tile) & SignalOnTrack(track)) == SignalOnTrack(track)) {
01081 SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | KillFirstBit(SignalOnTrack(track)));
01082 }
01083 }
01084
01085 } else if (ctrl_pressed) {
01086
01087 sigtype = (SignalType)(GetSignalType(tile, track) + 1);
01088
01089 if (sigtype < cycle_start || sigtype > cycle_stop) sigtype = cycle_start;
01090
01091 SetSignalType(tile, track, sigtype);
01092 if (IsPbsSignal(sigtype) && (GetPresentSignals(tile) & SignalOnTrack(track)) == SignalOnTrack(track)) {
01093 SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | KillFirstBit(SignalOnTrack(track)));
01094 }
01095 } else {
01096
01097 CycleSignalSide(tile, track);
01098
01099 sigtype = GetSignalType(tile, track);
01100 }
01101 }
01102 } else {
01103
01104
01105 SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | (p2 & SignalOnTrack(track)));
01106 SetSignalVariant(tile, track, sigvar);
01107 SetSignalType(tile, track, sigtype);
01108 }
01109
01110
01111 Company::Get(GetTileOwner(tile))->infrastructure.signal += CountBits(GetPresentSignals(tile));
01112 DirtyCompanyInfrastructureWindows(GetTileOwner(tile));
01113
01114 if (IsPbsSignal(sigtype)) {
01115
01116 uint mask = GetPresentSignals(tile) & SignalOnTrack(track);
01117 SetSignalStates(tile, (GetSignalStates(tile) & ~mask) | ((HasBit(GetRailReservationTrackBits(tile), track) ? UINT_MAX : 0) & mask));
01118 }
01119 MarkTileDirtyByTile(tile);
01120 AddTrackToSignalBuffer(tile, track, _current_company);
01121 YapfNotifyTrackLayoutChange(tile, track);
01122 if (v != NULL) {
01123
01124 if (!(((v->vehstatus & VS_STOPPED) && v->cur_speed == 0) || v->current_order.IsType(OT_LOADING)) ||
01125 !IsSafeWaitingPosition(v, v->tile, v->GetVehicleTrackdir(), true, _settings_game.pf.forbid_90_deg)) {
01126 TryPathReserve(v, true);
01127 }
01128 }
01129 }
01130
01131 return cost;
01132 }
01133
01134 static bool CheckSignalAutoFill(TileIndex &tile, Trackdir &trackdir, int &signal_ctr, bool remove)
01135 {
01136 tile = AddTileIndexDiffCWrap(tile, _trackdelta[trackdir]);
01137 if (tile == INVALID_TILE) return false;
01138
01139
01140 TrackdirBits trackdirbits = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0));
01141
01142 if (TracksOverlap(TrackdirBitsToTrackBits(trackdirbits))) return false;
01143 trackdirbits &= TrackdirReachesTrackdirs(trackdir);
01144
01145
01146 if (trackdirbits == TRACKDIR_BIT_NONE) return false;
01147
01148
01149 trackdir = RemoveFirstTrackdir(&trackdirbits);
01150
01151
01152 if (trackdirbits != TRACKDIR_BIT_NONE) return false;
01153
01154 switch (GetTileType(tile)) {
01155 case MP_RAILWAY:
01156 if (IsRailDepot(tile)) return false;
01157 if (!remove && HasSignalOnTrack(tile, TrackdirToTrack(trackdir))) return false;
01158 signal_ctr++;
01159 if (IsDiagonalTrackdir(trackdir)) {
01160 signal_ctr++;
01161
01162 ClrBit(signal_ctr, 0);
01163 }
01164 return true;
01165
01166 case MP_ROAD:
01167 if (!IsLevelCrossing(tile)) return false;
01168 signal_ctr += 2;
01169 return true;
01170
01171 case MP_TUNNELBRIDGE: {
01172 TileIndex orig_tile = tile;
01173
01174 if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) return false;
01175 if (GetTunnelBridgeDirection(tile) != TrackdirToExitdir(trackdir)) return false;
01176
01177
01178
01179 tile = GetOtherTunnelBridgeEnd(tile);
01180
01181 signal_ctr += (GetTunnelBridgeLength(orig_tile, tile) + 2) * 2;
01182 return true;
01183 }
01184
01185 default: return false;
01186 }
01187 }
01188
01205 static CommandCost CmdSignalTrackHelper(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01206 {
01207 CommandCost total_cost(EXPENSES_CONSTRUCTION);
01208 TileIndex start_tile = tile;
01209
01210 Track track = Extract<Track, 0, 3>(p2);
01211 bool mode = HasBit(p2, 3);
01212 bool semaphores = HasBit(p2, 4);
01213 bool remove = HasBit(p2, 5);
01214 bool autofill = HasBit(p2, 6);
01215 byte signal_density = GB(p2, 24, 8);
01216
01217 if (p1 >= MapSize() || !ValParamTrackOrientation(track)) return CMD_ERROR;
01218 TileIndex end_tile = p1;
01219 if (signal_density == 0 || signal_density > 20) return CMD_ERROR;
01220
01221 if (!IsPlainRailTile(tile)) return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
01222
01223
01224
01225 signal_density *= 2;
01226
01227 Trackdir trackdir = TrackToTrackdir(track);
01228 CommandCost ret = ValidateAutoDrag(&trackdir, tile, end_tile);
01229 if (ret.Failed()) return ret;
01230
01231 track = TrackdirToTrack(trackdir);
01232 Trackdir start_trackdir = trackdir;
01233
01234
01235 if (!HasTrack(tile, track)) return CMD_ERROR;
01236
01237 SignalType sigtype = (SignalType)GB(p2, 7, 3);
01238 if (sigtype > SIGTYPE_LAST) return CMD_ERROR;
01239
01240 byte signals;
01241
01242 if (HasSignalOnTrack(tile, track)) {
01243 signals = GetPresentSignals(tile) & SignalOnTrack(track);
01244 assert(signals != 0);
01245
01246
01247 semaphores = GetSignalVariant(tile, track) != SIG_ELECTRIC;
01248
01249 sigtype = GetSignalType(tile, track);
01250
01251 if (sigtype == SIGTYPE_ENTRY || sigtype == SIGTYPE_EXIT) sigtype = SIGTYPE_NORMAL;
01252 } else {
01253 signals = IsPbsSignal(sigtype) ? SignalAlongTrackdir(trackdir) : SignalOnTrack(track);
01254 }
01255
01256 byte signal_dir = 0;
01257 if (signals & SignalAlongTrackdir(trackdir)) SetBit(signal_dir, 0);
01258 if (signals & SignalAgainstTrackdir(trackdir)) SetBit(signal_dir, 1);
01259
01260
01261
01262
01263
01264
01265
01266
01267
01268 int signal_ctr = 0;
01269 CommandCost last_error = CMD_ERROR;
01270 bool had_success = false;
01271 for (;;) {
01272
01273 if (remove || signal_ctr % signal_density == 0) {
01274 uint32 p1 = GB(TrackdirToTrack(trackdir), 0, 3);
01275 SB(p1, 3, 1, mode);
01276 SB(p1, 4, 1, semaphores);
01277 SB(p1, 5, 3, sigtype);
01278 if (!remove && signal_ctr == 0) SetBit(p1, 17);
01279
01280
01281 signals = 0;
01282 if (HasBit(signal_dir, 0)) signals |= SignalAlongTrackdir(trackdir);
01283 if (HasBit(signal_dir, 1)) signals |= SignalAgainstTrackdir(trackdir);
01284
01285 CommandCost ret = DoCommand(tile, p1, signals, flags, remove ? CMD_REMOVE_SIGNALS : CMD_BUILD_SIGNALS);
01286
01287
01288 if (ret.Succeeded()) {
01289 had_success = true;
01290 total_cost.AddCost(ret);
01291 } else {
01292
01293 if (ret.GetErrorMessage() != STR_ERROR_THERE_IS_NO_RAILROAD_TRACK ||
01294 last_error.GetErrorMessage() == INVALID_STRING_ID) {
01295 last_error = ret;
01296 }
01297 }
01298 }
01299
01300 if (autofill) {
01301 if (!CheckSignalAutoFill(tile, trackdir, signal_ctr, remove)) break;
01302
01303
01304 if (tile == start_tile && trackdir == start_trackdir) break;
01305 } else {
01306 if (tile == end_tile) break;
01307
01308 tile += ToTileIndexDiff(_trackdelta[trackdir]);
01309 signal_ctr++;
01310
01311
01312 if (IsDiagonalTrackdir(trackdir)) {
01313 signal_ctr++;
01314 } else {
01315 ToggleBit(trackdir, 0);
01316 }
01317 }
01318 }
01319
01320 return had_success ? total_cost : last_error;
01321 }
01322
01341 CommandCost CmdBuildSignalTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01342 {
01343 return CmdSignalTrackHelper(tile, flags, p1, p2, text);
01344 }
01345
01358 CommandCost CmdRemoveSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01359 {
01360 Track track = Extract<Track, 0, 3>(p1);
01361
01362 if (!ValParamTrackOrientation(track) || !IsPlainRailTile(tile) || !HasTrack(tile, track)) {
01363 return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
01364 }
01365 if (!HasSignalOnTrack(tile, track)) {
01366 return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS);
01367 }
01368 CommandCost ret = EnsureNoTrainOnTrack(tile, track);
01369 if (ret.Failed()) return ret;
01370
01371
01372 if (_current_company != OWNER_WATER) {
01373 CommandCost ret = CheckTileOwnership(tile);
01374 if (ret.Failed()) return ret;
01375 }
01376
01377
01378 if (flags & DC_EXEC) {
01379 Train *v = NULL;
01380 if (HasReservedTracks(tile, TrackToTrackBits(track))) {
01381 v = GetTrainForReservation(tile, track);
01382 } else if (IsPbsSignal(GetSignalType(tile, track))) {
01383
01384 Trackdir td = TrackToTrackdir(track);
01385 for (int i = 0; v == NULL && i < 2; i++, td = ReverseTrackdir(td)) {
01386
01387 if (!HasSignalOnTrackdir(tile, ReverseTrackdir(td))) continue;
01388 TileIndex next = TileAddByDiagDir(tile, TrackdirToExitdir(td));
01389 TrackBits tracks = TrackdirBitsToTrackBits(TrackdirReachesTrackdirs(td));
01390 if (HasReservedTracks(next, tracks)) {
01391 v = GetTrainForReservation(next, TrackBitsToTrack(GetReservedTrackbits(next) & tracks));
01392 }
01393 }
01394 }
01395 Company::Get(GetTileOwner(tile))->infrastructure.signal -= CountBits(GetPresentSignals(tile));
01396 SetPresentSignals(tile, GetPresentSignals(tile) & ~SignalOnTrack(track));
01397 Company::Get(GetTileOwner(tile))->infrastructure.signal += CountBits(GetPresentSignals(tile));
01398 DirtyCompanyInfrastructureWindows(GetTileOwner(tile));
01399
01400
01401 if (GetPresentSignals(tile) == 0) {
01402 SetSignalStates(tile, 0);
01403 SetHasSignals(tile, false);
01404 SetSignalVariant(tile, INVALID_TRACK, SIG_ELECTRIC);
01405 }
01406
01407 AddTrackToSignalBuffer(tile, track, GetTileOwner(tile));
01408 YapfNotifyTrackLayoutChange(tile, track);
01409 if (v != NULL) TryPathReserve(v, false);
01410
01411 MarkTileDirtyByTile(tile);
01412 }
01413
01414 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_SIGNALS]);
01415 }
01416
01435 CommandCost CmdRemoveSignalTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01436 {
01437 return CmdSignalTrackHelper(tile, flags, p1, SetBit(p2, 5), text);
01438 }
01439
01441 static Vehicle *UpdateTrainPowerProc(Vehicle *v, void *data)
01442 {
01443 if (v->type != VEH_TRAIN) return NULL;
01444
01445 TrainList *affected_trains = static_cast<TrainList*>(data);
01446 affected_trains->Include(Train::From(v)->First());
01447
01448 return NULL;
01449 }
01450
01463 CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01464 {
01465 RailType totype = Extract<RailType, 0, 4>(p2);
01466
01467 if (!ValParamRailtype(totype)) return CMD_ERROR;
01468 if (p1 >= MapSize()) return CMD_ERROR;
01469
01470 TrainList affected_trains;
01471
01472 CommandCost cost(EXPENSES_CONSTRUCTION);
01473 CommandCost error = CommandCost(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK);
01474 TileArea ta(tile, p1);
01475 TileIterator *iter = HasBit(p2, 4) ? (TileIterator *)new DiagonalTileIterator(tile, p1) : new OrthogonalTileIterator(ta);
01476 for (; (tile = *iter) != INVALID_TILE; ++(*iter)) {
01477 TileType tt = GetTileType(tile);
01478
01479
01480 switch (tt) {
01481 case MP_RAILWAY:
01482 break;
01483 case MP_STATION:
01484 if (!HasStationRail(tile)) continue;
01485 break;
01486 case MP_ROAD:
01487 if (!IsLevelCrossing(tile)) continue;
01488 if (RailNoLevelCrossings(totype)) {
01489 error.MakeError(STR_ERROR_CROSSING_DISALLOWED);
01490 continue;
01491 }
01492 break;
01493 case MP_TUNNELBRIDGE:
01494 if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) continue;
01495 break;
01496 default: continue;
01497 }
01498
01499
01500 RailType type = GetRailType(tile);
01501
01502
01503 if (type == totype || (_settings_game.vehicle.disable_elrails && totype == RAILTYPE_RAIL && type == RAILTYPE_ELECTRIC)) continue;
01504
01505
01506 CommandCost ret = CheckTileOwnership(tile);
01507 if (ret.Failed()) {
01508 error = ret;
01509 continue;
01510 }
01511
01512 SmallVector<Train *, 2> vehicles_affected;
01513
01514
01515
01516 if (tt != MP_TUNNELBRIDGE) {
01517 if (!IsCompatibleRail(type, totype)) {
01518 CommandCost ret = EnsureNoVehicleOnGround(tile);
01519 if (ret.Failed()) {
01520 error = ret;
01521 continue;
01522 }
01523 }
01524 if (flags & DC_EXEC) {
01525 TrackBits reserved = GetReservedTrackbits(tile);
01526 Track track;
01527 while ((track = RemoveFirstTrack(&reserved)) != INVALID_TRACK) {
01528 Train *v = GetTrainForReservation(tile, track);
01529 if (v != NULL && !HasPowerOnRail(v->railtype, totype)) {
01530
01531 FreeTrainTrackReservation(v);
01532 *vehicles_affected.Append() = v;
01533 }
01534 }
01535
01536
01537 if (!IsRailStationTile(tile) || !IsStationTileBlocked(tile)) {
01538 Company *c = Company::Get(GetTileOwner(tile));
01539 uint num_pieces = IsLevelCrossingTile(tile) ? LEVELCROSSING_TRACKBIT_FACTOR : 1;
01540 if (IsPlainRailTile(tile)) {
01541 TrackBits bits = GetTrackBits(tile);
01542 num_pieces = CountBits(bits);
01543 if (TracksOverlap(bits)) num_pieces *= num_pieces;
01544 }
01545 c->infrastructure.rail[type] -= num_pieces;
01546 c->infrastructure.rail[totype] += num_pieces;
01547 DirtyCompanyInfrastructureWindows(c->index);
01548 }
01549
01550 SetRailType(tile, totype);
01551 MarkTileDirtyByTile(tile);
01552
01553 FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc);
01554 }
01555 }
01556
01557 switch (tt) {
01558 case MP_RAILWAY:
01559 switch (GetRailTileType(tile)) {
01560 case RAIL_TILE_DEPOT:
01561 if (flags & DC_EXEC) {
01562
01563 YapfNotifyTrackLayoutChange(tile, GetRailDepotTrack(tile));
01564
01565
01566 InvalidateWindowData(WC_VEHICLE_DEPOT, tile);
01567 InvalidateWindowData(WC_BUILD_VEHICLE, tile);
01568 }
01569 cost.AddCost(RailConvertCost(type, totype));
01570 break;
01571
01572 default:
01573 if (flags & DC_EXEC) {
01574
01575 TrackBits tracks = GetTrackBits(tile);
01576 while (tracks != TRACK_BIT_NONE) {
01577 YapfNotifyTrackLayoutChange(tile, RemoveFirstTrack(&tracks));
01578 }
01579 }
01580 cost.AddCost(RailConvertCost(type, totype) * CountBits(GetTrackBits(tile)));
01581 break;
01582 }
01583 break;
01584
01585 case MP_TUNNELBRIDGE: {
01586 TileIndex endtile = GetOtherTunnelBridgeEnd(tile);
01587
01588
01589
01590 if (endtile < tile && TileX(endtile) >= TileX(ta.tile) && TileX(endtile) < TileX(ta.tile) + ta.w &&
01591 TileY(endtile) >= TileY(ta.tile) && TileY(endtile) < TileY(ta.tile) + ta.h) continue;
01592
01593
01594 if (!IsCompatibleRail(GetRailType(tile), totype)) {
01595 CommandCost ret = TunnelBridgeIsFree(tile, endtile);
01596 if (ret.Failed()) {
01597 error = ret;
01598 continue;
01599 }
01600 }
01601
01602 if (flags & DC_EXEC) {
01603 Track track = DiagDirToDiagTrack(GetTunnelBridgeDirection(tile));
01604 if (HasTunnelBridgeReservation(tile)) {
01605 Train *v = GetTrainForReservation(tile, track);
01606 if (v != NULL && !HasPowerOnRail(v->railtype, totype)) {
01607
01608 FreeTrainTrackReservation(v);
01609 *vehicles_affected.Append() = v;
01610 }
01611 }
01612
01613
01614 uint num_pieces = (GetTunnelBridgeLength(tile, endtile) + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR;
01615 Company *c = Company::Get(GetTileOwner(tile));
01616 c->infrastructure.rail[GetRailType(tile)] -= num_pieces;
01617 c->infrastructure.rail[totype] += num_pieces;
01618 DirtyCompanyInfrastructureWindows(c->index);
01619
01620 SetRailType(tile, totype);
01621 SetRailType(endtile, totype);
01622
01623 FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc);
01624 FindVehicleOnPos(endtile, &affected_trains, &UpdateTrainPowerProc);
01625
01626 YapfNotifyTrackLayoutChange(tile, track);
01627 YapfNotifyTrackLayoutChange(endtile, track);
01628
01629 MarkTileDirtyByTile(tile);
01630 MarkTileDirtyByTile(endtile);
01631
01632 if (IsBridge(tile)) {
01633 TileIndexDiff delta = TileOffsByDiagDir(GetTunnelBridgeDirection(tile));
01634 TileIndex t = tile + delta;
01635 for (; t != endtile; t += delta) MarkTileDirtyByTile(t);
01636 }
01637 }
01638
01639 cost.AddCost((GetTunnelBridgeLength(tile, endtile) + 2) * RailConvertCost(type, totype));
01640 break;
01641 }
01642
01643 default:
01644 if (flags & DC_EXEC) {
01645 Track track = ((tt == MP_STATION) ? GetRailStationTrack(tile) : GetCrossingRailTrack(tile));
01646 YapfNotifyTrackLayoutChange(tile, track);
01647 }
01648
01649 cost.AddCost(RailConvertCost(type, totype));
01650 break;
01651 }
01652
01653 for (uint i = 0; i < vehicles_affected.Length(); ++i) {
01654 TryPathReserve(vehicles_affected[i], true);
01655 }
01656 }
01657
01658 if (flags & DC_EXEC) {
01659
01660 for (Train **v = affected_trains.Begin(); v != affected_trains.End(); v++) {
01661 (*v)->ConsistChanged(true);
01662 }
01663 }
01664
01665 delete iter;
01666 return (cost.GetCost() == 0) ? error : cost;
01667 }
01668
01669 static CommandCost RemoveTrainDepot(TileIndex tile, DoCommandFlag flags)
01670 {
01671 if (_current_company != OWNER_WATER) {
01672 CommandCost ret = CheckTileOwnership(tile);
01673 if (ret.Failed()) return ret;
01674 }
01675
01676 CommandCost ret = EnsureNoVehicleOnGround(tile);
01677 if (ret.Failed()) return ret;
01678
01679 if (flags & DC_EXEC) {
01680
01681 DiagDirection dir = GetRailDepotDirection(tile);
01682 Owner owner = GetTileOwner(tile);
01683 Train *v = NULL;
01684
01685 if (HasDepotReservation(tile)) {
01686 v = GetTrainForReservation(tile, DiagDirToDiagTrack(dir));
01687 if (v != NULL) FreeTrainTrackReservation(v);
01688 }
01689
01690 Company::Get(owner)->infrastructure.rail[GetRailType(tile)]--;
01691 DirtyCompanyInfrastructureWindows(owner);
01692
01693 delete Depot::GetByTile(tile);
01694 DoClearSquare(tile);
01695 AddSideToSignalBuffer(tile, dir, owner);
01696 YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
01697 if (v != NULL) TryPathReserve(v, true);
01698 }
01699
01700 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_TRAIN]);
01701 }
01702
01703 static CommandCost ClearTile_Track(TileIndex tile, DoCommandFlag flags)
01704 {
01705 CommandCost cost(EXPENSES_CONSTRUCTION);
01706
01707 if (flags & DC_AUTO) {
01708 if (!IsTileOwner(tile, _current_company)) {
01709 return_cmd_error(STR_ERROR_AREA_IS_OWNED_BY_ANOTHER);
01710 }
01711
01712 if (IsPlainRail(tile)) {
01713 return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
01714 } else {
01715 return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
01716 }
01717 }
01718
01719 switch (GetRailTileType(tile)) {
01720 case RAIL_TILE_SIGNALS:
01721 case RAIL_TILE_NORMAL: {
01722 Slope tileh = GetTileSlope(tile);
01723
01724 bool water_ground = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh));
01725
01726 TrackBits tracks = GetTrackBits(tile);
01727 while (tracks != TRACK_BIT_NONE) {
01728 Track track = RemoveFirstTrack(&tracks);
01729 CommandCost ret = DoCommand(tile, 0, track, flags, CMD_REMOVE_SINGLE_RAIL);
01730 if (ret.Failed()) return ret;
01731 cost.AddCost(ret);
01732 }
01733
01734
01735 if (water_ground && !(flags & DC_BANKRUPT)) {
01736 CommandCost ret = EnsureNoVehicleOnGround(tile);
01737 if (ret.Failed()) return ret;
01738
01739
01740 if (flags & DC_EXEC) DoClearSquare(tile);
01741 cost.AddCost(_price[PR_CLEAR_WATER]);
01742 }
01743
01744 return cost;
01745 }
01746
01747 case RAIL_TILE_DEPOT:
01748 return RemoveTrainDepot(tile, flags);
01749
01750 default:
01751 return CMD_ERROR;
01752 }
01753 }
01754
01759 static uint GetSaveSlopeZ(uint x, uint y, Track track)
01760 {
01761 switch (track) {
01762 case TRACK_UPPER: x &= ~0xF; y &= ~0xF; break;
01763 case TRACK_LOWER: x |= 0xF; y |= 0xF; break;
01764 case TRACK_LEFT: x |= 0xF; y &= ~0xF; break;
01765 case TRACK_RIGHT: x &= ~0xF; y |= 0xF; break;
01766 default: break;
01767 }
01768 return GetSlopePixelZ(x, y);
01769 }
01770
01771 static void DrawSingleSignal(TileIndex tile, Track track, byte condition, uint image, uint pos)
01772 {
01773 bool side = (_settings_game.vehicle.road_side != 0) && _settings_game.construction.signal_side;
01774 static const Point SignalPositions[2][12] = {
01775 {
01776
01777 { 8, 5}, {14, 1}, { 1, 14}, { 9, 11}, { 1, 0}, { 3, 10},
01778
01779 {11, 4}, {14, 14}, {11, 3}, { 4, 13}, { 3, 4}, {11, 13}
01780 }, {
01781
01782 {14, 1}, {12, 10}, { 4, 6}, { 1, 14}, {10, 4}, { 0, 1},
01783
01784 {14, 14}, { 5, 12}, {11, 13}, { 4, 3}, {13, 4}, { 3, 11}
01785 }
01786 };
01787
01788 uint x = TileX(tile) * TILE_SIZE + SignalPositions[side][pos].x;
01789 uint y = TileY(tile) * TILE_SIZE + SignalPositions[side][pos].y;
01790
01791 SpriteID sprite;
01792
01793 SignalType type = GetSignalType(tile, track);
01794 SignalVariant variant = GetSignalVariant(tile, track);
01795
01796 if (type == SIGTYPE_NORMAL && variant == SIG_ELECTRIC) {
01797
01798 sprite = SPR_ORIGINAL_SIGNALS_BASE + image + condition;
01799 } else {
01800
01801 sprite = SPR_SIGNALS_BASE + (type - 1) * 16 + variant * 64 + image + condition + (type > SIGTYPE_LAST_NOPBS ? 64 : 0);
01802 }
01803
01804 AddSortableSpriteToDraw(sprite, PAL_NONE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, GetSaveSlopeZ(x, y, track));
01805 }
01806
01807 static uint32 _drawtile_track_palette;
01808
01809
01810 static void DrawTrackFence_NW(const TileInfo *ti, SpriteID base_image)
01811 {
01812 RailFenceOffset rfo = RFO_FLAT_X;
01813 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SW : RFO_SLOPE_NE;
01814 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01815 ti->x, ti->y + 1, 16, 1, 4, ti->z);
01816 }
01817
01818 static void DrawTrackFence_SE(const TileInfo *ti, SpriteID base_image)
01819 {
01820 RailFenceOffset rfo = RFO_FLAT_X;
01821 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SW : RFO_SLOPE_NE;
01822 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01823 ti->x, ti->y + TILE_SIZE - 1, 16, 1, 4, ti->z);
01824 }
01825
01826 static void DrawTrackFence_NW_SE(const TileInfo *ti, SpriteID base_image)
01827 {
01828 DrawTrackFence_NW(ti, base_image);
01829 DrawTrackFence_SE(ti, base_image);
01830 }
01831
01832 static void DrawTrackFence_NE(const TileInfo *ti, SpriteID base_image)
01833 {
01834 RailFenceOffset rfo = RFO_FLAT_Y;
01835 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SE : RFO_SLOPE_NW;
01836 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01837 ti->x + 1, ti->y, 1, 16, 4, ti->z);
01838 }
01839
01840 static void DrawTrackFence_SW(const TileInfo *ti, SpriteID base_image)
01841 {
01842 RailFenceOffset rfo = RFO_FLAT_Y;
01843 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SE : RFO_SLOPE_NW;
01844 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01845 ti->x + TILE_SIZE - 1, ti->y, 1, 16, 4, ti->z);
01846 }
01847
01848 static void DrawTrackFence_NE_SW(const TileInfo *ti, SpriteID base_image)
01849 {
01850 DrawTrackFence_NE(ti, base_image);
01851 DrawTrackFence_SW(ti, base_image);
01852 }
01853
01857 static void DrawTrackFence_NS_1(const TileInfo *ti, SpriteID base_image)
01858 {
01859 int z = ti->z + GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_W);
01860 AddSortableSpriteToDraw(base_image + RFO_FLAT_VERT, _drawtile_track_palette,
01861 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01862 }
01863
01867 static void DrawTrackFence_NS_2(const TileInfo *ti, SpriteID base_image)
01868 {
01869 int z = ti->z + GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_E);
01870 AddSortableSpriteToDraw(base_image + RFO_FLAT_VERT, _drawtile_track_palette,
01871 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01872 }
01873
01877 static void DrawTrackFence_WE_1(const TileInfo *ti, SpriteID base_image)
01878 {
01879 int z = ti->z + GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_N);
01880 AddSortableSpriteToDraw(base_image + RFO_FLAT_HORZ, _drawtile_track_palette,
01881 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01882 }
01883
01887 static void DrawTrackFence_WE_2(const TileInfo *ti, SpriteID base_image)
01888 {
01889 int z = ti->z + GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_S);
01890 AddSortableSpriteToDraw(base_image + RFO_FLAT_HORZ, _drawtile_track_palette,
01891 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01892 }
01893
01894
01895 static void DrawTrackDetails(const TileInfo *ti, const RailtypeInfo *rti)
01896 {
01897
01898
01899 SpriteID base_image = GetCustomRailSprite(rti, ti->tile, RTSG_FENCES, IsHalftileSlope(ti->tileh) ? TCX_UPPER_HALFTILE : TCX_NORMAL);
01900 if (base_image == 0) base_image = SPR_TRACK_FENCE_FLAT_X;
01901
01902 switch (GetRailGroundType(ti->tile)) {
01903 case RAIL_GROUND_FENCE_NW: DrawTrackFence_NW(ti, base_image); break;
01904 case RAIL_GROUND_FENCE_SE: DrawTrackFence_SE(ti, base_image); break;
01905 case RAIL_GROUND_FENCE_SENW: DrawTrackFence_NW_SE(ti, base_image); break;
01906 case RAIL_GROUND_FENCE_NE: DrawTrackFence_NE(ti, base_image); break;
01907 case RAIL_GROUND_FENCE_SW: DrawTrackFence_SW(ti, base_image); break;
01908 case RAIL_GROUND_FENCE_NESW: DrawTrackFence_NE_SW(ti, base_image); break;
01909 case RAIL_GROUND_FENCE_VERT1: DrawTrackFence_NS_1(ti, base_image); break;
01910 case RAIL_GROUND_FENCE_VERT2: DrawTrackFence_NS_2(ti, base_image); break;
01911 case RAIL_GROUND_FENCE_HORIZ1: DrawTrackFence_WE_1(ti, base_image); break;
01912 case RAIL_GROUND_FENCE_HORIZ2: DrawTrackFence_WE_2(ti, base_image); break;
01913 case RAIL_GROUND_WATER: {
01914 Corner track_corner;
01915 if (IsHalftileSlope(ti->tileh)) {
01916
01917 track_corner = GetHalftileSlopeCorner(ti->tileh);
01918 } else {
01919
01920 track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh)));
01921 }
01922 switch (track_corner) {
01923 case CORNER_W: DrawTrackFence_NS_1(ti, base_image); break;
01924 case CORNER_S: DrawTrackFence_WE_2(ti, base_image); break;
01925 case CORNER_E: DrawTrackFence_NS_2(ti, base_image); break;
01926 case CORNER_N: DrawTrackFence_WE_1(ti, base_image); break;
01927 default: NOT_REACHED();
01928 }
01929 break;
01930 }
01931 default: break;
01932 }
01933 }
01934
01935
01936 static const int INF = 1000;
01937 static const SubSprite _halftile_sub_sprite[4] = {
01938 { -INF , -INF , 32 - 33, INF },
01939 { -INF , 0 + 7, INF , INF },
01940 { -31 + 33, -INF , INF , INF },
01941 { -INF , -INF , INF , 30 - 23 }
01942 };
01943
01944 static inline void DrawTrackSprite(SpriteID sprite, PaletteID pal, const TileInfo *ti, Slope s)
01945 {
01946 DrawGroundSprite(sprite, pal, NULL, 0, (ti->tileh & s) ? -8 : 0);
01947 }
01948
01949 static void DrawTrackBitsOverlay(TileInfo *ti, TrackBits track, const RailtypeInfo *rti)
01950 {
01951 RailGroundType rgt = GetRailGroundType(ti->tile);
01952 Foundation f = GetRailFoundation(ti->tileh, track);
01953 Corner halftile_corner = CORNER_INVALID;
01954
01955 if (IsNonContinuousFoundation(f)) {
01956
01957 halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f));
01958
01959 track &= ~CornerToTrackBits(halftile_corner);
01960 f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE);
01961 }
01962
01963 DrawFoundation(ti, f);
01964
01965
01966
01967 if (rgt == RAIL_GROUND_WATER) {
01968 if (track != TRACK_BIT_NONE || IsSteepSlope(ti->tileh)) {
01969
01970 DrawShoreTile(ti->tileh);
01971 } else {
01972
01973 DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
01974 }
01975 } else {
01976 SpriteID image;
01977
01978 switch (rgt) {
01979 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
01980 case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOW_DESERT_TILE; break;
01981 default: image = SPR_FLAT_GRASS_TILE; break;
01982 }
01983
01984 image += SlopeToSpriteOffset(ti->tileh);
01985
01986 DrawGroundSprite(image, PAL_NONE);
01987 }
01988
01989 SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
01990 SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
01991 TrackBits pbs = _settings_client.gui.show_track_reservation ? GetRailReservationTrackBits(ti->tile) : TRACK_BIT_NONE;
01992
01993 if (track == TRACK_BIT_NONE) {
01994
01995 } else if (ti->tileh == SLOPE_NW && track == TRACK_BIT_Y) {
01996 DrawGroundSprite(ground + RTO_SLOPE_NW, PAL_NONE);
01997 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 9, PALETTE_CRASH);
01998 } else if (ti->tileh == SLOPE_NE && track == TRACK_BIT_X) {
01999 DrawGroundSprite(ground + RTO_SLOPE_NE, PAL_NONE);
02000 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 6, PALETTE_CRASH);
02001 } else if (ti->tileh == SLOPE_SE && track == TRACK_BIT_Y) {
02002 DrawGroundSprite(ground + RTO_SLOPE_SE, PAL_NONE);
02003 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 7, PALETTE_CRASH);
02004 } else if (ti->tileh == SLOPE_SW && track == TRACK_BIT_X) {
02005 DrawGroundSprite(ground + RTO_SLOPE_SW, PAL_NONE);
02006 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 8, PALETTE_CRASH);
02007 } else {
02008 switch (track) {
02009
02010
02011 case TRACK_BIT_X: DrawGroundSprite(ground + RTO_X, PAL_NONE); break;
02012 case TRACK_BIT_Y: DrawGroundSprite(ground + RTO_Y, PAL_NONE); break;
02013 case TRACK_BIT_UPPER: DrawTrackSprite(ground + RTO_N, PAL_NONE, ti, SLOPE_N); break;
02014 case TRACK_BIT_LOWER: DrawTrackSprite(ground + RTO_S, PAL_NONE, ti, SLOPE_S); break;
02015 case TRACK_BIT_RIGHT: DrawTrackSprite(ground + RTO_E, PAL_NONE, ti, SLOPE_E); break;
02016 case TRACK_BIT_LEFT: DrawTrackSprite(ground + RTO_W, PAL_NONE, ti, SLOPE_W); break;
02017 case TRACK_BIT_CROSS: DrawGroundSprite(ground + RTO_CROSSING_XY, PAL_NONE); break;
02018 case TRACK_BIT_HORZ: DrawTrackSprite(ground + RTO_N, PAL_NONE, ti, SLOPE_N);
02019 DrawTrackSprite(ground + RTO_S, PAL_NONE, ti, SLOPE_S); break;
02020 case TRACK_BIT_VERT: DrawTrackSprite(ground + RTO_E, PAL_NONE, ti, SLOPE_E);
02021 DrawTrackSprite(ground + RTO_W, PAL_NONE, ti, SLOPE_W); break;
02022
02023 default:
02024
02025 if ((track & TRACK_BIT_3WAY_NE) == 0) {
02026 DrawGroundSprite(ground + RTO_JUNCTION_SW, PAL_NONE);
02027 } else if ((track & TRACK_BIT_3WAY_SW) == 0) {
02028 DrawGroundSprite(ground + RTO_JUNCTION_NE, PAL_NONE);
02029 } else if ((track & TRACK_BIT_3WAY_NW) == 0) {
02030 DrawGroundSprite(ground + RTO_JUNCTION_SE, PAL_NONE);
02031 } else if ((track & TRACK_BIT_3WAY_SE) == 0) {
02032 DrawGroundSprite(ground + RTO_JUNCTION_NW, PAL_NONE);
02033 } else {
02034 DrawGroundSprite(ground + RTO_JUNCTION_NSEW, PAL_NONE);
02035 }
02036
02037
02038 track &= ~pbs;
02039
02040
02041 if (track & TRACK_BIT_X) DrawGroundSprite(overlay + RTO_X, PAL_NONE);
02042 if (track & TRACK_BIT_Y) DrawGroundSprite(overlay + RTO_Y, PAL_NONE);
02043 if (track & TRACK_BIT_UPPER) DrawGroundSprite(overlay + RTO_N, PAL_NONE);
02044 if (track & TRACK_BIT_LOWER) DrawGroundSprite(overlay + RTO_S, PAL_NONE);
02045 if (track & TRACK_BIT_RIGHT) DrawGroundSprite(overlay + RTO_E, PAL_NONE);
02046 if (track & TRACK_BIT_LEFT) DrawGroundSprite(overlay + RTO_W, PAL_NONE);
02047 }
02048
02049
02050 if (pbs & TRACK_BIT_X) DrawGroundSprite(overlay + RTO_X, PALETTE_CRASH);
02051 if (pbs & TRACK_BIT_Y) DrawGroundSprite(overlay + RTO_Y, PALETTE_CRASH);
02052 if (pbs & TRACK_BIT_UPPER) DrawTrackSprite(overlay + RTO_N, PALETTE_CRASH, ti, SLOPE_N);
02053 if (pbs & TRACK_BIT_LOWER) DrawTrackSprite(overlay + RTO_S, PALETTE_CRASH, ti, SLOPE_S);
02054 if (pbs & TRACK_BIT_RIGHT) DrawTrackSprite(overlay + RTO_E, PALETTE_CRASH, ti, SLOPE_E);
02055 if (pbs & TRACK_BIT_LEFT) DrawTrackSprite(overlay + RTO_W, PALETTE_CRASH, ti, SLOPE_W);
02056 }
02057
02058 if (IsValidCorner(halftile_corner)) {
02059 DrawFoundation(ti, HalftileFoundation(halftile_corner));
02060 overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY, TCX_UPPER_HALFTILE);
02061 ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND, TCX_UPPER_HALFTILE);
02062
02063
02064 Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
02065
02066 SpriteID image;
02067 switch (rgt) {
02068 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
02069 case RAIL_GROUND_ICE_DESERT:
02070 case RAIL_GROUND_HALF_SNOW: image = SPR_FLAT_SNOW_DESERT_TILE; break;
02071 default: image = SPR_FLAT_GRASS_TILE; break;
02072 }
02073
02074 image += SlopeToSpriteOffset(fake_slope);
02075
02076 DrawGroundSprite(image, PAL_NONE, &(_halftile_sub_sprite[halftile_corner]));
02077
02078 track = CornerToTrackBits(halftile_corner);
02079
02080 int offset;
02081 switch (track) {
02082 default: NOT_REACHED();
02083 case TRACK_BIT_UPPER: offset = RTO_N; break;
02084 case TRACK_BIT_LOWER: offset = RTO_S; break;
02085 case TRACK_BIT_RIGHT: offset = RTO_E; break;
02086 case TRACK_BIT_LEFT: offset = RTO_W; break;
02087 }
02088
02089 DrawTrackSprite(ground + offset, PAL_NONE, ti, fake_slope);
02090 if (_settings_client.gui.show_track_reservation && HasReservedTracks(ti->tile, track)) {
02091 DrawTrackSprite(overlay + offset, PALETTE_CRASH, ti, fake_slope);
02092 }
02093 }
02094 }
02095
02101 static void DrawTrackBits(TileInfo *ti, TrackBits track)
02102 {
02103 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
02104
02105 if (rti->UsesOverlay()) {
02106 DrawTrackBitsOverlay(ti, track, rti);
02107 return;
02108 }
02109
02110 RailGroundType rgt = GetRailGroundType(ti->tile);
02111 Foundation f = GetRailFoundation(ti->tileh, track);
02112 Corner halftile_corner = CORNER_INVALID;
02113
02114 if (IsNonContinuousFoundation(f)) {
02115
02116 halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f));
02117
02118 track &= ~CornerToTrackBits(halftile_corner);
02119 f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE);
02120 }
02121
02122 DrawFoundation(ti, f);
02123
02124
02125 SpriteID image;
02126 PaletteID pal = PAL_NONE;
02127 const SubSprite *sub = NULL;
02128 bool junction = false;
02129
02130
02131 if (track == 0) {
02132
02133 if (rgt == RAIL_GROUND_WATER) {
02134 if (IsSteepSlope(ti->tileh)) {
02135 DrawShoreTile(ti->tileh);
02136 image = 0;
02137 } else {
02138 image = SPR_FLAT_WATER_TILE;
02139 }
02140 } else {
02141 switch (rgt) {
02142 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
02143 case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOW_DESERT_TILE; break;
02144 default: image = SPR_FLAT_GRASS_TILE; break;
02145 }
02146 image += SlopeToSpriteOffset(ti->tileh);
02147 }
02148 } else {
02149 if (ti->tileh != SLOPE_FLAT) {
02150
02151 image = _track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.track_y;
02152 } else {
02153
02154 (image = rti->base_sprites.track_y, track == TRACK_BIT_Y) ||
02155 (image++, track == TRACK_BIT_X) ||
02156 (image++, track == TRACK_BIT_UPPER) ||
02157 (image++, track == TRACK_BIT_LOWER) ||
02158 (image++, track == TRACK_BIT_RIGHT) ||
02159 (image++, track == TRACK_BIT_LEFT) ||
02160 (image++, track == TRACK_BIT_CROSS) ||
02161
02162 (image = rti->base_sprites.track_ns, track == TRACK_BIT_HORZ) ||
02163 (image++, track == TRACK_BIT_VERT) ||
02164
02165 (junction = true, false) ||
02166 (image = rti->base_sprites.ground, (track & TRACK_BIT_3WAY_NE) == 0) ||
02167 (image++, (track & TRACK_BIT_3WAY_SW) == 0) ||
02168 (image++, (track & TRACK_BIT_3WAY_NW) == 0) ||
02169 (image++, (track & TRACK_BIT_3WAY_SE) == 0) ||
02170 (image++, true);
02171 }
02172
02173 switch (rgt) {
02174 case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
02175 case RAIL_GROUND_ICE_DESERT: image += rti->snow_offset; break;
02176 case RAIL_GROUND_WATER: {
02177
02178 DrawShoreTile(ti->tileh);
02179 Corner track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh)));
02180 sub = &(_halftile_sub_sprite[track_corner]);
02181 break;
02182 }
02183 default: break;
02184 }
02185 }
02186
02187 if (image != 0) DrawGroundSprite(image, pal, sub);
02188
02189
02190 if (junction) {
02191 if (track & TRACK_BIT_X) DrawGroundSprite(rti->base_sprites.single_x, PAL_NONE);
02192 if (track & TRACK_BIT_Y) DrawGroundSprite(rti->base_sprites.single_y, PAL_NONE);
02193 if (track & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PAL_NONE);
02194 if (track & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PAL_NONE);
02195 if (track & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PAL_NONE);
02196 if (track & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PAL_NONE);
02197 }
02198
02199
02200 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation) {
02201
02202 TrackBits pbs = GetRailReservationTrackBits(ti->tile) & track;
02203 if (pbs & TRACK_BIT_X) {
02204 if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
02205 DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH);
02206 } else {
02207 DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
02208 }
02209 }
02210 if (pbs & TRACK_BIT_Y) {
02211 if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
02212 DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH);
02213 } else {
02214 DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
02215 }
02216 }
02217 if (pbs & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_N ? -(int)TILE_HEIGHT : 0);
02218 if (pbs & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_S ? -(int)TILE_HEIGHT : 0);
02219 if (pbs & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_W ? -(int)TILE_HEIGHT : 0);
02220 if (pbs & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_E ? -(int)TILE_HEIGHT : 0);
02221 }
02222
02223 if (IsValidCorner(halftile_corner)) {
02224 DrawFoundation(ti, HalftileFoundation(halftile_corner));
02225
02226
02227 Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
02228 image = _track_sloped_sprites[fake_slope - 1] + rti->base_sprites.track_y;
02229 pal = PAL_NONE;
02230 switch (rgt) {
02231 case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
02232 case RAIL_GROUND_ICE_DESERT:
02233 case RAIL_GROUND_HALF_SNOW: image += rti->snow_offset; break;
02234 default: break;
02235 }
02236 DrawGroundSprite(image, pal, &(_halftile_sub_sprite[halftile_corner]));
02237
02238 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasReservedTracks(ti->tile, CornerToTrackBits(halftile_corner))) {
02239 static const byte _corner_to_track_sprite[] = {3, 1, 2, 0};
02240 DrawGroundSprite(_corner_to_track_sprite[halftile_corner] + rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, -(int)TILE_HEIGHT);
02241 }
02242 }
02243 }
02244
02252 enum SignalOffsets {
02253 SIGNAL_TO_SOUTHWEST = 0,
02254 SIGNAL_TO_NORTHEAST = 2,
02255 SIGNAL_TO_SOUTHEAST = 4,
02256 SIGNAL_TO_NORTHWEST = 6,
02257 SIGNAL_TO_EAST = 8,
02258 SIGNAL_TO_WEST = 10,
02259 SIGNAL_TO_SOUTH = 12,
02260 SIGNAL_TO_NORTH = 14,
02261 };
02262
02263 static void DrawSignals(TileIndex tile, TrackBits rails)
02264 {
02265 #define MAYBE_DRAW_SIGNAL(x, y, z, t) if (IsSignalPresent(tile, x)) DrawSingleSignal(tile, t, GetSingleSignalState(tile, x), y, z)
02266
02267 if (!(rails & TRACK_BIT_Y)) {
02268 if (!(rails & TRACK_BIT_X)) {
02269 if (rails & TRACK_BIT_LEFT) {
02270 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTH, 0, TRACK_LEFT);
02271 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTH, 1, TRACK_LEFT);
02272 }
02273 if (rails & TRACK_BIT_RIGHT) {
02274 MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_NORTH, 2, TRACK_RIGHT);
02275 MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_SOUTH, 3, TRACK_RIGHT);
02276 }
02277 if (rails & TRACK_BIT_UPPER) {
02278 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_WEST, 4, TRACK_UPPER);
02279 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_EAST, 5, TRACK_UPPER);
02280 }
02281 if (rails & TRACK_BIT_LOWER) {
02282 MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_WEST, 6, TRACK_LOWER);
02283 MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_EAST, 7, TRACK_LOWER);
02284 }
02285 } else {
02286 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHWEST, 8, TRACK_X);
02287 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHEAST, 9, TRACK_X);
02288 }
02289 } else {
02290 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHEAST, 10, TRACK_Y);
02291 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHWEST, 11, TRACK_Y);
02292 }
02293 }
02294
02295 static void DrawTile_Track(TileInfo *ti)
02296 {
02297 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
02298
02299 _drawtile_track_palette = COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile));
02300
02301 if (IsPlainRail(ti->tile)) {
02302 TrackBits rails = GetTrackBits(ti->tile);
02303
02304 DrawTrackBits(ti, rails);
02305
02306 if (HasBit(_display_opt, DO_FULL_DETAIL)) DrawTrackDetails(ti, rti);
02307
02308 if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
02309
02310 if (HasSignals(ti->tile)) DrawSignals(ti->tile, rails);
02311 } else {
02312
02313 const DrawTileSprites *dts;
02314 PaletteID pal = PAL_NONE;
02315 SpriteID relocation;
02316
02317 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
02318
02319 if (IsInvisibilitySet(TO_BUILDINGS)) {
02320
02321 dts = &_depot_invisible_gfx_table[GetRailDepotDirection(ti->tile)];
02322 } else {
02323 dts = &_depot_gfx_table[GetRailDepotDirection(ti->tile)];
02324 }
02325
02326 SpriteID image;
02327 if (rti->UsesOverlay()) {
02328 image = SPR_FLAT_GRASS_TILE;
02329 } else {
02330 image = dts->ground.sprite;
02331 if (image != SPR_FLAT_GRASS_TILE) image += rti->GetRailtypeSpriteOffset();
02332 }
02333
02334
02335
02336 if (IsSnowRailGround(ti->tile) && _settings_game.game_creation.landscape == LT_TROPIC) {
02337 if (image != SPR_FLAT_GRASS_TILE) {
02338 image += rti->snow_offset;
02339 } else {
02340 image = SPR_FLAT_SNOW_DESERT_TILE;
02341 }
02342 }
02343
02344 DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, _drawtile_track_palette));
02345
02346 if (rti->UsesOverlay()) {
02347 SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
02348
02349 switch (GetRailDepotDirection(ti->tile)) {
02350 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02351 case DIAGDIR_SW: DrawGroundSprite(ground + RTO_X, PAL_NONE); break;
02352 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02353 case DIAGDIR_SE: DrawGroundSprite(ground + RTO_Y, PAL_NONE); break;
02354 default: break;
02355 }
02356
02357 if (_settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile)) {
02358 SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
02359
02360 switch (GetRailDepotDirection(ti->tile)) {
02361 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02362 case DIAGDIR_SW: DrawGroundSprite(overlay + RTO_X, PALETTE_CRASH); break;
02363 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02364 case DIAGDIR_SE: DrawGroundSprite(overlay + RTO_Y, PALETTE_CRASH); break;
02365 default: break;
02366 }
02367 }
02368 } else {
02369
02370 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile)) {
02371 switch (GetRailDepotDirection(ti->tile)) {
02372 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02373 case DIAGDIR_SW: DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH); break;
02374 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02375 case DIAGDIR_SE: DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH); break;
02376 default: break;
02377 }
02378 }
02379 }
02380 int depot_sprite = GetCustomRailSprite(rti, ti->tile, RTSG_DEPOT);
02381 relocation = depot_sprite != 0 ? depot_sprite - SPR_RAIL_DEPOT_SE_1 : rti->GetRailtypeSpriteOffset();
02382
02383 if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
02384
02385 DrawRailTileSeq(ti, dts, TO_BUILDINGS, relocation, 0, _drawtile_track_palette);
02386 }
02387 DrawBridgeMiddle(ti);
02388 }
02389
02390 void DrawTrainDepotSprite(int x, int y, int dir, RailType railtype)
02391 {
02392 const DrawTileSprites *dts = &_depot_gfx_table[dir];
02393 const RailtypeInfo *rti = GetRailTypeInfo(railtype);
02394 SpriteID image = rti->UsesOverlay() ? SPR_FLAT_GRASS_TILE : dts->ground.sprite;
02395 uint32 offset = rti->GetRailtypeSpriteOffset();
02396
02397 x += 33;
02398 y += 17;
02399
02400 if (image != SPR_FLAT_GRASS_TILE) image += offset;
02401 PaletteID palette = COMPANY_SPRITE_COLOUR(_local_company);
02402
02403 DrawSprite(image, PAL_NONE, x, y);
02404
02405 if (rti->UsesOverlay()) {
02406 SpriteID ground = GetCustomRailSprite(rti, INVALID_TILE, RTSG_GROUND);
02407
02408 switch (dir) {
02409 case DIAGDIR_SW: DrawSprite(ground + RTO_X, PAL_NONE, x, y); break;
02410 case DIAGDIR_SE: DrawSprite(ground + RTO_Y, PAL_NONE, x, y); break;
02411 default: break;
02412 }
02413 }
02414 int depot_sprite = GetCustomRailSprite(rti, INVALID_TILE, RTSG_DEPOT);
02415 if (depot_sprite != 0) offset = depot_sprite - SPR_RAIL_DEPOT_SE_1;
02416
02417 DrawRailTileSeqInGUI(x, y, dts, offset, 0, palette);
02418 }
02419
02420 static int GetSlopePixelZ_Track(TileIndex tile, uint x, uint y)
02421 {
02422 if (IsPlainRail(tile)) {
02423 int z;
02424 Slope tileh = GetTilePixelSlope(tile, &z);
02425 if (tileh == SLOPE_FLAT) return z;
02426
02427 z += ApplyPixelFoundationToSlope(GetRailFoundation(tileh, GetTrackBits(tile)), &tileh);
02428 return z + GetPartialPixelZ(x & 0xF, y & 0xF, tileh);
02429 } else {
02430 return GetTileMaxPixelZ(tile);
02431 }
02432 }
02433
02434 static Foundation GetFoundation_Track(TileIndex tile, Slope tileh)
02435 {
02436 return IsPlainRail(tile) ? GetRailFoundation(tileh, GetTrackBits(tile)) : FlatteningFoundation(tileh);
02437 }
02438
02439 static void TileLoop_Track(TileIndex tile)
02440 {
02441 RailGroundType old_ground = GetRailGroundType(tile);
02442 RailGroundType new_ground;
02443
02444 if (old_ground == RAIL_GROUND_WATER) {
02445 TileLoop_Water(tile);
02446 return;
02447 }
02448
02449 switch (_settings_game.game_creation.landscape) {
02450 case LT_ARCTIC: {
02451 int z;
02452 Slope slope = GetTileSlope(tile, &z);
02453 bool half = false;
02454
02455
02456
02457 if (IsPlainRail(tile)) {
02458 TrackBits track = GetTrackBits(tile);
02459 Foundation f = GetRailFoundation(slope, track);
02460
02461 switch (f) {
02462 case FOUNDATION_NONE:
02463
02464 if (IsSlopeWithThreeCornersRaised(slope)) z++;
02465 break;
02466
02467 case FOUNDATION_INCLINED_X:
02468 case FOUNDATION_INCLINED_Y:
02469
02470 if (IsSteepSlope(slope)) z++;
02471 break;
02472
02473 case FOUNDATION_STEEP_LOWER:
02474
02475 z++;
02476 break;
02477
02478 default:
02479
02480 if (IsSteepSlope(slope)) z++;
02481 z++;
02482 break;
02483 }
02484
02485 half = IsInsideMM(f, FOUNDATION_STEEP_BOTH, FOUNDATION_HALFTILE_N + 1);
02486 } else {
02487
02488 if (slope != SLOPE_FLAT) z++;
02489 }
02490
02491
02492
02493
02494
02495 if (z > GetSnowLine()) {
02496 if (half && z - GetSnowLine() == 1) {
02497
02498 new_ground = RAIL_GROUND_HALF_SNOW;
02499 } else {
02500 new_ground = RAIL_GROUND_ICE_DESERT;
02501 }
02502 goto set_ground;
02503 }
02504 break;
02505 }
02506
02507 case LT_TROPIC:
02508 if (GetTropicZone(tile) == TROPICZONE_DESERT) {
02509 new_ground = RAIL_GROUND_ICE_DESERT;
02510 goto set_ground;
02511 }
02512 break;
02513 }
02514
02515 new_ground = RAIL_GROUND_GRASS;
02516
02517 if (IsPlainRail(tile) && old_ground != RAIL_GROUND_BARREN) {
02518
02519 TrackBits rail = GetTrackBits(tile);
02520
02521 switch (rail) {
02522 case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
02523 case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
02524 case TRACK_BIT_LEFT: new_ground = RAIL_GROUND_FENCE_VERT1; break;
02525 case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2; break;
02526
02527 default: {
02528 Owner owner = GetTileOwner(tile);
02529
02530 if (rail == (TRACK_BIT_LOWER | TRACK_BIT_RIGHT) || (
02531 (rail & TRACK_BIT_3WAY_NW) == 0 &&
02532 (rail & TRACK_BIT_X)
02533 )) {
02534 TileIndex n = tile + TileDiffXY(0, -1);
02535 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02536
02537 if ((!IsTileType(n, MP_RAILWAY) && !IsRailWaypointTile(n)) ||
02538 !IsTileOwner(n, owner) ||
02539 nrail == TRACK_BIT_UPPER ||
02540 nrail == TRACK_BIT_LEFT) {
02541 new_ground = RAIL_GROUND_FENCE_NW;
02542 }
02543 }
02544
02545 if (rail == (TRACK_BIT_UPPER | TRACK_BIT_LEFT) || (
02546 (rail & TRACK_BIT_3WAY_SE) == 0 &&
02547 (rail & TRACK_BIT_X)
02548 )) {
02549 TileIndex n = tile + TileDiffXY(0, 1);
02550 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02551
02552 if ((!IsTileType(n, MP_RAILWAY) && !IsRailWaypointTile(n)) ||
02553 !IsTileOwner(n, owner) ||
02554 nrail == TRACK_BIT_LOWER ||
02555 nrail == TRACK_BIT_RIGHT) {
02556 new_ground = (new_ground == RAIL_GROUND_FENCE_NW) ?
02557 RAIL_GROUND_FENCE_SENW : RAIL_GROUND_FENCE_SE;
02558 }
02559 }
02560
02561 if (rail == (TRACK_BIT_LOWER | TRACK_BIT_LEFT) || (
02562 (rail & TRACK_BIT_3WAY_NE) == 0 &&
02563 (rail & TRACK_BIT_Y)
02564 )) {
02565 TileIndex n = tile + TileDiffXY(-1, 0);
02566 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02567
02568 if ((!IsTileType(n, MP_RAILWAY) && !IsRailWaypointTile(n)) ||
02569 !IsTileOwner(n, owner) ||
02570 nrail == TRACK_BIT_UPPER ||
02571 nrail == TRACK_BIT_RIGHT) {
02572 new_ground = RAIL_GROUND_FENCE_NE;
02573 }
02574 }
02575
02576 if (rail == (TRACK_BIT_UPPER | TRACK_BIT_RIGHT) || (
02577 (rail & TRACK_BIT_3WAY_SW) == 0 &&
02578 (rail & TRACK_BIT_Y)
02579 )) {
02580 TileIndex n = tile + TileDiffXY(1, 0);
02581 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02582
02583 if ((!IsTileType(n, MP_RAILWAY) && !IsRailWaypointTile(n)) ||
02584 !IsTileOwner(n, owner) ||
02585 nrail == TRACK_BIT_LOWER ||
02586 nrail == TRACK_BIT_LEFT) {
02587 new_ground = (new_ground == RAIL_GROUND_FENCE_NE) ?
02588 RAIL_GROUND_FENCE_NESW : RAIL_GROUND_FENCE_SW;
02589 }
02590 }
02591 break;
02592 }
02593 }
02594 }
02595
02596 set_ground:
02597 if (old_ground != new_ground) {
02598 SetRailGroundType(tile, new_ground);
02599 MarkTileDirtyByTile(tile);
02600 }
02601 }
02602
02603
02604 static TrackStatus GetTileTrackStatus_Track(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
02605 {
02606
02607 if (mode == TRANSPORT_WATER && IsPlainRail(tile) && GetRailGroundType(tile) == RAIL_GROUND_WATER) {
02608 TrackBits tb = GetTrackBits(tile);
02609 switch (tb) {
02610 default: NOT_REACHED();
02611 case TRACK_BIT_UPPER: tb = TRACK_BIT_LOWER; break;
02612 case TRACK_BIT_LOWER: tb = TRACK_BIT_UPPER; break;
02613 case TRACK_BIT_LEFT: tb = TRACK_BIT_RIGHT; break;
02614 case TRACK_BIT_RIGHT: tb = TRACK_BIT_LEFT; break;
02615 }
02616 return CombineTrackStatus(TrackBitsToTrackdirBits(tb), TRACKDIR_BIT_NONE);
02617 }
02618
02619 if (mode != TRANSPORT_RAIL) return 0;
02620
02621 TrackBits trackbits = TRACK_BIT_NONE;
02622 TrackdirBits red_signals = TRACKDIR_BIT_NONE;
02623
02624 switch (GetRailTileType(tile)) {
02625 default: NOT_REACHED();
02626 case RAIL_TILE_NORMAL:
02627 trackbits = GetTrackBits(tile);
02628 break;
02629
02630 case RAIL_TILE_SIGNALS: {
02631 trackbits = GetTrackBits(tile);
02632 byte a = GetPresentSignals(tile);
02633 uint b = GetSignalStates(tile);
02634
02635 b &= a;
02636
02637
02638
02639
02640
02641
02642 if (!IsOnewaySignal(tile, TRACK_UPPER) || (a & SignalOnTrack(TRACK_UPPER)) == 0) b |= ~a & SignalOnTrack(TRACK_UPPER);
02643 if (!IsOnewaySignal(tile, TRACK_LOWER) || (a & SignalOnTrack(TRACK_LOWER)) == 0) b |= ~a & SignalOnTrack(TRACK_LOWER);
02644
02645 if ((b & 0x8) == 0) red_signals |= (TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_X_NE | TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_UPPER_E);
02646 if ((b & 0x4) == 0) red_signals |= (TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_X_SW | TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_UPPER_W);
02647 if ((b & 0x2) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_LOWER_E);
02648 if ((b & 0x1) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_S | TRACKDIR_BIT_LOWER_W);
02649
02650 break;
02651 }
02652
02653 case RAIL_TILE_DEPOT: {
02654 DiagDirection dir = GetRailDepotDirection(tile);
02655
02656 if (side != INVALID_DIAGDIR && side != dir) break;
02657
02658 trackbits = DiagDirToDiagTrackBits(dir);
02659 break;
02660 }
02661 }
02662
02663 return CombineTrackStatus(TrackBitsToTrackdirBits(trackbits), red_signals);
02664 }
02665
02666 static bool ClickTile_Track(TileIndex tile)
02667 {
02668 if (!IsRailDepot(tile)) return false;
02669
02670 ShowDepotWindow(tile, VEH_TRAIN);
02671 return true;
02672 }
02673
02674 static void GetTileDesc_Track(TileIndex tile, TileDesc *td)
02675 {
02676 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(tile));
02677 td->rail_speed = rti->max_speed;
02678 td->owner[0] = GetTileOwner(tile);
02679 SetDParamX(td->dparam, 0, rti->strings.name);
02680 switch (GetRailTileType(tile)) {
02681 case RAIL_TILE_NORMAL:
02682 td->str = STR_LAI_RAIL_DESCRIPTION_TRACK;
02683 break;
02684
02685 case RAIL_TILE_SIGNALS: {
02686 static const StringID signal_type[6][6] = {
02687 {
02688 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS,
02689 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS,
02690 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS,
02691 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS,
02692 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS,
02693 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS
02694 },
02695 {
02696 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS,
02697 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRESIGNALS,
02698 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS,
02699 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS,
02700 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS,
02701 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS
02702 },
02703 {
02704 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS,
02705 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS,
02706 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXITSIGNALS,
02707 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS,
02708 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS,
02709 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS
02710 },
02711 {
02712 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS,
02713 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS,
02714 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS,
02715 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBOSIGNALS,
02716 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS,
02717 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS
02718 },
02719 {
02720 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS,
02721 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS,
02722 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS,
02723 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS,
02724 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBSSIGNALS,
02725 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS
02726 },
02727 {
02728 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS,
02729 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS,
02730 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS,
02731 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS,
02732 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS,
02733 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRYSIGNALS
02734 }
02735 };
02736
02737 SignalType primary_signal;
02738 SignalType secondary_signal;
02739 if (HasSignalOnTrack(tile, TRACK_UPPER)) {
02740 primary_signal = GetSignalType(tile, TRACK_UPPER);
02741 secondary_signal = HasSignalOnTrack(tile, TRACK_LOWER) ? GetSignalType(tile, TRACK_LOWER) : primary_signal;
02742 } else {
02743 secondary_signal = primary_signal = GetSignalType(tile, TRACK_LOWER);
02744 }
02745
02746 td->str = signal_type[secondary_signal][primary_signal];
02747 break;
02748 }
02749
02750 case RAIL_TILE_DEPOT:
02751 td->str = STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT;
02752 if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL) {
02753 if (td->rail_speed > 0) {
02754 td->rail_speed = min(td->rail_speed, 61);
02755 } else {
02756 td->rail_speed = 61;
02757 }
02758 }
02759 td->build_date = Depot::GetByTile(tile)->build_date;
02760 break;
02761
02762 default:
02763 NOT_REACHED();
02764 }
02765 }
02766
02767 static void ChangeTileOwner_Track(TileIndex tile, Owner old_owner, Owner new_owner)
02768 {
02769 if (!IsTileOwner(tile, old_owner)) return;
02770
02771 if (new_owner != INVALID_OWNER) {
02772
02773 uint num_pieces = 1;
02774 if (IsPlainRail(tile)) {
02775 TrackBits bits = GetTrackBits(tile);
02776 num_pieces = CountBits(bits);
02777 if (TracksOverlap(bits)) num_pieces *= num_pieces;
02778 }
02779 RailType rt = GetRailType(tile);
02780 Company::Get(old_owner)->infrastructure.rail[rt] -= num_pieces;
02781 Company::Get(new_owner)->infrastructure.rail[rt] += num_pieces;
02782
02783 if (HasSignals(tile)) {
02784 uint num_sigs = CountBits(GetPresentSignals(tile));
02785 Company::Get(old_owner)->infrastructure.signal -= num_sigs;
02786 Company::Get(new_owner)->infrastructure.signal += num_sigs;
02787 }
02788
02789 SetTileOwner(tile, new_owner);
02790 } else {
02791 DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
02792 }
02793 }
02794
02795 static const byte _fractcoords_behind[4] = { 0x8F, 0x8, 0x80, 0xF8 };
02796 static const byte _fractcoords_enter[4] = { 0x8A, 0x48, 0x84, 0xA8 };
02797 static const int8 _deltacoord_leaveoffset[8] = {
02798 -1, 0, 1, 0,
02799 0, 1, 0, -1
02800 };
02801
02802
02809 int TicksToLeaveDepot(const Train *v)
02810 {
02811 DiagDirection dir = GetRailDepotDirection(v->tile);
02812 int length = v->CalcNextVehicleOffset();
02813
02814 switch (dir) {
02815 case DIAGDIR_NE: return ((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) - (length + 1)));
02816 case DIAGDIR_SE: return -((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) + (length + 1)));
02817 case DIAGDIR_SW: return -((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) + (length + 1)));
02818 default:
02819 case DIAGDIR_NW: return ((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) - (length + 1)));
02820 }
02821
02822 return 0;
02823 }
02824
02829 static VehicleEnterTileStatus VehicleEnter_Track(Vehicle *u, TileIndex tile, int x, int y)
02830 {
02831
02832 if (u->type != VEH_TRAIN || !IsRailDepotTile(tile)) return VETSB_CONTINUE;
02833
02834 Train *v = Train::From(u);
02835
02836
02837 DiagDirection dir = GetRailDepotDirection(tile);
02838
02839
02840 int length = v->CalcNextVehicleOffset();
02841
02842 byte fract_coord_leave =
02843 ((_fractcoords_enter[dir] & 0x0F) +
02844 (length + 1) * _deltacoord_leaveoffset[dir]) +
02845 (((_fractcoords_enter[dir] >> 4) +
02846 ((length + 1) * _deltacoord_leaveoffset[dir + 4])) << 4);
02847
02848 byte fract_coord = (x & 0xF) + ((y & 0xF) << 4);
02849
02850 if (_fractcoords_behind[dir] == fract_coord) {
02851
02852 return VETSB_CANNOT_ENTER;
02853 } else if (_fractcoords_enter[dir] == fract_coord) {
02854 if (DiagDirToDir(ReverseDiagDir(dir)) == v->direction) {
02855
02856 v->track = TRACK_BIT_DEPOT,
02857 v->vehstatus |= VS_HIDDEN;
02858 v->direction = ReverseDir(v->direction);
02859 if (v->Next() == NULL) VehicleEnterDepot(v->First());
02860 v->tile = tile;
02861
02862 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
02863 return VETSB_ENTERED_WORMHOLE;
02864 }
02865 } else if (fract_coord_leave == fract_coord) {
02866 if (DiagDirToDir(dir) == v->direction) {
02867
02868 if ((v = v->Next()) != NULL) {
02869 v->vehstatus &= ~VS_HIDDEN;
02870 v->track = (DiagDirToAxis(dir) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y);
02871 }
02872 }
02873 }
02874
02875 return VETSB_CONTINUE;
02876 }
02877
02889 static CommandCost TestAutoslopeOnRailTile(TileIndex tile, uint flags, int z_old, Slope tileh_old, int z_new, Slope tileh_new, TrackBits rail_bits)
02890 {
02891 if (!_settings_game.construction.build_on_slopes || !AutoslopeEnabled()) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02892
02893
02894 if (CheckRailSlope(tileh_new, rail_bits, TRACK_BIT_NONE, tile).Failed()) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02895
02896
02897 z_old += ApplyFoundationToSlope(GetRailFoundation(tileh_old, rail_bits), &tileh_old);
02898 z_new += ApplyFoundationToSlope(GetRailFoundation(tileh_new, rail_bits), &tileh_new);
02899
02900 Corner track_corner;
02901 switch (rail_bits) {
02902 case TRACK_BIT_LEFT: track_corner = CORNER_W; break;
02903 case TRACK_BIT_LOWER: track_corner = CORNER_S; break;
02904 case TRACK_BIT_RIGHT: track_corner = CORNER_E; break;
02905 case TRACK_BIT_UPPER: track_corner = CORNER_N; break;
02906
02907
02908 default:
02909 if (z_old != z_new || tileh_old != tileh_new) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02910 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02911 }
02912
02913
02914 z_old += GetSlopeZInCorner(RemoveHalftileSlope(tileh_old), track_corner);
02915 z_new += GetSlopeZInCorner(RemoveHalftileSlope(tileh_new), track_corner);
02916 if (z_old != z_new) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02917
02918 CommandCost cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02919
02920 if (tileh_old != tileh_new) {
02921
02922 if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old)) cost.AddCost(_price[PR_CLEAR_WATER]);
02923 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
02924 }
02925 return cost;
02926 }
02927
02928 static CommandCost TerraformTile_Track(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new)
02929 {
02930 int z_old;
02931 Slope tileh_old = GetTileSlope(tile, &z_old);
02932 if (IsPlainRail(tile)) {
02933 TrackBits rail_bits = GetTrackBits(tile);
02934
02935 bool was_water = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old));
02936
02937
02938 CommandCost autoslope_result = TestAutoslopeOnRailTile(tile, flags, z_old, tileh_old, z_new, tileh_new, rail_bits);
02939
02940
02941 Corner allowed_corner;
02942 switch (rail_bits) {
02943 case TRACK_BIT_RIGHT: allowed_corner = CORNER_W; break;
02944 case TRACK_BIT_UPPER: allowed_corner = CORNER_S; break;
02945 case TRACK_BIT_LEFT: allowed_corner = CORNER_E; break;
02946 case TRACK_BIT_LOWER: allowed_corner = CORNER_N; break;
02947 default: return autoslope_result;
02948 }
02949
02950 Foundation f_old = GetRailFoundation(tileh_old, rail_bits);
02951
02952
02953 if (tileh_old != SLOPE_NS && tileh_old != SLOPE_EW && IsSpecialRailFoundation(f_old)) return autoslope_result;
02954
02955
02956 for (Corner corner = (Corner)0; corner < CORNER_END; corner = (Corner)(corner + 1)) {
02957 if (allowed_corner == corner) continue;
02958 if (z_old + GetSlopeZInCorner(tileh_old, corner) != z_new + GetSlopeZInCorner(tileh_new, corner)) return autoslope_result;
02959 }
02960
02961
02962 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
02963
02964
02965 return CommandCost(EXPENSES_CONSTRUCTION, was_water ? _price[PR_CLEAR_WATER] : (Money)0);
02966 } else if (_settings_game.construction.build_on_slopes && AutoslopeEnabled() &&
02967 AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetRailDepotDirection(tile))) {
02968 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02969 }
02970 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
02971 }
02972
02973
02974 extern const TileTypeProcs _tile_type_rail_procs = {
02975 DrawTile_Track,
02976 GetSlopePixelZ_Track,
02977 ClearTile_Track,
02978 NULL,
02979 GetTileDesc_Track,
02980 GetTileTrackStatus_Track,
02981 ClickTile_Track,
02982 NULL,
02983 TileLoop_Track,
02984 ChangeTileOwner_Track,
02985 NULL,
02986 VehicleEnter_Track,
02987 GetFoundation_Track,
02988 TerraformTile_Track,
02989 };