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