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 if (RailNoLevelCrossings(totype)) {
01400 _error_message = STR_ERROR_CROSSING_DISALLOWED;
01401 continue;
01402 }
01403 break;
01404 case MP_TUNNELBRIDGE:
01405 if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) continue;
01406 break;
01407 default: continue;
01408 }
01409
01410
01411 RailType type = GetRailType(tile);
01412
01413
01414 if (type == totype || (_settings_game.vehicle.disable_elrails && totype == RAILTYPE_RAIL && type == RAILTYPE_ELECTRIC)) continue;
01415
01416
01417 if (!CheckTileOwnership(tile)) continue;
01418
01419 SmallVector<Train *, 2> vehicles_affected;
01420
01421
01422
01423 if (tt != MP_TUNNELBRIDGE) {
01424 if (!IsCompatibleRail(type, totype) && !EnsureNoVehicleOnGround(tile)) continue;
01425 if (flags & DC_EXEC) {
01426 TrackBits reserved = GetReservedTrackbits(tile);
01427 Track track;
01428 while ((track = RemoveFirstTrack(&reserved)) != INVALID_TRACK) {
01429 Train *v = GetTrainForReservation(tile, track);
01430 if (v != NULL && !HasPowerOnRail(v->railtype, totype)) {
01431
01432 FreeTrainTrackReservation(v);
01433 *vehicles_affected.Append() = v;
01434 }
01435 }
01436
01437 SetRailType(tile, totype);
01438 MarkTileDirtyByTile(tile);
01439
01440 FindVehicleOnPos(tile, NULL, &UpdateTrainPowerProc);
01441 }
01442 }
01443
01444 switch (tt) {
01445 case MP_RAILWAY:
01446 switch (GetRailTileType(tile)) {
01447 case RAIL_TILE_DEPOT:
01448 if (flags & DC_EXEC) {
01449
01450 YapfNotifyTrackLayoutChange(tile, GetRailDepotTrack(tile));
01451
01452
01453 InvalidateWindowData(WC_VEHICLE_DEPOT, tile);
01454 InvalidateWindowData(WC_BUILD_VEHICLE, tile);
01455 }
01456 cost.AddCost(RailConvertCost(type, totype));
01457 break;
01458
01459 default:
01460 if (flags & DC_EXEC) {
01461
01462 TrackBits tracks = GetTrackBits(tile);
01463 while (tracks != TRACK_BIT_NONE) {
01464 YapfNotifyTrackLayoutChange(tile, RemoveFirstTrack(&tracks));
01465 }
01466 }
01467 cost.AddCost(RailConvertCost(type, totype) * CountBits(GetTrackBits(tile)));
01468 break;
01469 }
01470 break;
01471
01472 case MP_TUNNELBRIDGE: {
01473 TileIndex endtile = GetOtherTunnelBridgeEnd(tile);
01474
01475
01476
01477 if (endtile < tile && TileX(endtile) >= sx && TileX(endtile) <= ex &&
01478 TileY(endtile) >= sy && TileY(endtile) <= ey) continue;
01479
01480
01481 if (!IsCompatibleRail(GetRailType(tile), totype) &&
01482 HasVehicleOnTunnelBridge(tile, endtile)) continue;
01483
01484 if (flags & DC_EXEC) {
01485 Track track = DiagDirToDiagTrack(GetTunnelBridgeDirection(tile));
01486 if (HasTunnelBridgeReservation(tile)) {
01487 Train *v = GetTrainForReservation(tile, track);
01488 if (v != NULL && !HasPowerOnRail(v->railtype, totype)) {
01489
01490 FreeTrainTrackReservation(v);
01491 *vehicles_affected.Append() = v;
01492 }
01493 }
01494 SetRailType(tile, totype);
01495 SetRailType(endtile, totype);
01496
01497 FindVehicleOnPos(tile, NULL, &UpdateTrainPowerProc);
01498 FindVehicleOnPos(endtile, NULL, &UpdateTrainPowerProc);
01499
01500 YapfNotifyTrackLayoutChange(tile, track);
01501 YapfNotifyTrackLayoutChange(endtile, track);
01502
01503 MarkTileDirtyByTile(tile);
01504 MarkTileDirtyByTile(endtile);
01505
01506 if (IsBridge(tile)) {
01507 TileIndexDiff delta = TileOffsByDiagDir(GetTunnelBridgeDirection(tile));
01508 TileIndex t = tile + delta;
01509 for (; t != endtile; t += delta) MarkTileDirtyByTile(t);
01510 }
01511 }
01512
01513 cost.AddCost((GetTunnelBridgeLength(tile, endtile) + 2) * RailConvertCost(type, totype));
01514 } break;
01515
01516 default:
01517 if (flags & DC_EXEC) {
01518 Track track = ((tt == MP_STATION) ? GetRailStationTrack(tile) : GetCrossingRailTrack(tile));
01519 YapfNotifyTrackLayoutChange(tile, track);
01520 }
01521
01522 cost.AddCost(RailConvertCost(type, totype));
01523 break;
01524 }
01525
01526 for (uint i = 0; i < vehicles_affected.Length(); ++i) {
01527 TryPathReserve(vehicles_affected[i], true);
01528 }
01529 }
01530 }
01531
01532 return (cost.GetCost() == 0) ? CMD_ERROR : cost;
01533 }
01534
01535 static CommandCost RemoveTrainDepot(TileIndex tile, DoCommandFlag flags)
01536 {
01537 if (!CheckTileOwnership(tile) && _current_company != OWNER_WATER)
01538 return CMD_ERROR;
01539
01540 if (!EnsureNoVehicleOnGround(tile))
01541 return CMD_ERROR;
01542
01543 if (flags & DC_EXEC) {
01544
01545 DiagDirection dir = GetRailDepotDirection(tile);
01546 Owner owner = GetTileOwner(tile);
01547 Train *v = NULL;
01548
01549 if (HasDepotReservation(tile)) {
01550 v = GetTrainForReservation(tile, DiagDirToDiagTrack(dir));
01551 if (v != NULL) FreeTrainTrackReservation(v);
01552 }
01553
01554 delete Depot::GetByTile(tile);
01555 DoClearSquare(tile);
01556 AddSideToSignalBuffer(tile, dir, owner);
01557 YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
01558 if (v != NULL) TryPathReserve(v, true);
01559 }
01560
01561 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_TRAIN]);
01562 }
01563
01564 static CommandCost ClearTile_Track(TileIndex tile, DoCommandFlag flags)
01565 {
01566 CommandCost cost(EXPENSES_CONSTRUCTION);
01567
01568 if (flags & DC_AUTO) {
01569 if (!IsTileOwner(tile, _current_company)) {
01570 return_cmd_error(STR_ERROR_AREA_IS_OWNED_BY_ANOTHER);
01571 }
01572
01573 if (IsPlainRail(tile)) {
01574 return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK);
01575 } else {
01576 return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
01577 }
01578 }
01579
01580 switch (GetRailTileType(tile)) {
01581 case RAIL_TILE_SIGNALS:
01582 case RAIL_TILE_NORMAL: {
01583 Slope tileh = GetTileSlope(tile, NULL);
01584
01585 bool water_ground = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh));
01586
01587 TrackBits tracks = GetTrackBits(tile);
01588 while (tracks != TRACK_BIT_NONE) {
01589 Track track = RemoveFirstTrack(&tracks);
01590 CommandCost ret = DoCommand(tile, 0, track, flags, CMD_REMOVE_SINGLE_RAIL);
01591 if (ret.Failed()) return CMD_ERROR;
01592 cost.AddCost(ret);
01593 }
01594
01595
01596 if (water_ground && !(flags & DC_BANKRUPT)) {
01597 if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
01598
01599
01600 if (flags & DC_EXEC) DoClearSquare(tile);
01601 cost.AddCost(_price[PR_CLEAR_WATER]);
01602 }
01603
01604 return cost;
01605 }
01606
01607 case RAIL_TILE_DEPOT:
01608 return RemoveTrainDepot(tile, flags);
01609
01610 default:
01611 return CMD_ERROR;
01612 }
01613 }
01614
01619 static uint GetSaveSlopeZ(uint x, uint y, Track track)
01620 {
01621 switch (track) {
01622 case TRACK_UPPER: x &= ~0xF; y &= ~0xF; break;
01623 case TRACK_LOWER: x |= 0xF; y |= 0xF; break;
01624 case TRACK_LEFT: x |= 0xF; y &= ~0xF; break;
01625 case TRACK_RIGHT: x &= ~0xF; y |= 0xF; break;
01626 default: break;
01627 }
01628 return GetSlopeZ(x, y);
01629 }
01630
01631 static void DrawSingleSignal(TileIndex tile, Track track, byte condition, uint image, uint pos)
01632 {
01633 bool side = (_settings_game.vehicle.road_side != 0) && _settings_game.construction.signal_side;
01634 static const Point SignalPositions[2][12] = {
01635 {
01636
01637 { 8, 5}, {14, 1}, { 1, 14}, { 9, 11}, { 1, 0}, { 3, 10},
01638
01639 {11, 4}, {14, 14}, {11, 3}, { 4, 13}, { 3, 4}, {11, 13}
01640 }, {
01641
01642 {14, 1}, {12, 10}, { 4, 6}, { 1, 14}, {10, 4}, { 0, 1},
01643
01644 {14, 14}, { 5, 12}, {11, 13}, { 4, 3}, {13, 4}, { 3, 11}
01645 }
01646 };
01647
01648 uint x = TileX(tile) * TILE_SIZE + SignalPositions[side][pos].x;
01649 uint y = TileY(tile) * TILE_SIZE + SignalPositions[side][pos].y;
01650
01651 SpriteID sprite;
01652
01653 SignalType type = GetSignalType(tile, track);
01654 SignalVariant variant = GetSignalVariant(tile, track);
01655
01656 if (type == SIGTYPE_NORMAL && variant == SIG_ELECTRIC) {
01657
01658 sprite = SPR_ORIGINAL_SIGNALS_BASE + image + condition;
01659 } else {
01660
01661 sprite = SPR_SIGNALS_BASE + (type - 1) * 16 + variant * 64 + image + condition + (type > SIGTYPE_LAST_NOPBS ? 64 : 0);
01662 }
01663
01664 AddSortableSpriteToDraw(sprite, PAL_NONE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, GetSaveSlopeZ(x, y, track));
01665 }
01666
01667 static uint32 _drawtile_track_palette;
01668
01669
01670 static void DrawTrackFence_NW(const TileInfo *ti, SpriteID base_image)
01671 {
01672 RailFenceOffset rfo = RFO_FLAT_X;
01673 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SW : RFO_SLOPE_NE;
01674 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01675 ti->x, ti->y + 1, 16, 1, 4, ti->z);
01676 }
01677
01678 static void DrawTrackFence_SE(const TileInfo *ti, SpriteID base_image)
01679 {
01680 RailFenceOffset rfo = RFO_FLAT_X;
01681 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SW : RFO_SLOPE_NE;
01682 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01683 ti->x, ti->y + TILE_SIZE - 1, 16, 1, 4, ti->z);
01684 }
01685
01686 static void DrawTrackFence_NW_SE(const TileInfo *ti, SpriteID base_image)
01687 {
01688 DrawTrackFence_NW(ti, base_image);
01689 DrawTrackFence_SE(ti, base_image);
01690 }
01691
01692 static void DrawTrackFence_NE(const TileInfo *ti, SpriteID base_image)
01693 {
01694 RailFenceOffset rfo = RFO_FLAT_Y;
01695 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SE : RFO_SLOPE_NW;
01696 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01697 ti->x + 1, ti->y, 1, 16, 4, ti->z);
01698 }
01699
01700 static void DrawTrackFence_SW(const TileInfo *ti, SpriteID base_image)
01701 {
01702 RailFenceOffset rfo = RFO_FLAT_Y;
01703 if (ti->tileh != SLOPE_FLAT) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SE : RFO_SLOPE_NW;
01704 AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette,
01705 ti->x + TILE_SIZE - 1, ti->y, 1, 16, 4, ti->z);
01706 }
01707
01708 static void DrawTrackFence_NE_SW(const TileInfo *ti, SpriteID base_image)
01709 {
01710 DrawTrackFence_NE(ti, base_image);
01711 DrawTrackFence_SW(ti, base_image);
01712 }
01713
01717 static void DrawTrackFence_NS_1(const TileInfo *ti, SpriteID base_image)
01718 {
01719 uint z = ti->z + GetSlopeZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_W);
01720 AddSortableSpriteToDraw(base_image + RFO_FLAT_VERT, _drawtile_track_palette,
01721 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01722 }
01723
01727 static void DrawTrackFence_NS_2(const TileInfo *ti, SpriteID base_image)
01728 {
01729 uint z = ti->z + GetSlopeZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_E);
01730 AddSortableSpriteToDraw(base_image + RFO_FLAT_VERT, _drawtile_track_palette,
01731 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01732 }
01733
01737 static void DrawTrackFence_WE_1(const TileInfo *ti, SpriteID base_image)
01738 {
01739 uint z = ti->z + GetSlopeZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_N);
01740 AddSortableSpriteToDraw(base_image + RFO_FLAT_HORZ, _drawtile_track_palette,
01741 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01742 }
01743
01747 static void DrawTrackFence_WE_2(const TileInfo *ti, SpriteID base_image)
01748 {
01749 uint z = ti->z + GetSlopeZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_S);
01750 AddSortableSpriteToDraw(base_image + RFO_FLAT_HORZ, _drawtile_track_palette,
01751 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01752 }
01753
01754
01755 static void DrawTrackDetails(const TileInfo *ti, const RailtypeInfo *rti)
01756 {
01757
01758
01759 SpriteID base_image = GetCustomRailSprite(rti, ti->tile, RTSG_FENCES, IsHalftileSlope(ti->tileh));
01760 if (base_image == 0) base_image = SPR_TRACK_FENCE_FLAT_X;
01761
01762 switch (GetRailGroundType(ti->tile)) {
01763 case RAIL_GROUND_FENCE_NW: DrawTrackFence_NW(ti, base_image); break;
01764 case RAIL_GROUND_FENCE_SE: DrawTrackFence_SE(ti, base_image); break;
01765 case RAIL_GROUND_FENCE_SENW: DrawTrackFence_NW_SE(ti, base_image); break;
01766 case RAIL_GROUND_FENCE_NE: DrawTrackFence_NE(ti, base_image); break;
01767 case RAIL_GROUND_FENCE_SW: DrawTrackFence_SW(ti, base_image); break;
01768 case RAIL_GROUND_FENCE_NESW: DrawTrackFence_NE_SW(ti, base_image); break;
01769 case RAIL_GROUND_FENCE_VERT1: DrawTrackFence_NS_1(ti, base_image); break;
01770 case RAIL_GROUND_FENCE_VERT2: DrawTrackFence_NS_2(ti, base_image); break;
01771 case RAIL_GROUND_FENCE_HORIZ1: DrawTrackFence_WE_1(ti, base_image); break;
01772 case RAIL_GROUND_FENCE_HORIZ2: DrawTrackFence_WE_2(ti, base_image); break;
01773 case RAIL_GROUND_WATER: {
01774 Corner track_corner;
01775 if (IsHalftileSlope(ti->tileh)) {
01776
01777 track_corner = GetHalftileSlopeCorner(ti->tileh);
01778 } else {
01779
01780 track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh)));
01781 }
01782 switch (track_corner) {
01783 case CORNER_W: DrawTrackFence_NS_1(ti, base_image); break;
01784 case CORNER_S: DrawTrackFence_WE_2(ti, base_image); break;
01785 case CORNER_E: DrawTrackFence_NS_2(ti, base_image); break;
01786 case CORNER_N: DrawTrackFence_WE_1(ti, base_image); break;
01787 default: NOT_REACHED();
01788 }
01789 break;
01790 }
01791 default: break;
01792 }
01793 }
01794
01795
01796 static const int INF = 1000;
01797 static const SubSprite _halftile_sub_sprite[4] = {
01798 { -INF , -INF , 32 - 33, INF },
01799 { -INF , 0 + 7, INF , INF },
01800 { -31 + 33, -INF , INF , INF },
01801 { -INF , -INF , INF , 30 - 23 }
01802 };
01803
01804 static inline void DrawTrackSprite(SpriteID sprite, PaletteID pal, const TileInfo *ti, Slope s)
01805 {
01806 DrawGroundSprite(sprite, pal, NULL, 0, (ti->tileh & s) ? -8 : 0);
01807 }
01808
01809 static void DrawTrackBitsOverlay(TileInfo *ti, TrackBits track, const RailtypeInfo *rti)
01810 {
01811 RailGroundType rgt = GetRailGroundType(ti->tile);
01812 Foundation f = GetRailFoundation(ti->tileh, track);
01813 Corner halftile_corner = CORNER_INVALID;
01814
01815 if (IsNonContinuousFoundation(f)) {
01816
01817 halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f));
01818
01819 track &= ~CornerToTrackBits(halftile_corner);
01820 f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE);
01821 }
01822
01823 DrawFoundation(ti, f);
01824
01825
01826
01827 if (track == TRACK_BIT_NONE && rgt == RAIL_GROUND_WATER) {
01828 if (IsSteepSlope(ti->tileh)) {
01829 DrawShoreTile(ti->tileh);
01830 } else {
01831 DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE);
01832 }
01833 } else {
01834 SpriteID image;
01835
01836 switch (rgt) {
01837 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
01838 case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOW_DESERT_TILE; break;
01839 default: image = SPR_FLAT_GRASS_TILE; break;
01840 }
01841
01842 image += _tileh_to_sprite[ti->tileh];
01843
01844 DrawGroundSprite(image, PAL_NONE);
01845 }
01846
01847 SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
01848 SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
01849 TrackBits pbs = _settings_client.gui.show_track_reservation ? GetRailReservationTrackBits(ti->tile) : TRACK_BIT_NONE;
01850
01851 if (track == TRACK_BIT_NONE) {
01852
01853 } else if (ti->tileh == SLOPE_NW && track == TRACK_BIT_Y) {
01854 DrawGroundSprite(ground + RTO_SLOPE_NW, PAL_NONE);
01855 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 9, PALETTE_CRASH);
01856 } else if (ti->tileh == SLOPE_NE && track == TRACK_BIT_X) {
01857 DrawGroundSprite(ground + RTO_SLOPE_NE, PAL_NONE);
01858 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 6, PALETTE_CRASH);
01859 } else if (ti->tileh == SLOPE_SE && track == TRACK_BIT_Y) {
01860 DrawGroundSprite(ground + RTO_SLOPE_SE, PAL_NONE);
01861 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 7, PALETTE_CRASH);
01862 } else if (ti->tileh == SLOPE_SW && track == TRACK_BIT_X) {
01863 DrawGroundSprite(ground + RTO_SLOPE_SW, PAL_NONE);
01864 if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 8, PALETTE_CRASH);
01865 } else {
01866 switch (track) {
01867
01868
01869 case TRACK_BIT_X: DrawGroundSprite(ground + RTO_X, PAL_NONE); break;
01870 case TRACK_BIT_Y: DrawGroundSprite(ground + RTO_Y, PAL_NONE); break;
01871 case TRACK_BIT_UPPER: DrawTrackSprite(ground + RTO_N, PAL_NONE, ti, SLOPE_N); break;
01872 case TRACK_BIT_LOWER: DrawTrackSprite(ground + RTO_S, PAL_NONE, ti, SLOPE_S); break;
01873 case TRACK_BIT_RIGHT: DrawTrackSprite(ground + RTO_E, PAL_NONE, ti, SLOPE_E); break;
01874 case TRACK_BIT_LEFT: DrawTrackSprite(ground + RTO_W, PAL_NONE, ti, SLOPE_W); break;
01875 case TRACK_BIT_CROSS: DrawGroundSprite(ground + RTO_CROSSING_XY, PAL_NONE); break;
01876 case TRACK_BIT_HORZ: DrawTrackSprite(ground + RTO_N, PAL_NONE, ti, SLOPE_N);
01877 DrawTrackSprite(ground + RTO_S, PAL_NONE, ti, SLOPE_S); break;
01878 case TRACK_BIT_VERT: DrawTrackSprite(ground + RTO_E, PAL_NONE, ti, SLOPE_E);
01879 DrawTrackSprite(ground + RTO_W, PAL_NONE, ti, SLOPE_W); break;
01880
01881 default:
01882
01883 if ((track & TRACK_BIT_3WAY_NE) == 0) {
01884 DrawGroundSprite(ground + RTO_JUNCTION_SW, PAL_NONE);
01885 } else if ((track & TRACK_BIT_3WAY_SW) == 0) {
01886 DrawGroundSprite(ground + RTO_JUNCTION_NE, PAL_NONE);
01887 } else if ((track & TRACK_BIT_3WAY_NW) == 0) {
01888 DrawGroundSprite(ground + RTO_JUNCTION_SE, PAL_NONE);
01889 } else if ((track & TRACK_BIT_3WAY_SE) == 0) {
01890 DrawGroundSprite(ground + RTO_JUNCTION_NW, PAL_NONE);
01891 } else {
01892 DrawGroundSprite(ground + RTO_JUNCTION_NSEW, PAL_NONE);
01893 }
01894
01895
01896 track &= ~pbs;
01897
01898
01899 if (track & TRACK_BIT_X) DrawGroundSprite(overlay + RTO_X, PAL_NONE);
01900 if (track & TRACK_BIT_Y) DrawGroundSprite(overlay + RTO_Y, PAL_NONE);
01901 if (track & TRACK_BIT_UPPER) DrawGroundSprite(overlay + RTO_N, PAL_NONE);
01902 if (track & TRACK_BIT_LOWER) DrawGroundSprite(overlay + RTO_S, PAL_NONE);
01903 if (track & TRACK_BIT_RIGHT) DrawGroundSprite(overlay + RTO_E, PAL_NONE);
01904 if (track & TRACK_BIT_LEFT) DrawGroundSprite(overlay + RTO_W, PAL_NONE);
01905 }
01906
01907
01908 if (pbs & TRACK_BIT_X) DrawGroundSprite(overlay + RTO_X, PALETTE_CRASH);
01909 if (pbs & TRACK_BIT_Y) DrawGroundSprite(overlay + RTO_Y, PALETTE_CRASH);
01910 if (pbs & TRACK_BIT_UPPER) DrawTrackSprite(overlay + RTO_N, PALETTE_CRASH, ti, SLOPE_N);
01911 if (pbs & TRACK_BIT_LOWER) DrawTrackSprite(overlay + RTO_S, PALETTE_CRASH, ti, SLOPE_S);
01912 if (pbs & TRACK_BIT_RIGHT) DrawTrackSprite(overlay + RTO_E, PALETTE_CRASH, ti, SLOPE_E);
01913 if (pbs & TRACK_BIT_LEFT) DrawTrackSprite(overlay + RTO_W, PALETTE_CRASH, ti, SLOPE_W);
01914 }
01915
01916 if (IsValidCorner(halftile_corner)) {
01917 DrawFoundation(ti, HalftileFoundation(halftile_corner));
01918 overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY, true);
01919 ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND, true);
01920
01921
01922 Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
01923
01924 SpriteID image;
01925 switch (rgt) {
01926 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
01927 case RAIL_GROUND_ICE_DESERT:
01928 case RAIL_GROUND_HALF_SNOW: image = SPR_FLAT_SNOW_DESERT_TILE; break;
01929 default: image = SPR_FLAT_GRASS_TILE; break;
01930 }
01931
01932 image += _tileh_to_sprite[fake_slope];
01933
01934 DrawGroundSprite(image, PAL_NONE, &(_halftile_sub_sprite[halftile_corner]));
01935
01936 track = CornerToTrackBits(halftile_corner);
01937
01938 int offset;
01939 switch (track) {
01940 default: NOT_REACHED();
01941 case TRACK_BIT_UPPER: offset = RTO_N; break;
01942 case TRACK_BIT_LOWER: offset = RTO_S; break;
01943 case TRACK_BIT_RIGHT: offset = RTO_E; break;
01944 case TRACK_BIT_LEFT: offset = RTO_W; break;
01945 }
01946
01947 DrawTrackSprite(ground + offset, PAL_NONE, ti, fake_slope);
01948 if (HasReservedTracks(ti->tile, track)) {
01949 DrawTrackSprite(overlay + offset, PALETTE_CRASH, ti, fake_slope);
01950 }
01951 }
01952 }
01953
01959 static void DrawTrackBits(TileInfo *ti, TrackBits track)
01960 {
01961 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
01962
01963 if (rti->UsesOverlay()) {
01964 DrawTrackBitsOverlay(ti, track, rti);
01965 return;
01966 }
01967
01968 RailGroundType rgt = GetRailGroundType(ti->tile);
01969 Foundation f = GetRailFoundation(ti->tileh, track);
01970 Corner halftile_corner = CORNER_INVALID;
01971
01972 if (IsNonContinuousFoundation(f)) {
01973
01974 halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f));
01975
01976 track &= ~CornerToTrackBits(halftile_corner);
01977 f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE);
01978 }
01979
01980 DrawFoundation(ti, f);
01981
01982
01983 SpriteID image;
01984 PaletteID pal = PAL_NONE;
01985 const SubSprite *sub = NULL;
01986 bool junction = false;
01987
01988
01989 if (track == 0) {
01990
01991 if (rgt == RAIL_GROUND_WATER) {
01992 if (IsSteepSlope(ti->tileh)) {
01993 DrawShoreTile(ti->tileh);
01994 image = 0;
01995 } else {
01996 image = SPR_FLAT_WATER_TILE;
01997 }
01998 } else {
01999 switch (rgt) {
02000 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
02001 case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOW_DESERT_TILE; break;
02002 default: image = SPR_FLAT_GRASS_TILE; break;
02003 }
02004 image += _tileh_to_sprite[ti->tileh];
02005 }
02006 } else {
02007 if (ti->tileh != SLOPE_FLAT) {
02008
02009 image = _track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.track_y;
02010 } else {
02011
02012 (image = rti->base_sprites.track_y, track == TRACK_BIT_Y) ||
02013 (image++, track == TRACK_BIT_X) ||
02014 (image++, track == TRACK_BIT_UPPER) ||
02015 (image++, track == TRACK_BIT_LOWER) ||
02016 (image++, track == TRACK_BIT_RIGHT) ||
02017 (image++, track == TRACK_BIT_LEFT) ||
02018 (image++, track == TRACK_BIT_CROSS) ||
02019
02020 (image = rti->base_sprites.track_ns, track == TRACK_BIT_HORZ) ||
02021 (image++, track == TRACK_BIT_VERT) ||
02022
02023 (junction = true, false) ||
02024 (image = rti->base_sprites.ground, (track & TRACK_BIT_3WAY_NE) == 0) ||
02025 (image++, (track & TRACK_BIT_3WAY_SW) == 0) ||
02026 (image++, (track & TRACK_BIT_3WAY_NW) == 0) ||
02027 (image++, (track & TRACK_BIT_3WAY_SE) == 0) ||
02028 (image++, true);
02029 }
02030
02031 switch (rgt) {
02032 case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
02033 case RAIL_GROUND_ICE_DESERT: image += rti->snow_offset; break;
02034 case RAIL_GROUND_WATER: {
02035
02036 DrawShoreTile(ti->tileh);
02037 Corner track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh)));
02038 sub = &(_halftile_sub_sprite[track_corner]);
02039 break;
02040 }
02041 default: break;
02042 }
02043 }
02044
02045 if (image != 0) DrawGroundSprite(image, pal, sub);
02046
02047
02048 if (junction) {
02049 if (track & TRACK_BIT_X) DrawGroundSprite(rti->base_sprites.single_x, PAL_NONE);
02050 if (track & TRACK_BIT_Y) DrawGroundSprite(rti->base_sprites.single_y, PAL_NONE);
02051 if (track & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PAL_NONE);
02052 if (track & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PAL_NONE);
02053 if (track & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PAL_NONE);
02054 if (track & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PAL_NONE);
02055 }
02056
02057
02058 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation) {
02059
02060 TrackBits pbs = GetRailReservationTrackBits(ti->tile) & track;
02061 if (pbs & TRACK_BIT_X) {
02062 if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
02063 DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH);
02064 } else {
02065 DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
02066 }
02067 }
02068 if (pbs & TRACK_BIT_Y) {
02069 if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
02070 DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH);
02071 } else {
02072 DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
02073 }
02074 }
02075 if (pbs & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_N ? -TILE_HEIGHT : 0);
02076 if (pbs & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_S ? -TILE_HEIGHT : 0);
02077 if (pbs & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_W ? -TILE_HEIGHT : 0);
02078 if (pbs & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_E ? -TILE_HEIGHT : 0);
02079 }
02080
02081 if (IsValidCorner(halftile_corner)) {
02082 DrawFoundation(ti, HalftileFoundation(halftile_corner));
02083
02084
02085 Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
02086 image = _track_sloped_sprites[fake_slope - 1] + rti->base_sprites.track_y;
02087 pal = PAL_NONE;
02088 switch (rgt) {
02089 case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
02090 case RAIL_GROUND_ICE_DESERT:
02091 case RAIL_GROUND_HALF_SNOW: image += rti->snow_offset; break;
02092 default: break;
02093 }
02094 DrawGroundSprite(image, pal, &(_halftile_sub_sprite[halftile_corner]));
02095
02096 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasReservedTracks(ti->tile, CornerToTrackBits(halftile_corner))) {
02097 static const byte _corner_to_track_sprite[] = {3, 1, 2, 0};
02098 DrawGroundSprite(_corner_to_track_sprite[halftile_corner] + rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, -TILE_HEIGHT);
02099 }
02100 }
02101 }
02102
02108 enum {
02109 SIGNAL_TO_SOUTHWEST = 0,
02110 SIGNAL_TO_NORTHEAST = 2,
02111 SIGNAL_TO_SOUTHEAST = 4,
02112 SIGNAL_TO_NORTHWEST = 6,
02113 SIGNAL_TO_EAST = 8,
02114 SIGNAL_TO_WEST = 10,
02115 SIGNAL_TO_SOUTH = 12,
02116 SIGNAL_TO_NORTH = 14,
02117 };
02118
02119 static void DrawSignals(TileIndex tile, TrackBits rails)
02120 {
02121 #define MAYBE_DRAW_SIGNAL(x, y, z, t) if (IsSignalPresent(tile, x)) DrawSingleSignal(tile, t, GetSingleSignalState(tile, x), y, z)
02122
02123 if (!(rails & TRACK_BIT_Y)) {
02124 if (!(rails & TRACK_BIT_X)) {
02125 if (rails & TRACK_BIT_LEFT) {
02126 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTH, 0, TRACK_LEFT);
02127 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTH, 1, TRACK_LEFT);
02128 }
02129 if (rails & TRACK_BIT_RIGHT) {
02130 MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_NORTH, 2, TRACK_RIGHT);
02131 MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_SOUTH, 3, TRACK_RIGHT);
02132 }
02133 if (rails & TRACK_BIT_UPPER) {
02134 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_WEST, 4, TRACK_UPPER);
02135 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_EAST, 5, TRACK_UPPER);
02136 }
02137 if (rails & TRACK_BIT_LOWER) {
02138 MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_WEST, 6, TRACK_LOWER);
02139 MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_EAST, 7, TRACK_LOWER);
02140 }
02141 } else {
02142 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHWEST, 8, TRACK_X);
02143 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHEAST, 9, TRACK_X);
02144 }
02145 } else {
02146 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHEAST, 10, TRACK_Y);
02147 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHWEST, 11, TRACK_Y);
02148 }
02149 }
02150
02151 static void DrawTile_Track(TileInfo *ti)
02152 {
02153 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
02154
02155 _drawtile_track_palette = COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile));
02156
02157 if (IsPlainRail(ti->tile)) {
02158 TrackBits rails = GetTrackBits(ti->tile);
02159
02160 DrawTrackBits(ti, rails);
02161
02162 if (HasBit(_display_opt, DO_FULL_DETAIL)) DrawTrackDetails(ti, rti);
02163
02164 if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
02165
02166 if (HasSignals(ti->tile)) DrawSignals(ti->tile, rails);
02167 } else {
02168
02169 const DrawTileSprites *dts;
02170 PaletteID pal = PAL_NONE;
02171 SpriteID relocation;
02172
02173 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
02174
02175 if (IsInvisibilitySet(TO_BUILDINGS)) {
02176
02177 dts = &_depot_invisible_gfx_table[GetRailDepotDirection(ti->tile)];
02178 } else {
02179 dts = &_depot_gfx_table[GetRailDepotDirection(ti->tile)];
02180 }
02181
02182 SpriteID image;
02183 if (rti->UsesOverlay()) {
02184 image = SPR_FLAT_GRASS_TILE;
02185 } else {
02186 image = dts->ground.sprite;
02187 if (image != SPR_FLAT_GRASS_TILE) image += rti->total_offset;
02188 }
02189
02190
02191
02192 if (IsSnowRailGround(ti->tile) && _settings_game.game_creation.landscape == LT_TROPIC) {
02193 if (image != SPR_FLAT_GRASS_TILE) {
02194 image += rti->snow_offset;
02195 } else {
02196 image = SPR_FLAT_SNOW_DESERT_TILE;
02197 }
02198 }
02199
02200 DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, _drawtile_track_palette));
02201
02202 if (rti->UsesOverlay()) {
02203 SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
02204
02205 switch (GetRailDepotDirection(ti->tile)) {
02206 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02207 case DIAGDIR_SW: DrawGroundSprite(ground + RTO_X, PAL_NONE); break;
02208 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02209 case DIAGDIR_SE: DrawGroundSprite(ground + RTO_Y, PAL_NONE); break;
02210 default: break;
02211 }
02212
02213 if (_settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile)) {
02214 SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
02215
02216 switch (GetRailDepotDirection(ti->tile)) {
02217 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02218 case DIAGDIR_SW: DrawGroundSprite(overlay + RTO_X, PALETTE_CRASH); break;
02219 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02220 case DIAGDIR_SE: DrawGroundSprite(overlay + RTO_Y, PALETTE_CRASH); break;
02221 default: break;
02222 }
02223 }
02224
02225 relocation = GetCustomRailSprite(rti, ti->tile, RTSG_DEPOT);
02226 relocation -= SPR_RAIL_DEPOT_SE_1;
02227 } else {
02228
02229 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile)) {
02230 switch (GetRailDepotDirection(ti->tile)) {
02231 case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02232 case DIAGDIR_SW: DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH); break;
02233 case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break;
02234 case DIAGDIR_SE: DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH); break;
02235 default: break;
02236 }
02237 }
02238
02239 relocation = rti->total_offset;
02240 }
02241
02242 if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
02243
02244 DrawRailTileSeq(ti, dts, TO_BUILDINGS, relocation, 0, _drawtile_track_palette);
02245 }
02246 DrawBridgeMiddle(ti);
02247 }
02248
02249 void DrawTrainDepotSprite(int x, int y, int dir, RailType railtype)
02250 {
02251 const DrawTileSprites *dts = &_depot_gfx_table[dir];
02252 const RailtypeInfo *rti = GetRailTypeInfo(railtype);
02253 SpriteID image = rti->UsesOverlay() ? SPR_FLAT_GRASS_TILE : dts->ground.sprite;
02254 uint32 offset = rti->total_offset;
02255
02256 x += 33;
02257 y += 17;
02258
02259 if (image != SPR_FLAT_GRASS_TILE) image += offset;
02260 PaletteID palette = COMPANY_SPRITE_COLOUR(_local_company);
02261
02262 DrawSprite(image, PAL_NONE, x, y);
02263
02264 if (rti->UsesOverlay()) {
02265 SpriteID ground = GetCustomRailSprite(rti, INVALID_TILE, RTSG_GROUND);
02266
02267 switch (dir) {
02268 case DIAGDIR_SW: DrawSprite(ground + RTO_X, PAL_NONE, x, y); break;
02269 case DIAGDIR_SE: DrawSprite(ground + RTO_Y, PAL_NONE, x, y); break;
02270 default: break;
02271 }
02272
02273 offset = GetCustomRailSprite(rti, INVALID_TILE, RTSG_DEPOT);
02274 offset -= SPR_RAIL_DEPOT_SE_1;
02275 }
02276
02277 DrawRailTileSeqInGUI(x, y, dts, offset, 0, palette);
02278 }
02279
02280 static uint GetSlopeZ_Track(TileIndex tile, uint x, uint y)
02281 {
02282 uint z;
02283 Slope tileh = GetTileSlope(tile, &z);
02284
02285 if (tileh == SLOPE_FLAT) return z;
02286 if (IsPlainRail(tile)) {
02287 z += ApplyFoundationToSlope(GetRailFoundation(tileh, GetTrackBits(tile)), &tileh);
02288 return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
02289 } else {
02290 return z + TILE_HEIGHT;
02291 }
02292 }
02293
02294 static Foundation GetFoundation_Track(TileIndex tile, Slope tileh)
02295 {
02296 return IsPlainRail(tile) ? GetRailFoundation(tileh, GetTrackBits(tile)) : FlatteningFoundation(tileh);
02297 }
02298
02299 static void TileLoop_Track(TileIndex tile)
02300 {
02301 RailGroundType old_ground = GetRailGroundType(tile);
02302 RailGroundType new_ground;
02303
02304 if (old_ground == RAIL_GROUND_WATER) {
02305 TileLoop_Water(tile);
02306 return;
02307 }
02308
02309 switch (_settings_game.game_creation.landscape) {
02310 case LT_ARCTIC: {
02311 uint z;
02312 Slope slope = GetTileSlope(tile, &z);
02313 bool half = false;
02314
02315
02316
02317 if (IsPlainRail(tile)) {
02318 TrackBits track = GetTrackBits(tile);
02319 Foundation f = GetRailFoundation(slope, track);
02320
02321 switch (f) {
02322 case FOUNDATION_NONE:
02323
02324 if (IsSlopeWithThreeCornersRaised(slope)) z += TILE_HEIGHT;
02325 break;
02326
02327 case FOUNDATION_INCLINED_X:
02328 case FOUNDATION_INCLINED_Y:
02329
02330 if (IsSteepSlope(slope)) z += TILE_HEIGHT;
02331 break;
02332
02333 case FOUNDATION_STEEP_LOWER:
02334
02335 z += TILE_HEIGHT;
02336 break;
02337
02338 default:
02339
02340 if (IsSteepSlope(slope)) z += TILE_HEIGHT;
02341 z += TILE_HEIGHT;
02342 break;
02343 }
02344
02345 half = IsInsideMM(f, FOUNDATION_STEEP_BOTH, FOUNDATION_HALFTILE_N + 1);
02346 } else {
02347
02348 if (slope != SLOPE_FLAT) z += TILE_HEIGHT;
02349 }
02350
02351
02352
02353
02354
02355 if (z > GetSnowLine()) {
02356 if (half && z - GetSnowLine() == TILE_HEIGHT) {
02357
02358 new_ground = RAIL_GROUND_HALF_SNOW;
02359 } else {
02360 new_ground = RAIL_GROUND_ICE_DESERT;
02361 }
02362 goto set_ground;
02363 }
02364 break;
02365 }
02366
02367 case LT_TROPIC:
02368 if (GetTropicZone(tile) == TROPICZONE_DESERT) {
02369 new_ground = RAIL_GROUND_ICE_DESERT;
02370 goto set_ground;
02371 }
02372 break;
02373 }
02374
02375 if (!IsPlainRail(tile)) return;
02376
02377 new_ground = RAIL_GROUND_GRASS;
02378
02379 if (old_ground != RAIL_GROUND_BARREN) {
02380
02381 TrackBits rail = GetTrackBits(tile);
02382
02383 switch (rail) {
02384 case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
02385 case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
02386 case TRACK_BIT_LEFT: new_ground = RAIL_GROUND_FENCE_VERT1; break;
02387 case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2; break;
02388
02389 default: {
02390 Owner owner = GetTileOwner(tile);
02391
02392 if (rail == (TRACK_BIT_LOWER | TRACK_BIT_RIGHT) || (
02393 (rail & TRACK_BIT_3WAY_NW) == 0 &&
02394 (rail & TRACK_BIT_X)
02395 )) {
02396 TileIndex n = tile + TileDiffXY(0, -1);
02397 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02398
02399 if (!IsTileType(n, MP_RAILWAY) ||
02400 !IsTileOwner(n, owner) ||
02401 nrail == TRACK_BIT_UPPER ||
02402 nrail == TRACK_BIT_LEFT) {
02403 new_ground = RAIL_GROUND_FENCE_NW;
02404 }
02405 }
02406
02407 if (rail == (TRACK_BIT_UPPER | TRACK_BIT_LEFT) || (
02408 (rail & TRACK_BIT_3WAY_SE) == 0 &&
02409 (rail & TRACK_BIT_X)
02410 )) {
02411 TileIndex n = tile + TileDiffXY(0, 1);
02412 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02413
02414 if (!IsTileType(n, MP_RAILWAY) ||
02415 !IsTileOwner(n, owner) ||
02416 nrail == TRACK_BIT_LOWER ||
02417 nrail == TRACK_BIT_RIGHT) {
02418 new_ground = (new_ground == RAIL_GROUND_FENCE_NW) ?
02419 RAIL_GROUND_FENCE_SENW : RAIL_GROUND_FENCE_SE;
02420 }
02421 }
02422
02423 if (rail == (TRACK_BIT_LOWER | TRACK_BIT_LEFT) || (
02424 (rail & TRACK_BIT_3WAY_NE) == 0 &&
02425 (rail & TRACK_BIT_Y)
02426 )) {
02427 TileIndex n = tile + TileDiffXY(-1, 0);
02428 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02429
02430 if (!IsTileType(n, MP_RAILWAY) ||
02431 !IsTileOwner(n, owner) ||
02432 nrail == TRACK_BIT_UPPER ||
02433 nrail == TRACK_BIT_RIGHT) {
02434 new_ground = RAIL_GROUND_FENCE_NE;
02435 }
02436 }
02437
02438 if (rail == (TRACK_BIT_UPPER | TRACK_BIT_RIGHT) || (
02439 (rail & TRACK_BIT_3WAY_SW) == 0 &&
02440 (rail & TRACK_BIT_Y)
02441 )) {
02442 TileIndex n = tile + TileDiffXY(1, 0);
02443 TrackBits nrail = (IsPlainRailTile(n) ? GetTrackBits(n) : TRACK_BIT_NONE);
02444
02445 if (!IsTileType(n, MP_RAILWAY) ||
02446 !IsTileOwner(n, owner) ||
02447 nrail == TRACK_BIT_LOWER ||
02448 nrail == TRACK_BIT_LEFT) {
02449 new_ground = (new_ground == RAIL_GROUND_FENCE_NE) ?
02450 RAIL_GROUND_FENCE_NESW : RAIL_GROUND_FENCE_SW;
02451 }
02452 }
02453 break;
02454 }
02455 }
02456 }
02457
02458 set_ground:
02459 if (old_ground != new_ground) {
02460 SetRailGroundType(tile, new_ground);
02461 MarkTileDirtyByTile(tile);
02462 }
02463 }
02464
02465
02466 static TrackStatus GetTileTrackStatus_Track(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
02467 {
02468
02469 if (mode == TRANSPORT_WATER && IsPlainRail(tile) && GetRailGroundType(tile) == RAIL_GROUND_WATER) {
02470 TrackBits tb = GetTrackBits(tile);
02471 switch (tb) {
02472 default: NOT_REACHED();
02473 case TRACK_BIT_UPPER: tb = TRACK_BIT_LOWER; break;
02474 case TRACK_BIT_LOWER: tb = TRACK_BIT_UPPER; break;
02475 case TRACK_BIT_LEFT: tb = TRACK_BIT_RIGHT; break;
02476 case TRACK_BIT_RIGHT: tb = TRACK_BIT_LEFT; break;
02477 }
02478 return CombineTrackStatus(TrackBitsToTrackdirBits(tb), TRACKDIR_BIT_NONE);
02479 }
02480
02481 if (mode != TRANSPORT_RAIL) return 0;
02482
02483 TrackBits trackbits = TRACK_BIT_NONE;
02484 TrackdirBits red_signals = TRACKDIR_BIT_NONE;
02485
02486 switch (GetRailTileType(tile)) {
02487 default: NOT_REACHED();
02488 case RAIL_TILE_NORMAL:
02489 trackbits = GetTrackBits(tile);
02490 break;
02491
02492 case RAIL_TILE_SIGNALS: {
02493 trackbits = GetTrackBits(tile);
02494 byte a = GetPresentSignals(tile);
02495 uint b = GetSignalStates(tile);
02496
02497 b &= a;
02498
02499
02500
02501
02502
02503
02504 if (!IsOnewaySignal(tile, TRACK_UPPER) || (a & SignalOnTrack(TRACK_UPPER)) == 0) b |= ~a & SignalOnTrack(TRACK_UPPER);
02505 if (!IsOnewaySignal(tile, TRACK_LOWER) || (a & SignalOnTrack(TRACK_LOWER)) == 0) b |= ~a & SignalOnTrack(TRACK_LOWER);
02506
02507 if ((b & 0x8) == 0) red_signals |= (TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_X_NE | TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_UPPER_E);
02508 if ((b & 0x4) == 0) red_signals |= (TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_X_SW | TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_UPPER_W);
02509 if ((b & 0x2) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_LOWER_E);
02510 if ((b & 0x1) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_S | TRACKDIR_BIT_LOWER_W);
02511
02512 break;
02513 }
02514
02515 case RAIL_TILE_DEPOT: {
02516 DiagDirection dir = GetRailDepotDirection(tile);
02517
02518 if (side != INVALID_DIAGDIR && side != dir) break;
02519
02520 trackbits = DiagDirToDiagTrackBits(dir);
02521 break;
02522 }
02523 }
02524
02525 return CombineTrackStatus(TrackBitsToTrackdirBits(trackbits), red_signals);
02526 }
02527
02528 static bool ClickTile_Track(TileIndex tile)
02529 {
02530 if (!IsRailDepot(tile)) return false;
02531
02532 ShowDepotWindow(tile, VEH_TRAIN);
02533 return true;
02534 }
02535
02536 static void GetTileDesc_Track(TileIndex tile, TileDesc *td)
02537 {
02538 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(tile));
02539 td->rail_speed = rti->max_speed;
02540 td->owner[0] = GetTileOwner(tile);
02541 switch (GetRailTileType(tile)) {
02542 case RAIL_TILE_NORMAL:
02543 td->str = STR_LAI_RAIL_DESCRIPTION_TRACK;
02544 break;
02545
02546 case RAIL_TILE_SIGNALS: {
02547 static const StringID signal_type[6][6] = {
02548 {
02549 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS,
02550 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS,
02551 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS,
02552 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS,
02553 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS,
02554 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS
02555 },
02556 {
02557 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS,
02558 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRESIGNALS,
02559 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS,
02560 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS,
02561 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS,
02562 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS
02563 },
02564 {
02565 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS,
02566 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS,
02567 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXITSIGNALS,
02568 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS,
02569 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS,
02570 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS
02571 },
02572 {
02573 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS,
02574 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS,
02575 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS,
02576 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBOSIGNALS,
02577 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS,
02578 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS
02579 },
02580 {
02581 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS,
02582 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS,
02583 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS,
02584 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS,
02585 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBSSIGNALS,
02586 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS
02587 },
02588 {
02589 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS,
02590 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS,
02591 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS,
02592 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS,
02593 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS,
02594 STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRYSIGNALS
02595 }
02596 };
02597
02598 SignalType primary_signal;
02599 SignalType secondary_signal;
02600 if (HasSignalOnTrack(tile, TRACK_UPPER)) {
02601 primary_signal = GetSignalType(tile, TRACK_UPPER);
02602 secondary_signal = HasSignalOnTrack(tile, TRACK_LOWER) ? GetSignalType(tile, TRACK_LOWER) : primary_signal;
02603 } else {
02604 secondary_signal = primary_signal = GetSignalType(tile, TRACK_LOWER);
02605 }
02606
02607 td->str = signal_type[secondary_signal][primary_signal];
02608 break;
02609 }
02610
02611 case RAIL_TILE_DEPOT:
02612 td->str = STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT;
02613 if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL) {
02614 if (td->rail_speed > 0) {
02615 td->rail_speed = min(td->rail_speed, 61);
02616 } else {
02617 td->rail_speed = 61;
02618 }
02619 }
02620 break;
02621
02622 default:
02623 NOT_REACHED();
02624 }
02625 }
02626
02627 static void ChangeTileOwner_Track(TileIndex tile, Owner old_owner, Owner new_owner)
02628 {
02629 if (!IsTileOwner(tile, old_owner)) return;
02630
02631 if (new_owner != INVALID_OWNER) {
02632 SetTileOwner(tile, new_owner);
02633 } else {
02634 DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
02635 }
02636 }
02637
02638 static const byte _fractcoords_behind[4] = { 0x8F, 0x8, 0x80, 0xF8 };
02639 static const byte _fractcoords_enter[4] = { 0x8A, 0x48, 0x84, 0xA8 };
02640 static const int8 _deltacoord_leaveoffset[8] = {
02641 -1, 0, 1, 0,
02642 0, 1, 0, -1
02643 };
02644
02645
02651 int TicksToLeaveDepot(const Train *v)
02652 {
02653 DiagDirection dir = GetRailDepotDirection(v->tile);
02654 int length = v->tcache.cached_veh_length;
02655
02656 switch (dir) {
02657 case DIAGDIR_NE: return ((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) - (length + 1)));
02658 case DIAGDIR_SE: return -((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) + (length + 1)));
02659 case DIAGDIR_SW: return -((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) + (length + 1)));
02660 default:
02661 case DIAGDIR_NW: return ((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) - (length + 1)));
02662 }
02663
02664 return 0;
02665 }
02666
02669 static VehicleEnterTileStatus VehicleEnter_Track(Vehicle *u, TileIndex tile, int x, int y)
02670 {
02671
02672 if (u->type != VEH_TRAIN || !IsRailDepotTile(tile)) return VETSB_CONTINUE;
02673
02674 Train *v = Train::From(u);
02675
02676
02677 DiagDirection dir = GetRailDepotDirection(tile);
02678
02679
02680
02681 int length = v->tcache.cached_veh_length;
02682
02683 byte fract_coord_leave =
02684 ((_fractcoords_enter[dir] & 0x0F) +
02685 (length + 1) * _deltacoord_leaveoffset[dir]) +
02686 (((_fractcoords_enter[dir] >> 4) +
02687 ((length + 1) * _deltacoord_leaveoffset[dir + 4])) << 4);
02688
02689 byte fract_coord = (x & 0xF) + ((y & 0xF) << 4);
02690
02691 if (_fractcoords_behind[dir] == fract_coord) {
02692
02693 return VETSB_CANNOT_ENTER;
02694 } else if (_fractcoords_enter[dir] == fract_coord) {
02695 if (DiagDirToDir(ReverseDiagDir(dir)) == v->direction) {
02696
02697 v->track = TRACK_BIT_DEPOT,
02698 v->vehstatus |= VS_HIDDEN;
02699 v->direction = ReverseDir(v->direction);
02700 if (v->Next() == NULL) VehicleEnterDepot(v->First());
02701 v->tile = tile;
02702
02703 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
02704 return VETSB_ENTERED_WORMHOLE;
02705 }
02706 } else if (fract_coord_leave == fract_coord) {
02707 if (DiagDirToDir(dir) == v->direction) {
02708
02709 if ((v = v->Next()) != NULL) {
02710 v->vehstatus &= ~VS_HIDDEN;
02711 v->track = (DiagDirToAxis(dir) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y);
02712 }
02713 }
02714 }
02715
02716 return VETSB_CONTINUE;
02717 }
02718
02730 static CommandCost TestAutoslopeOnRailTile(TileIndex tile, uint flags, uint z_old, Slope tileh_old, uint z_new, Slope tileh_new, TrackBits rail_bits)
02731 {
02732 if (!_settings_game.construction.build_on_slopes || !AutoslopeEnabled()) return CMD_ERROR;
02733
02734
02735 if (CheckRailSlope(tileh_new, rail_bits, TRACK_BIT_NONE, tile).Failed()) return CMD_ERROR;
02736
02737
02738 z_old += ApplyFoundationToSlope(GetRailFoundation(tileh_old, rail_bits), &tileh_old);
02739 z_new += ApplyFoundationToSlope(GetRailFoundation(tileh_new, rail_bits), &tileh_new);
02740
02741 Corner track_corner;
02742 switch (rail_bits) {
02743 case TRACK_BIT_LEFT: track_corner = CORNER_W; break;
02744 case TRACK_BIT_LOWER: track_corner = CORNER_S; break;
02745 case TRACK_BIT_RIGHT: track_corner = CORNER_E; break;
02746 case TRACK_BIT_UPPER: track_corner = CORNER_N; break;
02747
02748
02749 default: return (((z_old != z_new) || (tileh_old != tileh_new)) ? CMD_ERROR : CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]));
02750 }
02751
02752
02753 z_old += GetSlopeZInCorner(RemoveHalftileSlope(tileh_old), track_corner);
02754 z_new += GetSlopeZInCorner(RemoveHalftileSlope(tileh_new), track_corner);
02755 if (z_old != z_new) return CMD_ERROR;
02756
02757 CommandCost cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02758
02759 if (tileh_old != tileh_new) {
02760
02761 if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old)) cost.AddCost(_price[PR_CLEAR_WATER]);
02762 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
02763 }
02764 return cost;
02765 }
02766
02767 static CommandCost TerraformTile_Track(TileIndex tile, DoCommandFlag flags, uint z_new, Slope tileh_new)
02768 {
02769 uint z_old;
02770 Slope tileh_old = GetTileSlope(tile, &z_old);
02771 if (IsPlainRail(tile)) {
02772 TrackBits rail_bits = GetTrackBits(tile);
02773
02774 bool was_water = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old));
02775
02776 _error_message = STR_ERROR_MUST_REMOVE_RAILROAD_TRACK;
02777
02778
02779 CommandCost autoslope_result = TestAutoslopeOnRailTile(tile, flags, z_old, tileh_old, z_new, tileh_new, rail_bits);
02780
02781
02782 Corner allowed_corner;
02783 switch (rail_bits) {
02784 case TRACK_BIT_RIGHT: allowed_corner = CORNER_W; break;
02785 case TRACK_BIT_UPPER: allowed_corner = CORNER_S; break;
02786 case TRACK_BIT_LEFT: allowed_corner = CORNER_E; break;
02787 case TRACK_BIT_LOWER: allowed_corner = CORNER_N; break;
02788 default: return autoslope_result;
02789 }
02790
02791 Foundation f_old = GetRailFoundation(tileh_old, rail_bits);
02792
02793
02794 if (tileh_old != SLOPE_NS && tileh_old != SLOPE_EW && IsSpecialRailFoundation(f_old)) return autoslope_result;
02795
02796
02797 for (Corner corner = (Corner)0; corner < CORNER_END; corner = (Corner)(corner + 1)) {
02798 if (allowed_corner == corner) continue;
02799 if (z_old + GetSlopeZInCorner(tileh_old, corner) != z_new + GetSlopeZInCorner(tileh_new, corner)) return autoslope_result;
02800 }
02801
02802
02803 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
02804
02805
02806 return CommandCost(EXPENSES_CONSTRUCTION, was_water ? _price[PR_CLEAR_WATER] : (Money)0);
02807 } else if (_settings_game.construction.build_on_slopes && AutoslopeEnabled() &&
02808 AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetRailDepotDirection(tile))) {
02809 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
02810 }
02811 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
02812 }
02813
02814
02815 extern const TileTypeProcs _tile_type_rail_procs = {
02816 DrawTile_Track,
02817 GetSlopeZ_Track,
02818 ClearTile_Track,
02819 NULL,
02820 GetTileDesc_Track,
02821 GetTileTrackStatus_Track,
02822 ClickTile_Track,
02823 NULL,
02824 TileLoop_Track,
02825 ChangeTileOwner_Track,
02826 NULL,
02827 VehicleEnter_Track,
02828 GetFoundation_Track,
02829 TerraformTile_Track,
02830 };