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 = (_settings_game.vehicle.road_side != 0) && _settings_game.construction.signal_side;
01809 static const Point SignalPositions[2][12] = {
01810 {
01811
01812 { 8, 5}, {14, 1}, { 1, 14}, { 9, 11}, { 1, 0}, { 3, 10},
01813
01814 {11, 4}, {14, 14}, {11, 3}, { 4, 13}, { 3, 4}, {11, 13}
01815 }, {
01816
01817 {14, 1}, {12, 10}, { 4, 6}, { 1, 14}, {10, 4}, { 0, 1},
01818
01819 {14, 14}, { 5, 12}, {11, 13}, { 4, 3}, {13, 4}, { 3, 11}
01820 }
01821 };
01822
01823 uint x = TileX(tile) * TILE_SIZE + SignalPositions[side][pos].x;
01824 uint y = TileY(tile) * TILE_SIZE + SignalPositions[side][pos].y;
01825
01826 SpriteID sprite;
01827
01828 SignalType type = GetSignalType(tile, track);
01829 SignalVariant variant = GetSignalVariant(tile, track);
01830
01831 if (type == SIGTYPE_NORMAL && variant == SIG_ELECTRIC) {
01832
01833 sprite = SPR_ORIGINAL_SIGNALS_BASE + image + condition;
01834 } else {
01835
01836 sprite = SPR_SIGNALS_BASE + (type - 1) * 16 + variant * 64 + image + condition + (type > SIGTYPE_LAST_NOPBS ? 64 : 0);
01837 }
01838
01839 AddSortableSpriteToDraw(sprite, PAL_NONE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, GetSaveSlopeZ(x, y, track));
01840 }
01841
01842 static uint32 _drawtile_track_palette;
01843
01844
01845 static void DrawTrackFence_NW(const TileInfo *ti, SpriteID base_image)
01846 {
01847 RailFenceOffset rfo = RFO_FLAT_X;
01848 if (ti->tileh & SLOPE_NW) rfo = (ti->tileh & SLOPE_W) ? RFO_SLOPE_SW : RFO_SLOPE_NE;
01849 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01850 ti->x, ti->y + 1, 16, 1, 4, ti->z);
01851 }
01852
01853 static void DrawTrackFence_SE(const TileInfo *ti, SpriteID base_image)
01854 {
01855 RailFenceOffset rfo = RFO_FLAT_X;
01856 if (ti->tileh & SLOPE_SE) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SW : RFO_SLOPE_NE;
01857 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01858 ti->x, ti->y + TILE_SIZE - 1, 16, 1, 4, ti->z);
01859 }
01860
01861 static void DrawTrackFence_NW_SE(const TileInfo *ti, SpriteID base_image)
01862 {
01863 DrawTrackFence_NW(ti, base_image);
01864 DrawTrackFence_SE(ti, base_image);
01865 }
01866
01867 static void DrawTrackFence_NE(const TileInfo *ti, SpriteID base_image)
01868 {
01869 RailFenceOffset rfo = RFO_FLAT_Y;
01870 if (ti->tileh & SLOPE_NE) rfo = (ti->tileh & SLOPE_E) ? RFO_SLOPE_SE : RFO_SLOPE_NW;
01871 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01872 ti->x + 1, ti->y, 1, 16, 4, ti->z);
01873 }
01874
01875 static void DrawTrackFence_SW(const TileInfo *ti, SpriteID base_image)
01876 {
01877 RailFenceOffset rfo = RFO_FLAT_Y;
01878 if (ti->tileh & SLOPE_SW) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SE : RFO_SLOPE_NW;
01879 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01880 ti->x + TILE_SIZE - 1, ti->y, 1, 16, 4, ti->z);
01881 }
01882
01883 static void DrawTrackFence_NE_SW(const TileInfo *ti, SpriteID base_image)
01884 {
01885 DrawTrackFence_NE(ti, base_image);
01886 DrawTrackFence_SW(ti, base_image);
01887 }
01888
01892 static void DrawTrackFence_NS_1(const TileInfo *ti, SpriteID base_image)
01893 {
01894 int z = ti->z + GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_W);
01895 AddSortableSpriteToDraw(base_image + RFO_FLAT_VERT, _drawtile_track_palette,
01896 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01897 }
01898
01902 static void DrawTrackFence_NS_2(const TileInfo *ti, SpriteID base_image)
01903 {
01904 int z = ti->z + GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_E);
01905 AddSortableSpriteToDraw(base_image + RFO_FLAT_VERT, _drawtile_track_palette,
01906 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01907 }
01908
01912 static void DrawTrackFence_WE_1(const TileInfo *ti, SpriteID base_image)
01913 {
01914 int z = ti->z + GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_N);
01915 AddSortableSpriteToDraw(base_image + RFO_FLAT_HORZ, _drawtile_track_palette,
01916 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01917 }
01918
01922 static void DrawTrackFence_WE_2(const TileInfo *ti, SpriteID base_image)
01923 {
01924 int z = ti->z + GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_S);
01925 AddSortableSpriteToDraw(base_image + RFO_FLAT_HORZ, _drawtile_track_palette,
01926 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01927 }
01928
01929
01930 static void DrawTrackDetails(const TileInfo *ti, const RailtypeInfo *rti)
01931 {
01932
01933
01934 SpriteID base_image = GetCustomRailSprite(rti, ti->tile, RTSG_FENCES, IsHalftileSlope(ti->tileh) ? TCX_UPPER_HALFTILE : TCX_NORMAL);
01935 if (base_image == 0) base_image = SPR_TRACK_FENCE_FLAT_X;
01936
01937 switch (GetRailGroundType(ti->tile)) {
01938 case RAIL_GROUND_FENCE_NW: DrawTrackFence_NW(ti, base_image); break;
01939 case RAIL_GROUND_FENCE_SE: DrawTrackFence_SE(ti, base_image); break;
01940 case RAIL_GROUND_FENCE_SENW: DrawTrackFence_NW_SE(ti, base_image); break;
01941 case RAIL_GROUND_FENCE_NE: DrawTrackFence_NE(ti, base_image); break;
01942 case RAIL_GROUND_FENCE_SW: DrawTrackFence_SW(ti, base_image); break;
01943 case RAIL_GROUND_FENCE_NESW: DrawTrackFence_NE_SW(ti, base_image); break;
01944 case RAIL_GROUND_FENCE_VERT1: DrawTrackFence_NS_1(ti, base_image); break;
01945 case RAIL_GROUND_FENCE_VERT2: DrawTrackFence_NS_2(ti, base_image); break;
01946 case RAIL_GROUND_FENCE_HORIZ1: DrawTrackFence_WE_1(ti, base_image); break;
01947 case RAIL_GROUND_FENCE_HORIZ2: DrawTrackFence_WE_2(ti, base_image); break;
01948 case RAIL_GROUND_WATER: {
01949 Corner track_corner;
01950 if (IsHalftileSlope(ti->tileh)) {
01951
01952 track_corner = GetHalftileSlopeCorner(ti->tileh);
01953 } else {
01954
01955 track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh)));
01956 }
01957 switch (track_corner) {
01958 case CORNER_W: DrawTrackFence_NS_1(ti, base_image); break;
01959 case CORNER_S: DrawTrackFence_WE_2(ti, base_image); break;
01960 case CORNER_E: DrawTrackFence_NS_2(ti, base_image); break;
01961 case CORNER_N: DrawTrackFence_WE_1(ti, base_image); break;
01962 default: NOT_REACHED();
01963 }
01964 break;
01965 }
01966 default: break;
01967 }
01968 }
01969
01970
01971 static const int INF = 1000;
01972 static const SubSprite _halftile_sub_sprite[4] = {
01973 { -INF , -INF , 32 - 33, INF },
01974 { -INF , 0 + 7, INF , INF },
01975 { -31 + 33, -INF , INF , INF },
01976 { -INF , -INF , INF , 30 - 23 }
01977 };
01978
01979 static inline void DrawTrackSprite(SpriteID sprite, PaletteID pal, const TileInfo *ti, Slope s)
01980 {
01981 DrawGroundSprite(sprite, pal, NULL, 0, (ti->tileh & s) ? -8 : 0);
01982 }
01983
01984 static void DrawTrackBitsOverlay(TileInfo *ti, TrackBits track, const RailtypeInfo *rti)
01985 {
01986 RailGroundType rgt = GetRailGroundType(ti->tile);
01987 Foundation f = GetRailFoundation(ti->tileh, track);
01988 Corner halftile_corner = CORNER_INVALID;
01989
01990 if (IsNonContinuousFoundation(f)) {
01991
01992 halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f));
01993
01994 track &= ~CornerToTrackBits(halftile_corner);
01995 f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE);
01996 }
01997
01998 DrawFoundation(ti, f);
01999
02000
02001
02002 if (rgt == RAIL_GROUND_WATER) {
02003 if (track != TRACK_BIT_NONE || IsSteepSlope(ti->tileh)) {
02004
02005 DrawShoreTile(ti->tileh);
02006 } else {
02007
02008 DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
02009 }
02010 } else {
02011 SpriteID image;
02012
02013 switch (rgt) {
02014 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
02015 case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOW_DESERT_TILE; break;
02016 default: image = SPR_FLAT_GRASS_TILE; break;
02017 }
02018
02019 image += SlopeToSpriteOffset(ti->tileh);
02020
02021 DrawGroundSprite(image, PAL_NONE);
02022 }
02023
02024 SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
02025 SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
02026 TrackBits pbs = _settings_client.gui.show_track_reservation ? GetRailReservationTrackBits(ti->tile) : TRACK_BIT_NONE;
02027
02028 if (track == TRACK_BIT_NONE) {
02029
02030 } else if (ti->tileh == SLOPE_NW && track == TRACK_BIT_Y) {
02031 DrawGroundSprite(ground + RTO_SLOPE_NW, PAL_NONE);
02032 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 9, PALETTE_CRASH);
02033 } else if (ti->tileh == SLOPE_NE && track == TRACK_BIT_X) {
02034 DrawGroundSprite(ground + RTO_SLOPE_NE, PAL_NONE);
02035 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 6, PALETTE_CRASH);
02036 } else if (ti->tileh == SLOPE_SE && track == TRACK_BIT_Y) {
02037 DrawGroundSprite(ground + RTO_SLOPE_SE, PAL_NONE);
02038 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 7, PALETTE_CRASH);
02039 } else if (ti->tileh == SLOPE_SW && track == TRACK_BIT_X) {
02040 DrawGroundSprite(ground + RTO_SLOPE_SW, PAL_NONE);
02041 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 8, PALETTE_CRASH);
02042 } else {
02043 switch (track) {
02044
02045
02046 case TRACK_BIT_X: DrawGroundSprite(ground + RTO_X, PAL_NONE); break;
02047 case TRACK_BIT_Y: DrawGroundSprite(ground + RTO_Y, PAL_NONE); break;
02048 case TRACK_BIT_UPPER: DrawTrackSprite(ground + RTO_N, PAL_NONE, ti, SLOPE_N); break;
02049 case TRACK_BIT_LOWER: DrawTrackSprite(ground + RTO_S, PAL_NONE, ti, SLOPE_S); break;
02050 case TRACK_BIT_RIGHT: DrawTrackSprite(ground + RTO_E, PAL_NONE, ti, SLOPE_E); break;
02051 case TRACK_BIT_LEFT: DrawTrackSprite(ground + RTO_W, PAL_NONE, ti, SLOPE_W); break;
02052 case TRACK_BIT_CROSS: DrawGroundSprite(ground + RTO_CROSSING_XY, PAL_NONE); break;
02053 case TRACK_BIT_HORZ: DrawTrackSprite(ground + RTO_N, PAL_NONE, ti, SLOPE_N);
02054 DrawTrackSprite(ground + RTO_S, PAL_NONE, ti, SLOPE_S); break;
02055 case TRACK_BIT_VERT: DrawTrackSprite(ground + RTO_E, PAL_NONE, ti, SLOPE_E);
02056 DrawTrackSprite(ground + RTO_W, PAL_NONE, ti, SLOPE_W); break;
02057
02058 default:
02059
02060 if ((track & TRACK_BIT_3WAY_NE) == 0) {
02061 DrawGroundSprite(ground + RTO_JUNCTION_SW, PAL_NONE);
02062 } else if ((track & TRACK_BIT_3WAY_SW) == 0) {
02063 DrawGroundSprite(ground + RTO_JUNCTION_NE, PAL_NONE);
02064 } else if ((track & TRACK_BIT_3WAY_NW) == 0) {
02065 DrawGroundSprite(ground + RTO_JUNCTION_SE, PAL_NONE);
02066 } else if ((track & TRACK_BIT_3WAY_SE) == 0) {
02067 DrawGroundSprite(ground + RTO_JUNCTION_NW, PAL_NONE);
02068 } else {
02069 DrawGroundSprite(ground + RTO_JUNCTION_NSEW, PAL_NONE);
02070 }
02071
02072
02073 track &= ~pbs;
02074
02075
02076 if (track & TRACK_BIT_X) DrawGroundSprite(overlay + RTO_X, PAL_NONE);
02077 if (track & TRACK_BIT_Y) DrawGroundSprite(overlay + RTO_Y, PAL_NONE);
02078 if (track & TRACK_BIT_UPPER) DrawGroundSprite(overlay + RTO_N, PAL_NONE);
02079 if (track & TRACK_BIT_LOWER) DrawGroundSprite(overlay + RTO_S, PAL_NONE);
02080 if (track & TRACK_BIT_RIGHT) DrawGroundSprite(overlay + RTO_E, PAL_NONE);
02081 if (track & TRACK_BIT_LEFT) DrawGroundSprite(overlay + RTO_W, PAL_NONE);
02082 }
02083
02084
02085 if (pbs & TRACK_BIT_X) DrawGroundSprite(overlay + RTO_X, PALETTE_CRASH);
02086 if (pbs & TRACK_BIT_Y) DrawGroundSprite(overlay + RTO_Y, PALETTE_CRASH);
02087 if (pbs & TRACK_BIT_UPPER) DrawTrackSprite(overlay + RTO_N, PALETTE_CRASH, ti, SLOPE_N);
02088 if (pbs & TRACK_BIT_LOWER) DrawTrackSprite(overlay + RTO_S, PALETTE_CRASH, ti, SLOPE_S);
02089 if (pbs & TRACK_BIT_RIGHT) DrawTrackSprite(overlay + RTO_E, PALETTE_CRASH, ti, SLOPE_E);
02090 if (pbs & TRACK_BIT_LEFT) DrawTrackSprite(overlay + RTO_W, PALETTE_CRASH, ti, SLOPE_W);
02091 }
02092
02093 if (IsValidCorner(halftile_corner)) {
02094 DrawFoundation(ti, HalftileFoundation(halftile_corner));
02095 overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY, TCX_UPPER_HALFTILE);
02096 ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND, TCX_UPPER_HALFTILE);
02097
02098
02099 Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
02100
02101 SpriteID image;
02102 switch (rgt) {
02103 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
02104 case RAIL_GROUND_ICE_DESERT:
02105 case RAIL_GROUND_HALF_SNOW: image = SPR_FLAT_SNOW_DESERT_TILE; break;
02106 default: image = SPR_FLAT_GRASS_TILE; break;
02107 }
02108
02109 image += SlopeToSpriteOffset(fake_slope);
02110
02111 DrawGroundSprite(image, PAL_NONE, &(_halftile_sub_sprite[halftile_corner]));
02112
02113 track = CornerToTrackBits(halftile_corner);
02114
02115 int offset;
02116 switch (track) {
02117 default: NOT_REACHED();
02118 case TRACK_BIT_UPPER: offset = RTO_N; break;
02119 case TRACK_BIT_LOWER: offset = RTO_S; break;
02120 case TRACK_BIT_RIGHT: offset = RTO_E; break;
02121 case TRACK_BIT_LEFT: offset = RTO_W; break;
02122 }
02123
02124 DrawTrackSprite(ground + offset, PAL_NONE, ti, fake_slope);
02125 if (_settings_client.gui.show_track_reservation && HasReservedTracks(ti->tile, track)) {
02126 DrawTrackSprite(overlay + offset, PALETTE_CRASH, ti, fake_slope);
02127 }
02128 }
02129 }
02130
02136 static void DrawTrackBits(TileInfo *ti, TrackBits track)
02137 {
02138 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
02139
02140 if (rti->UsesOverlay()) {
02141 DrawTrackBitsOverlay(ti, track, rti);
02142 return;
02143 }
02144
02145 RailGroundType rgt = GetRailGroundType(ti->tile);
02146 Foundation f = GetRailFoundation(ti->tileh, track);
02147 Corner halftile_corner = CORNER_INVALID;
02148
02149 if (IsNonContinuousFoundation(f)) {
02150
02151 halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f));
02152
02153 track &= ~CornerToTrackBits(halftile_corner);
02154 f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE);
02155 }
02156
02157 DrawFoundation(ti, f);
02158
02159
02160 SpriteID image;
02161 PaletteID pal = PAL_NONE;
02162 const SubSprite *sub = NULL;
02163 bool junction = false;
02164
02165
02166 if (track == 0) {
02167
02168 if (rgt == RAIL_GROUND_WATER) {
02169 if (IsSteepSlope(ti->tileh)) {
02170 DrawShoreTile(ti->tileh);
02171 image = 0;
02172 } else {
02173 image = SPR_FLAT_WATER_TILE;
02174 }
02175 } else {
02176 switch (rgt) {
02177 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
02178 case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOW_DESERT_TILE; break;
02179 default: image = SPR_FLAT_GRASS_TILE; break;
02180 }
02181 image += SlopeToSpriteOffset(ti->tileh);
02182 }
02183 } else {
02184 if (ti->tileh != SLOPE_FLAT) {
02185
02186 image = _track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.track_y;
02187 } else {
02188
02189 (image = rti->base_sprites.track_y, track == TRACK_BIT_Y) ||
02190 (image++, track == TRACK_BIT_X) ||
02191 (image++, track == TRACK_BIT_UPPER) ||
02192 (image++, track == TRACK_BIT_LOWER) ||
02193 (image++, track == TRACK_BIT_RIGHT) ||
02194 (image++, track == TRACK_BIT_LEFT) ||
02195 (image++, track == TRACK_BIT_CROSS) ||
02196
02197 (image = rti->base_sprites.track_ns, track == TRACK_BIT_HORZ) ||
02198 (image++, track == TRACK_BIT_VERT) ||
02199
02200 (junction = true, false) ||
02201 (image = rti->base_sprites.ground, (track & TRACK_BIT_3WAY_NE) == 0) ||
02202 (image++, (track & TRACK_BIT_3WAY_SW) == 0) ||
02203 (image++, (track & TRACK_BIT_3WAY_NW) == 0) ||
02204 (image++, (track & TRACK_BIT_3WAY_SE) == 0) ||
02205 (image++, true);
02206 }
02207
02208 switch (rgt) {
02209 case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
02210 case RAIL_GROUND_ICE_DESERT: image += rti->snow_offset; break;
02211 case RAIL_GROUND_WATER: {
02212
02213 DrawShoreTile(ti->tileh);
02214 Corner track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh)));
02215 sub = &(_halftile_sub_sprite[track_corner]);
02216 break;
02217 }
02218 default: break;
02219 }
02220 }
02221
02222 if (image != 0) DrawGroundSprite(image, pal, sub);
02223
02224
02225 if (junction) {
02226 if (track & TRACK_BIT_X) DrawGroundSprite(rti->base_sprites.single_x, PAL_NONE);
02227 if (track & TRACK_BIT_Y) DrawGroundSprite(rti->base_sprites.single_y, PAL_NONE);
02228 if (track & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PAL_NONE);
02229 if (track & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PAL_NONE);
02230 if (track & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PAL_NONE);
02231 if (track & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PAL_NONE);
02232 }
02233
02234
02235 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation) {
02236
02237 TrackBits pbs = GetRailReservationTrackBits(ti->tile) & track;
02238 if (pbs & TRACK_BIT_X) {
02239 if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
02240 DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH);
02241 } else {
02242 DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
02243 }
02244 }
02245 if (pbs & TRACK_BIT_Y) {
02246 if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
02247 DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH);
02248 } else {
02249 DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
02250 }
02251 }
02252 if (pbs & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_N ? -(int)TILE_HEIGHT : 0);
02253 if (pbs & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_S ? -(int)TILE_HEIGHT : 0);
02254 if (pbs & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_W ? -(int)TILE_HEIGHT : 0);
02255 if (pbs & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_E ? -(int)TILE_HEIGHT : 0);
02256 }
02257
02258 if (IsValidCorner(halftile_corner)) {
02259 DrawFoundation(ti, HalftileFoundation(halftile_corner));
02260
02261
02262 Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
02263 image = _track_sloped_sprites[fake_slope - 1] + rti->base_sprites.track_y;
02264 pal = PAL_NONE;
02265 switch (rgt) {
02266 case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
02267 case RAIL_GROUND_ICE_DESERT:
02268 case RAIL_GROUND_HALF_SNOW: image += rti->snow_offset; break;
02269 default: break;
02270 }
02271 DrawGroundSprite(image, pal, &(_halftile_sub_sprite[halftile_corner]));
02272
02273 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasReservedTracks(ti->tile, CornerToTrackBits(halftile_corner))) {
02274 static const byte _corner_to_track_sprite[] = {3, 1, 2, 0};
02275 DrawGroundSprite(_corner_to_track_sprite[halftile_corner] + rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, -(int)TILE_HEIGHT);
02276 }
02277 }
02278 }
02279
02287 enum SignalOffsets {
02288 SIGNAL_TO_SOUTHWEST = 0,
02289 SIGNAL_TO_NORTHEAST = 2,
02290 SIGNAL_TO_SOUTHEAST = 4,
02291 SIGNAL_TO_NORTHWEST = 6,
02292 SIGNAL_TO_EAST = 8,
02293 SIGNAL_TO_WEST = 10,
02294 SIGNAL_TO_SOUTH = 12,
02295 SIGNAL_TO_NORTH = 14,
02296 };
02297
02298 static void DrawSignals(TileIndex tile, TrackBits rails)
02299 {
02300 #define MAYBE_DRAW_SIGNAL(x, y, z, t) if (IsSignalPresent(tile, x)) DrawSingleSignal(tile, t, GetSingleSignalState(tile, x), y, z)
02301
02302 if (!(rails & TRACK_BIT_Y)) {
02303 if (!(rails & TRACK_BIT_X)) {
02304 if (rails & TRACK_BIT_LEFT) {
02305 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTH, 0, TRACK_LEFT);
02306 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTH, 1, TRACK_LEFT);
02307 }
02308 if (rails & TRACK_BIT_RIGHT) {
02309 MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_NORTH, 2, TRACK_RIGHT);
02310 MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_SOUTH, 3, TRACK_RIGHT);
02311 }
02312 if (rails & TRACK_BIT_UPPER) {
02313 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_WEST, 4, TRACK_UPPER);
02314 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_EAST, 5, TRACK_UPPER);
02315 }
02316 if (rails & TRACK_BIT_LOWER) {
02317 MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_WEST, 6, TRACK_LOWER);
02318 MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_EAST, 7, TRACK_LOWER);
02319 }
02320 } else {
02321 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHWEST, 8, TRACK_X);
02322 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHEAST, 9, TRACK_X);
02323 }
02324 } else {
02325 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHEAST, 10, TRACK_Y);
02326 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHWEST, 11, TRACK_Y);
02327 }
02328 }
02329
02330 static void DrawTile_Track(TileInfo *ti)
02331 {
02332 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
02333
02334 _drawtile_track_palette = COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile));
02335
02336 if (IsPlainRail(ti->tile)) {
02337 TrackBits rails = GetTrackBits(ti->tile);
02338
02339 DrawTrackBits(ti, rails);
02340
02341 if (HasBit(_display_opt, DO_FULL_DETAIL)) DrawTrackDetails(ti, rti);
02342
02343 if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
02344
02345 if (HasSignals(ti->tile)) DrawSignals(ti->tile, rails);
02346 } else {
02347
02348 const DrawTileSprites *dts;
02349 PaletteID pal = PAL_NONE;
02350 SpriteID relocation;
02351
02352 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
02353
02354 if (IsInvisibilitySet(TO_BUILDINGS)) {
02355
02356 dts = &_depot_invisible_gfx_table[GetRailDepotDirection(ti->tile)];
02357 } else {
02358 dts = &_depot_gfx_table[GetRailDepotDirection(ti->tile)];
02359 }
02360
02361 SpriteID image;
02362 if (rti->UsesOverlay()) {
02363 image = SPR_FLAT_GRASS_TILE;
02364 } else {
02365 image = dts->ground.sprite;
02366 if (image != SPR_FLAT_GRASS_TILE) image += rti->GetRailtypeSpriteOffset();
02367 }
02368
02369
02370
02371 if (IsSnowRailGround(ti->tile) && _settings_game.game_creation.landscape == LT_TROPIC) {
02372 if (image != SPR_FLAT_GRASS_TILE) {
02373 image += rti->snow_offset;
02374 } else {
02375 image = SPR_FLAT_SNOW_DESERT_TILE;
02376 }
02377 }
02378
02379 DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, _drawtile_track_palette));
02380
02381 if (rti->UsesOverlay()) {
02382 SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
02383
02384 switch (GetRailDepotDirection(ti->tile)) {
02385 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02386 case DIAGDIR_SW: DrawGroundSprite(ground + RTO_X, PAL_NONE); break;
02387 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02388 case DIAGDIR_SE: DrawGroundSprite(ground + RTO_Y, PAL_NONE); break;
02389 default: break;
02390 }
02391
02392 if (_settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile)) {
02393 SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
02394
02395 switch (GetRailDepotDirection(ti->tile)) {
02396 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02397 case DIAGDIR_SW: DrawGroundSprite(overlay + RTO_X, PALETTE_CRASH); break;
02398 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02399 case DIAGDIR_SE: DrawGroundSprite(overlay + RTO_Y, PALETTE_CRASH); break;
02400 default: break;
02401 }
02402 }
02403 } else {
02404
02405 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile)) {
02406 switch (GetRailDepotDirection(ti->tile)) {
02407 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02408 case DIAGDIR_SW: DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH); break;
02409 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02410 case DIAGDIR_SE: DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH); break;
02411 default: break;
02412 }
02413 }
02414 }
02415 int depot_sprite = GetCustomRailSprite(rti, ti->tile, RTSG_DEPOT);
02416 relocation = depot_sprite != 0 ? depot_sprite - SPR_RAIL_DEPOT_SE_1 : rti->GetRailtypeSpriteOffset();
02417
02418 if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
02419
02420 DrawRailTileSeq(ti, dts, TO_BUILDINGS, relocation, 0, _drawtile_track_palette);
02421 }
02422 DrawBridgeMiddle(ti);
02423 }
02424
02425 void DrawTrainDepotSprite(int x, int y, int dir, RailType railtype)
02426 {
02427 const DrawTileSprites *dts = &_depot_gfx_table[dir];
02428 const RailtypeInfo *rti = GetRailTypeInfo(railtype);
02429 SpriteID image = rti->UsesOverlay() ? SPR_FLAT_GRASS_TILE : dts->ground.sprite;
02430 uint32 offset = rti->GetRailtypeSpriteOffset();
02431
02432 x += 33;
02433 y += 17;
02434
02435 if (image != SPR_FLAT_GRASS_TILE) image += offset;
02436 PaletteID palette = COMPANY_SPRITE_COLOUR(_local_company);
02437
02438 DrawSprite(image, PAL_NONE, x, y);
02439
02440 if (rti->UsesOverlay()) {
02441 SpriteID ground = GetCustomRailSprite(rti, INVALID_TILE, RTSG_GROUND);
02442
02443 switch (dir) {
02444 case DIAGDIR_SW: DrawSprite(ground + RTO_X, PAL_NONE, x, y); break;
02445 case DIAGDIR_SE: DrawSprite(ground + RTO_Y, PAL_NONE, x, y); break;
02446 default: break;
02447 }
02448 }
02449 int depot_sprite = GetCustomRailSprite(rti, INVALID_TILE, RTSG_DEPOT);
02450 if (depot_sprite != 0) offset = depot_sprite - SPR_RAIL_DEPOT_SE_1;
02451
02452 DrawRailTileSeqInGUI(x, y, dts, offset, 0, palette);
02453 }
02454
02455 static int GetSlopePixelZ_Track(TileIndex tile, uint x, uint y)
02456 {
02457 if (IsPlainRail(tile)) {
02458 int z;
02459 Slope tileh = GetTilePixelSlope(tile, &z);
02460 if (tileh == SLOPE_FLAT) return z;
02461
02462 z += ApplyPixelFoundationToSlope(GetRailFoundation(tileh, GetTrackBits(tile)), &tileh);
02463 return z + GetPartialPixelZ(x & 0xF, y & 0xF, tileh);
02464 } else {
02465 return GetTileMaxPixelZ(tile);
02466 }
02467 }
02468
02469 static Foundation GetFoundation_Track(TileIndex tile, Slope tileh)
02470 {
02471 return IsPlainRail(tile) ? GetRailFoundation(tileh, GetTrackBits(tile)) : FlatteningFoundation(tileh);
02472 }
02473
02474 static void TileLoop_Track(TileIndex tile)
02475 {
02476 RailGroundType old_ground = GetRailGroundType(tile);
02477 RailGroundType new_ground;
02478
02479 if (old_ground == RAIL_GROUND_WATER) {
02480 TileLoop_Water(tile);
02481 return;
02482 }
02483
02484 switch (_settings_game.game_creation.landscape) {
02485 case LT_ARCTIC: {
02486 int z;
02487 Slope slope = GetTileSlope(tile, &z);
02488 bool half = false;
02489
02490
02491
02492 if (IsPlainRail(tile)) {
02493 TrackBits track = GetTrackBits(tile);
02494 Foundation f = GetRailFoundation(slope, track);
02495
02496 switch (f) {
02497 case FOUNDATION_NONE:
02498
02499 if (IsSlopeWithThreeCornersRaised(slope)) z++;
02500 break;
02501
02502 case FOUNDATION_INCLINED_X:
02503 case FOUNDATION_INCLINED_Y:
02504
02505 if (IsSteepSlope(slope)) z++;
02506 break;
02507
02508 case FOUNDATION_STEEP_LOWER:
02509
02510 z++;
02511 break;
02512
02513 default:
02514
02515 if (IsSteepSlope(slope)) z++;
02516 z++;
02517 break;
02518 }
02519
02520 half = IsInsideMM(f, FOUNDATION_STEEP_BOTH, FOUNDATION_HALFTILE_N + 1);
02521 } else {
02522
02523 if (slope != SLOPE_FLAT) z++;
02524 }
02525
02526
02527
02528
02529
02530 if (z > GetSnowLine()) {
02531 if (half && z - GetSnowLine() == 1) {
02532
02533 new_ground = RAIL_GROUND_HALF_SNOW;
02534 } else {
02535 new_ground = RAIL_GROUND_ICE_DESERT;
02536 }
02537 goto set_ground;
02538 }
02539 break;
02540 }
02541
02542 case LT_TROPIC:
02543 if (GetTropicZone(tile) == TROPICZONE_DESERT) {
02544 new_ground = RAIL_GROUND_ICE_DESERT;
02545 goto set_ground;
02546 }
02547 break;
02548 }
02549
02550 new_ground = RAIL_GROUND_GRASS;
02551
02552 if (IsPlainRail(tile) && old_ground != RAIL_GROUND_BARREN) {
02553
02554 TrackBits rail = GetTrackBits(tile);
02555
02556 Owner owner = GetTileOwner(tile);
02557 byte fences = 0;
02558
02559 for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
02560 static const TrackBits dir_to_trackbits[DIAGDIR_END] = {TRACK_BIT_3WAY_NE, TRACK_BIT_3WAY_SE, TRACK_BIT_3WAY_SW, TRACK_BIT_3WAY_NW};
02561
02562
02563 if ((rail & dir_to_trackbits[d]) != TRACK_BIT_NONE) continue;
02564
02565 TileIndex tile2 = tile + TileOffsByDiagDir(d);
02566
02567
02568 if (!IsValidTile(tile2) || IsTileType(tile2, MP_HOUSE) || IsTileType(tile2, MP_INDUSTRY) ||
02569 IsTileType(tile2, MP_ROAD) || IsTileType(tile2, MP_TUNNELBRIDGE) || !IsTileOwner(tile2, owner)) {
02570 fences |= 1 << d;
02571 }
02572 }
02573
02574 switch (fences) {
02575 case 0: break;
02576 case (1 << DIAGDIR_NE): new_ground = RAIL_GROUND_FENCE_NE; break;
02577 case (1 << DIAGDIR_SE): new_ground = RAIL_GROUND_FENCE_SE; break;
02578 case (1 << DIAGDIR_SW): new_ground = RAIL_GROUND_FENCE_SW; break;
02579 case (1 << DIAGDIR_NW): new_ground = RAIL_GROUND_FENCE_NW; break;
02580 case (1 << DIAGDIR_NE) | (1 << DIAGDIR_SW): new_ground = RAIL_GROUND_FENCE_NESW; break;
02581 case (1 << DIAGDIR_SE) | (1 << DIAGDIR_NW): new_ground = RAIL_GROUND_FENCE_SENW; break;
02582 case (1 << DIAGDIR_NE) | (1 << DIAGDIR_SE): new_ground = RAIL_GROUND_FENCE_VERT1; break;
02583 case (1 << DIAGDIR_NE) | (1 << DIAGDIR_NW): new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
02584 case (1 << DIAGDIR_SE) | (1 << DIAGDIR_SW): new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
02585 case (1 << DIAGDIR_SW) | (1 << DIAGDIR_NW): new_ground = RAIL_GROUND_FENCE_VERT2; break;
02586 default: NOT_REACHED();
02587 }
02588 }
02589
02590 set_ground:
02591 if (old_ground != new_ground) {
02592 SetRailGroundType(tile, new_ground);
02593 MarkTileDirtyByTile(tile);
02594 }
02595 }
02596
02597
02598 static TrackStatus GetTileTrackStatus_Track(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
02599 {
02600
02601 if (mode == TRANSPORT_WATER && IsPlainRail(tile) && GetRailGroundType(tile) == RAIL_GROUND_WATER) {
02602 TrackBits tb = GetTrackBits(tile);
02603 switch (tb) {
02604 default: NOT_REACHED();
02605 case TRACK_BIT_UPPER: tb = TRACK_BIT_LOWER; break;
02606 case TRACK_BIT_LOWER: tb = TRACK_BIT_UPPER; break;
02607 case TRACK_BIT_LEFT: tb = TRACK_BIT_RIGHT; break;
02608 case TRACK_BIT_RIGHT: tb = TRACK_BIT_LEFT; break;
02609 }
02610 return CombineTrackStatus(TrackBitsToTrackdirBits(tb), TRACKDIR_BIT_NONE);
02611 }
02612
02613 if (mode != TRANSPORT_RAIL) return 0;
02614
02615 TrackBits trackbits = TRACK_BIT_NONE;
02616 TrackdirBits red_signals = TRACKDIR_BIT_NONE;
02617
02618 switch (GetRailTileType(tile)) {
02619 default: NOT_REACHED();
02620 case RAIL_TILE_NORMAL:
02621 trackbits = GetTrackBits(tile);
02622 break;
02623
02624 case RAIL_TILE_SIGNALS: {
02625 trackbits = GetTrackBits(tile);
02626 byte a = GetPresentSignals(tile);
02627 uint b = GetSignalStates(tile);
02628
02629 b &= a;
02630
02631
02632
02633
02634
02635
02636 if (!IsOnewaySignal(tile, TRACK_UPPER) || (a & SignalOnTrack(TRACK_UPPER)) == 0) b |= ~a & SignalOnTrack(TRACK_UPPER);
02637 if (!IsOnewaySignal(tile, TRACK_LOWER) || (a & SignalOnTrack(TRACK_LOWER)) == 0) b |= ~a & SignalOnTrack(TRACK_LOWER);
02638
02639 if ((b & 0x8) == 0) red_signals |= (TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_X_NE | TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_UPPER_E);
02640 if ((b & 0x4) == 0) red_signals |= (TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_X_SW | TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_UPPER_W);
02641 if ((b & 0x2) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_LOWER_E);
02642 if ((b & 0x1) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_S | TRACKDIR_BIT_LOWER_W);
02643
02644 break;
02645 }
02646
02647 case RAIL_TILE_DEPOT: {
02648 DiagDirection dir = GetRailDepotDirection(tile);
02649
02650 if (side != INVALID_DIAGDIR && side != dir) break;
02651
02652 trackbits = DiagDirToDiagTrackBits(dir);
02653 break;
02654 }
02655 }
02656
02657 return CombineTrackStatus(TrackBitsToTrackdirBits(trackbits), red_signals);
02658 }
02659
02660 static bool ClickTile_Track(TileIndex tile)
02661 {
02662 if (!IsRailDepot(tile)) return false;
02663
02664 ShowDepotWindow(tile, VEH_TRAIN);
02665 return true;
02666 }
02667
02668 static void GetTileDesc_Track(TileIndex tile, TileDesc *td)
02669 {
02670 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(tile));
02671 td->rail_speed = rti->max_speed;
02672 td->owner[0] = GetTileOwner(tile);
02673 SetDParamX(td->dparam, 0, rti->strings.name);
02674 switch (GetRailTileType(tile)) {
02675 case RAIL_TILE_NORMAL:
02676 td->str = STR_LAI_RAIL_DESCRIPTION_TRACK;
02677 break;
02678
02679 case RAIL_TILE_SIGNALS: {
02680 static const StringID signal_type[6][6] = {
02681 {
02682 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS,
02683 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS,
02684 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS,
02685 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS,
02686 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS,
02687 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS
02688 },
02689 {
02690 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS,
02691 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRESIGNALS,
02692 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS,
02693 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS,
02694 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS,
02695 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS
02696 },
02697 {
02698 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS,
02699 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS,
02700 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXITSIGNALS,
02701 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS,
02702 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS,
02703 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS
02704 },
02705 {
02706 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS,
02707 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS,
02708 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS,
02709 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBOSIGNALS,
02710 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS,
02711 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS
02712 },
02713 {
02714 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS,
02715 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS,
02716 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS,
02717 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS,
02718 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBSSIGNALS,
02719 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS
02720 },
02721 {
02722 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS,
02723 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS,
02724 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS,
02725 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS,
02726 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS,
02727 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRYSIGNALS
02728 }
02729 };
02730
02731 SignalType primary_signal;
02732 SignalType secondary_signal;
02733 if (HasSignalOnTrack(tile, TRACK_UPPER)) {
02734 primary_signal = GetSignalType(tile, TRACK_UPPER);
02735 secondary_signal = HasSignalOnTrack(tile, TRACK_LOWER) ? GetSignalType(tile, TRACK_LOWER) : primary_signal;
02736 } else {
02737 secondary_signal = primary_signal = GetSignalType(tile, TRACK_LOWER);
02738 }
02739
02740 td->str = signal_type[secondary_signal][primary_signal];
02741 break;
02742 }
02743
02744 case RAIL_TILE_DEPOT:
02745 td->str = STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT;
02746 if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL) {
02747 if (td->rail_speed > 0) {
02748 td->rail_speed = min(td->rail_speed, 61);
02749 } else {
02750 td->rail_speed = 61;
02751 }
02752 }
02753 td->build_date = Depot::GetByTile(tile)->build_date;
02754 break;
02755
02756 default:
02757 NOT_REACHED();
02758 }
02759 }
02760
02761 static void ChangeTileOwner_Track(TileIndex tile, Owner old_owner, Owner new_owner)
02762 {
02763 if (!IsTileOwner(tile, old_owner)) return;
02764
02765 if (new_owner != INVALID_OWNER) {
02766
02767 uint num_pieces = 1;
02768 if (IsPlainRail(tile)) {
02769 TrackBits bits = GetTrackBits(tile);
02770 num_pieces = CountBits(bits);
02771 if (TracksOverlap(bits)) num_pieces *= num_pieces;
02772 }
02773 RailType rt = GetRailType(tile);
02774 Company::Get(old_owner)->infrastructure.rail[rt] -= num_pieces;
02775 Company::Get(new_owner)->infrastructure.rail[rt] += num_pieces;
02776
02777 if (HasSignals(tile)) {
02778 uint num_sigs = CountBits(GetPresentSignals(tile));
02779 Company::Get(old_owner)->infrastructure.signal -= num_sigs;
02780 Company::Get(new_owner)->infrastructure.signal += num_sigs;
02781 }
02782
02783 SetTileOwner(tile, new_owner);
02784 } else {
02785 DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
02786 }
02787 }
02788
02789 static const byte _fractcoords_behind[4] = { 0x8F, 0x8, 0x80, 0xF8 };
02790 static const byte _fractcoords_enter[4] = { 0x8A, 0x48, 0x84, 0xA8 };
02791 static const int8 _deltacoord_leaveoffset[8] = {
02792 -1, 0, 1, 0,
02793 0, 1, 0, -1
02794 };
02795
02796
02803 int TicksToLeaveDepot(const Train *v)
02804 {
02805 DiagDirection dir = GetRailDepotDirection(v->tile);
02806 int length = v->CalcNextVehicleOffset();
02807
02808 switch (dir) {
02809 case DIAGDIR_NE: return ((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) - (length + 1)));
02810 case DIAGDIR_SE: return -((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) + (length + 1)));
02811 case DIAGDIR_SW: return -((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) + (length + 1)));
02812 default:
02813 case DIAGDIR_NW: return ((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) - (length + 1)));
02814 }
02815
02816 return 0;
02817 }
02818
02823 static VehicleEnterTileStatus VehicleEnter_Track(Vehicle *u, TileIndex tile, int x, int y)
02824 {
02825
02826 if (u->type != VEH_TRAIN || !IsRailDepotTile(tile)) return VETSB_CONTINUE;
02827
02828 Train *v = Train::From(u);
02829
02830
02831 DiagDirection dir = GetRailDepotDirection(tile);
02832
02833
02834 int length = v->CalcNextVehicleOffset();
02835
02836 byte fract_coord_leave =
02837 ((_fractcoords_enter[dir] & 0x0F) +
02838 (length + 1) * _deltacoord_leaveoffset[dir]) +
02839 (((_fractcoords_enter[dir] >> 4) +
02840 ((length + 1) * _deltacoord_leaveoffset[dir + 4])) << 4);
02841
02842 byte fract_coord = (x & 0xF) + ((y & 0xF) << 4);
02843
02844 if (_fractcoords_behind[dir] == fract_coord) {
02845
02846 return VETSB_CANNOT_ENTER;
02847 } else if (_fractcoords_enter[dir] == fract_coord) {
02848 if (DiagDirToDir(ReverseDiagDir(dir)) == v->direction) {
02849
02850 v->track = TRACK_BIT_DEPOT,
02851 v->vehstatus |= VS_HIDDEN;
02852 v->direction = ReverseDir(v->direction);
02853 if (v->Next() == NULL) VehicleEnterDepot(v->First());
02854 v->tile = tile;
02855
02856 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
02857 return VETSB_ENTERED_WORMHOLE;
02858 }
02859 } else if (fract_coord_leave == fract_coord) {
02860 if (DiagDirToDir(dir) == v->direction) {
02861
02862 if ((v = v->Next()) != NULL) {
02863 v->vehstatus &= ~VS_HIDDEN;
02864 v->track = (DiagDirToAxis(dir) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y);
02865 }
02866 }
02867 }
02868
02869 return VETSB_CONTINUE;
02870 }
02871
02883 static CommandCost TestAutoslopeOnRailTile(TileIndex tile, uint flags, int z_old, Slope tileh_old, int z_new, Slope tileh_new, TrackBits rail_bits)
02884 {
02885 if (!_settings_game.construction.build_on_slopes || !AutoslopeEnabled()) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02886
02887
02888 if (CheckRailSlope(tileh_new, rail_bits, TRACK_BIT_NONE, tile).Failed()) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02889
02890
02891 z_old += ApplyFoundationToSlope(GetRailFoundation(tileh_old, rail_bits), &tileh_old);
02892 z_new += ApplyFoundationToSlope(GetRailFoundation(tileh_new, rail_bits), &tileh_new);
02893
02894 Corner track_corner;
02895 switch (rail_bits) {
02896 case TRACK_BIT_LEFT: track_corner = CORNER_W; break;
02897 case TRACK_BIT_LOWER: track_corner = CORNER_S; break;
02898 case TRACK_BIT_RIGHT: track_corner = CORNER_E; break;
02899 case TRACK_BIT_UPPER: track_corner = CORNER_N; break;
02900
02901
02902 default:
02903 if (z_old != z_new || tileh_old != tileh_new) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02904 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02905 }
02906
02907
02908 z_old += GetSlopeZInCorner(RemoveHalftileSlope(tileh_old), track_corner);
02909 z_new += GetSlopeZInCorner(RemoveHalftileSlope(tileh_new), track_corner);
02910 if (z_old != z_new) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
02911
02912 CommandCost cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02913
02914 if (tileh_old != tileh_new) {
02915
02916 if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old)) cost.AddCost(_price[PR_CLEAR_WATER]);
02917 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
02918 }
02919 return cost;
02920 }
02921
02922 static CommandCost TerraformTile_Track(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new)
02923 {
02924 int z_old;
02925 Slope tileh_old = GetTileSlope(tile, &z_old);
02926 if (IsPlainRail(tile)) {
02927 TrackBits rail_bits = GetTrackBits(tile);
02928
02929 bool was_water = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old));
02930
02931
02932 CommandCost autoslope_result = TestAutoslopeOnRailTile(tile, flags, z_old, tileh_old, z_new, tileh_new, rail_bits);
02933
02934
02935 Corner allowed_corner;
02936 switch (rail_bits) {
02937 case TRACK_BIT_RIGHT: allowed_corner = CORNER_W; break;
02938 case TRACK_BIT_UPPER: allowed_corner = CORNER_S; break;
02939 case TRACK_BIT_LEFT: allowed_corner = CORNER_E; break;
02940 case TRACK_BIT_LOWER: allowed_corner = CORNER_N; break;
02941 default: return autoslope_result;
02942 }
02943
02944 Foundation f_old = GetRailFoundation(tileh_old, rail_bits);
02945
02946
02947 if (tileh_old != SLOPE_NS && tileh_old != SLOPE_EW && IsSpecialRailFoundation(f_old)) return autoslope_result;
02948
02949
02950 for (Corner corner = (Corner)0; corner < CORNER_END; corner = (Corner)(corner + 1)) {
02951 if (allowed_corner == corner) continue;
02952 if (z_old + GetSlopeZInCorner(tileh_old, corner) != z_new + GetSlopeZInCorner(tileh_new, corner)) return autoslope_result;
02953 }
02954
02955
02956 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
02957
02958
02959 return CommandCost(EXPENSES_CONSTRUCTION, was_water ? _price[PR_CLEAR_WATER] : (Money)0);
02960 } else if (_settings_game.construction.build_on_slopes && AutoslopeEnabled() &&
02961 AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetRailDepotDirection(tile))) {
02962 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02963 }
02964 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
02965 }
02966
02967
02968 extern const TileTypeProcs _tile_type_rail_procs = {
02969 DrawTile_Track,
02970 GetSlopePixelZ_Track,
02971 ClearTile_Track,
02972 NULL,
02973 GetTileDesc_Track,
02974 GetTileTrackStatus_Track,
02975 ClickTile_Track,
02976 NULL,
02977 TileLoop_Track,
02978 ChangeTileOwner_Track,
02979 NULL,
02980 VehicleEnter_Track,
02981 GetFoundation_Track,
02982 TerraformTile_Track,
02983 };