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 = Extract<RailType, 0, 4>(p1);
00373 Track track = Extract<Track, 0, 3>(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 = Extract<Track, 0, 3>(p2);
00513 CommandCost cost(EXPENSES_CONSTRUCTION);
00514 bool crossing = false;
00515
00516 if (!ValParamTrackOrientation(track)) 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 = Extract<Track, 4, 3>(p2);
00747 bool remove = HasBit(p2, 7);
00748 RailType railtype = Extract<RailType, 0, 4>(p2);
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 RailType railtype = Extract<RailType, 0, 4>(p1);
00834 if (!ValParamRailtype(railtype)) return CMD_ERROR;
00835
00836 Slope tileh = GetTileSlope(tile, NULL);
00837
00838 DiagDirection dir = Extract<DiagDirection, 0, 2>(p2);
00839
00840
00841
00842
00843
00844
00845
00846
00847 if (tileh != SLOPE_FLAT && (
00848 !_settings_game.construction.build_on_slopes ||
00849 IsSteepSlope(tileh) ||
00850 !CanBuildDepotByTileh(dir, tileh)
00851 )) {
00852 return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
00853 }
00854
00855 CommandCost cost = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00856 if (cost.Failed()) return CMD_ERROR;
00857
00858 if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
00859
00860 if (!Depot::CanAllocateItem()) return CMD_ERROR;
00861
00862 if (flags & DC_EXEC) {
00863 Depot *d = new Depot(tile);
00864 d->town_index = ClosestTownFromTile(tile, UINT_MAX)->index;
00865
00866 MakeRailDepot(tile, _current_company, d->index, dir, railtype);
00867 MarkTileDirtyByTile(tile);
00868
00869 AddSideToSignalBuffer(tile, INVALID_DIAGDIR, _current_company);
00870 YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
00871 }
00872
00873 cost.AddCost(_price[PR_BUILD_DEPOT_TRAIN]);
00874 cost.AddCost(RailBuildCost(railtype));
00875 return cost;
00876 }
00877
00898 CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00899 {
00900 Track track = Extract<Track, 0, 3>(p1);
00901 bool ctrl_pressed = HasBit(p1, 3);
00902 SignalVariant sigvar = (ctrl_pressed ^ HasBit(p1, 4)) ? SIG_SEMAPHORE : SIG_ELECTRIC;
00903 SignalType sigtype = Extract<SignalType, 5, 3>(p1);
00904 bool convert_signal = HasBit(p1, 8);
00905 SignalType cycle_start = Extract<SignalType, 9, 3>(p1);
00906 SignalType cycle_stop = Extract<SignalType, 12, 3>(p1);
00907 uint num_dir_cycle = GB(p1, 15, 2);
00908
00909 if (sigtype > SIGTYPE_LAST) return CMD_ERROR;
00910 if (cycle_start > cycle_stop || cycle_stop > SIGTYPE_LAST) return CMD_ERROR;
00911
00912
00913 if (!ValParamTrackOrientation(track) || !IsPlainRailTile(tile) ||
00914 !HasTrack(tile, track) || !EnsureNoTrainOnTrack(tile, track)) {
00915 return CMD_ERROR;
00916 }
00917
00918
00919 if (p2 != 0 && (p2 & SignalOnTrack(track)) == 0) return CMD_ERROR;
00920
00921 if (!CheckTileOwnership(tile)) return CMD_ERROR;
00922
00923 {
00924
00925 TrackBits trackbits = GetTrackBits(tile);
00926 if (KillFirstBit(trackbits) != TRACK_BIT_NONE &&
00927 trackbits != TRACK_BIT_HORZ &&
00928 trackbits != TRACK_BIT_VERT) {
00929 return_cmd_error(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK);
00930 }
00931 }
00932
00933
00934 if (HasBit(p1, 17) && HasSignalOnTrack(tile, track)) return CommandCost();
00935
00936
00937 if (convert_signal && !HasSignalOnTrack(tile, track)) return CMD_ERROR;
00938
00939 CommandCost cost;
00940 if (!HasSignalOnTrack(tile, track)) {
00941
00942 cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS]);
00943 } else {
00944 if (p2 != 0 && sigvar != GetSignalVariant(tile, track)) {
00945
00946 cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] + _price[PR_CLEAR_SIGNALS]);
00947
00948 } else if (convert_signal) {
00949
00950 if (ctrl_pressed || GetSignalVariant(tile, track) != sigvar) {
00951
00952 cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] + _price[PR_CLEAR_SIGNALS]);
00953 } else {
00954
00955 cost = CommandCost();
00956 }
00957
00958 } else {
00959
00960 cost = CommandCost();
00961 }
00962 }
00963
00964 if (flags & DC_EXEC) {
00965 Train *v = NULL;
00966
00967
00968
00969 if (HasReservedTracks(tile, TrackToTrackBits(track))) {
00970 v = GetTrainForReservation(tile, track);
00971 if (v != NULL) FreeTrainTrackReservation(v);
00972 }
00973
00974 if (!HasSignals(tile)) {
00975
00976 SetHasSignals(tile, true);
00977 SetSignalStates(tile, 0xF);
00978 SetPresentSignals(tile, 0);
00979 SetSignalType(tile, track, sigtype);
00980 SetSignalVariant(tile, track, sigvar);
00981 }
00982
00983 if (p2 == 0) {
00984 if (!HasSignalOnTrack(tile, track)) {
00985
00986 SetPresentSignals(tile, GetPresentSignals(tile) | (IsPbsSignal(sigtype) ? KillFirstBit(SignalOnTrack(track)) : SignalOnTrack(track)));
00987 SetSignalType(tile, track, sigtype);
00988 SetSignalVariant(tile, track, sigvar);
00989 while (num_dir_cycle-- > 0) CycleSignalSide(tile, track);
00990 } else {
00991 if (convert_signal) {
00992
00993 if (ctrl_pressed) {
00994
00995 SetSignalVariant(tile, track, (GetSignalVariant(tile, track) == SIG_ELECTRIC) ? SIG_SEMAPHORE : SIG_ELECTRIC);
00996
00997 sigtype = GetSignalType(tile, track);
00998 } else {
00999
01000 SetSignalType(tile, track, sigtype);
01001 SetSignalVariant(tile, track, sigvar);
01002 if (IsPbsSignal(sigtype) && (GetPresentSignals(tile) & SignalOnTrack(track)) == SignalOnTrack(track)) {
01003 SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | KillFirstBit(SignalOnTrack(track)));
01004 }
01005 }
01006
01007 } else if (ctrl_pressed) {
01008
01009 sigtype = (SignalType)(GetSignalType(tile, track) + 1);
01010
01011 if (sigtype < cycle_start || sigtype > cycle_stop) sigtype = cycle_start;
01012
01013 SetSignalType(tile, track, sigtype);
01014 if (IsPbsSignal(sigtype) && (GetPresentSignals(tile) & SignalOnTrack(track)) == SignalOnTrack(track)) {
01015 SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | KillFirstBit(SignalOnTrack(track)));
01016 }
01017 } else {
01018
01019 CycleSignalSide(tile, track);
01020
01021 sigtype = GetSignalType(tile, track);
01022 }
01023 }
01024 } else {
01025
01026
01027 SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | (p2 & SignalOnTrack(track)));
01028 SetSignalVariant(tile, track, sigvar);
01029 SetSignalType(tile, track, sigtype);
01030 }
01031
01032 if (IsPbsSignal(sigtype)) {
01033
01034 uint mask = GetPresentSignals(tile) & SignalOnTrack(track);
01035 SetSignalStates(tile, (GetSignalStates(tile) & ~mask) | ((HasBit(GetRailReservationTrackBits(tile), track) ? UINT_MAX : 0) & mask));
01036 }
01037 MarkTileDirtyByTile(tile);
01038 AddTrackToSignalBuffer(tile, track, _current_company);
01039 YapfNotifyTrackLayoutChange(tile, track);
01040 if (v != NULL) {
01041
01042 if (!(((v->vehstatus & VS_STOPPED) && v->cur_speed == 0) || v->current_order.IsType(OT_LOADING)) ||
01043 !IsSafeWaitingPosition(v, v->tile, v->GetVehicleTrackdir(), true, _settings_game.pf.forbid_90_deg)) {
01044 TryPathReserve(v, true);
01045 }
01046 }
01047 }
01048
01049 return cost;
01050 }
01051
01052 static bool CheckSignalAutoFill(TileIndex &tile, Trackdir &trackdir, int &signal_ctr, bool remove)
01053 {
01054 tile = AddTileIndexDiffCWrap(tile, _trackdelta[trackdir]);
01055 if (tile == INVALID_TILE) return false;
01056
01057
01058 TrackdirBits trackdirbits = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0));
01059
01060 if (TracksOverlap(TrackdirBitsToTrackBits(trackdirbits))) return false;
01061 trackdirbits &= TrackdirReachesTrackdirs(trackdir);
01062
01063
01064 if (trackdirbits == TRACKDIR_BIT_NONE) return false;
01065
01066
01067 trackdir = RemoveFirstTrackdir(&trackdirbits);
01068
01069
01070 if (trackdirbits != TRACKDIR_BIT_NONE) return false;
01071
01072 switch (GetTileType(tile)) {
01073 case MP_RAILWAY:
01074 if (IsRailDepot(tile)) return false;
01075 if (!remove && HasSignalOnTrack(tile, TrackdirToTrack(trackdir))) return false;
01076 signal_ctr++;
01077 if (IsDiagonalTrackdir(trackdir)) {
01078 signal_ctr++;
01079
01080 ClrBit(signal_ctr, 0);
01081 }
01082 return true;
01083
01084 case MP_ROAD:
01085 if (!IsLevelCrossing(tile)) return false;
01086 signal_ctr += 2;
01087 return true;
01088
01089 case MP_TUNNELBRIDGE: {
01090 TileIndex orig_tile = tile;
01091
01092 if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) return false;
01093 if (GetTunnelBridgeDirection(tile) != TrackdirToExitdir(trackdir)) return false;
01094
01095
01096
01097 tile = GetOtherTunnelBridgeEnd(tile);
01098
01099 signal_ctr += (GetTunnelBridgeLength(orig_tile, tile) + 2) * 2;
01100 return true;
01101 }
01102
01103 default: return false;
01104 }
01105 }
01106
01122 static CommandCost CmdSignalTrackHelper(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01123 {
01124 CommandCost ret, total_cost(EXPENSES_CONSTRUCTION);
01125 bool err = true;
01126 TileIndex start_tile = tile;
01127
01128 Track track = Extract<Track, 0, 3>(p2);
01129 bool mode = HasBit(p2, 3);
01130 bool semaphores = HasBit(p2, 4);
01131 bool remove = HasBit(p2, 5);
01132 bool autofill = HasBit(p2, 6);
01133 byte signal_density = GB(p2, 24, 8);
01134
01135 if (p1 >= MapSize() || !ValParamTrackOrientation(track)) return CMD_ERROR;
01136 TileIndex end_tile = p1;
01137 if (signal_density == 0 || signal_density > 20) return CMD_ERROR;
01138
01139 if (!IsPlainRailTile(tile)) return CMD_ERROR;
01140
01141
01142
01143 signal_density *= 2;
01144
01145 Trackdir trackdir = TrackToTrackdir(track);
01146 if (ValidateAutoDrag(&trackdir, tile, end_tile).Failed()) return CMD_ERROR;
01147
01148 track = TrackdirToTrack(trackdir);
01149 Trackdir start_trackdir = trackdir;
01150
01151
01152 if (!HasTrack(tile, track)) return CMD_ERROR;
01153
01154 SignalType sigtype = (SignalType)GB(p2, 7, 3);
01155 if (sigtype > SIGTYPE_LAST) return CMD_ERROR;
01156
01157 byte signals;
01158
01159 if (HasSignalOnTrack(tile, track)) {
01160 signals = GetPresentSignals(tile) & SignalOnTrack(track);
01161 assert(signals != 0);
01162
01163
01164 semaphores = GetSignalVariant(tile, track) != SIG_ELECTRIC;
01165
01166 sigtype = GetSignalType(tile, track);
01167
01168 if (sigtype < SIGTYPE_PBS) sigtype = SIGTYPE_NORMAL;
01169 } else {
01170 signals = IsPbsSignal(sigtype) ? SignalAlongTrackdir(trackdir) : SignalOnTrack(track);
01171 }
01172
01173 byte signal_dir = 0;
01174 if (signals & SignalAlongTrackdir(trackdir)) SetBit(signal_dir, 0);
01175 if (signals & SignalAgainstTrackdir(trackdir)) SetBit(signal_dir, 1);
01176
01177
01178
01179
01180
01181
01182
01183
01184
01185 int signal_ctr = 0;
01186 for (;;) {
01187
01188 if ((remove && autofill) || signal_ctr % signal_density == 0) {
01189 uint32 p1 = GB(TrackdirToTrack(trackdir), 0, 3);
01190 SB(p1, 3, 1, mode);
01191 SB(p1, 4, 1, semaphores);
01192 SB(p1, 5, 3, sigtype);
01193 if (!remove && signal_ctr == 0) SetBit(p1, 17);
01194
01195
01196 signals = 0;
01197 if (HasBit(signal_dir, 0)) signals |= SignalAlongTrackdir(trackdir);
01198 if (HasBit(signal_dir, 1)) signals |= SignalAgainstTrackdir(trackdir);
01199
01200 ret = DoCommand(tile, p1, signals, flags, remove ? CMD_REMOVE_SIGNALS : CMD_BUILD_SIGNALS);
01201
01202
01203 if (ret.Succeeded()) {
01204 err = false;
01205 total_cost.AddCost(ret);
01206 }
01207 }
01208
01209 if (autofill) {
01210 if (!CheckSignalAutoFill(tile, trackdir, signal_ctr, remove)) break;
01211
01212
01213 if (tile == start_tile && trackdir == start_trackdir) break;
01214 } else {
01215 if (tile == end_tile) break;
01216
01217 tile += ToTileIndexDiff(_trackdelta[trackdir]);
01218 signal_ctr++;
01219
01220
01221 if (IsDiagonalTrackdir(trackdir)) {
01222 signal_ctr++;
01223 } else {
01224 ToggleBit(trackdir, 0);
01225 }
01226 }
01227 }
01228
01229 return err ? CMD_ERROR : total_cost;
01230 }
01231
01249 CommandCost CmdBuildSignalTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01250 {
01251 return CmdSignalTrackHelper(tile, flags, p1, p2, text);
01252 }
01253
01265 CommandCost CmdRemoveSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01266 {
01267 Track track = Extract<Track, 0, 3>(p1);
01268
01269 if (!ValParamTrackOrientation(track) ||
01270 !IsPlainRailTile(tile) ||
01271 !HasTrack(tile, track) ||
01272 !EnsureNoTrainOnTrack(tile, track) ||
01273 !HasSignalOnTrack(tile, track)) {
01274 return CMD_ERROR;
01275 }
01276
01277
01278 if (_current_company != OWNER_WATER && !CheckTileOwnership(tile)) return CMD_ERROR;
01279
01280
01281 if (flags & DC_EXEC) {
01282 Train *v = NULL;
01283 if (HasReservedTracks(tile, TrackToTrackBits(track))) {
01284 v = GetTrainForReservation(tile, track);
01285 } else if (IsPbsSignal(GetSignalType(tile, track))) {
01286
01287 Trackdir td = TrackToTrackdir(track);
01288 for (int i = 0; v == NULL && i < 2; i++, td = ReverseTrackdir(td)) {
01289
01290 if (!HasSignalOnTrackdir(tile, ReverseTrackdir(td))) continue;
01291 TileIndex next = TileAddByDiagDir(tile, TrackdirToExitdir(td));
01292 TrackBits tracks = TrackdirBitsToTrackBits(TrackdirReachesTrackdirs(td));
01293 if (HasReservedTracks(next, tracks)) {
01294 v = GetTrainForReservation(next, TrackBitsToTrack(GetReservedTrackbits(next) & tracks));
01295 }
01296 }
01297 }
01298 SetPresentSignals(tile, GetPresentSignals(tile) & ~SignalOnTrack(track));
01299
01300
01301 if (GetPresentSignals(tile) == 0) {
01302 SetSignalStates(tile, 0);
01303 SetHasSignals(tile, false);
01304 SetSignalVariant(tile, INVALID_TRACK, SIG_ELECTRIC);
01305 }
01306
01307 AddTrackToSignalBuffer(tile, track, GetTileOwner(tile));
01308 YapfNotifyTrackLayoutChange(tile, track);
01309 if (v != NULL) TryPathReserve(v, false);
01310
01311 MarkTileDirtyByTile(tile);
01312 }
01313
01314 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_SIGNALS]);
01315 }
01316
01334 CommandCost CmdRemoveSignalTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01335 {
01336 return CmdSignalTrackHelper(tile, flags, p1, SetBit(p2, 5), text);
01337 }
01338
01340 static Vehicle *UpdateTrainPowerProc(Vehicle *v, void *data)
01341 {
01342 if (v->type != VEH_TRAIN) return NULL;
01343
01344
01345
01346 Train *t = Train::From(v);
01347 if (t->IsArticulatedPart()) return NULL;
01348
01349 const RailVehicleInfo *rvi = RailVehInfo(t->engine_type);
01350 if (GetVehicleProperty(t, PROP_TRAIN_POWER, rvi->power) != 0) t->First()->PowerChanged();
01351
01352 return NULL;
01353 }
01354
01364 CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01365 {
01366 CommandCost cost(EXPENSES_CONSTRUCTION);
01367 RailType totype = Extract<RailType, 0, 4>(p2);
01368
01369 if (!ValParamRailtype(totype)) return CMD_ERROR;
01370 if (p1 >= MapSize()) return CMD_ERROR;
01371
01372 uint ex = TileX(tile);
01373 uint ey = TileY(tile);
01374 uint sx = TileX(p1);
01375 uint sy = TileY(p1);
01376
01377
01378 if (ex < sx) Swap(ex, sx);
01379 if (ey < sy) Swap(ey, sy);
01380
01381 _error_message = STR_ERROR_NO_SUITABLE_RAILROAD_TRACK;
01382
01383 for (uint x = sx; x <= ex; ++x) {
01384 for (uint y = sy; y <= ey; ++y) {
01385 TileIndex tile = TileXY(x, y);
01386 TileType tt = GetTileType(tile);
01387
01388
01389 switch (tt) {
01390 case MP_RAILWAY:
01391 break;
01392 case MP_STATION:
01393 if (!HasStationRail(tile)) continue;
01394 break;
01395 case MP_ROAD:
01396 if (!IsLevelCrossing(tile)) continue;
01397 break;
01398 case MP_TUNNELBRIDGE:
01399 if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) continue;
01400 break;
01401 default: continue;
01402 }
01403
01404
01405 RailType type = GetRailType(tile);
01406
01407
01408 if (type == totype || (_settings_game.vehicle.disable_elrails && totype == RAILTYPE_RAIL && type == RAILTYPE_ELECTRIC)) continue;
01409
01410
01411 if (!CheckTileOwnership(tile)) continue;
01412
01413 SmallVector<Train *, 2> vehicles_affected;
01414
01415
01416
01417 if (tt != MP_TUNNELBRIDGE) {
01418 if (!IsCompatibleRail(type, totype) && !EnsureNoVehicleOnGround(tile)) continue;
01419 if (flags & DC_EXEC) {
01420 TrackBits reserved = GetReservedTrackbits(tile);
01421 Track track;
01422 while ((track = RemoveFirstTrack(&reserved)) != INVALID_TRACK) {
01423 Train *v = GetTrainForReservation(tile, track);
01424 if (v != NULL && !HasPowerOnRail(v->railtype, totype)) {
01425
01426 FreeTrainTrackReservation(v);
01427 *vehicles_affected.Append() = v;
01428 }
01429 }
01430
01431 SetRailType(tile, totype);
01432 MarkTileDirtyByTile(tile);
01433
01434 FindVehicleOnPos(tile, NULL, &UpdateTrainPowerProc);
01435 }
01436 }
01437
01438 switch (tt) {
01439 case MP_RAILWAY:
01440 switch (GetRailTileType(tile)) {
01441 case RAIL_TILE_DEPOT:
01442 if (flags & DC_EXEC) {
01443
01444 YapfNotifyTrackLayoutChange(tile, GetRailDepotTrack(tile));
01445
01446
01447 InvalidateWindowData(WC_VEHICLE_DEPOT, tile);
01448 InvalidateWindowData(WC_BUILD_VEHICLE, tile);
01449 }
01450 cost.AddCost(RailConvertCost(type, totype));
01451 break;
01452
01453 default:
01454 if (flags & DC_EXEC) {
01455
01456 TrackBits tracks = GetTrackBits(tile);
01457 while (tracks != TRACK_BIT_NONE) {
01458 YapfNotifyTrackLayoutChange(tile, RemoveFirstTrack(&tracks));
01459 }
01460 }
01461 cost.AddCost(RailConvertCost(type, totype) * CountBits(GetTrackBits(tile)));
01462 break;
01463 }
01464 break;
01465
01466 case MP_TUNNELBRIDGE: {
01467 TileIndex endtile = GetOtherTunnelBridgeEnd(tile);
01468
01469
01470
01471 if (endtile < tile && TileX(endtile) >= sx && TileX(endtile) <= ex &&
01472 TileY(endtile) >= sy && TileY(endtile) <= ey) continue;
01473
01474
01475 if (!IsCompatibleRail(GetRailType(tile), totype) &&
01476 HasVehicleOnTunnelBridge(tile, endtile)) continue;
01477
01478 if (flags & DC_EXEC) {
01479 Track track = DiagDirToDiagTrack(GetTunnelBridgeDirection(tile));
01480 if (HasTunnelBridgeReservation(tile)) {
01481 Train *v = GetTrainForReservation(tile, track);
01482 if (v != NULL && !HasPowerOnRail(v->railtype, totype)) {
01483
01484 FreeTrainTrackReservation(v);
01485 *vehicles_affected.Append() = v;
01486 }
01487 }
01488 SetRailType(tile, totype);
01489 SetRailType(endtile, totype);
01490
01491 FindVehicleOnPos(tile, NULL, &UpdateTrainPowerProc);
01492 FindVehicleOnPos(endtile, NULL, &UpdateTrainPowerProc);
01493
01494 YapfNotifyTrackLayoutChange(tile, track);
01495 YapfNotifyTrackLayoutChange(endtile, track);
01496
01497 MarkTileDirtyByTile(tile);
01498 MarkTileDirtyByTile(endtile);
01499
01500 if (IsBridge(tile)) {
01501 TileIndexDiff delta = TileOffsByDiagDir(GetTunnelBridgeDirection(tile));
01502 TileIndex t = tile + delta;
01503 for (; t != endtile; t += delta) MarkTileDirtyByTile(t);
01504 }
01505 }
01506
01507 cost.AddCost((GetTunnelBridgeLength(tile, endtile) + 2) * RailConvertCost(type, totype));
01508 } break;
01509
01510 default:
01511 if (flags & DC_EXEC) {
01512 Track track = ((tt == MP_STATION) ? GetRailStationTrack(tile) : GetCrossingRailTrack(tile));
01513 YapfNotifyTrackLayoutChange(tile, track);
01514 }
01515
01516 cost.AddCost(RailConvertCost(type, totype));
01517 break;
01518 }
01519
01520 for (uint i = 0; i < vehicles_affected.Length(); ++i) {
01521 TryPathReserve(vehicles_affected[i], true);
01522 }
01523 }
01524 }
01525
01526 return (cost.GetCost() == 0) ? CMD_ERROR : cost;
01527 }
01528
01529 static CommandCost RemoveTrainDepot(TileIndex tile, DoCommandFlag flags)
01530 {
01531 if (!CheckTileOwnership(tile) && _current_company != OWNER_WATER)
01532 return CMD_ERROR;
01533
01534 if (!EnsureNoVehicleOnGround(tile))
01535 return CMD_ERROR;
01536
01537 if (flags & DC_EXEC) {
01538
01539 DiagDirection dir = GetRailDepotDirection(tile);
01540 Owner owner = GetTileOwner(tile);
01541 Train *v = NULL;
01542
01543 if (HasDepotReservation(tile)) {
01544 v = GetTrainForReservation(tile, DiagDirToDiagTrack(dir));
01545 if (v != NULL) FreeTrainTrackReservation(v);
01546 }
01547
01548 delete Depot::GetByTile(tile);
01549 DoClearSquare(tile);
01550 AddSideToSignalBuffer(tile, dir, owner);
01551 YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
01552 if (v != NULL) TryPathReserve(v, true);
01553 }
01554
01555 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_TRAIN]);
01556 }
01557
01558 static CommandCost ClearTile_Track(TileIndex tile, DoCommandFlag flags)
01559 {
01560 CommandCost cost(EXPENSES_CONSTRUCTION);
01561
01562 if (flags & DC_AUTO) {
01563 if (!IsTileOwner(tile, _current_company)) {
01564 return_cmd_error(STR_ERROR_AREA_IS_OWNED_BY_ANOTHER);
01565 }
01566
01567 if (IsPlainRail(tile)) {
01568 return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
01569 } else {
01570 return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
01571 }
01572 }
01573
01574 switch (GetRailTileType(tile)) {
01575 case RAIL_TILE_SIGNALS:
01576 case RAIL_TILE_NORMAL: {
01577 Slope tileh = GetTileSlope(tile, NULL);
01578
01579 bool water_ground = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh));
01580
01581 TrackBits tracks = GetTrackBits(tile);
01582 while (tracks != TRACK_BIT_NONE) {
01583 Track track = RemoveFirstTrack(&tracks);
01584 CommandCost ret = DoCommand(tile, 0, track, flags, CMD_REMOVE_SINGLE_RAIL);
01585 if (ret.Failed()) return CMD_ERROR;
01586 cost.AddCost(ret);
01587 }
01588
01589
01590 if (water_ground && !(flags & DC_BANKRUPT)) {
01591 if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
01592
01593
01594 if (flags & DC_EXEC) DoClearSquare(tile);
01595 cost.AddCost(_price[PR_CLEAR_WATER]);
01596 }
01597
01598 return cost;
01599 }
01600
01601 case RAIL_TILE_DEPOT:
01602 return RemoveTrainDepot(tile, flags);
01603
01604 default:
01605 return CMD_ERROR;
01606 }
01607 }
01608
01613 static uint GetSaveSlopeZ(uint x, uint y, Track track)
01614 {
01615 switch (track) {
01616 case TRACK_UPPER: x &= ~0xF; y &= ~0xF; break;
01617 case TRACK_LOWER: x |= 0xF; y |= 0xF; break;
01618 case TRACK_LEFT: x |= 0xF; y &= ~0xF; break;
01619 case TRACK_RIGHT: x &= ~0xF; y |= 0xF; break;
01620 default: break;
01621 }
01622 return GetSlopeZ(x, y);
01623 }
01624
01625 static void DrawSingleSignal(TileIndex tile, Track track, byte condition, uint image, uint pos)
01626 {
01627 bool side = (_settings_game.vehicle.road_side != 0) && _settings_game.construction.signal_side;
01628 static const Point SignalPositions[2][12] = {
01629 {
01630
01631 { 8, 5}, {14, 1}, { 1, 14}, { 9, 11}, { 1, 0}, { 3, 10},
01632
01633 {11, 4}, {14, 14}, {11, 3}, { 4, 13}, { 3, 4}, {11, 13}
01634 }, {
01635
01636 {14, 1}, {12, 10}, { 4, 6}, { 1, 14}, {10, 4}, { 0, 1},
01637
01638 {14, 14}, { 5, 12}, {11, 13}, { 4, 3}, {13, 4}, { 3, 11}
01639 }
01640 };
01641
01642 uint x = TileX(tile) * TILE_SIZE + SignalPositions[side][pos].x;
01643 uint y = TileY(tile) * TILE_SIZE + SignalPositions[side][pos].y;
01644
01645 SpriteID sprite;
01646
01647 SignalType type = GetSignalType(tile, track);
01648 SignalVariant variant = GetSignalVariant(tile, track);
01649
01650 if (type == SIGTYPE_NORMAL && variant == SIG_ELECTRIC) {
01651
01652 sprite = SPR_ORIGINAL_SIGNALS_BASE + image + condition;
01653 } else {
01654
01655 sprite = SPR_SIGNALS_BASE + (type - 1) * 16 + variant * 64 + image + condition + (type > SIGTYPE_LAST_NOPBS ? 64 : 0);
01656 }
01657
01658 AddSortableSpriteToDraw(sprite, PAL_NONE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, GetSaveSlopeZ(x, y, track));
01659 }
01660
01661 static uint32 _drawtile_track_palette;
01662
01663
01664 static void DrawTrackFence_NW(const TileInfo *ti, SpriteID base_image)
01665 {
01666 RailFenceOffset rfo = RFO_FLAT_X;
01667 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SW : RFO_SLOPE_NE;
01668 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01669 ti->x, ti->y + 1, 16, 1, 4, ti->z);
01670 }
01671
01672 static void DrawTrackFence_SE(const TileInfo *ti, SpriteID base_image)
01673 {
01674 RailFenceOffset rfo = RFO_FLAT_X;
01675 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SW : RFO_SLOPE_NE;
01676 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01677 ti->x, ti->y + TILE_SIZE - 1, 16, 1, 4, ti->z);
01678 }
01679
01680 static void DrawTrackFence_NW_SE(const TileInfo *ti, SpriteID base_image)
01681 {
01682 DrawTrackFence_NW(ti, base_image);
01683 DrawTrackFence_SE(ti, base_image);
01684 }
01685
01686 static void DrawTrackFence_NE(const TileInfo *ti, SpriteID base_image)
01687 {
01688 RailFenceOffset rfo = RFO_FLAT_Y;
01689 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SE : RFO_SLOPE_NW;
01690 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01691 ti->x + 1, ti->y, 1, 16, 4, ti->z);
01692 }
01693
01694 static void DrawTrackFence_SW(const TileInfo *ti, SpriteID base_image)
01695 {
01696 RailFenceOffset rfo = RFO_FLAT_Y;
01697 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SE : RFO_SLOPE_NW;
01698 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01699 ti->x + TILE_SIZE - 1, ti->y, 1, 16, 4, ti->z);
01700 }
01701
01702 static void DrawTrackFence_NE_SW(const TileInfo *ti, SpriteID base_image)
01703 {
01704 DrawTrackFence_NE(ti, base_image);
01705 DrawTrackFence_SW(ti, base_image);
01706 }
01707
01711 static void DrawTrackFence_NS_1(const TileInfo *ti, SpriteID base_image)
01712 {
01713 uint z = ti->z + GetSlopeZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_W);
01714 AddSortableSpriteToDraw(base_image + RFO_FLAT_VERT, _drawtile_track_palette,
01715 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01716 }
01717
01721 static void DrawTrackFence_NS_2(const TileInfo *ti, SpriteID base_image)
01722 {
01723 uint z = ti->z + GetSlopeZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_E);
01724 AddSortableSpriteToDraw(base_image + RFO_FLAT_VERT, _drawtile_track_palette,
01725 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01726 }
01727
01731 static void DrawTrackFence_WE_1(const TileInfo *ti, SpriteID base_image)
01732 {
01733 uint z = ti->z + GetSlopeZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_N);
01734 AddSortableSpriteToDraw(base_image + RFO_FLAT_HORZ, _drawtile_track_palette,
01735 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01736 }
01737
01741 static void DrawTrackFence_WE_2(const TileInfo *ti, SpriteID base_image)
01742 {
01743 uint z = ti->z + GetSlopeZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_S);
01744 AddSortableSpriteToDraw(base_image + RFO_FLAT_HORZ, _drawtile_track_palette,
01745 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01746 }
01747
01748
01749 static void DrawTrackDetails(const TileInfo *ti, const RailtypeInfo *rti)
01750 {
01751
01752 SpriteID base_image = GetCustomRailSprite(rti, ti->tile, RTSG_FENCES);
01753 if (base_image == 0) base_image = SPR_TRACK_FENCE_FLAT_X;
01754
01755 switch (GetRailGroundType(ti->tile)) {
01756 case RAIL_GROUND_FENCE_NW: DrawTrackFence_NW(ti, base_image); break;
01757 case RAIL_GROUND_FENCE_SE: DrawTrackFence_SE(ti, base_image); break;
01758 case RAIL_GROUND_FENCE_SENW: DrawTrackFence_NW_SE(ti, base_image); break;
01759 case RAIL_GROUND_FENCE_NE: DrawTrackFence_NE(ti, base_image); break;
01760 case RAIL_GROUND_FENCE_SW: DrawTrackFence_SW(ti, base_image); break;
01761 case RAIL_GROUND_FENCE_NESW: DrawTrackFence_NE_SW(ti, base_image); break;
01762 case RAIL_GROUND_FENCE_VERT1: DrawTrackFence_NS_1(ti, base_image); break;
01763 case RAIL_GROUND_FENCE_VERT2: DrawTrackFence_NS_2(ti, base_image); break;
01764 case RAIL_GROUND_FENCE_HORIZ1: DrawTrackFence_WE_1(ti, base_image); break;
01765 case RAIL_GROUND_FENCE_HORIZ2: DrawTrackFence_WE_2(ti, base_image); break;
01766 case RAIL_GROUND_WATER: {
01767 Corner track_corner;
01768 if (IsHalftileSlope(ti->tileh)) {
01769
01770 track_corner = GetHalftileSlopeCorner(ti->tileh);
01771 } else {
01772
01773 track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh)));
01774 }
01775 switch (track_corner) {
01776 case CORNER_W: DrawTrackFence_NS_1(ti, base_image); break;
01777 case CORNER_S: DrawTrackFence_WE_2(ti, base_image); break;
01778 case CORNER_E: DrawTrackFence_NS_2(ti, base_image); break;
01779 case CORNER_N: DrawTrackFence_WE_1(ti, base_image); break;
01780 default: NOT_REACHED();
01781 }
01782 break;
01783 }
01784 default: break;
01785 }
01786 }
01787
01788
01789 static const int INF = 1000;
01790 static const SubSprite _halftile_sub_sprite[4] = {
01791 { -INF , -INF , 32 - 33, INF },
01792 { -INF , 0 + 7, INF , INF },
01793 { -31 + 33, -INF , INF , INF },
01794 { -INF , -INF , INF , 30 - 23 }
01795 };
01796
01797 static inline void DrawTrackSprite(SpriteID sprite, PaletteID pal, const TileInfo *ti, Slope s)
01798 {
01799 DrawGroundSprite(sprite, pal, NULL, 0, (ti->tileh & s) ? -8 : 0);
01800 }
01801
01802 static void DrawTrackBitsOverlay(TileInfo *ti, TrackBits track, const RailtypeInfo *rti)
01803 {
01804 RailGroundType rgt = GetRailGroundType(ti->tile);
01805 Foundation f = GetRailFoundation(ti->tileh, track);
01806 Corner halftile_corner = CORNER_INVALID;
01807
01808 if (IsNonContinuousFoundation(f)) {
01809
01810 halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f));
01811
01812 track &= ~CornerToTrackBits(halftile_corner);
01813 f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE);
01814 }
01815
01816 DrawFoundation(ti, f);
01817
01818
01819
01820 if (track == TRACK_BIT_NONE && rgt == RAIL_GROUND_WATER) {
01821 if (IsSteepSlope(ti->tileh)) {
01822 DrawShoreTile(ti->tileh);
01823 } else {
01824 DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
01825 }
01826 } else {
01827 SpriteID image;
01828
01829 switch (rgt) {
01830 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
01831 case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOW_DESERT_TILE; break;
01832 default: image = SPR_FLAT_GRASS_TILE; break;
01833 }
01834
01835 image += _tileh_to_sprite[ti->tileh];
01836
01837 DrawGroundSprite(image, PAL_NONE);
01838 }
01839
01840 SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
01841 SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
01842 TrackBits pbs = _settings_client.gui.show_track_reservation ? GetRailReservationTrackBits(ti->tile) : TRACK_BIT_NONE;
01843
01844 if (track == TRACK_BIT_NONE) {
01845
01846 } else if (ti->tileh == SLOPE_NW && track == TRACK_BIT_Y) {
01847 DrawGroundSprite(ground + RTO_SLOPE_NW, PAL_NONE);
01848 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 9, PALETTE_CRASH);
01849 } else if (ti->tileh == SLOPE_NE && track == TRACK_BIT_X) {
01850 DrawGroundSprite(ground + RTO_SLOPE_NE, PAL_NONE);
01851 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 6, PALETTE_CRASH);
01852 } else if (ti->tileh == SLOPE_SE && track == TRACK_BIT_Y) {
01853 DrawGroundSprite(ground + RTO_SLOPE_SE, PAL_NONE);
01854 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 7, PALETTE_CRASH);
01855 } else if (ti->tileh == SLOPE_SW && track == TRACK_BIT_X) {
01856 DrawGroundSprite(ground + RTO_SLOPE_SW, PAL_NONE);
01857 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 8, PALETTE_CRASH);
01858 } else {
01859 switch (track) {
01860
01861
01862 case TRACK_BIT_X: DrawGroundSprite(ground + RTO_X, PAL_NONE); break;
01863 case TRACK_BIT_Y: DrawGroundSprite(ground + RTO_Y, PAL_NONE); break;
01864 case TRACK_BIT_UPPER: DrawTrackSprite(ground + RTO_N, PAL_NONE, ti, SLOPE_N); break;
01865 case TRACK_BIT_LOWER: DrawTrackSprite(ground + RTO_S, PAL_NONE, ti, SLOPE_S); break;
01866 case TRACK_BIT_RIGHT: DrawTrackSprite(ground + RTO_E, PAL_NONE, ti, SLOPE_E); break;
01867 case TRACK_BIT_LEFT: DrawTrackSprite(ground + RTO_W, PAL_NONE, ti, SLOPE_W); break;
01868 case TRACK_BIT_CROSS: DrawGroundSprite(ground + RTO_CROSSING_XY, PAL_NONE); break;
01869 case TRACK_BIT_HORZ: DrawTrackSprite(ground + RTO_N, PAL_NONE, ti, SLOPE_N);
01870 DrawTrackSprite(ground + RTO_S, PAL_NONE, ti, SLOPE_S); break;
01871 case TRACK_BIT_VERT: DrawTrackSprite(ground + RTO_E, PAL_NONE, ti, SLOPE_E);
01872 DrawTrackSprite(ground + RTO_W, PAL_NONE, ti, SLOPE_W); break;
01873
01874 default:
01875
01876 if ((track & TRACK_BIT_3WAY_NE) == 0) {
01877 DrawGroundSprite(ground + RTO_JUNCTION_SW, PAL_NONE);
01878 } else if ((track & TRACK_BIT_3WAY_SW) == 0) {
01879 DrawGroundSprite(ground + RTO_JUNCTION_NE, PAL_NONE);
01880 } else if ((track & TRACK_BIT_3WAY_NW) == 0) {
01881 DrawGroundSprite(ground + RTO_JUNCTION_SE, PAL_NONE);
01882 } else if ((track & TRACK_BIT_3WAY_SE) == 0) {
01883 DrawGroundSprite(ground + RTO_JUNCTION_NW, PAL_NONE);
01884 } else {
01885 DrawGroundSprite(ground + RTO_JUNCTION_NSEW, PAL_NONE);
01886 }
01887
01888
01889 track &= ~pbs;
01890
01891
01892 if (track & TRACK_BIT_X) DrawGroundSprite(overlay + RTO_X, PAL_NONE);
01893 if (track & TRACK_BIT_Y) DrawGroundSprite(overlay + RTO_Y, PAL_NONE);
01894 if (track & TRACK_BIT_UPPER) DrawGroundSprite(overlay + RTO_N, PAL_NONE);
01895 if (track & TRACK_BIT_LOWER) DrawGroundSprite(overlay + RTO_S, PAL_NONE);
01896 if (track & TRACK_BIT_RIGHT) DrawGroundSprite(overlay + RTO_E, PAL_NONE);
01897 if (track & TRACK_BIT_LEFT) DrawGroundSprite(overlay + RTO_W, PAL_NONE);
01898 }
01899
01900
01901 if (pbs & TRACK_BIT_X) DrawGroundSprite(overlay + RTO_X, PALETTE_CRASH);
01902 if (pbs & TRACK_BIT_Y) DrawGroundSprite(overlay + RTO_Y, PALETTE_CRASH);
01903 if (pbs & TRACK_BIT_UPPER) DrawTrackSprite(overlay + RTO_N, PALETTE_CRASH, ti, SLOPE_N);
01904 if (pbs & TRACK_BIT_LOWER) DrawTrackSprite(overlay + RTO_S, PALETTE_CRASH, ti, SLOPE_S);
01905 if (pbs & TRACK_BIT_RIGHT) DrawTrackSprite(overlay + RTO_E, PALETTE_CRASH, ti, SLOPE_E);
01906 if (pbs & TRACK_BIT_LEFT) DrawTrackSprite(overlay + RTO_W, PALETTE_CRASH, ti, SLOPE_W);
01907 }
01908
01909 if (IsValidCorner(halftile_corner)) {
01910 DrawFoundation(ti, HalftileFoundation(halftile_corner));
01911
01912
01913 Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
01914
01915 SpriteID image;
01916 switch (rgt) {
01917 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
01918 case RAIL_GROUND_ICE_DESERT:
01919 case RAIL_GROUND_HALF_SNOW: image = SPR_FLAT_SNOW_DESERT_TILE; break;
01920 default: image = SPR_FLAT_GRASS_TILE; break;
01921 }
01922
01923 image += _tileh_to_sprite[fake_slope];
01924
01925 DrawGroundSprite(image, PAL_NONE, &(_halftile_sub_sprite[halftile_corner]));
01926
01927 track = CornerToTrackBits(halftile_corner);
01928
01929 int offset;
01930 switch (track) {
01931 default: NOT_REACHED();
01932 case TRACK_BIT_UPPER: offset = RTO_N; break;
01933 case TRACK_BIT_LOWER: offset = RTO_S; break;
01934 case TRACK_BIT_RIGHT: offset = RTO_E; break;
01935 case TRACK_BIT_LEFT: offset = RTO_W; break;
01936 }
01937
01938 DrawTrackSprite(ground + offset, PAL_NONE, ti, fake_slope);
01939 if (HasReservedTracks(ti->tile, track)) {
01940 DrawTrackSprite(overlay + offset, PALETTE_CRASH, ti, fake_slope);
01941 }
01942 }
01943 }
01944
01950 static void DrawTrackBits(TileInfo *ti, TrackBits track)
01951 {
01952 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
01953
01954 if (rti->UsesOverlay()) {
01955 DrawTrackBitsOverlay(ti, track, rti);
01956 return;
01957 }
01958
01959 RailGroundType rgt = GetRailGroundType(ti->tile);
01960 Foundation f = GetRailFoundation(ti->tileh, track);
01961 Corner halftile_corner = CORNER_INVALID;
01962
01963 if (IsNonContinuousFoundation(f)) {
01964
01965 halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f));
01966
01967 track &= ~CornerToTrackBits(halftile_corner);
01968 f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE);
01969 }
01970
01971 DrawFoundation(ti, f);
01972
01973
01974 SpriteID image;
01975 PaletteID pal = PAL_NONE;
01976 const SubSprite *sub = NULL;
01977 bool junction = false;
01978
01979
01980 if (track == 0) {
01981
01982 if (rgt == RAIL_GROUND_WATER) {
01983 if (IsSteepSlope(ti->tileh)) {
01984 DrawShoreTile(ti->tileh);
01985 image = 0;
01986 } else {
01987 image = SPR_FLAT_WATER_TILE;
01988 }
01989 } else {
01990 switch (rgt) {
01991 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
01992 case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOW_DESERT_TILE; break;
01993 default: image = SPR_FLAT_GRASS_TILE; break;
01994 }
01995 image += _tileh_to_sprite[ti->tileh];
01996 }
01997 } else {
01998 if (ti->tileh != SLOPE_FLAT) {
01999
02000 image = _track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.track_y;
02001 } else {
02002
02003 (image = rti->base_sprites.track_y, track == TRACK_BIT_Y) ||
02004 (image++, track == TRACK_BIT_X) ||
02005 (image++, track == TRACK_BIT_UPPER) ||
02006 (image++, track == TRACK_BIT_LOWER) ||
02007 (image++, track == TRACK_BIT_RIGHT) ||
02008 (image++, track == TRACK_BIT_LEFT) ||
02009 (image++, track == TRACK_BIT_CROSS) ||
02010
02011 (image = rti->base_sprites.track_ns, track == TRACK_BIT_HORZ) ||
02012 (image++, track == TRACK_BIT_VERT) ||
02013
02014 (junction = true, false) ||
02015 (image = rti->base_sprites.ground, (track & TRACK_BIT_3WAY_NE) == 0) ||
02016 (image++, (track & TRACK_BIT_3WAY_SW) == 0) ||
02017 (image++, (track & TRACK_BIT_3WAY_NW) == 0) ||
02018 (image++, (track & TRACK_BIT_3WAY_SE) == 0) ||
02019 (image++, true);
02020 }
02021
02022 switch (rgt) {
02023 case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
02024 case RAIL_GROUND_ICE_DESERT: image += rti->snow_offset; break;
02025 case RAIL_GROUND_WATER: {
02026
02027 DrawShoreTile(ti->tileh);
02028 Corner track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh)));
02029 sub = &(_halftile_sub_sprite[track_corner]);
02030 break;
02031 }
02032 default: break;
02033 }
02034 }
02035
02036 if (image != 0) DrawGroundSprite(image, pal, sub);
02037
02038
02039 if (junction) {
02040 if (track & TRACK_BIT_X) DrawGroundSprite(rti->base_sprites.single_x, PAL_NONE);
02041 if (track & TRACK_BIT_Y) DrawGroundSprite(rti->base_sprites.single_y, PAL_NONE);
02042 if (track & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PAL_NONE);
02043 if (track & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PAL_NONE);
02044 if (track & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PAL_NONE);
02045 if (track & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PAL_NONE);
02046 }
02047
02048
02049 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation) {
02050
02051 TrackBits pbs = GetRailReservationTrackBits(ti->tile) & track;
02052 if (pbs & TRACK_BIT_X) {
02053 if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
02054 DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH);
02055 } else {
02056 DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
02057 }
02058 }
02059 if (pbs & TRACK_BIT_Y) {
02060 if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
02061 DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH);
02062 } else {
02063 DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
02064 }
02065 }
02066 if (pbs & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_N ? -TILE_HEIGHT : 0);
02067 if (pbs & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_S ? -TILE_HEIGHT : 0);
02068 if (pbs & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_W ? -TILE_HEIGHT : 0);
02069 if (pbs & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_E ? -TILE_HEIGHT : 0);
02070 }
02071
02072 if (IsValidCorner(halftile_corner)) {
02073 DrawFoundation(ti, HalftileFoundation(halftile_corner));
02074
02075
02076 Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
02077 image = _track_sloped_sprites[fake_slope - 1] + rti->base_sprites.track_y;
02078 pal = PAL_NONE;
02079 switch (rgt) {
02080 case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
02081 case RAIL_GROUND_ICE_DESERT:
02082 case RAIL_GROUND_HALF_SNOW: image += rti->snow_offset; break;
02083 default: break;
02084 }
02085 DrawGroundSprite(image, pal, &(_halftile_sub_sprite[halftile_corner]));
02086
02087 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasReservedTracks(ti->tile, CornerToTrackBits(halftile_corner))) {
02088 static const byte _corner_to_track_sprite[] = {3, 1, 2, 0};
02089 DrawGroundSprite(_corner_to_track_sprite[halftile_corner] + rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, -TILE_HEIGHT);
02090 }
02091 }
02092 }
02093
02099 enum {
02100 SIGNAL_TO_SOUTHWEST = 0,
02101 SIGNAL_TO_NORTHEAST = 2,
02102 SIGNAL_TO_SOUTHEAST = 4,
02103 SIGNAL_TO_NORTHWEST = 6,
02104 SIGNAL_TO_EAST = 8,
02105 SIGNAL_TO_WEST = 10,
02106 SIGNAL_TO_SOUTH = 12,
02107 SIGNAL_TO_NORTH = 14,
02108 };
02109
02110 static void DrawSignals(TileIndex tile, TrackBits rails)
02111 {
02112 #define MAYBE_DRAW_SIGNAL(x, y, z, t) if (IsSignalPresent(tile, x)) DrawSingleSignal(tile, t, GetSingleSignalState(tile, x), y, z)
02113
02114 if (!(rails & TRACK_BIT_Y)) {
02115 if (!(rails & TRACK_BIT_X)) {
02116 if (rails & TRACK_BIT_LEFT) {
02117 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTH, 0, TRACK_LEFT);
02118 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTH, 1, TRACK_LEFT);
02119 }
02120 if (rails & TRACK_BIT_RIGHT) {
02121 MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_NORTH, 2, TRACK_RIGHT);
02122 MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_SOUTH, 3, TRACK_RIGHT);
02123 }
02124 if (rails & TRACK_BIT_UPPER) {
02125 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_WEST, 4, TRACK_UPPER);
02126 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_EAST, 5, TRACK_UPPER);
02127 }
02128 if (rails & TRACK_BIT_LOWER) {
02129 MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_WEST, 6, TRACK_LOWER);
02130 MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_EAST, 7, TRACK_LOWER);
02131 }
02132 } else {
02133 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHWEST, 8, TRACK_X);
02134 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHEAST, 9, TRACK_X);
02135 }
02136 } else {
02137 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHEAST, 10, TRACK_Y);
02138 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHWEST, 11, TRACK_Y);
02139 }
02140 }
02141
02142 static void DrawTile_Track(TileInfo *ti)
02143 {
02144 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
02145
02146 _drawtile_track_palette = COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile));
02147
02148 if (IsPlainRail(ti->tile)) {
02149 TrackBits rails = GetTrackBits(ti->tile);
02150
02151 DrawTrackBits(ti, rails);
02152
02153 if (HasBit(_display_opt, DO_FULL_DETAIL)) DrawTrackDetails(ti, rti);
02154
02155 if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
02156
02157 if (HasSignals(ti->tile)) DrawSignals(ti->tile, rails);
02158 } else {
02159
02160 const DrawTileSprites *dts;
02161 PaletteID pal = PAL_NONE;
02162 SpriteID relocation;
02163
02164 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
02165
02166 if (IsInvisibilitySet(TO_BUILDINGS)) {
02167
02168 dts = &_depot_invisible_gfx_table[GetRailDepotDirection(ti->tile)];
02169 } else {
02170 dts = &_depot_gfx_table[GetRailDepotDirection(ti->tile)];
02171 }
02172
02173 SpriteID image;
02174 if (rti->UsesOverlay()) {
02175 image = SPR_FLAT_GRASS_TILE;
02176 } else {
02177 image = dts->ground.sprite;
02178 if (image != SPR_FLAT_GRASS_TILE) image += rti->total_offset;
02179 }
02180
02181
02182
02183 if (IsSnowRailGround(ti->tile) && _settings_game.game_creation.landscape == LT_TROPIC) {
02184 if (image != SPR_FLAT_GRASS_TILE) {
02185 image += rti->snow_offset;
02186 } else {
02187 image = SPR_FLAT_SNOW_DESERT_TILE;
02188 }
02189 }
02190
02191 DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, _drawtile_track_palette));
02192
02193 if (rti->UsesOverlay()) {
02194 SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
02195
02196 switch (GetRailDepotDirection(ti->tile)) {
02197 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02198 case DIAGDIR_SW: DrawGroundSprite(ground + RTO_X, PAL_NONE); break;
02199 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02200 case DIAGDIR_SE: DrawGroundSprite(ground + RTO_Y, PAL_NONE); break;
02201 default: break;
02202 }
02203
02204 if (_settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile)) {
02205 SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
02206
02207 switch (GetRailDepotDirection(ti->tile)) {
02208 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02209 case DIAGDIR_SW: DrawGroundSprite(overlay + RTO_X, PALETTE_CRASH); break;
02210 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02211 case DIAGDIR_SE: DrawGroundSprite(overlay + RTO_Y, PALETTE_CRASH); break;
02212 default: break;
02213 }
02214 }
02215
02216 relocation = GetCustomRailSprite(rti, ti->tile, RTSG_DEPOT);
02217 relocation -= SPR_RAIL_DEPOT_SE_1;
02218 } else {
02219
02220 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile)) {
02221 switch (GetRailDepotDirection(ti->tile)) {
02222 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02223 case DIAGDIR_SW: DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH); break;
02224 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02225 case DIAGDIR_SE: DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH); break;
02226 default: break;
02227 }
02228 }
02229
02230 relocation = rti->total_offset;
02231 }
02232
02233 if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
02234
02235 DrawRailTileSeq(ti, dts, TO_BUILDINGS, relocation, 0, _drawtile_track_palette);
02236 }
02237 DrawBridgeMiddle(ti);
02238 }
02239
02240 void DrawTrainDepotSprite(int x, int y, int dir, RailType railtype)
02241 {
02242 const DrawTileSprites *dts = &_depot_gfx_table[dir];
02243 const RailtypeInfo *rti = GetRailTypeInfo(railtype);
02244 SpriteID image = rti->UsesOverlay() ? SPR_FLAT_GRASS_TILE : dts->ground.sprite;
02245 uint32 offset = rti->total_offset;
02246
02247 x += 33;
02248 y += 17;
02249
02250 if (image != SPR_FLAT_GRASS_TILE) image += offset;
02251 PaletteID palette = COMPANY_SPRITE_COLOUR(_local_company);
02252
02253 DrawSprite(image, PAL_NONE, x, y);
02254
02255 if (rti->UsesOverlay()) {
02256 SpriteID ground = GetCustomRailSprite(rti, INVALID_TILE, RTSG_GROUND);
02257
02258 switch (dir) {
02259 case DIAGDIR_SW: DrawSprite(ground + RTO_X, PAL_NONE, x, y); break;
02260 case DIAGDIR_SE: DrawSprite(ground + RTO_Y, PAL_NONE, x, y); break;
02261 default: break;
02262 }
02263
02264 offset = GetCustomRailSprite(rti, INVALID_TILE, RTSG_DEPOT);
02265 offset -= SPR_RAIL_DEPOT_SE_1;
02266 }
02267
02268 DrawRailTileSeqInGUI(x, y, dts, offset, 0, palette);
02269 }
02270
02271 static uint GetSlopeZ_Track(TileIndex tile, uint x, uint y)
02272 {
02273 uint z;
02274 Slope tileh = GetTileSlope(tile, &z);
02275
02276 if (tileh == SLOPE_FLAT) return z;
02277 if (IsPlainRail(tile)) {
02278 z += ApplyFoundationToSlope(GetRailFoundation(tileh, GetTrackBits(tile)), &tileh);
02279 return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
02280 } else {
02281 return z + TILE_HEIGHT;
02282 }
02283 }
02284
02285 static Foundation GetFoundation_Track(TileIndex tile, Slope tileh)
02286 {
02287 return IsPlainRail(tile) ? GetRailFoundation(tileh, GetTrackBits(tile)) : FlatteningFoundation(tileh);
02288 }
02289
02290 static void TileLoop_Track(TileIndex tile)
02291 {
02292 RailGroundType old_ground = GetRailGroundType(tile);
02293 RailGroundType new_ground;
02294
02295 if (old_ground == RAIL_GROUND_WATER) {
02296 TileLoop_Water(tile);
02297 return;
02298 }
02299
02300 switch (_settings_game.game_creation.landscape) {
02301 case LT_ARCTIC: {
02302 uint z;
02303 Slope slope = GetTileSlope(tile, &z);
02304 bool half = false;
02305
02306
02307
02308 if (IsPlainRail(tile)) {
02309 TrackBits track = GetTrackBits(tile);
02310 Foundation f = GetRailFoundation(slope, track);
02311
02312 switch (f) {
02313 case FOUNDATION_NONE:
02314
02315 if (IsSlopeWithThreeCornersRaised(slope)) z += TILE_HEIGHT;
02316 break;
02317
02318 case FOUNDATION_INCLINED_X:
02319 case FOUNDATION_INCLINED_Y:
02320
02321 if (IsSteepSlope(slope)) z += TILE_HEIGHT;
02322 break;
02323
02324 case FOUNDATION_STEEP_LOWER:
02325
02326 z += TILE_HEIGHT;
02327 break;
02328
02329 default:
02330
02331 if (IsSteepSlope(slope)) z += TILE_HEIGHT;
02332 z += TILE_HEIGHT;
02333 break;
02334 }
02335
02336 half = IsInsideMM(f, FOUNDATION_STEEP_BOTH, FOUNDATION_HALFTILE_N + 1);
02337 } else {
02338
02339 if (slope != SLOPE_FLAT) z += TILE_HEIGHT;
02340 }
02341
02342
02343
02344
02345
02346 if (z > GetSnowLine()) {
02347 if (half && z - GetSnowLine() == TILE_HEIGHT) {
02348
02349 new_ground = RAIL_GROUND_HALF_SNOW;
02350 } else {
02351 new_ground = RAIL_GROUND_ICE_DESERT;
02352 }
02353 goto set_ground;
02354 }
02355 break;
02356 }
02357
02358 case LT_TROPIC:
02359 if (GetTropicZone(tile) == TROPICZONE_DESERT) {
02360 new_ground = RAIL_GROUND_ICE_DESERT;
02361 goto set_ground;
02362 }
02363 break;
02364 }
02365
02366 if (!IsPlainRail(tile)) return;
02367
02368 new_ground = RAIL_GROUND_GRASS;
02369
02370 if (old_ground != RAIL_GROUND_BARREN) {
02371
02372 TrackBits rail = GetTrackBits(tile);
02373
02374 switch (rail) {
02375 case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
02376 case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
02377 case TRACK_BIT_LEFT: new_ground = RAIL_GROUND_FENCE_VERT1; break;
02378 case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2; break;
02379
02380 default: {
02381 Owner owner = GetTileOwner(tile);
02382
02383 if (rail == (TRACK_BIT_LOWER | TRACK_BIT_RIGHT) || (
02384 (rail & TRACK_BIT_3WAY_NW) == 0 &&
02385 (rail & TRACK_BIT_X)
02386 )) {
02387 TileIndex n = tile + TileDiffXY(0, -1);
02388 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02389
02390 if (!IsTileType(n, MP_RAILWAY) ||
02391 !IsTileOwner(n, owner) ||
02392 nrail == TRACK_BIT_UPPER ||
02393 nrail == TRACK_BIT_LEFT) {
02394 new_ground = RAIL_GROUND_FENCE_NW;
02395 }
02396 }
02397
02398 if (rail == (TRACK_BIT_UPPER | TRACK_BIT_LEFT) || (
02399 (rail & TRACK_BIT_3WAY_SE) == 0 &&
02400 (rail & TRACK_BIT_X)
02401 )) {
02402 TileIndex n = tile + TileDiffXY(0, 1);
02403 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02404
02405 if (!IsTileType(n, MP_RAILWAY) ||
02406 !IsTileOwner(n, owner) ||
02407 nrail == TRACK_BIT_LOWER ||
02408 nrail == TRACK_BIT_RIGHT) {
02409 new_ground = (new_ground == RAIL_GROUND_FENCE_NW) ?
02410 RAIL_GROUND_FENCE_SENW : RAIL_GROUND_FENCE_SE;
02411 }
02412 }
02413
02414 if (rail == (TRACK_BIT_LOWER | TRACK_BIT_LEFT) || (
02415 (rail & TRACK_BIT_3WAY_NE) == 0 &&
02416 (rail & TRACK_BIT_Y)
02417 )) {
02418 TileIndex n = tile + TileDiffXY(-1, 0);
02419 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02420
02421 if (!IsTileType(n, MP_RAILWAY) ||
02422 !IsTileOwner(n, owner) ||
02423 nrail == TRACK_BIT_UPPER ||
02424 nrail == TRACK_BIT_RIGHT) {
02425 new_ground = RAIL_GROUND_FENCE_NE;
02426 }
02427 }
02428
02429 if (rail == (TRACK_BIT_UPPER | TRACK_BIT_RIGHT) || (
02430 (rail & TRACK_BIT_3WAY_SW) == 0 &&
02431 (rail & TRACK_BIT_Y)
02432 )) {
02433 TileIndex n = tile + TileDiffXY(1, 0);
02434 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02435
02436 if (!IsTileType(n, MP_RAILWAY) ||
02437 !IsTileOwner(n, owner) ||
02438 nrail == TRACK_BIT_LOWER ||
02439 nrail == TRACK_BIT_LEFT) {
02440 new_ground = (new_ground == RAIL_GROUND_FENCE_NE) ?
02441 RAIL_GROUND_FENCE_NESW : RAIL_GROUND_FENCE_SW;
02442 }
02443 }
02444 break;
02445 }
02446 }
02447 }
02448
02449 set_ground:
02450 if (old_ground != new_ground) {
02451 SetRailGroundType(tile, new_ground);
02452 MarkTileDirtyByTile(tile);
02453 }
02454 }
02455
02456
02457 static TrackStatus GetTileTrackStatus_Track(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
02458 {
02459
02460 if (mode == TRANSPORT_WATER && IsPlainRail(tile) && GetRailGroundType(tile) == RAIL_GROUND_WATER) {
02461 TrackBits tb = GetTrackBits(tile);
02462 switch (tb) {
02463 default: NOT_REACHED();
02464 case TRACK_BIT_UPPER: tb = TRACK_BIT_LOWER; break;
02465 case TRACK_BIT_LOWER: tb = TRACK_BIT_UPPER; break;
02466 case TRACK_BIT_LEFT: tb = TRACK_BIT_RIGHT; break;
02467 case TRACK_BIT_RIGHT: tb = TRACK_BIT_LEFT; break;
02468 }
02469 return CombineTrackStatus(TrackBitsToTrackdirBits(tb), TRACKDIR_BIT_NONE);
02470 }
02471
02472 if (mode != TRANSPORT_RAIL) return 0;
02473
02474 TrackBits trackbits = TRACK_BIT_NONE;
02475 TrackdirBits red_signals = TRACKDIR_BIT_NONE;
02476
02477 switch (GetRailTileType(tile)) {
02478 default: NOT_REACHED();
02479 case RAIL_TILE_NORMAL:
02480 trackbits = GetTrackBits(tile);
02481 break;
02482
02483 case RAIL_TILE_SIGNALS: {
02484 trackbits = GetTrackBits(tile);
02485 byte a = GetPresentSignals(tile);
02486 uint b = GetSignalStates(tile);
02487
02488 b &= a;
02489
02490
02491
02492
02493
02494
02495 if (!IsOnewaySignal(tile, TRACK_UPPER) || (a & SignalOnTrack(TRACK_UPPER)) == 0) b |= ~a & SignalOnTrack(TRACK_UPPER);
02496 if (!IsOnewaySignal(tile, TRACK_LOWER) || (a & SignalOnTrack(TRACK_LOWER)) == 0) b |= ~a & SignalOnTrack(TRACK_LOWER);
02497
02498 if ((b & 0x8) == 0) red_signals |= (TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_X_NE | TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_UPPER_E);
02499 if ((b & 0x4) == 0) red_signals |= (TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_X_SW | TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_UPPER_W);
02500 if ((b & 0x2) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_LOWER_E);
02501 if ((b & 0x1) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_S | TRACKDIR_BIT_LOWER_W);
02502
02503 break;
02504 }
02505
02506 case RAIL_TILE_DEPOT: {
02507 DiagDirection dir = GetRailDepotDirection(tile);
02508
02509 if (side != INVALID_DIAGDIR && side != dir) break;
02510
02511 trackbits = DiagDirToDiagTrackBits(dir);
02512 break;
02513 }
02514 }
02515
02516 return CombineTrackStatus(TrackBitsToTrackdirBits(trackbits), red_signals);
02517 }
02518
02519 static bool ClickTile_Track(TileIndex tile)
02520 {
02521 if (!IsRailDepot(tile)) return false;
02522
02523 ShowDepotWindow(tile, VEH_TRAIN);
02524 return true;
02525 }
02526
02527 static void GetTileDesc_Track(TileIndex tile, TileDesc *td)
02528 {
02529 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(tile));
02530 td->rail_speed = rti->max_speed;
02531 td->owner[0] = GetTileOwner(tile);
02532 switch (GetRailTileType(tile)) {
02533 case RAIL_TILE_NORMAL:
02534 td->str = STR_LAI_RAIL_DESCRIPTION_TRACK;
02535 break;
02536
02537 case RAIL_TILE_SIGNALS: {
02538 static const StringID signal_type[6][6] = {
02539 {
02540 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS,
02541 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS,
02542 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS,
02543 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS,
02544 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS,
02545 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS
02546 },
02547 {
02548 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS,
02549 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRESIGNALS,
02550 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS,
02551 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS,
02552 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS,
02553 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS
02554 },
02555 {
02556 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS,
02557 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS,
02558 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXITSIGNALS,
02559 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS,
02560 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS,
02561 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS
02562 },
02563 {
02564 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS,
02565 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS,
02566 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS,
02567 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBOSIGNALS,
02568 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS,
02569 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS
02570 },
02571 {
02572 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS,
02573 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS,
02574 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS,
02575 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS,
02576 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBSSIGNALS,
02577 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS
02578 },
02579 {
02580 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS,
02581 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS,
02582 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS,
02583 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS,
02584 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS,
02585 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRYSIGNALS
02586 }
02587 };
02588
02589 SignalType primary_signal;
02590 SignalType secondary_signal;
02591 if (HasSignalOnTrack(tile, TRACK_UPPER)) {
02592 primary_signal = GetSignalType(tile, TRACK_UPPER);
02593 secondary_signal = HasSignalOnTrack(tile, TRACK_LOWER) ? GetSignalType(tile, TRACK_LOWER) : primary_signal;
02594 } else {
02595 secondary_signal = primary_signal = GetSignalType(tile, TRACK_LOWER);
02596 }
02597
02598 td->str = signal_type[secondary_signal][primary_signal];
02599 break;
02600 }
02601
02602 case RAIL_TILE_DEPOT:
02603 td->str = STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT;
02604 if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL) {
02605 if (td->rail_speed > 0) {
02606 td->rail_speed = min(td->rail_speed, 61);
02607 } else {
02608 td->rail_speed = 61;
02609 }
02610 }
02611 break;
02612
02613 default:
02614 NOT_REACHED();
02615 }
02616 }
02617
02618 static void ChangeTileOwner_Track(TileIndex tile, Owner old_owner, Owner new_owner)
02619 {
02620 if (!IsTileOwner(tile, old_owner)) return;
02621
02622 if (new_owner != INVALID_OWNER) {
02623 SetTileOwner(tile, new_owner);
02624 } else {
02625 DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
02626 }
02627 }
02628
02629 static const byte _fractcoords_behind[4] = { 0x8F, 0x8, 0x80, 0xF8 };
02630 static const byte _fractcoords_enter[4] = { 0x8A, 0x48, 0x84, 0xA8 };
02631 static const int8 _deltacoord_leaveoffset[8] = {
02632 -1, 0, 1, 0,
02633 0, 1, 0, -1
02634 };
02635
02636
02642 int TicksToLeaveDepot(const Train *v)
02643 {
02644 DiagDirection dir = GetRailDepotDirection(v->tile);
02645 int length = v->tcache.cached_veh_length;
02646
02647 switch (dir) {
02648 case DIAGDIR_NE: return ((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) - (length + 1)));
02649 case DIAGDIR_SE: return -((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) + (length + 1)));
02650 case DIAGDIR_SW: return -((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) + (length + 1)));
02651 default:
02652 case DIAGDIR_NW: return ((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) - (length + 1)));
02653 }
02654
02655 return 0;
02656 }
02657
02660 static VehicleEnterTileStatus VehicleEnter_Track(Vehicle *u, TileIndex tile, int x, int y)
02661 {
02662
02663 if (u->type != VEH_TRAIN || !IsRailDepotTile(tile)) return VETSB_CONTINUE;
02664
02665 Train *v = Train::From(u);
02666
02667
02668 DiagDirection dir = GetRailDepotDirection(tile);
02669
02670
02671
02672 int length = v->tcache.cached_veh_length;
02673
02674 byte fract_coord_leave =
02675 ((_fractcoords_enter[dir] & 0x0F) +
02676 (length + 1) * _deltacoord_leaveoffset[dir]) +
02677 (((_fractcoords_enter[dir] >> 4) +
02678 ((length + 1) * _deltacoord_leaveoffset[dir + 4])) << 4);
02679
02680 byte fract_coord = (x & 0xF) + ((y & 0xF) << 4);
02681
02682 if (_fractcoords_behind[dir] == fract_coord) {
02683
02684 return VETSB_CANNOT_ENTER;
02685 } else if (_fractcoords_enter[dir] == fract_coord) {
02686 if (DiagDirToDir(ReverseDiagDir(dir)) == v->direction) {
02687
02688 v->track = TRACK_BIT_DEPOT,
02689 v->vehstatus |= VS_HIDDEN;
02690 v->direction = ReverseDir(v->direction);
02691 if (v->Next() == NULL) VehicleEnterDepot(v->First());
02692 v->tile = tile;
02693
02694 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
02695 return VETSB_ENTERED_WORMHOLE;
02696 }
02697 } else if (fract_coord_leave == fract_coord) {
02698 if (DiagDirToDir(dir) == v->direction) {
02699
02700 if ((v = v->Next()) != NULL) {
02701 v->vehstatus &= ~VS_HIDDEN;
02702 v->track = (DiagDirToAxis(dir) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y);
02703 }
02704 }
02705 }
02706
02707 return VETSB_CONTINUE;
02708 }
02709
02721 static CommandCost TestAutoslopeOnRailTile(TileIndex tile, uint flags, uint z_old, Slope tileh_old, uint z_new, Slope tileh_new, TrackBits rail_bits)
02722 {
02723 if (!_settings_game.construction.build_on_slopes || !AutoslopeEnabled()) return CMD_ERROR;
02724
02725
02726 if (CheckRailSlope(tileh_new, rail_bits, TRACK_BIT_NONE, tile).Failed()) return CMD_ERROR;
02727
02728
02729 z_old += ApplyFoundationToSlope(GetRailFoundation(tileh_old, rail_bits), &tileh_old);
02730 z_new += ApplyFoundationToSlope(GetRailFoundation(tileh_new, rail_bits), &tileh_new);
02731
02732 Corner track_corner;
02733 switch (rail_bits) {
02734 case TRACK_BIT_LEFT: track_corner = CORNER_W; break;
02735 case TRACK_BIT_LOWER: track_corner = CORNER_S; break;
02736 case TRACK_BIT_RIGHT: track_corner = CORNER_E; break;
02737 case TRACK_BIT_UPPER: track_corner = CORNER_N; break;
02738
02739
02740 default: return (((z_old != z_new) || (tileh_old != tileh_new)) ? CMD_ERROR : CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]));
02741 }
02742
02743
02744 z_old += GetSlopeZInCorner(RemoveHalftileSlope(tileh_old), track_corner);
02745 z_new += GetSlopeZInCorner(RemoveHalftileSlope(tileh_new), track_corner);
02746 if (z_old != z_new) return CMD_ERROR;
02747
02748 CommandCost cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02749
02750 if (tileh_old != tileh_new) {
02751
02752 if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old)) cost.AddCost(_price[PR_CLEAR_WATER]);
02753 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
02754 }
02755 return cost;
02756 }
02757
02758 static CommandCost TerraformTile_Track(TileIndex tile, DoCommandFlag flags, uint z_new, Slope tileh_new)
02759 {
02760 uint z_old;
02761 Slope tileh_old = GetTileSlope(tile, &z_old);
02762 if (IsPlainRail(tile)) {
02763 TrackBits rail_bits = GetTrackBits(tile);
02764
02765 bool was_water = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old));
02766
02767 _error_message = STR_ERROR_MUST_REMOVE_RAILROAD_TRACK;
02768
02769
02770 CommandCost autoslope_result = TestAutoslopeOnRailTile(tile, flags, z_old, tileh_old, z_new, tileh_new, rail_bits);
02771
02772
02773 Corner allowed_corner;
02774 switch (rail_bits) {
02775 case TRACK_BIT_RIGHT: allowed_corner = CORNER_W; break;
02776 case TRACK_BIT_UPPER: allowed_corner = CORNER_S; break;
02777 case TRACK_BIT_LEFT: allowed_corner = CORNER_E; break;
02778 case TRACK_BIT_LOWER: allowed_corner = CORNER_N; break;
02779 default: return autoslope_result;
02780 }
02781
02782 Foundation f_old = GetRailFoundation(tileh_old, rail_bits);
02783
02784
02785 if (tileh_old != SLOPE_NS && tileh_old != SLOPE_EW && IsSpecialRailFoundation(f_old)) return autoslope_result;
02786
02787
02788 for (Corner corner = (Corner)0; corner < CORNER_END; corner = (Corner)(corner + 1)) {
02789 if (allowed_corner == corner) continue;
02790 if (z_old + GetSlopeZInCorner(tileh_old, corner) != z_new + GetSlopeZInCorner(tileh_new, corner)) return autoslope_result;
02791 }
02792
02793
02794 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
02795
02796
02797 return CommandCost(EXPENSES_CONSTRUCTION, was_water ? _price[PR_CLEAR_WATER] : (Money)0);
02798 } else if (_settings_game.construction.build_on_slopes && AutoslopeEnabled() &&
02799 AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetRailDepotDirection(tile))) {
02800 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02801 }
02802 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
02803 }
02804
02805
02806 extern const TileTypeProcs _tile_type_rail_procs = {
02807 DrawTile_Track,
02808 GetSlopeZ_Track,
02809 ClearTile_Track,
02810 NULL,
02811 GetTileDesc_Track,
02812 GetTileTrackStatus_Track,
02813 ClickTile_Track,
02814 NULL,
02815 TileLoop_Track,
02816 ChangeTileOwner_Track,
02817 NULL,
02818 VehicleEnter_Track,
02819 GetFoundation_Track,
02820 TerraformTile_Track,
02821 };