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