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