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