00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "cmd_helper.h"
00014 #include "landscape.h"
00015 #include "viewport_func.h"
00016 #include "command_func.h"
00017 #include "engine_base.h"
00018 #include "depot_base.h"
00019 #include "pathfinder/yapf/yapf_cache.h"
00020 #include "newgrf_engine.h"
00021 #include "landscape_type.h"
00022 #include "newgrf_railtype.h"
00023 #include "newgrf_commons.h"
00024 #include "train.h"
00025 #include "variables.h"
00026 #include "autoslope.h"
00027 #include "water.h"
00028 #include "tunnelbridge_map.h"
00029 #include "window_func.h"
00030 #include "vehicle_func.h"
00031 #include "sound_func.h"
00032 #include "tunnelbridge.h"
00033 #include "functions.h"
00034 #include "elrail_func.h"
00035 #include "town.h"
00036 #include "pbs.h"
00037 #include "company_base.h"
00038
00039 #include "table/strings.h"
00040 #include "table/sprites.h"
00041 #include "table/railtypes.h"
00042 #include "table/track_land.h"
00043
00044 RailtypeInfo _railtypes[RAILTYPE_END];
00045
00046 assert_compile(sizeof(_original_railtypes) <= sizeof(_railtypes));
00047
00051 void ResetRailTypes()
00052 {
00053 memset(_railtypes, 0, sizeof(_railtypes));
00054 memcpy(_railtypes, _original_railtypes, sizeof(_original_railtypes));
00055 }
00056
00057 void ResolveRailTypeGUISprites(RailtypeInfo *rti)
00058 {
00059 SpriteID cursors_base = GetCustomRailSprite(rti, INVALID_TILE, RTSG_CURSORS);
00060 if (cursors_base != 0) {
00061 rti->gui_sprites.build_ns_rail = cursors_base + 0;
00062 rti->gui_sprites.build_x_rail = cursors_base + 1;
00063 rti->gui_sprites.build_ew_rail = cursors_base + 2;
00064 rti->gui_sprites.build_y_rail = cursors_base + 3;
00065 rti->gui_sprites.auto_rail = cursors_base + 4;
00066 rti->gui_sprites.build_depot = cursors_base + 5;
00067 rti->gui_sprites.build_tunnel = cursors_base + 6;
00068 rti->gui_sprites.convert_rail = cursors_base + 7;
00069 rti->cursor.rail_ns = cursors_base + 8;
00070 rti->cursor.rail_swne = cursors_base + 9;
00071 rti->cursor.rail_ew = cursors_base + 10;
00072 rti->cursor.rail_nwse = cursors_base + 11;
00073 rti->cursor.autorail = cursors_base + 12;
00074 rti->cursor.depot = cursors_base + 13;
00075 rti->cursor.tunnel = cursors_base + 14;
00076 rti->cursor.convert = cursors_base + 15;
00077 }
00078 }
00079
00080 void InitRailTypes()
00081 {
00082 for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
00083 RailtypeInfo *rti = &_railtypes[rt];
00084 ResolveRailTypeGUISprites(rti);
00085 }
00086 }
00087
00088 RailType AllocateRailType(RailTypeLabel label)
00089 {
00090 for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
00091 RailtypeInfo *rti = &_railtypes[rt];
00092
00093 if (rti->label == 0) {
00094
00095 memcpy(rti, &_railtypes[RAILTYPE_RAIL], sizeof(*rti));
00096 rti->label = label;
00097
00098
00099 rti->powered_railtypes = (RailTypes)(1 << rt);
00100 rti->compatible_railtypes = (RailTypes)(1 << rt);
00101 return rt;
00102 }
00103 }
00104
00105 return INVALID_RAILTYPE;
00106 }
00107
00108 static const byte _track_sloped_sprites[14] = {
00109 14, 15, 22, 13,
00110 0, 21, 17, 12,
00111 23, 0, 18, 20,
00112 19, 16
00113 };
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148 Vehicle *EnsureNoTrainOnTrackProc(Vehicle *v, void *data)
00149 {
00150 TrackBits rail_bits = *(TrackBits *)data;
00151
00152 if (v->type != VEH_TRAIN) return NULL;
00153
00154 Train *t = Train::From(v);
00155 if ((t->track != rail_bits) && !TracksOverlap(t->track | rail_bits)) return NULL;
00156
00157 _error_message = STR_ERROR_TRAIN_IN_THE_WAY + v->type;
00158 return v;
00159 }
00160
00168 static bool EnsureNoTrainOnTrack(TileIndex tile, Track track)
00169 {
00170 TrackBits rail_bits = TrackToTrackBits(track);
00171
00172 return !HasVehicleOnPos(tile, &rail_bits, &EnsureNoTrainOnTrackProc);
00173 }
00174
00181 static CommandCost CheckTrackCombination(TileIndex tile, TrackBits to_build, uint flags)
00182 {
00183 if (!IsPlainRail(tile)) return_cmd_error(STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION);
00184
00185
00186
00187 TrackBits current = GetTrackBits(tile);
00188 TrackBits future = current | to_build;
00189
00190
00191 if (current == future) {
00192
00193 return_cmd_error(STR_ERROR_ALREADY_BUILT);
00194 }
00195
00196
00197 if ((flags & DC_NO_RAIL_OVERLAP) || HasSignals(tile)) {
00198
00199
00200 if (future != TRACK_BIT_HORZ && future != TRACK_BIT_VERT) {
00201 return_cmd_error((flags & DC_NO_RAIL_OVERLAP) ? STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION : STR_ERROR_MUST_REMOVE_SIGNALS_FIRST);
00202 }
00203 }
00204
00205 return CommandCost();
00206 }
00207
00208
00210 static const TrackBits _valid_tracks_without_foundation[15] = {
00211 TRACK_BIT_ALL,
00212 TRACK_BIT_RIGHT,
00213 TRACK_BIT_UPPER,
00214 TRACK_BIT_X,
00215
00216 TRACK_BIT_LEFT,
00217 TRACK_BIT_NONE,
00218 TRACK_BIT_Y,
00219 TRACK_BIT_LOWER,
00220
00221 TRACK_BIT_LOWER,
00222 TRACK_BIT_Y,
00223 TRACK_BIT_NONE,
00224 TRACK_BIT_LEFT,
00225
00226 TRACK_BIT_X,
00227 TRACK_BIT_UPPER,
00228 TRACK_BIT_RIGHT,
00229 };
00230
00232 static const TrackBits _valid_tracks_on_leveled_foundation[15] = {
00233 TRACK_BIT_NONE,
00234 TRACK_BIT_LEFT,
00235 TRACK_BIT_LOWER,
00236 TRACK_BIT_Y | TRACK_BIT_LOWER | TRACK_BIT_LEFT,
00237
00238 TRACK_BIT_RIGHT,
00239 TRACK_BIT_ALL,
00240 TRACK_BIT_X | TRACK_BIT_LOWER | TRACK_BIT_RIGHT,
00241 TRACK_BIT_ALL,
00242
00243 TRACK_BIT_UPPER,
00244 TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_LEFT,
00245 TRACK_BIT_ALL,
00246 TRACK_BIT_ALL,
00247
00248 TRACK_BIT_Y | TRACK_BIT_UPPER | TRACK_BIT_RIGHT,
00249 TRACK_BIT_ALL,
00250 TRACK_BIT_ALL
00251 };
00252
00260 Foundation GetRailFoundation(Slope tileh, TrackBits bits)
00261 {
00262 if (bits == TRACK_BIT_NONE) return FOUNDATION_NONE;
00263
00264 if (IsSteepSlope(tileh)) {
00265
00266 if (bits == TRACK_BIT_X) return FOUNDATION_INCLINED_X;
00267 if (bits == TRACK_BIT_Y) return FOUNDATION_INCLINED_Y;
00268
00269
00270 Corner highest_corner = GetHighestSlopeCorner(tileh);
00271 TrackBits higher_track = CornerToTrackBits(highest_corner);
00272
00273
00274 if (bits == higher_track) return HalftileFoundation(highest_corner);
00275
00276
00277 if (TracksOverlap(bits | higher_track)) return FOUNDATION_INVALID;
00278
00279
00280 return ((bits & higher_track) != 0 ? FOUNDATION_STEEP_BOTH : FOUNDATION_STEEP_LOWER);
00281 } else {
00282 if ((~_valid_tracks_without_foundation[tileh] & bits) == 0) return FOUNDATION_NONE;
00283
00284 bool valid_on_leveled = ((~_valid_tracks_on_leveled_foundation[tileh] & bits) == 0);
00285
00286 Corner track_corner;
00287 switch (bits) {
00288 case TRACK_BIT_LEFT: track_corner = CORNER_W; break;
00289 case TRACK_BIT_LOWER: track_corner = CORNER_S; break;
00290 case TRACK_BIT_RIGHT: track_corner = CORNER_E; break;
00291 case TRACK_BIT_UPPER: track_corner = CORNER_N; break;
00292
00293 case TRACK_BIT_HORZ:
00294 if (tileh == SLOPE_N) return HalftileFoundation(CORNER_N);
00295 if (tileh == SLOPE_S) return HalftileFoundation(CORNER_S);
00296 return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
00297
00298 case TRACK_BIT_VERT:
00299 if (tileh == SLOPE_W) return HalftileFoundation(CORNER_W);
00300 if (tileh == SLOPE_E) return HalftileFoundation(CORNER_E);
00301 return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
00302
00303 case TRACK_BIT_X:
00304 if (IsSlopeWithOneCornerRaised(tileh)) return FOUNDATION_INCLINED_X;
00305 return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
00306
00307 case TRACK_BIT_Y:
00308 if (IsSlopeWithOneCornerRaised(tileh)) return FOUNDATION_INCLINED_Y;
00309 return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
00310
00311 default:
00312 return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
00313 }
00314
00315
00316
00317 if (!valid_on_leveled) return FOUNDATION_INVALID;
00318
00319
00320 if (IsSlopeWithThreeCornersRaised(tileh)) return FOUNDATION_LEVELED;
00321
00322
00323 if ((tileh & SlopeWithThreeCornersRaised(OppositeCorner(track_corner))) == SlopeWithOneCornerRaised(track_corner)) return HalftileFoundation(track_corner);
00324
00325
00326 return SpecialRailFoundation(track_corner);
00327 }
00328 }
00329
00330
00340 static CommandCost CheckRailSlope(Slope tileh, TrackBits rail_bits, TrackBits existing, TileIndex tile)
00341 {
00342
00343 if (IsTileType(tile, MP_WATER) || (IsTileType(tile, MP_RAILWAY) && (GetRailGroundType(tile) == RAIL_GROUND_WATER))) {
00344 if (!IsSteepSlope(tileh) && ((~_valid_tracks_on_leveled_foundation[tileh] & (rail_bits | existing)) != 0)) return_cmd_error(STR_ERROR_CAN_T_BUILD_ON_WATER);
00345 }
00346
00347 Foundation f_new = GetRailFoundation(tileh, rail_bits | existing);
00348
00349
00350 if ((f_new == FOUNDATION_INVALID) ||
00351 ((f_new != FOUNDATION_NONE) && (!_settings_game.construction.build_on_slopes))) {
00352 return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
00353 }
00354
00355 Foundation f_old = GetRailFoundation(tileh, existing);
00356 return CommandCost(EXPENSES_CONSTRUCTION, f_new != f_old ? _price[PR_BUILD_FOUNDATION] : (Money)0);
00357 }
00358
00359
00360 static inline bool ValParamTrackOrientation(Track track) {return IsValidTrack(track);}
00361
00370 CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00371 {
00372 RailType railtype = (RailType)p1;
00373 Track track = (Track)p2;
00374 CommandCost cost(EXPENSES_CONSTRUCTION);
00375
00376 if (!ValParamRailtype(railtype) || !ValParamTrackOrientation(track)) return CMD_ERROR;
00377
00378 Slope tileh = GetTileSlope(tile, NULL);
00379 TrackBits trackbit = TrackToTrackBits(track);
00380
00381 switch (GetTileType(tile)) {
00382 case MP_RAILWAY: {
00383 if (!CheckTileOwnership(tile)) return CMD_ERROR;
00384
00385 if (!IsPlainRail(tile)) return CMD_ERROR;
00386
00387 if (!IsCompatibleRail(GetRailType(tile), railtype)) return_cmd_error(STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION);
00388
00389 CommandCost ret = CheckTrackCombination(tile, trackbit, flags);
00390 ret.SetGlobalErrorMessage();
00391 if (ret.Failed()) return ret;
00392
00393 if (!EnsureNoTrainOnTrack(tile, track)) return CMD_ERROR;
00394
00395 ret = CheckRailSlope(tileh, trackbit, GetTrackBits(tile), tile);
00396 if (ret.Failed()) return ret;
00397 cost.AddCost(ret);
00398
00399
00400
00401
00402 if (GetRailType(tile) != railtype && !HasPowerOnRail(railtype, GetRailType(tile))) {
00403 if (HasPowerOnRail(GetRailType(tile), railtype)) {
00404 ret = DoCommand(tile, tile, railtype, flags, CMD_CONVERT_RAIL);
00405 if (ret.Failed()) return ret;
00406 cost.AddCost(ret);
00407 } else {
00408 return CMD_ERROR;
00409 }
00410 }
00411
00412 if (flags & DC_EXEC) {
00413 SetRailGroundType(tile, RAIL_GROUND_BARREN);
00414 SetTrackBits(tile, GetTrackBits(tile) | trackbit);
00415 }
00416 break;
00417 }
00418
00419 case MP_ROAD:
00420 #define M(x) (1 << (x))
00421
00422 if (!HasBit(M(SLOPE_SEN) | M(SLOPE_ENW) | M(SLOPE_NWS) | M(SLOPE_NS) | M(SLOPE_WSE) | M(SLOPE_EW) | M(SLOPE_FLAT), tileh)) {
00423 return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
00424 }
00425 #undef M
00426
00427 if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
00428
00429 if (IsNormalRoad(tile)) {
00430 if (HasRoadWorks(tile)) return_cmd_error(STR_ERROR_ROAD_WORKS_IN_PROGRESS);
00431
00432 if (GetDisallowedRoadDirections(tile) != DRD_NONE) return_cmd_error(STR_ERROR_CROSSING_ON_ONEWAY_ROAD);
00433
00434 RoadTypes roadtypes = GetRoadTypes(tile);
00435 RoadBits road = GetRoadBits(tile, ROADTYPE_ROAD);
00436 RoadBits tram = GetRoadBits(tile, ROADTYPE_TRAM);
00437 switch (roadtypes) {
00438 default: break;
00439 case ROADTYPES_TRAM:
00440
00441 if (flags & DC_EXEC) SetRoadOwner(tile, ROADTYPE_ROAD, _current_company);
00442 roadtypes |= ROADTYPES_ROAD;
00443 break;
00444
00445 case ROADTYPES_ALL:
00446 if (road != tram) return CMD_ERROR;
00447 break;
00448 }
00449
00450 road |= tram;
00451
00452 if ((track == TRACK_X && road == ROAD_Y) ||
00453 (track == TRACK_Y && road == ROAD_X)) {
00454 if (flags & DC_EXEC) {
00455 MakeRoadCrossing(tile, GetRoadOwner(tile, ROADTYPE_ROAD), GetRoadOwner(tile, ROADTYPE_TRAM), _current_company, (track == TRACK_X ? AXIS_Y : AXIS_X), railtype, roadtypes, GetTownIndex(tile));
00456 UpdateLevelCrossing(tile, false);
00457 }
00458 break;
00459 }
00460 }
00461
00462 if (IsLevelCrossing(tile) && GetCrossingRailBits(tile) == trackbit) {
00463 return_cmd_error(STR_ERROR_ALREADY_BUILT);
00464 }
00465
00466
00467 default: {
00468
00469 bool water_ground = IsTileType(tile, MP_WATER) && IsSlopeWithOneCornerRaised(tileh);
00470
00471 CommandCost ret = CheckRailSlope(tileh, trackbit, TRACK_BIT_NONE, tile);
00472 if (ret.Failed()) return ret;
00473 cost.AddCost(ret);
00474
00475 ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00476 if (ret.Failed()) return ret;
00477 cost.AddCost(ret);
00478
00479 if (water_ground) {
00480 cost.AddCost(-_price[PR_CLEAR_WATER]);
00481 cost.AddCost(_price[PR_CLEAR_ROUGH]);
00482 }
00483
00484 if (flags & DC_EXEC) {
00485 MakeRailNormal(tile, _current_company, trackbit, railtype);
00486 if (water_ground) SetRailGroundType(tile, RAIL_GROUND_WATER);
00487 }
00488 break;
00489 }
00490 }
00491
00492 if (flags & DC_EXEC) {
00493 MarkTileDirtyByTile(tile);
00494 AddTrackToSignalBuffer(tile, track, _current_company);
00495 YapfNotifyTrackLayoutChange(tile, track);
00496 }
00497
00498 cost.AddCost(RailBuildCost(railtype));
00499 return cost;
00500 }
00501
00510 CommandCost CmdRemoveSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00511 {
00512 Track track = (Track)p2;
00513 CommandCost cost(EXPENSES_CONSTRUCTION);
00514 bool crossing = false;
00515
00516 if (!ValParamTrackOrientation((Track)p2)) return CMD_ERROR;
00517 TrackBits trackbit = TrackToTrackBits(track);
00518
00519
00520
00521
00522
00523 Owner owner = INVALID_OWNER;
00524
00525 Train *v = NULL;
00526
00527 switch (GetTileType(tile)) {
00528 case MP_ROAD: {
00529 if (!IsLevelCrossing(tile) ||
00530 GetCrossingRailBits(tile) != trackbit ||
00531 (_current_company != OWNER_WATER && !CheckTileOwnership(tile)) ||
00532 (!(flags & DC_BANKRUPT) && !EnsureNoVehicleOnGround(tile))) {
00533 return CMD_ERROR;
00534 }
00535
00536 cost.AddCost(RailClearCost(GetRailType(tile)));
00537
00538 if (flags & DC_EXEC) {
00539 if (HasReservedTracks(tile, trackbit)) {
00540 v = GetTrainForReservation(tile, track);
00541 if (v != NULL) FreeTrainTrackReservation(v);
00542 }
00543 owner = GetTileOwner(tile);
00544 MakeRoadNormal(tile, GetCrossingRoadBits(tile), GetRoadTypes(tile), GetTownIndex(tile), GetRoadOwner(tile, ROADTYPE_ROAD), GetRoadOwner(tile, ROADTYPE_TRAM));
00545 }
00546 break;
00547 }
00548
00549 case MP_RAILWAY: {
00550 TrackBits present;
00551
00552 if (!IsPlainRail(tile) ||
00553 (_current_company != OWNER_WATER && !CheckTileOwnership(tile)) ||
00554 !EnsureNoTrainOnTrack(tile, track)) {
00555 return CMD_ERROR;
00556 }
00557
00558 present = GetTrackBits(tile);
00559 if ((present & trackbit) == 0) return CMD_ERROR;
00560 if (present == (TRACK_BIT_X | TRACK_BIT_Y)) crossing = true;
00561
00562 cost.AddCost(RailClearCost(GetRailType(tile)));
00563
00564
00565 if (HasSignalOnTrack(tile, track))
00566 cost.AddCost(DoCommand(tile, track, 0, flags, CMD_REMOVE_SIGNALS));
00567
00568 if (flags & DC_EXEC) {
00569 if (HasReservedTracks(tile, trackbit)) {
00570 v = GetTrainForReservation(tile, track);
00571 if (v != NULL) FreeTrainTrackReservation(v);
00572 }
00573 owner = GetTileOwner(tile);
00574 present ^= trackbit;
00575 if (present == 0) {
00576 Slope tileh = GetTileSlope(tile, NULL);
00577
00578 if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh)) {
00579 MakeShore(tile);
00580 } else {
00581 DoClearSquare(tile);
00582 }
00583 } else {
00584 SetTrackBits(tile, present);
00585 SetTrackReservation(tile, GetRailReservationTrackBits(tile) & present);
00586 }
00587 }
00588 break;
00589 }
00590
00591 default: return CMD_ERROR;
00592 }
00593
00594 if (flags & DC_EXEC) {
00595
00596 assert(Company::IsValidID(owner));
00597
00598 MarkTileDirtyByTile(tile);
00599 if (crossing) {
00600
00601
00602
00603
00604 AddTrackToSignalBuffer(tile, TRACK_X, owner);
00605 AddTrackToSignalBuffer(tile, TRACK_Y, owner);
00606 YapfNotifyTrackLayoutChange(tile, TRACK_X);
00607 YapfNotifyTrackLayoutChange(tile, TRACK_Y);
00608 } else {
00609 AddTrackToSignalBuffer(tile, track, owner);
00610 YapfNotifyTrackLayoutChange(tile, track);
00611 }
00612
00613 if (v != NULL) TryPathReserve(v, true);
00614 }
00615
00616 return cost;
00617 }
00618
00619
00627 bool FloodHalftile(TileIndex t)
00628 {
00629 assert(IsPlainRailTile(t));
00630
00631 bool flooded = false;
00632 if (GetRailGroundType(t) == RAIL_GROUND_WATER) return flooded;
00633
00634 Slope tileh = GetTileSlope(t, NULL);
00635 TrackBits rail_bits = GetTrackBits(t);
00636
00637 if (IsSlopeWithOneCornerRaised(tileh)) {
00638 TrackBits lower_track = CornerToTrackBits(OppositeCorner(GetHighestSlopeCorner(tileh)));
00639
00640 TrackBits to_remove = lower_track & rail_bits;
00641 if (to_remove != 0) {
00642 _current_company = OWNER_WATER;
00643 if (DoCommand(t, 0, FIND_FIRST_BIT(to_remove), DC_EXEC, CMD_REMOVE_SINGLE_RAIL).Failed()) return flooded;
00644 flooded = true;
00645 rail_bits = rail_bits & ~to_remove;
00646 if (rail_bits == 0) {
00647 MakeShore(t);
00648 MarkTileDirtyByTile(t);
00649 return flooded;
00650 }
00651 }
00652
00653 if (IsNonContinuousFoundation(GetRailFoundation(tileh, rail_bits))) {
00654 flooded = true;
00655 SetRailGroundType(t, RAIL_GROUND_WATER);
00656 MarkTileDirtyByTile(t);
00657 }
00658 } else {
00659
00660 if (ApplyFoundationToSlope(GetRailFoundation(tileh, rail_bits), &tileh) == 0) {
00661 if (IsSteepSlope(tileh) || IsSlopeWithThreeCornersRaised(tileh)) {
00662 flooded = true;
00663 SetRailGroundType(t, RAIL_GROUND_WATER);
00664 MarkTileDirtyByTile(t);
00665 }
00666 }
00667 }
00668 return flooded;
00669 }
00670
00671 static const TileIndexDiffC _trackdelta[] = {
00672 { -1, 0 }, { 0, 1 }, { -1, 0 }, { 0, 1 }, { 1, 0 }, { 0, 1 },
00673 { 0, 0 },
00674 { 0, 0 },
00675 { 1, 0 }, { 0, -1 }, { 0, -1 }, { 1, 0 }, { 0, -1 }, { -1, 0 },
00676 { 0, 0 },
00677 { 0, 0 }
00678 };
00679
00680
00681 static CommandCost ValidateAutoDrag(Trackdir *trackdir, TileIndex start, TileIndex end)
00682 {
00683 int x = TileX(start);
00684 int y = TileY(start);
00685 int ex = TileX(end);
00686 int ey = TileY(end);
00687
00688 if (!ValParamTrackOrientation(TrackdirToTrack(*trackdir))) return CMD_ERROR;
00689
00690
00691 int dx = ex - x;
00692 int dy = ey - y;
00693
00694
00695 int trdx = _trackdelta[*trackdir].x;
00696 int trdy = _trackdelta[*trackdir].y;
00697
00698 if (!IsDiagonalTrackdir(*trackdir)) {
00699 trdx += _trackdelta[*trackdir ^ 1].x;
00700 trdy += _trackdelta[*trackdir ^ 1].y;
00701 }
00702
00703
00704 while (
00705 (trdx <= 0 && dx > 0) ||
00706 (trdx >= 0 && dx < 0) ||
00707 (trdy <= 0 && dy > 0) ||
00708 (trdy >= 0 && dy < 0)
00709 ) {
00710 if (!HasBit(*trackdir, 3)) {
00711 SetBit(*trackdir, 3);
00712 trdx = -trdx;
00713 trdy = -trdy;
00714 } else {
00715 return CMD_ERROR;
00716 }
00717 }
00718
00719
00720
00721 if (!IsDiagonalTrackdir(*trackdir)) {
00722 trdx = _trackdelta[*trackdir].x;
00723 trdy = _trackdelta[*trackdir].y;
00724 if (abs(dx) != abs(dy) && abs(dx) + abs(trdy) != abs(dy) + abs(trdx))
00725 return CMD_ERROR;
00726 }
00727
00728 return CommandCost();
00729 }
00730
00743 static CommandCost CmdRailTrackHelper(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00744 {
00745 CommandCost ret, total_cost(EXPENSES_CONSTRUCTION);
00746 Track track = (Track)GB(p2, 4, 3);
00747 bool remove = HasBit(p2, 7);
00748 RailType railtype = (RailType)GB(p2, 0, 4);
00749
00750 if (!ValParamRailtype(railtype) || !ValParamTrackOrientation(track)) return CMD_ERROR;
00751 if (p1 >= MapSize()) return CMD_ERROR;
00752 TileIndex end_tile = p1;
00753 Trackdir trackdir = TrackToTrackdir(track);
00754
00755 if (ValidateAutoDrag(&trackdir, tile, end_tile).Failed()) return CMD_ERROR;
00756
00757 if (flags & DC_EXEC) SndPlayTileFx(SND_20_SPLAT_2, tile);
00758
00759 for (;;) {
00760 ret = DoCommand(tile, railtype, TrackdirToTrack(trackdir), flags, remove ? CMD_REMOVE_SINGLE_RAIL : CMD_BUILD_SINGLE_RAIL);
00761
00762 if (ret.Failed()) {
00763 if (_error_message != STR_ERROR_ALREADY_BUILT && !remove) {
00764 if (HasBit(p2, 8)) return CMD_ERROR;
00765 break;
00766 }
00767 _error_message = INVALID_STRING_ID;
00768 } else {
00769 total_cost.AddCost(ret);
00770 }
00771
00772 if (tile == end_tile) break;
00773
00774 tile += ToTileIndexDiff(_trackdelta[trackdir]);
00775
00776
00777 if (!IsDiagonalTrackdir(trackdir)) ToggleBit(trackdir, 0);
00778 }
00779
00780 return (total_cost.GetCost() == 0) ? CommandCost(remove ? INVALID_STRING_ID : (_error_message == INVALID_STRING_ID ? STR_ERROR_ALREADY_BUILT : _error_message)) : total_cost;
00781 }
00782
00796 CommandCost CmdBuildRailroadTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00797 {
00798 return CmdRailTrackHelper(tile, flags, p1, ClrBit(p2, 7), text);
00799 }
00800
00814 CommandCost CmdRemoveRailroadTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00815 {
00816 return CmdRailTrackHelper(tile, flags, p1, SetBit(p2, 7), text);
00817 }
00818
00830 CommandCost CmdBuildTrainDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00831 {
00832
00833 if (!ValParamRailtype((RailType)p1)) return CMD_ERROR;
00834
00835 Slope tileh = GetTileSlope(tile, NULL);
00836
00837 DiagDirection dir = Extract<DiagDirection, 0>(p2);
00838
00839
00840
00841
00842
00843
00844
00845
00846 if (tileh != SLOPE_FLAT && (
00847 !_settings_game.construction.build_on_slopes ||
00848 IsSteepSlope(tileh) ||
00849 !CanBuildDepotByTileh(dir, tileh)
00850 )) {
00851 return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
00852 }
00853
00854 CommandCost cost = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00855 if (cost.Failed()) return CMD_ERROR;
00856
00857 if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
00858
00859 if (!Depot::CanAllocateItem()) return CMD_ERROR;
00860
00861 if (flags & DC_EXEC) {
00862 Depot *d = new Depot(tile);
00863 d->town_index = ClosestTownFromTile(tile, UINT_MAX)->index;
00864
00865 MakeRailDepot(tile, _current_company, d->index, dir, (RailType)p1);
00866 MarkTileDirtyByTile(tile);
00867
00868 AddSideToSignalBuffer(tile, INVALID_DIAGDIR, _current_company);
00869 YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
00870 }
00871
00872 cost.AddCost(_price[PR_BUILD_DEPOT_TRAIN]);
00873 return cost;
00874 }
00875
00896 CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00897 {
00898 Track track = (Track)GB(p1, 0, 3);
00899 bool ctrl_pressed = HasBit(p1, 3);
00900 SignalVariant sigvar = (ctrl_pressed ^ HasBit(p1, 4)) ? SIG_SEMAPHORE : SIG_ELECTRIC;
00901 SignalType sigtype = (SignalType)GB(p1, 5, 3);
00902 bool convert_signal = HasBit(p1, 8);
00903 SignalType cycle_start = (SignalType)GB(p1, 9, 3);
00904 SignalType cycle_stop = (SignalType)GB(p1, 12, 3);
00905 uint num_dir_cycle = GB(p1, 15, 2);
00906
00907 if (sigtype > SIGTYPE_LAST) return CMD_ERROR;
00908
00909
00910 if (!ValParamTrackOrientation(track) || !IsPlainRailTile(tile) ||
00911 !HasTrack(tile, track) || !EnsureNoTrainOnTrack(tile, track)) {
00912 return CMD_ERROR;
00913 }
00914
00915
00916 if (p2 != 0 && (p2 & SignalOnTrack(track)) == 0) return CMD_ERROR;
00917
00918 if (!CheckTileOwnership(tile)) return CMD_ERROR;
00919
00920 {
00921
00922 TrackBits trackbits = GetTrackBits(tile);
00923 if (KillFirstBit(trackbits) != TRACK_BIT_NONE &&
00924 trackbits != TRACK_BIT_HORZ &&
00925 trackbits != TRACK_BIT_VERT) {
00926 return_cmd_error(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK);
00927 }
00928 }
00929
00930
00931 if (HasBit(p1, 17) && HasSignalOnTrack(tile, track)) return CommandCost();
00932
00933
00934 if (convert_signal && !HasSignalOnTrack(tile, track)) return CMD_ERROR;
00935
00936 CommandCost cost;
00937 if (!HasSignalOnTrack(tile, track)) {
00938
00939 cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS]);
00940 } else {
00941 if (p2 != 0 && sigvar != GetSignalVariant(tile, track)) {
00942
00943 cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] + _price[PR_CLEAR_SIGNALS]);
00944
00945 } else if (convert_signal) {
00946
00947 if (ctrl_pressed || GetSignalVariant(tile, track) != sigvar) {
00948
00949 cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] + _price[PR_CLEAR_SIGNALS]);
00950 } else {
00951
00952 cost = CommandCost();
00953 }
00954
00955 } else {
00956
00957 cost = CommandCost();
00958 }
00959 }
00960
00961 if (flags & DC_EXEC) {
00962 Train *v = NULL;
00963
00964
00965
00966 if (HasReservedTracks(tile, TrackToTrackBits(track))) {
00967 v = GetTrainForReservation(tile, track);
00968 if (v != NULL) FreeTrainTrackReservation(v);
00969 }
00970
00971 if (!HasSignals(tile)) {
00972
00973 SetHasSignals(tile, true);
00974 SetSignalStates(tile, 0xF);
00975 SetPresentSignals(tile, 0);
00976 SetSignalType(tile, track, sigtype);
00977 SetSignalVariant(tile, track, sigvar);
00978 }
00979
00980 if (p2 == 0) {
00981 if (!HasSignalOnTrack(tile, track)) {
00982
00983 SetPresentSignals(tile, GetPresentSignals(tile) | (IsPbsSignal(sigtype) ? KillFirstBit(SignalOnTrack(track)) : SignalOnTrack(track)));
00984 SetSignalType(tile, track, sigtype);
00985 SetSignalVariant(tile, track, sigvar);
00986 while (num_dir_cycle-- > 0) CycleSignalSide(tile, track);
00987 } else {
00988 if (convert_signal) {
00989
00990 if (ctrl_pressed) {
00991
00992 SetSignalVariant(tile, track, (GetSignalVariant(tile, track) == SIG_ELECTRIC) ? SIG_SEMAPHORE : SIG_ELECTRIC);
00993
00994 sigtype = GetSignalType(tile, track);
00995 } else {
00996
00997 SetSignalType(tile, track, sigtype);
00998 SetSignalVariant(tile, track, sigvar);
00999 if (IsPbsSignal(sigtype) && (GetPresentSignals(tile) & SignalOnTrack(track)) == SignalOnTrack(track)) {
01000 SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | KillFirstBit(SignalOnTrack(track)));
01001 }
01002 }
01003
01004 } else if (ctrl_pressed) {
01005
01006 sigtype = (SignalType)(GetSignalType(tile, track) + 1);
01007
01008 if (sigtype < cycle_start || sigtype > cycle_stop) sigtype = cycle_start;
01009
01010 SetSignalType(tile, track, sigtype);
01011 if (IsPbsSignal(sigtype) && (GetPresentSignals(tile) & SignalOnTrack(track)) == SignalOnTrack(track)) {
01012 SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | KillFirstBit(SignalOnTrack(track)));
01013 }
01014 } else {
01015
01016 CycleSignalSide(tile, track);
01017
01018 sigtype = GetSignalType(tile, track);
01019 }
01020 }
01021 } else {
01022
01023
01024 SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | (p2 & SignalOnTrack(track)));
01025 SetSignalVariant(tile, track, sigvar);
01026 SetSignalType(tile, track, sigtype);
01027 }
01028
01029 if (IsPbsSignal(sigtype)) {
01030
01031 uint mask = GetPresentSignals(tile) & SignalOnTrack(track);
01032 SetSignalStates(tile, (GetSignalStates(tile) & ~mask) | ((HasBit(GetRailReservationTrackBits(tile), track) ? UINT_MAX : 0) & mask));
01033 }
01034 MarkTileDirtyByTile(tile);
01035 AddTrackToSignalBuffer(tile, track, _current_company);
01036 YapfNotifyTrackLayoutChange(tile, track);
01037 if (v != NULL) {
01038
01039 if (!(((v->vehstatus & VS_STOPPED) && v->cur_speed == 0) || v->current_order.IsType(OT_LOADING)) ||
01040 !IsSafeWaitingPosition(v, v->tile, v->GetVehicleTrackdir(), true, _settings_game.pf.forbid_90_deg)) {
01041 TryPathReserve(v, true);
01042 }
01043 }
01044 }
01045
01046 return cost;
01047 }
01048
01049 static bool CheckSignalAutoFill(TileIndex &tile, Trackdir &trackdir, int &signal_ctr, bool remove)
01050 {
01051 tile = AddTileIndexDiffCWrap(tile, _trackdelta[trackdir]);
01052 if (tile == INVALID_TILE) return false;
01053
01054
01055 TrackdirBits trackdirbits = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0));
01056
01057 if (TracksOverlap(TrackdirBitsToTrackBits(trackdirbits))) return false;
01058 trackdirbits &= TrackdirReachesTrackdirs(trackdir);
01059
01060
01061 if (trackdirbits == TRACKDIR_BIT_NONE) return false;
01062
01063
01064 trackdir = RemoveFirstTrackdir(&trackdirbits);
01065
01066
01067 if (trackdirbits != TRACKDIR_BIT_NONE) return false;
01068
01069 switch (GetTileType(tile)) {
01070 case MP_RAILWAY:
01071 if (IsRailDepot(tile)) return false;
01072 if (!remove && HasSignalOnTrack(tile, TrackdirToTrack(trackdir))) return false;
01073 signal_ctr++;
01074 if (IsDiagonalTrackdir(trackdir)) {
01075 signal_ctr++;
01076
01077 ClrBit(signal_ctr, 0);
01078 }
01079 return true;
01080
01081 case MP_ROAD:
01082 if (!IsLevelCrossing(tile)) return false;
01083 signal_ctr += 2;
01084 return true;
01085
01086 case MP_TUNNELBRIDGE: {
01087 TileIndex orig_tile = tile;
01088
01089 if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) return false;
01090 if (GetTunnelBridgeDirection(tile) != TrackdirToExitdir(trackdir)) return false;
01091
01092
01093
01094 tile = GetOtherTunnelBridgeEnd(tile);
01095
01096 signal_ctr += (GetTunnelBridgeLength(orig_tile, tile) + 2) * 2;
01097 return true;
01098 }
01099
01100 default: return false;
01101 }
01102 }
01103
01119 static CommandCost CmdSignalTrackHelper(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01120 {
01121 CommandCost ret, total_cost(EXPENSES_CONSTRUCTION);
01122 bool err = true;
01123 TileIndex start_tile = tile;
01124
01125 Track track = (Track)GB(p2, 0, 3);
01126 bool mode = HasBit(p2, 3);
01127 bool semaphores = HasBit(p2, 4);
01128 bool remove = HasBit(p2, 5);
01129 bool autofill = HasBit(p2, 6);
01130 Trackdir trackdir = TrackToTrackdir(track);
01131 byte signal_density = GB(p2, 24, 8);
01132
01133 if (p1 >= MapSize()) return CMD_ERROR;
01134 TileIndex end_tile = p1;
01135 if (signal_density == 0 || signal_density > 20) return CMD_ERROR;
01136
01137 if (!IsPlainRailTile(tile)) return CMD_ERROR;
01138
01139
01140
01141 signal_density *= 2;
01142
01143 if (ValidateAutoDrag(&trackdir, tile, end_tile).Failed()) return CMD_ERROR;
01144
01145 track = TrackdirToTrack(trackdir);
01146 Trackdir start_trackdir = trackdir;
01147
01148
01149 if (!HasTrack(tile, track)) return CMD_ERROR;
01150
01151 SignalType sigtype = (SignalType)GB(p2, 7, 3);
01152 if (sigtype > SIGTYPE_LAST) return CMD_ERROR;
01153
01154 byte signals;
01155
01156 if (HasSignalOnTrack(tile, track)) {
01157 signals = GetPresentSignals(tile) & SignalOnTrack(track);
01158 assert(signals != 0);
01159
01160
01161 semaphores = GetSignalVariant(tile, track) != SIG_ELECTRIC;
01162
01163 sigtype = GetSignalType(tile, track);
01164
01165 if (sigtype < SIGTYPE_PBS) sigtype = SIGTYPE_NORMAL;
01166 } else {
01167 signals = IsPbsSignal(sigtype) ? SignalAlongTrackdir(trackdir) : SignalOnTrack(track);
01168 }
01169
01170 byte signal_dir = 0;
01171 if (signals & SignalAlongTrackdir(trackdir)) SetBit(signal_dir, 0);
01172 if (signals & SignalAgainstTrackdir(trackdir)) SetBit(signal_dir, 1);
01173
01174
01175
01176
01177
01178
01179
01180
01181
01182 int signal_ctr = 0;
01183 for (;;) {
01184
01185 if ((remove && autofill) || signal_ctr % signal_density == 0) {
01186 uint32 p1 = GB(TrackdirToTrack(trackdir), 0, 3);
01187 SB(p1, 3, 1, mode);
01188 SB(p1, 4, 1, semaphores);
01189 SB(p1, 5, 3, sigtype);
01190 if (!remove && signal_ctr == 0) SetBit(p1, 17);
01191
01192
01193 signals = 0;
01194 if (HasBit(signal_dir, 0)) signals |= SignalAlongTrackdir(trackdir);
01195 if (HasBit(signal_dir, 1)) signals |= SignalAgainstTrackdir(trackdir);
01196
01197 ret = DoCommand(tile, p1, signals, flags, remove ? CMD_REMOVE_SIGNALS : CMD_BUILD_SIGNALS);
01198
01199
01200 if (ret.Succeeded()) {
01201 err = false;
01202 total_cost.AddCost(ret);
01203 }
01204 }
01205
01206 if (autofill) {
01207 if (!CheckSignalAutoFill(tile, trackdir, signal_ctr, remove)) break;
01208
01209
01210 if (tile == start_tile && trackdir == start_trackdir) break;
01211 } else {
01212 if (tile == end_tile) break;
01213
01214 tile += ToTileIndexDiff(_trackdelta[trackdir]);
01215 signal_ctr++;
01216
01217
01218 if (IsDiagonalTrackdir(trackdir)) {
01219 signal_ctr++;
01220 } else {
01221 ToggleBit(trackdir, 0);
01222 }
01223 }
01224 }
01225
01226 return err ? CMD_ERROR : total_cost;
01227 }
01228
01246 CommandCost CmdBuildSignalTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01247 {
01248 return CmdSignalTrackHelper(tile, flags, p1, p2, text);
01249 }
01250
01262 CommandCost CmdRemoveSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01263 {
01264 Track track = (Track)GB(p1, 0, 3);
01265
01266 if (!ValParamTrackOrientation(track) ||
01267 !IsPlainRailTile(tile) ||
01268 !HasTrack(tile, track) ||
01269 !EnsureNoTrainOnTrack(tile, track) ||
01270 !HasSignalOnTrack(tile, track)) {
01271 return CMD_ERROR;
01272 }
01273
01274
01275 if (_current_company != OWNER_WATER && !CheckTileOwnership(tile)) return CMD_ERROR;
01276
01277
01278 if (flags & DC_EXEC) {
01279 Train *v = NULL;
01280 if (HasReservedTracks(tile, TrackToTrackBits(track))) {
01281 v = GetTrainForReservation(tile, track);
01282 } else if (IsPbsSignal(GetSignalType(tile, track))) {
01283
01284 Trackdir td = TrackToTrackdir(track);
01285 for (int i = 0; v == NULL && i < 2; i++, td = ReverseTrackdir(td)) {
01286
01287 if (!HasSignalOnTrackdir(tile, ReverseTrackdir(td))) continue;
01288 TileIndex next = TileAddByDiagDir(tile, TrackdirToExitdir(td));
01289 TrackBits tracks = TrackdirBitsToTrackBits(TrackdirReachesTrackdirs(td));
01290 if (HasReservedTracks(next, tracks)) {
01291 v = GetTrainForReservation(next, TrackBitsToTrack(GetReservedTrackbits(next) & tracks));
01292 }
01293 }
01294 }
01295 SetPresentSignals(tile, GetPresentSignals(tile) & ~SignalOnTrack(track));
01296
01297
01298 if (GetPresentSignals(tile) == 0) {
01299 SetSignalStates(tile, 0);
01300 SetHasSignals(tile, false);
01301 SetSignalVariant(tile, INVALID_TRACK, SIG_ELECTRIC);
01302 }
01303
01304 AddTrackToSignalBuffer(tile, track, GetTileOwner(tile));
01305 YapfNotifyTrackLayoutChange(tile, track);
01306 if (v != NULL) TryPathReserve(v, false);
01307
01308 MarkTileDirtyByTile(tile);
01309 }
01310
01311 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_SIGNALS]);
01312 }
01313
01331 CommandCost CmdRemoveSignalTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01332 {
01333 return CmdSignalTrackHelper(tile, flags, p1, SetBit(p2, 5), text);
01334 }
01335
01337 static Vehicle *UpdateTrainPowerProc(Vehicle *v, void *data)
01338 {
01339 if (v->type != VEH_TRAIN) return NULL;
01340
01341
01342
01343 Train *t = Train::From(v);
01344 if (t->IsArticulatedPart()) return NULL;
01345
01346 const RailVehicleInfo *rvi = RailVehInfo(t->engine_type);
01347 if (GetVehicleProperty(t, PROP_TRAIN_POWER, rvi->power) != 0) t->First()->PowerChanged();
01348
01349 return NULL;
01350 }
01351
01361 CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01362 {
01363 CommandCost cost(EXPENSES_CONSTRUCTION);
01364 RailType totype = (RailType)p2;
01365
01366 if (!ValParamRailtype(totype)) return CMD_ERROR;
01367 if (p1 >= MapSize()) return CMD_ERROR;
01368
01369 uint ex = TileX(tile);
01370 uint ey = TileY(tile);
01371 uint sx = TileX(p1);
01372 uint sy = TileY(p1);
01373
01374
01375 if (ex < sx) Swap(ex, sx);
01376 if (ey < sy) Swap(ey, sy);
01377
01378 _error_message = STR_ERROR_NO_SUITABLE_RAILROAD_TRACK;
01379
01380 for (uint x = sx; x <= ex; ++x) {
01381 for (uint y = sy; y <= ey; ++y) {
01382 TileIndex tile = TileXY(x, y);
01383 TileType tt = GetTileType(tile);
01384
01385
01386 switch (tt) {
01387 case MP_RAILWAY:
01388 break;
01389 case MP_STATION:
01390 if (!HasStationRail(tile)) continue;
01391 break;
01392 case MP_ROAD:
01393 if (!IsLevelCrossing(tile)) continue;
01394 break;
01395 case MP_TUNNELBRIDGE:
01396 if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) continue;
01397 break;
01398 default: continue;
01399 }
01400
01401
01402 RailType type = GetRailType(tile);
01403
01404
01405 if (type == totype || (_settings_game.vehicle.disable_elrails && totype == RAILTYPE_RAIL && type == RAILTYPE_ELECTRIC)) continue;
01406
01407
01408 if (!CheckTileOwnership(tile)) continue;
01409
01410 SmallVector<Train *, 2> vehicles_affected;
01411
01412
01413
01414 if (tt != MP_TUNNELBRIDGE) {
01415 if (!IsCompatibleRail(type, totype) && !EnsureNoVehicleOnGround(tile)) continue;
01416 if (flags & DC_EXEC) {
01417 TrackBits reserved = GetReservedTrackbits(tile);
01418 Track track;
01419 while ((track = RemoveFirstTrack(&reserved)) != INVALID_TRACK) {
01420 Train *v = GetTrainForReservation(tile, track);
01421 if (v != NULL && !HasPowerOnRail(v->railtype, totype)) {
01422
01423 FreeTrainTrackReservation(v);
01424 *vehicles_affected.Append() = v;
01425 }
01426 }
01427
01428 SetRailType(tile, totype);
01429 MarkTileDirtyByTile(tile);
01430
01431 FindVehicleOnPos(tile, NULL, &UpdateTrainPowerProc);
01432 }
01433 }
01434
01435 switch (tt) {
01436 case MP_RAILWAY:
01437 switch (GetRailTileType(tile)) {
01438 case RAIL_TILE_DEPOT:
01439 if (flags & DC_EXEC) {
01440
01441 YapfNotifyTrackLayoutChange(tile, GetRailDepotTrack(tile));
01442
01443
01444 InvalidateWindowData(WC_VEHICLE_DEPOT, tile);
01445 InvalidateWindowData(WC_BUILD_VEHICLE, tile);
01446 }
01447 cost.AddCost(RailConvertCost(type, totype));
01448 break;
01449
01450 default:
01451 if (flags & DC_EXEC) {
01452
01453 TrackBits tracks = GetTrackBits(tile);
01454 while (tracks != TRACK_BIT_NONE) {
01455 YapfNotifyTrackLayoutChange(tile, RemoveFirstTrack(&tracks));
01456 }
01457 }
01458 cost.AddCost(RailConvertCost(type, totype) * CountBits(GetTrackBits(tile)));
01459 break;
01460 }
01461 break;
01462
01463 case MP_TUNNELBRIDGE: {
01464 TileIndex endtile = GetOtherTunnelBridgeEnd(tile);
01465
01466
01467
01468 if (endtile < tile && TileX(endtile) >= sx && TileX(endtile) <= ex &&
01469 TileY(endtile) >= sy && TileY(endtile) <= ey) continue;
01470
01471
01472 if (!IsCompatibleRail(GetRailType(tile), totype) &&
01473 HasVehicleOnTunnelBridge(tile, endtile)) continue;
01474
01475 if (flags & DC_EXEC) {
01476 Track track = DiagDirToDiagTrack(GetTunnelBridgeDirection(tile));
01477 if (HasTunnelBridgeReservation(tile)) {
01478 Train *v = GetTrainForReservation(tile, track);
01479 if (v != NULL && !HasPowerOnRail(v->railtype, totype)) {
01480
01481 FreeTrainTrackReservation(v);
01482 *vehicles_affected.Append() = v;
01483 }
01484 }
01485 SetRailType(tile, totype);
01486 SetRailType(endtile, totype);
01487
01488 FindVehicleOnPos(tile, NULL, &UpdateTrainPowerProc);
01489 FindVehicleOnPos(endtile, NULL, &UpdateTrainPowerProc);
01490
01491 YapfNotifyTrackLayoutChange(tile, track);
01492 YapfNotifyTrackLayoutChange(endtile, track);
01493
01494 MarkTileDirtyByTile(tile);
01495 MarkTileDirtyByTile(endtile);
01496
01497 if (IsBridge(tile)) {
01498 TileIndexDiff delta = TileOffsByDiagDir(GetTunnelBridgeDirection(tile));
01499 TileIndex t = tile + delta;
01500 for (; t != endtile; t += delta) MarkTileDirtyByTile(t);
01501 }
01502 }
01503
01504 cost.AddCost((GetTunnelBridgeLength(tile, endtile) + 2) * RailConvertCost(type, totype));
01505 } break;
01506
01507 default:
01508 if (flags & DC_EXEC) {
01509 Track track = ((tt == MP_STATION) ? GetRailStationTrack(tile) : GetCrossingRailTrack(tile));
01510 YapfNotifyTrackLayoutChange(tile, track);
01511 }
01512
01513 cost.AddCost(RailConvertCost(type, totype));
01514 break;
01515 }
01516
01517 for (uint i = 0; i < vehicles_affected.Length(); ++i) {
01518 TryPathReserve(vehicles_affected[i], true);
01519 }
01520 }
01521 }
01522
01523 return (cost.GetCost() == 0) ? CMD_ERROR : cost;
01524 }
01525
01526 static CommandCost RemoveTrainDepot(TileIndex tile, DoCommandFlag flags)
01527 {
01528 if (!CheckTileOwnership(tile) && _current_company != OWNER_WATER)
01529 return CMD_ERROR;
01530
01531 if (!EnsureNoVehicleOnGround(tile))
01532 return CMD_ERROR;
01533
01534 if (flags & DC_EXEC) {
01535
01536 DiagDirection dir = GetRailDepotDirection(tile);
01537 Owner owner = GetTileOwner(tile);
01538 Train *v = NULL;
01539
01540 if (HasDepotReservation(tile)) {
01541 v = GetTrainForReservation(tile, DiagDirToDiagTrack(dir));
01542 if (v != NULL) FreeTrainTrackReservation(v);
01543 }
01544
01545 delete Depot::GetByTile(tile);
01546 DoClearSquare(tile);
01547 AddSideToSignalBuffer(tile, dir, owner);
01548 YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
01549 if (v != NULL) TryPathReserve(v, true);
01550 }
01551
01552 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_TRAIN]);
01553 }
01554
01555 static CommandCost ClearTile_Track(TileIndex tile, DoCommandFlag flags)
01556 {
01557 CommandCost cost(EXPENSES_CONSTRUCTION);
01558
01559 if (flags & DC_AUTO) {
01560 if (!IsTileOwner(tile, _current_company)) {
01561 return_cmd_error(STR_ERROR_AREA_IS_OWNED_BY_ANOTHER);
01562 }
01563
01564 if (IsPlainRail(tile)) {
01565 return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
01566 } else {
01567 return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
01568 }
01569 }
01570
01571 switch (GetRailTileType(tile)) {
01572 case RAIL_TILE_SIGNALS:
01573 case RAIL_TILE_NORMAL: {
01574 Slope tileh = GetTileSlope(tile, NULL);
01575
01576 bool water_ground = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh));
01577
01578 TrackBits tracks = GetTrackBits(tile);
01579 while (tracks != TRACK_BIT_NONE) {
01580 Track track = RemoveFirstTrack(&tracks);
01581 CommandCost ret = DoCommand(tile, 0, track, flags, CMD_REMOVE_SINGLE_RAIL);
01582 if (ret.Failed()) return CMD_ERROR;
01583 cost.AddCost(ret);
01584 }
01585
01586
01587 if (water_ground && !(flags & DC_BANKRUPT)) {
01588 if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
01589
01590
01591 if (flags & DC_EXEC) DoClearSquare(tile);
01592 cost.AddCost(_price[PR_CLEAR_WATER]);
01593 }
01594
01595 return cost;
01596 }
01597
01598 case RAIL_TILE_DEPOT:
01599 return RemoveTrainDepot(tile, flags);
01600
01601 default:
01602 return CMD_ERROR;
01603 }
01604 }
01605
01610 static uint GetSaveSlopeZ(uint x, uint y, Track track)
01611 {
01612 switch (track) {
01613 case TRACK_UPPER: x &= ~0xF; y &= ~0xF; break;
01614 case TRACK_LOWER: x |= 0xF; y |= 0xF; break;
01615 case TRACK_LEFT: x |= 0xF; y &= ~0xF; break;
01616 case TRACK_RIGHT: x &= ~0xF; y |= 0xF; break;
01617 default: break;
01618 }
01619 return GetSlopeZ(x, y);
01620 }
01621
01622 static void DrawSingleSignal(TileIndex tile, Track track, byte condition, uint image, uint pos)
01623 {
01624 bool side = (_settings_game.vehicle.road_side != 0) && _settings_game.construction.signal_side;
01625 static const Point SignalPositions[2][12] = {
01626 {
01627
01628 { 8, 5}, {14, 1}, { 1, 14}, { 9, 11}, { 1, 0}, { 3, 10},
01629
01630 {11, 4}, {14, 14}, {11, 3}, { 4, 13}, { 3, 4}, {11, 13}
01631 }, {
01632
01633 {14, 1}, {12, 10}, { 4, 6}, { 1, 14}, {10, 4}, { 0, 1},
01634
01635 {14, 14}, { 5, 12}, {11, 13}, { 4, 3}, {13, 4}, { 3, 11}
01636 }
01637 };
01638
01639 uint x = TileX(tile) * TILE_SIZE + SignalPositions[side][pos].x;
01640 uint y = TileY(tile) * TILE_SIZE + SignalPositions[side][pos].y;
01641
01642 SpriteID sprite;
01643
01644 SignalType type = GetSignalType(tile, track);
01645 SignalVariant variant = GetSignalVariant(tile, track);
01646
01647 if (type == SIGTYPE_NORMAL && variant == SIG_ELECTRIC) {
01648
01649 sprite = SPR_ORIGINAL_SIGNALS_BASE + image + condition;
01650 } else {
01651
01652 sprite = SPR_SIGNALS_BASE + (type - 1) * 16 + variant * 64 + image + condition + (type > SIGTYPE_LAST_NOPBS ? 64 : 0);
01653 }
01654
01655 AddSortableSpriteToDraw(sprite, PAL_NONE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, GetSaveSlopeZ(x, y, track));
01656 }
01657
01658 static uint32 _drawtile_track_palette;
01659
01660
01661 static void DrawTrackFence_NW(const TileInfo *ti, SpriteID base_image)
01662 {
01663 RailFenceOffset rfo = RFO_FLAT_X;
01664 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SW : RFO_SLOPE_NE;
01665 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01666 ti->x, ti->y + 1, 16, 1, 4, ti->z);
01667 }
01668
01669 static void DrawTrackFence_SE(const TileInfo *ti, SpriteID base_image)
01670 {
01671 RailFenceOffset rfo = RFO_FLAT_X;
01672 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SW : RFO_SLOPE_NE;
01673 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01674 ti->x, ti->y + TILE_SIZE - 1, 16, 1, 4, ti->z);
01675 }
01676
01677 static void DrawTrackFence_NW_SE(const TileInfo *ti, SpriteID base_image)
01678 {
01679 DrawTrackFence_NW(ti, base_image);
01680 DrawTrackFence_SE(ti, base_image);
01681 }
01682
01683 static void DrawTrackFence_NE(const TileInfo *ti, SpriteID base_image)
01684 {
01685 RailFenceOffset rfo = RFO_FLAT_Y;
01686 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SE : RFO_SLOPE_NW;
01687 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01688 ti->x + 1, ti->y, 1, 16, 4, ti->z);
01689 }
01690
01691 static void DrawTrackFence_SW(const TileInfo *ti, SpriteID base_image)
01692 {
01693 RailFenceOffset rfo = RFO_FLAT_Y;
01694 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SE : RFO_SLOPE_NW;
01695 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01696 ti->x + TILE_SIZE - 1, ti->y, 1, 16, 4, ti->z);
01697 }
01698
01699 static void DrawTrackFence_NE_SW(const TileInfo *ti, SpriteID base_image)
01700 {
01701 DrawTrackFence_NE(ti, base_image);
01702 DrawTrackFence_SW(ti, base_image);
01703 }
01704
01708 static void DrawTrackFence_NS_1(const TileInfo *ti, SpriteID base_image)
01709 {
01710 uint z = ti->z + GetSlopeZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_W);
01711 AddSortableSpriteToDraw(base_image + RFO_FLAT_VERT, _drawtile_track_palette,
01712 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01713 }
01714
01718 static void DrawTrackFence_NS_2(const TileInfo *ti, SpriteID base_image)
01719 {
01720 uint z = ti->z + GetSlopeZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_E);
01721 AddSortableSpriteToDraw(base_image + RFO_FLAT_VERT, _drawtile_track_palette,
01722 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01723 }
01724
01728 static void DrawTrackFence_WE_1(const TileInfo *ti, SpriteID base_image)
01729 {
01730 uint z = ti->z + GetSlopeZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_N);
01731 AddSortableSpriteToDraw(base_image + RFO_FLAT_HORZ, _drawtile_track_palette,
01732 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01733 }
01734
01738 static void DrawTrackFence_WE_2(const TileInfo *ti, SpriteID base_image)
01739 {
01740 uint z = ti->z + GetSlopeZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_S);
01741 AddSortableSpriteToDraw(base_image + RFO_FLAT_HORZ, _drawtile_track_palette,
01742 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01743 }
01744
01745
01746 static void DrawTrackDetails(const TileInfo *ti, const RailtypeInfo *rti)
01747 {
01748
01749 SpriteID base_image = GetCustomRailSprite(rti, ti->tile, RTSG_FENCES);
01750 if (base_image == 0) base_image = SPR_TRACK_FENCE_FLAT_X;
01751
01752 switch (GetRailGroundType(ti->tile)) {
01753 case RAIL_GROUND_FENCE_NW: DrawTrackFence_NW(ti, base_image); break;
01754 case RAIL_GROUND_FENCE_SE: DrawTrackFence_SE(ti, base_image); break;
01755 case RAIL_GROUND_FENCE_SENW: DrawTrackFence_NW_SE(ti, base_image); break;
01756 case RAIL_GROUND_FENCE_NE: DrawTrackFence_NE(ti, base_image); break;
01757 case RAIL_GROUND_FENCE_SW: DrawTrackFence_SW(ti, base_image); break;
01758 case RAIL_GROUND_FENCE_NESW: DrawTrackFence_NE_SW(ti, base_image); break;
01759 case RAIL_GROUND_FENCE_VERT1: DrawTrackFence_NS_1(ti, base_image); break;
01760 case RAIL_GROUND_FENCE_VERT2: DrawTrackFence_NS_2(ti, base_image); break;
01761 case RAIL_GROUND_FENCE_HORIZ1: DrawTrackFence_WE_1(ti, base_image); break;
01762 case RAIL_GROUND_FENCE_HORIZ2: DrawTrackFence_WE_2(ti, base_image); break;
01763 case RAIL_GROUND_WATER: {
01764 Corner track_corner;
01765 if (IsHalftileSlope(ti->tileh)) {
01766
01767 track_corner = GetHalftileSlopeCorner(ti->tileh);
01768 } else {
01769
01770 track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh)));
01771 }
01772 switch (track_corner) {
01773 case CORNER_W: DrawTrackFence_NS_1(ti, base_image); break;
01774 case CORNER_S: DrawTrackFence_WE_2(ti, base_image); break;
01775 case CORNER_E: DrawTrackFence_NS_2(ti, base_image); break;
01776 case CORNER_N: DrawTrackFence_WE_1(ti, base_image); break;
01777 default: NOT_REACHED();
01778 }
01779 break;
01780 }
01781 default: break;
01782 }
01783 }
01784
01785
01786 static const int INF = 1000;
01787 static const SubSprite _halftile_sub_sprite[4] = {
01788 { -INF , -INF , 32 - 33, INF },
01789 { -INF , 0 + 7, INF , INF },
01790 { -31 + 33, -INF , INF , INF },
01791 { -INF , -INF , INF , 30 - 23 }
01792 };
01793
01794 static inline void DrawTrackSprite(SpriteID sprite, PaletteID pal, const TileInfo *ti, Slope s)
01795 {
01796 DrawGroundSprite(sprite, pal, NULL, 0, (ti->tileh & s) ? -8 : 0);
01797 }
01798
01799 static void DrawTrackBitsOverlay(TileInfo *ti, TrackBits track, const RailtypeInfo *rti)
01800 {
01801 RailGroundType rgt = GetRailGroundType(ti->tile);
01802 Foundation f = GetRailFoundation(ti->tileh, track);
01803 Corner halftile_corner = CORNER_INVALID;
01804
01805 if (IsNonContinuousFoundation(f)) {
01806
01807 halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f));
01808
01809 track &= ~CornerToTrackBits(halftile_corner);
01810 f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE);
01811 }
01812
01813 DrawFoundation(ti, f);
01814
01815
01816
01817 if (track == TRACK_BIT_NONE && rgt == RAIL_GROUND_WATER) {
01818 if (IsSteepSlope(ti->tileh)) {
01819 DrawShoreTile(ti->tileh);
01820 } else {
01821 DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
01822 }
01823 } else {
01824 SpriteID image;
01825
01826 switch (rgt) {
01827 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
01828 case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOW_DESERT_TILE; break;
01829 default: image = SPR_FLAT_GRASS_TILE; break;
01830 }
01831
01832 image += _tileh_to_sprite[ti->tileh];
01833
01834 DrawGroundSprite(image, PAL_NONE);
01835 }
01836
01837 SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
01838 SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
01839 TrackBits pbs = _settings_client.gui.show_track_reservation ? GetRailReservationTrackBits(ti->tile) : TRACK_BIT_NONE;
01840
01841 if (track == TRACK_BIT_NONE) {
01842
01843 } else if (ti->tileh == SLOPE_NW && track == TRACK_BIT_Y) {
01844 DrawGroundSprite(ground + RTO_SLOPE_NW, PAL_NONE);
01845 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 9, PALETTE_CRASH);
01846 } else if (ti->tileh == SLOPE_NE && track == TRACK_BIT_X) {
01847 DrawGroundSprite(ground + RTO_SLOPE_NE, PAL_NONE);
01848 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 6, PALETTE_CRASH);
01849 } else if (ti->tileh == SLOPE_SE && track == TRACK_BIT_Y) {
01850 DrawGroundSprite(ground + RTO_SLOPE_SE, PAL_NONE);
01851 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 7, PALETTE_CRASH);
01852 } else if (ti->tileh == SLOPE_SW && track == TRACK_BIT_X) {
01853 DrawGroundSprite(ground + RTO_SLOPE_SW, PAL_NONE);
01854 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 8, PALETTE_CRASH);
01855 } else {
01856 switch (track) {
01857
01858
01859 case TRACK_BIT_X: DrawGroundSprite(ground + RTO_X, PAL_NONE); break;
01860 case TRACK_BIT_Y: DrawGroundSprite(ground + RTO_Y, PAL_NONE); break;
01861 case TRACK_BIT_UPPER: DrawTrackSprite(ground + RTO_N, PAL_NONE, ti, SLOPE_N); break;
01862 case TRACK_BIT_LOWER: DrawTrackSprite(ground + RTO_S, PAL_NONE, ti, SLOPE_S); break;
01863 case TRACK_BIT_RIGHT: DrawTrackSprite(ground + RTO_E, PAL_NONE, ti, SLOPE_E); break;
01864 case TRACK_BIT_LEFT: DrawTrackSprite(ground + RTO_W, PAL_NONE, ti, SLOPE_W); break;
01865 case TRACK_BIT_CROSS: DrawGroundSprite(ground + RTO_CROSSING_XY, PAL_NONE); break;
01866 case TRACK_BIT_HORZ: DrawTrackSprite(ground + RTO_N, PAL_NONE, ti, SLOPE_N);
01867 DrawTrackSprite(ground + RTO_S, PAL_NONE, ti, SLOPE_S); break;
01868 case TRACK_BIT_VERT: DrawTrackSprite(ground + RTO_E, PAL_NONE, ti, SLOPE_E);
01869 DrawTrackSprite(ground + RTO_W, PAL_NONE, ti, SLOPE_W); break;
01870
01871 default:
01872
01873 if ((track & TRACK_BIT_3WAY_NE) == 0) {
01874 DrawGroundSprite(ground + RTO_JUNCTION_SW, PAL_NONE);
01875 } else if ((track & TRACK_BIT_3WAY_SW) == 0) {
01876 DrawGroundSprite(ground + RTO_JUNCTION_NE, PAL_NONE);
01877 } else if ((track & TRACK_BIT_3WAY_NW) == 0) {
01878 DrawGroundSprite(ground + RTO_JUNCTION_SE, PAL_NONE);
01879 } else if ((track & TRACK_BIT_3WAY_SE) == 0) {
01880 DrawGroundSprite(ground + RTO_JUNCTION_NW, PAL_NONE);
01881 } else {
01882 DrawGroundSprite(ground + RTO_JUNCTION_NSEW, PAL_NONE);
01883 }
01884
01885
01886 track &= ~pbs;
01887
01888
01889 if (track & TRACK_BIT_X) DrawGroundSprite(overlay + RTO_X, PAL_NONE);
01890 if (track & TRACK_BIT_Y) DrawGroundSprite(overlay + RTO_Y, PAL_NONE);
01891 if (track & TRACK_BIT_UPPER) DrawGroundSprite(overlay + RTO_N, PAL_NONE);
01892 if (track & TRACK_BIT_LOWER) DrawGroundSprite(overlay + RTO_S, PAL_NONE);
01893 if (track & TRACK_BIT_RIGHT) DrawGroundSprite(overlay + RTO_E, PAL_NONE);
01894 if (track & TRACK_BIT_LEFT) DrawGroundSprite(overlay + RTO_W, PAL_NONE);
01895 }
01896
01897
01898 if (pbs & TRACK_BIT_X) DrawGroundSprite(overlay + RTO_X, PALETTE_CRASH);
01899 if (pbs & TRACK_BIT_Y) DrawGroundSprite(overlay + RTO_Y, PALETTE_CRASH);
01900 if (pbs & TRACK_BIT_UPPER) DrawTrackSprite(overlay + RTO_N, PALETTE_CRASH, ti, SLOPE_N);
01901 if (pbs & TRACK_BIT_LOWER) DrawTrackSprite(overlay + RTO_S, PALETTE_CRASH, ti, SLOPE_S);
01902 if (pbs & TRACK_BIT_RIGHT) DrawTrackSprite(overlay + RTO_E, PALETTE_CRASH, ti, SLOPE_E);
01903 if (pbs & TRACK_BIT_LEFT) DrawTrackSprite(overlay + RTO_W, PALETTE_CRASH, ti, SLOPE_W);
01904 }
01905
01906 if (IsValidCorner(halftile_corner)) {
01907 DrawFoundation(ti, HalftileFoundation(halftile_corner));
01908
01909
01910 Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
01911
01912 SpriteID image;
01913 switch (rgt) {
01914 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
01915 case RAIL_GROUND_ICE_DESERT:
01916 case RAIL_GROUND_HALF_SNOW: image = SPR_FLAT_SNOW_DESERT_TILE; break;
01917 default: image = SPR_FLAT_GRASS_TILE; break;
01918 }
01919
01920 image += _tileh_to_sprite[fake_slope];
01921
01922 DrawGroundSprite(image, PAL_NONE, &(_halftile_sub_sprite[halftile_corner]));
01923
01924 track = CornerToTrackBits(halftile_corner);
01925
01926 int offset;
01927 switch (track) {
01928 default: NOT_REACHED();
01929 case TRACK_BIT_UPPER: offset = RTO_N; break;
01930 case TRACK_BIT_LOWER: offset = RTO_S; break;
01931 case TRACK_BIT_RIGHT: offset = RTO_E; break;
01932 case TRACK_BIT_LEFT: offset = RTO_W; break;
01933 }
01934
01935 DrawTrackSprite(ground + offset, PAL_NONE, ti, fake_slope);
01936 if (HasReservedTracks(ti->tile, track)) {
01937 DrawTrackSprite(overlay + offset, PALETTE_CRASH, ti, fake_slope);
01938 }
01939 }
01940 }
01941
01947 static void DrawTrackBits(TileInfo *ti, TrackBits track)
01948 {
01949 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
01950
01951 if (rti->UsesOverlay()) {
01952 DrawTrackBitsOverlay(ti, track, rti);
01953 return;
01954 }
01955
01956 RailGroundType rgt = GetRailGroundType(ti->tile);
01957 Foundation f = GetRailFoundation(ti->tileh, track);
01958 Corner halftile_corner = CORNER_INVALID;
01959
01960 if (IsNonContinuousFoundation(f)) {
01961
01962 halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f));
01963
01964 track &= ~CornerToTrackBits(halftile_corner);
01965 f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE);
01966 }
01967
01968 DrawFoundation(ti, f);
01969
01970
01971 SpriteID image;
01972 PaletteID pal = PAL_NONE;
01973 const SubSprite *sub = NULL;
01974 bool junction = false;
01975
01976
01977 if (track == 0) {
01978
01979 if (rgt == RAIL_GROUND_WATER) {
01980 if (IsSteepSlope(ti->tileh)) {
01981 DrawShoreTile(ti->tileh);
01982 image = 0;
01983 } else {
01984 image = SPR_FLAT_WATER_TILE;
01985 }
01986 } else {
01987 switch (rgt) {
01988 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
01989 case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOW_DESERT_TILE; break;
01990 default: image = SPR_FLAT_GRASS_TILE; break;
01991 }
01992 image += _tileh_to_sprite[ti->tileh];
01993 }
01994 } else {
01995 if (ti->tileh != SLOPE_FLAT) {
01996
01997 image = _track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.track_y;
01998 } else {
01999
02000 (image = rti->base_sprites.track_y, track == TRACK_BIT_Y) ||
02001 (image++, track == TRACK_BIT_X) ||
02002 (image++, track == TRACK_BIT_UPPER) ||
02003 (image++, track == TRACK_BIT_LOWER) ||
02004 (image++, track == TRACK_BIT_RIGHT) ||
02005 (image++, track == TRACK_BIT_LEFT) ||
02006 (image++, track == TRACK_BIT_CROSS) ||
02007
02008 (image = rti->base_sprites.track_ns, track == TRACK_BIT_HORZ) ||
02009 (image++, track == TRACK_BIT_VERT) ||
02010
02011 (junction = true, false) ||
02012 (image = rti->base_sprites.ground, (track & TRACK_BIT_3WAY_NE) == 0) ||
02013 (image++, (track & TRACK_BIT_3WAY_SW) == 0) ||
02014 (image++, (track & TRACK_BIT_3WAY_NW) == 0) ||
02015 (image++, (track & TRACK_BIT_3WAY_SE) == 0) ||
02016 (image++, true);
02017 }
02018
02019 switch (rgt) {
02020 case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
02021 case RAIL_GROUND_ICE_DESERT: image += rti->snow_offset; break;
02022 case RAIL_GROUND_WATER: {
02023
02024 DrawShoreTile(ti->tileh);
02025 Corner track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh)));
02026 sub = &(_halftile_sub_sprite[track_corner]);
02027 break;
02028 }
02029 default: break;
02030 }
02031 }
02032
02033 if (image != 0) DrawGroundSprite(image, pal, sub);
02034
02035
02036 if (junction) {
02037 if (track & TRACK_BIT_X) DrawGroundSprite(rti->base_sprites.single_x, PAL_NONE);
02038 if (track & TRACK_BIT_Y) DrawGroundSprite(rti->base_sprites.single_y, PAL_NONE);
02039 if (track & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PAL_NONE);
02040 if (track & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PAL_NONE);
02041 if (track & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PAL_NONE);
02042 if (track & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PAL_NONE);
02043 }
02044
02045
02046 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation) {
02047
02048 TrackBits pbs = GetRailReservationTrackBits(ti->tile) & track;
02049 if (pbs & TRACK_BIT_X) {
02050 if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
02051 DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH);
02052 } else {
02053 DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
02054 }
02055 }
02056 if (pbs & TRACK_BIT_Y) {
02057 if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
02058 DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH);
02059 } else {
02060 DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
02061 }
02062 }
02063 if (pbs & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_N ? -TILE_HEIGHT : 0);
02064 if (pbs & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_S ? -TILE_HEIGHT : 0);
02065 if (pbs & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_W ? -TILE_HEIGHT : 0);
02066 if (pbs & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_E ? -TILE_HEIGHT : 0);
02067 }
02068
02069 if (IsValidCorner(halftile_corner)) {
02070 DrawFoundation(ti, HalftileFoundation(halftile_corner));
02071
02072
02073 Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
02074 image = _track_sloped_sprites[fake_slope - 1] + rti->base_sprites.track_y;
02075 pal = PAL_NONE;
02076 switch (rgt) {
02077 case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
02078 case RAIL_GROUND_ICE_DESERT:
02079 case RAIL_GROUND_HALF_SNOW: image += rti->snow_offset; break;
02080 default: break;
02081 }
02082 DrawGroundSprite(image, pal, &(_halftile_sub_sprite[halftile_corner]));
02083
02084 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasReservedTracks(ti->tile, CornerToTrackBits(halftile_corner))) {
02085 static const byte _corner_to_track_sprite[] = {3, 1, 2, 0};
02086 DrawGroundSprite(_corner_to_track_sprite[halftile_corner] + rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, -TILE_HEIGHT);
02087 }
02088 }
02089 }
02090
02096 enum {
02097 SIGNAL_TO_SOUTHWEST = 0,
02098 SIGNAL_TO_NORTHEAST = 2,
02099 SIGNAL_TO_SOUTHEAST = 4,
02100 SIGNAL_TO_NORTHWEST = 6,
02101 SIGNAL_TO_EAST = 8,
02102 SIGNAL_TO_WEST = 10,
02103 SIGNAL_TO_SOUTH = 12,
02104 SIGNAL_TO_NORTH = 14,
02105 };
02106
02107 static void DrawSignals(TileIndex tile, TrackBits rails)
02108 {
02109 #define MAYBE_DRAW_SIGNAL(x, y, z, t) if (IsSignalPresent(tile, x)) DrawSingleSignal(tile, t, GetSingleSignalState(tile, x), y, z)
02110
02111 if (!(rails & TRACK_BIT_Y)) {
02112 if (!(rails & TRACK_BIT_X)) {
02113 if (rails & TRACK_BIT_LEFT) {
02114 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTH, 0, TRACK_LEFT);
02115 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTH, 1, TRACK_LEFT);
02116 }
02117 if (rails & TRACK_BIT_RIGHT) {
02118 MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_NORTH, 2, TRACK_RIGHT);
02119 MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_SOUTH, 3, TRACK_RIGHT);
02120 }
02121 if (rails & TRACK_BIT_UPPER) {
02122 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_WEST, 4, TRACK_UPPER);
02123 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_EAST, 5, TRACK_UPPER);
02124 }
02125 if (rails & TRACK_BIT_LOWER) {
02126 MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_WEST, 6, TRACK_LOWER);
02127 MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_EAST, 7, TRACK_LOWER);
02128 }
02129 } else {
02130 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHWEST, 8, TRACK_X);
02131 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHEAST, 9, TRACK_X);
02132 }
02133 } else {
02134 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHEAST, 10, TRACK_Y);
02135 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHWEST, 11, TRACK_Y);
02136 }
02137 }
02138
02139 static void DrawTile_Track(TileInfo *ti)
02140 {
02141 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
02142
02143 _drawtile_track_palette = COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile));
02144
02145 if (IsPlainRail(ti->tile)) {
02146 TrackBits rails = GetTrackBits(ti->tile);
02147
02148 DrawTrackBits(ti, rails);
02149
02150 if (HasBit(_display_opt, DO_FULL_DETAIL)) DrawTrackDetails(ti, rti);
02151
02152 if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
02153
02154 if (HasSignals(ti->tile)) DrawSignals(ti->tile, rails);
02155 } else {
02156
02157 const DrawTileSprites *dts;
02158 PaletteID pal = PAL_NONE;
02159 SpriteID relocation;
02160
02161 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
02162
02163 if (IsInvisibilitySet(TO_BUILDINGS)) {
02164
02165 dts = &_depot_invisible_gfx_table[GetRailDepotDirection(ti->tile)];
02166 } else {
02167 dts = &_depot_gfx_table[GetRailDepotDirection(ti->tile)];
02168 }
02169
02170 SpriteID image;
02171 if (rti->UsesOverlay()) {
02172 image = SPR_FLAT_GRASS_TILE;
02173 } else {
02174 image = dts->ground.sprite;
02175 if (image != SPR_FLAT_GRASS_TILE) image += rti->total_offset;
02176 }
02177
02178
02179
02180 if (IsSnowRailGround(ti->tile) && _settings_game.game_creation.landscape == LT_TROPIC) {
02181 if (image != SPR_FLAT_GRASS_TILE) {
02182 image += rti->snow_offset;
02183 } else {
02184 image = SPR_FLAT_SNOW_DESERT_TILE;
02185 }
02186 }
02187
02188 DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, _drawtile_track_palette));
02189
02190 if (rti->UsesOverlay()) {
02191 SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
02192
02193 switch (GetRailDepotDirection(ti->tile)) {
02194 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02195 case DIAGDIR_SW: DrawGroundSprite(ground + RTO_X, PAL_NONE); break;
02196 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02197 case DIAGDIR_SE: DrawGroundSprite(ground + RTO_Y, PAL_NONE); break;
02198 default: break;
02199 }
02200
02201 if (_settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile)) {
02202 SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
02203
02204 switch (GetRailDepotDirection(ti->tile)) {
02205 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02206 case DIAGDIR_SW: DrawGroundSprite(overlay + RTO_X, PALETTE_CRASH); break;
02207 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02208 case DIAGDIR_SE: DrawGroundSprite(overlay + RTO_Y, PALETTE_CRASH); break;
02209 default: break;
02210 }
02211 }
02212
02213 relocation = GetCustomRailSprite(rti, ti->tile, RTSG_DEPOT);
02214 relocation -= SPR_RAIL_DEPOT_SE_1;
02215 } else {
02216
02217 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile)) {
02218 switch (GetRailDepotDirection(ti->tile)) {
02219 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02220 case DIAGDIR_SW: DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH); break;
02221 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02222 case DIAGDIR_SE: DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH); break;
02223 default: break;
02224 }
02225 }
02226
02227 relocation = rti->total_offset;
02228 }
02229
02230 if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
02231
02232 DrawRailTileSeq(ti, dts, TO_BUILDINGS, relocation, 0, _drawtile_track_palette);
02233 }
02234 DrawBridgeMiddle(ti);
02235 }
02236
02237 void DrawTrainDepotSprite(int x, int y, int dir, RailType railtype)
02238 {
02239 const DrawTileSprites *dts = &_depot_gfx_table[dir];
02240 const RailtypeInfo *rti = GetRailTypeInfo(railtype);
02241 SpriteID image = rti->UsesOverlay() ? SPR_FLAT_GRASS_TILE : dts->ground.sprite;
02242 uint32 offset = rti->total_offset;
02243
02244 x += 33;
02245 y += 17;
02246
02247 if (image != SPR_FLAT_GRASS_TILE) image += offset;
02248 PaletteID palette = COMPANY_SPRITE_COLOUR(_local_company);
02249
02250 DrawSprite(image, PAL_NONE, x, y);
02251
02252 if (rti->UsesOverlay()) {
02253 SpriteID ground = GetCustomRailSprite(rti, INVALID_TILE, RTSG_GROUND);
02254
02255 switch (dir) {
02256 case DIAGDIR_SW: DrawSprite(ground + RTO_X, PAL_NONE, x, y); break;
02257 case DIAGDIR_SE: DrawSprite(ground + RTO_Y, PAL_NONE, x, y); break;
02258 default: break;
02259 }
02260
02261 offset = GetCustomRailSprite(rti, INVALID_TILE, RTSG_DEPOT);
02262 offset -= SPR_RAIL_DEPOT_SE_1;
02263 }
02264
02265 DrawRailTileSeqInGUI(x, y, dts, offset, 0, palette);
02266 }
02267
02268 static uint GetSlopeZ_Track(TileIndex tile, uint x, uint y)
02269 {
02270 uint z;
02271 Slope tileh = GetTileSlope(tile, &z);
02272
02273 if (tileh == SLOPE_FLAT) return z;
02274 if (IsPlainRail(tile)) {
02275 z += ApplyFoundationToSlope(GetRailFoundation(tileh, GetTrackBits(tile)), &tileh);
02276 return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
02277 } else {
02278 return z + TILE_HEIGHT;
02279 }
02280 }
02281
02282 static Foundation GetFoundation_Track(TileIndex tile, Slope tileh)
02283 {
02284 return IsPlainRail(tile) ? GetRailFoundation(tileh, GetTrackBits(tile)) : FlatteningFoundation(tileh);
02285 }
02286
02287 static void TileLoop_Track(TileIndex tile)
02288 {
02289 RailGroundType old_ground = GetRailGroundType(tile);
02290 RailGroundType new_ground;
02291
02292 if (old_ground == RAIL_GROUND_WATER) {
02293 TileLoop_Water(tile);
02294 return;
02295 }
02296
02297 switch (_settings_game.game_creation.landscape) {
02298 case LT_ARCTIC: {
02299 uint z;
02300 Slope slope = GetTileSlope(tile, &z);
02301 bool half = false;
02302
02303
02304
02305 if (IsPlainRail(tile)) {
02306 TrackBits track = GetTrackBits(tile);
02307 Foundation f = GetRailFoundation(slope, track);
02308
02309 switch (f) {
02310 case FOUNDATION_NONE:
02311
02312 if (IsSlopeWithThreeCornersRaised(slope)) z += TILE_HEIGHT;
02313 break;
02314
02315 case FOUNDATION_INCLINED_X:
02316 case FOUNDATION_INCLINED_Y:
02317
02318 if (IsSteepSlope(slope)) z += TILE_HEIGHT;
02319 break;
02320
02321 case FOUNDATION_STEEP_LOWER:
02322
02323 z += TILE_HEIGHT;
02324 break;
02325
02326 default:
02327
02328 if (IsSteepSlope(slope)) z += TILE_HEIGHT;
02329 z += TILE_HEIGHT;
02330 break;
02331 }
02332
02333 half = IsInsideMM(f, FOUNDATION_STEEP_BOTH, FOUNDATION_HALFTILE_N + 1);
02334 } else {
02335
02336 if (slope != SLOPE_FLAT) z += TILE_HEIGHT;
02337 }
02338
02339
02340
02341
02342
02343 if (z > GetSnowLine()) {
02344 if (half && z - GetSnowLine() == TILE_HEIGHT) {
02345
02346 new_ground = RAIL_GROUND_HALF_SNOW;
02347 } else {
02348 new_ground = RAIL_GROUND_ICE_DESERT;
02349 }
02350 goto set_ground;
02351 }
02352 break;
02353 }
02354
02355 case LT_TROPIC:
02356 if (GetTropicZone(tile) == TROPICZONE_DESERT) {
02357 new_ground = RAIL_GROUND_ICE_DESERT;
02358 goto set_ground;
02359 }
02360 break;
02361 }
02362
02363 if (!IsPlainRail(tile)) return;
02364
02365 new_ground = RAIL_GROUND_GRASS;
02366
02367 if (old_ground != RAIL_GROUND_BARREN) {
02368
02369 TrackBits rail = GetTrackBits(tile);
02370
02371 switch (rail) {
02372 case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
02373 case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
02374 case TRACK_BIT_LEFT: new_ground = RAIL_GROUND_FENCE_VERT1; break;
02375 case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2; break;
02376
02377 default: {
02378 Owner owner = GetTileOwner(tile);
02379
02380 if (rail == (TRACK_BIT_LOWER | TRACK_BIT_RIGHT) || (
02381 (rail & TRACK_BIT_3WAY_NW) == 0 &&
02382 (rail & TRACK_BIT_X)
02383 )) {
02384 TileIndex n = tile + TileDiffXY(0, -1);
02385 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02386
02387 if (!IsTileType(n, MP_RAILWAY) ||
02388 !IsTileOwner(n, owner) ||
02389 nrail == TRACK_BIT_UPPER ||
02390 nrail == TRACK_BIT_LEFT) {
02391 new_ground = RAIL_GROUND_FENCE_NW;
02392 }
02393 }
02394
02395 if (rail == (TRACK_BIT_UPPER | TRACK_BIT_LEFT) || (
02396 (rail & TRACK_BIT_3WAY_SE) == 0 &&
02397 (rail & TRACK_BIT_X)
02398 )) {
02399 TileIndex n = tile + TileDiffXY(0, 1);
02400 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02401
02402 if (!IsTileType(n, MP_RAILWAY) ||
02403 !IsTileOwner(n, owner) ||
02404 nrail == TRACK_BIT_LOWER ||
02405 nrail == TRACK_BIT_RIGHT) {
02406 new_ground = (new_ground == RAIL_GROUND_FENCE_NW) ?
02407 RAIL_GROUND_FENCE_SENW : RAIL_GROUND_FENCE_SE;
02408 }
02409 }
02410
02411 if (rail == (TRACK_BIT_LOWER | TRACK_BIT_LEFT) || (
02412 (rail & TRACK_BIT_3WAY_NE) == 0 &&
02413 (rail & TRACK_BIT_Y)
02414 )) {
02415 TileIndex n = tile + TileDiffXY(-1, 0);
02416 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02417
02418 if (!IsTileType(n, MP_RAILWAY) ||
02419 !IsTileOwner(n, owner) ||
02420 nrail == TRACK_BIT_UPPER ||
02421 nrail == TRACK_BIT_RIGHT) {
02422 new_ground = RAIL_GROUND_FENCE_NE;
02423 }
02424 }
02425
02426 if (rail == (TRACK_BIT_UPPER | TRACK_BIT_RIGHT) || (
02427 (rail & TRACK_BIT_3WAY_SW) == 0 &&
02428 (rail & TRACK_BIT_Y)
02429 )) {
02430 TileIndex n = tile + TileDiffXY(1, 0);
02431 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02432
02433 if (!IsTileType(n, MP_RAILWAY) ||
02434 !IsTileOwner(n, owner) ||
02435 nrail == TRACK_BIT_LOWER ||
02436 nrail == TRACK_BIT_LEFT) {
02437 new_ground = (new_ground == RAIL_GROUND_FENCE_NE) ?
02438 RAIL_GROUND_FENCE_NESW : RAIL_GROUND_FENCE_SW;
02439 }
02440 }
02441 break;
02442 }
02443 }
02444 }
02445
02446 set_ground:
02447 if (old_ground != new_ground) {
02448 SetRailGroundType(tile, new_ground);
02449 MarkTileDirtyByTile(tile);
02450 }
02451 }
02452
02453
02454 static TrackStatus GetTileTrackStatus_Track(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
02455 {
02456
02457 if (mode == TRANSPORT_WATER && IsPlainRail(tile) && GetRailGroundType(tile) == RAIL_GROUND_WATER) {
02458 TrackBits tb = GetTrackBits(tile);
02459 switch (tb) {
02460 default: NOT_REACHED();
02461 case TRACK_BIT_UPPER: tb = TRACK_BIT_LOWER; break;
02462 case TRACK_BIT_LOWER: tb = TRACK_BIT_UPPER; break;
02463 case TRACK_BIT_LEFT: tb = TRACK_BIT_RIGHT; break;
02464 case TRACK_BIT_RIGHT: tb = TRACK_BIT_LEFT; break;
02465 }
02466 return CombineTrackStatus(TrackBitsToTrackdirBits(tb), TRACKDIR_BIT_NONE);
02467 }
02468
02469 if (mode != TRANSPORT_RAIL) return 0;
02470
02471 TrackBits trackbits = TRACK_BIT_NONE;
02472 TrackdirBits red_signals = TRACKDIR_BIT_NONE;
02473
02474 switch (GetRailTileType(tile)) {
02475 default: NOT_REACHED();
02476 case RAIL_TILE_NORMAL:
02477 trackbits = GetTrackBits(tile);
02478 break;
02479
02480 case RAIL_TILE_SIGNALS: {
02481 trackbits = GetTrackBits(tile);
02482 byte a = GetPresentSignals(tile);
02483 uint b = GetSignalStates(tile);
02484
02485 b &= a;
02486
02487
02488
02489
02490
02491
02492 if (!IsOnewaySignal(tile, TRACK_UPPER) || (a & SignalOnTrack(TRACK_UPPER)) == 0) b |= ~a & SignalOnTrack(TRACK_UPPER);
02493 if (!IsOnewaySignal(tile, TRACK_LOWER) || (a & SignalOnTrack(TRACK_LOWER)) == 0) b |= ~a & SignalOnTrack(TRACK_LOWER);
02494
02495 if ((b & 0x8) == 0) red_signals |= (TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_X_NE | TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_UPPER_E);
02496 if ((b & 0x4) == 0) red_signals |= (TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_X_SW | TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_UPPER_W);
02497 if ((b & 0x2) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_LOWER_E);
02498 if ((b & 0x1) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_S | TRACKDIR_BIT_LOWER_W);
02499
02500 break;
02501 }
02502
02503 case RAIL_TILE_DEPOT: {
02504 DiagDirection dir = GetRailDepotDirection(tile);
02505
02506 if (side != INVALID_DIAGDIR && side != dir) break;
02507
02508 trackbits = DiagDirToDiagTrackBits(dir);
02509 break;
02510 }
02511 }
02512
02513 return CombineTrackStatus(TrackBitsToTrackdirBits(trackbits), red_signals);
02514 }
02515
02516 static bool ClickTile_Track(TileIndex tile)
02517 {
02518 if (!IsRailDepot(tile)) return false;
02519
02520 ShowDepotWindow(tile, VEH_TRAIN);
02521 return true;
02522 }
02523
02524 static void GetTileDesc_Track(TileIndex tile, TileDesc *td)
02525 {
02526 td->owner[0] = GetTileOwner(tile);
02527 switch (GetRailTileType(tile)) {
02528 case RAIL_TILE_NORMAL:
02529 td->str = STR_LAI_RAIL_DESCRIPTION_TRACK;
02530 break;
02531
02532 case RAIL_TILE_SIGNALS: {
02533 static const StringID signal_type[6][6] = {
02534 {
02535 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS,
02536 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS,
02537 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS,
02538 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS,
02539 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS,
02540 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS
02541 },
02542 {
02543 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS,
02544 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRESIGNALS,
02545 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS,
02546 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS,
02547 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS,
02548 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS
02549 },
02550 {
02551 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS,
02552 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS,
02553 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXITSIGNALS,
02554 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS,
02555 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS,
02556 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS
02557 },
02558 {
02559 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS,
02560 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS,
02561 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS,
02562 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBOSIGNALS,
02563 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS,
02564 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS
02565 },
02566 {
02567 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS,
02568 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS,
02569 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS,
02570 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS,
02571 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBSSIGNALS,
02572 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS
02573 },
02574 {
02575 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS,
02576 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS,
02577 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS,
02578 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS,
02579 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS,
02580 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRYSIGNALS
02581 }
02582 };
02583
02584 SignalType primary_signal;
02585 SignalType secondary_signal;
02586 if (HasSignalOnTrack(tile, TRACK_UPPER)) {
02587 primary_signal = GetSignalType(tile, TRACK_UPPER);
02588 secondary_signal = HasSignalOnTrack(tile, TRACK_LOWER) ? GetSignalType(tile, TRACK_LOWER) : primary_signal;
02589 } else {
02590 secondary_signal = primary_signal = GetSignalType(tile, TRACK_LOWER);
02591 }
02592
02593 td->str = signal_type[secondary_signal][primary_signal];
02594 break;
02595 }
02596
02597 case RAIL_TILE_DEPOT:
02598 td->str = STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT;
02599 break;
02600
02601 default:
02602 NOT_REACHED();
02603 }
02604 }
02605
02606 static void ChangeTileOwner_Track(TileIndex tile, Owner old_owner, Owner new_owner)
02607 {
02608 if (!IsTileOwner(tile, old_owner)) return;
02609
02610 if (new_owner != INVALID_OWNER) {
02611 SetTileOwner(tile, new_owner);
02612 } else {
02613 DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
02614 }
02615 }
02616
02617 static const byte _fractcoords_behind[4] = { 0x8F, 0x8, 0x80, 0xF8 };
02618 static const byte _fractcoords_enter[4] = { 0x8A, 0x48, 0x84, 0xA8 };
02619 static const int8 _deltacoord_leaveoffset[8] = {
02620 -1, 0, 1, 0,
02621 0, 1, 0, -1
02622 };
02623
02624
02630 int TicksToLeaveDepot(const Train *v)
02631 {
02632 DiagDirection dir = GetRailDepotDirection(v->tile);
02633 int length = v->tcache.cached_veh_length;
02634
02635 switch (dir) {
02636 case DIAGDIR_NE: return ((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) - (length + 1)));
02637 case DIAGDIR_SE: return -((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) + (length + 1)));
02638 case DIAGDIR_SW: return -((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) + (length + 1)));
02639 default:
02640 case DIAGDIR_NW: return ((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) - (length + 1)));
02641 }
02642
02643 return 0;
02644 }
02645
02648 static VehicleEnterTileStatus VehicleEnter_Track(Vehicle *u, TileIndex tile, int x, int y)
02649 {
02650
02651 if (u->type != VEH_TRAIN || !IsRailDepotTile(tile)) return VETSB_CONTINUE;
02652
02653 Train *v = Train::From(u);
02654
02655
02656 DiagDirection dir = GetRailDepotDirection(tile);
02657
02658
02659
02660 int length = v->tcache.cached_veh_length;
02661
02662 byte fract_coord_leave =
02663 ((_fractcoords_enter[dir] & 0x0F) +
02664 (length + 1) * _deltacoord_leaveoffset[dir]) +
02665 (((_fractcoords_enter[dir] >> 4) +
02666 ((length + 1) * _deltacoord_leaveoffset[dir + 4])) << 4);
02667
02668 byte fract_coord = (x & 0xF) + ((y & 0xF) << 4);
02669
02670 if (_fractcoords_behind[dir] == fract_coord) {
02671
02672 return VETSB_CANNOT_ENTER;
02673 } else if (_fractcoords_enter[dir] == fract_coord) {
02674 if (DiagDirToDir(ReverseDiagDir(dir)) == v->direction) {
02675
02676 v->track = TRACK_BIT_DEPOT,
02677 v->vehstatus |= VS_HIDDEN;
02678 v->direction = ReverseDir(v->direction);
02679 if (v->Next() == NULL) VehicleEnterDepot(v->First());
02680 v->tile = tile;
02681
02682 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
02683 return VETSB_ENTERED_WORMHOLE;
02684 }
02685 } else if (fract_coord_leave == fract_coord) {
02686 if (DiagDirToDir(dir) == v->direction) {
02687
02688 if ((v = v->Next()) != NULL) {
02689 v->vehstatus &= ~VS_HIDDEN;
02690 v->track = (DiagDirToAxis(dir) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y);
02691 }
02692 }
02693 }
02694
02695 return VETSB_CONTINUE;
02696 }
02697
02709 static CommandCost TestAutoslopeOnRailTile(TileIndex tile, uint flags, uint z_old, Slope tileh_old, uint z_new, Slope tileh_new, TrackBits rail_bits)
02710 {
02711 if (!_settings_game.construction.build_on_slopes || !AutoslopeEnabled()) return CMD_ERROR;
02712
02713
02714 if (CheckRailSlope(tileh_new, rail_bits, TRACK_BIT_NONE, tile).Failed()) return CMD_ERROR;
02715
02716
02717 z_old += ApplyFoundationToSlope(GetRailFoundation(tileh_old, rail_bits), &tileh_old);
02718 z_new += ApplyFoundationToSlope(GetRailFoundation(tileh_new, rail_bits), &tileh_new);
02719
02720 Corner track_corner;
02721 switch (rail_bits) {
02722 case TRACK_BIT_LEFT: track_corner = CORNER_W; break;
02723 case TRACK_BIT_LOWER: track_corner = CORNER_S; break;
02724 case TRACK_BIT_RIGHT: track_corner = CORNER_E; break;
02725 case TRACK_BIT_UPPER: track_corner = CORNER_N; break;
02726
02727
02728 default: return (((z_old != z_new) || (tileh_old != tileh_new)) ? CMD_ERROR : CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]));
02729 }
02730
02731
02732 z_old += GetSlopeZInCorner(RemoveHalftileSlope(tileh_old), track_corner);
02733 z_new += GetSlopeZInCorner(RemoveHalftileSlope(tileh_new), track_corner);
02734 if (z_old != z_new) return CMD_ERROR;
02735
02736 CommandCost cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02737
02738 if (tileh_old != tileh_new) {
02739
02740 if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old)) cost.AddCost(_price[PR_CLEAR_WATER]);
02741 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
02742 }
02743 return cost;
02744 }
02745
02746 static CommandCost TerraformTile_Track(TileIndex tile, DoCommandFlag flags, uint z_new, Slope tileh_new)
02747 {
02748 uint z_old;
02749 Slope tileh_old = GetTileSlope(tile, &z_old);
02750 if (IsPlainRail(tile)) {
02751 TrackBits rail_bits = GetTrackBits(tile);
02752
02753 bool was_water = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old));
02754
02755 _error_message = STR_ERROR_MUST_REMOVE_RAILROAD_TRACK;
02756
02757
02758 CommandCost autoslope_result = TestAutoslopeOnRailTile(tile, flags, z_old, tileh_old, z_new, tileh_new, rail_bits);
02759
02760
02761 Corner allowed_corner;
02762 switch (rail_bits) {
02763 case TRACK_BIT_RIGHT: allowed_corner = CORNER_W; break;
02764 case TRACK_BIT_UPPER: allowed_corner = CORNER_S; break;
02765 case TRACK_BIT_LEFT: allowed_corner = CORNER_E; break;
02766 case TRACK_BIT_LOWER: allowed_corner = CORNER_N; break;
02767 default: return autoslope_result;
02768 }
02769
02770 Foundation f_old = GetRailFoundation(tileh_old, rail_bits);
02771
02772
02773 if (tileh_old != SLOPE_NS && tileh_old != SLOPE_EW && IsSpecialRailFoundation(f_old)) return autoslope_result;
02774
02775
02776 for (Corner corner = (Corner)0; corner < CORNER_END; corner = (Corner)(corner + 1)) {
02777 if (allowed_corner == corner) continue;
02778 if (z_old + GetSlopeZInCorner(tileh_old, corner) != z_new + GetSlopeZInCorner(tileh_new, corner)) return autoslope_result;
02779 }
02780
02781
02782 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
02783
02784
02785 return CommandCost(EXPENSES_CONSTRUCTION, was_water ? _price[PR_CLEAR_WATER] : (Money)0);
02786 } else if (_settings_game.construction.build_on_slopes && AutoslopeEnabled() &&
02787 AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetRailDepotDirection(tile))) {
02788 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02789 }
02790 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
02791 }
02792
02793
02794 extern const TileTypeProcs _tile_type_rail_procs = {
02795 DrawTile_Track,
02796 GetSlopeZ_Track,
02797 ClearTile_Track,
02798 NULL,
02799 GetTileDesc_Track,
02800 GetTileTrackStatus_Track,
02801 ClickTile_Track,
02802 NULL,
02803 TileLoop_Track,
02804 ChangeTileOwner_Track,
02805 NULL,
02806 VehicleEnter_Track,
02807 GetFoundation_Track,
02808 TerraformTile_Track,
02809 };