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