00001
00002
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007 #include "bridge_map.h"
00008 #include "bridge.h"
00009 #include "cmd_helper.h"
00010 #include "debug.h"
00011 #include "tile_cmd.h"
00012 #include "rail_map.h"
00013 #include "road_map.h"
00014 #include "landscape.h"
00015 #include "town_map.h"
00016 #include "tunnel_map.h"
00017 #include "viewport_func.h"
00018 #include "command_func.h"
00019 #include "pathfind.h"
00020 #include "engine.h"
00021 #include "town.h"
00022 #include "station.h"
00023 #include "sprite.h"
00024 #include "depot.h"
00025 #include "waypoint.h"
00026 #include "rail.h"
00027 #include "newgrf.h"
00028 #include "yapf/yapf.h"
00029 #include "newgrf_engine.h"
00030 #include "newgrf_callbacks.h"
00031 #include "newgrf_station.h"
00032 #include "train.h"
00033 #include "variables.h"
00034 #include "autoslope.h"
00035 #include "transparency.h"
00036 #include "water.h"
00037 #include "tunnelbridge_map.h"
00038 #include "window_func.h"
00039 #include "vehicle_func.h"
00040 #include "sound_func.h"
00041 #include "signal_func.h"
00042 #include "tunnelbridge.h"
00043
00044 #include "table/sprites.h"
00045 #include "table/strings.h"
00046 #include "table/railtypes.h"
00047 #include "table/track_land.h"
00048
00049 const byte _track_sloped_sprites[14] = {
00050 14, 15, 22, 13,
00051 0, 21, 17, 12,
00052 23, 0, 18, 20,
00053 19, 16
00054 };
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089 void *EnsureNoTrainOnTrackProc(Vehicle *v, void *data)
00090 {
00091 TrackBits rail_bits = *(TrackBits *)data;
00092
00093 if (v->type != VEH_TRAIN) return NULL;
00094
00095 if ((v->u.rail.track != rail_bits) && !TracksOverlap(v->u.rail.track | rail_bits)) return NULL;
00096
00097 _error_message = VehicleInTheWayErrMsg(v);
00098 return v;
00099 }
00100
00108 static bool EnsureNoTrainOnTrack(TileIndex tile, Track track)
00109 {
00110 TrackBits rail_bits = TrackToTrackBits(track);
00111
00112 return !HasVehicleOnPos(tile, &rail_bits, &EnsureNoTrainOnTrackProc);
00113 }
00114
00115 static bool CheckTrackCombination(TileIndex tile, TrackBits to_build, uint flags)
00116 {
00117 TrackBits current;
00118 TrackBits future;
00119 _error_message = STR_1001_IMPOSSIBLE_TRACK_COMBINATION;
00120
00121 if (!IsPlainRailTile(tile)) return false;
00122
00123
00124
00125 current = GetTrackBits(tile);
00126 future = current | to_build;
00127
00128
00129 if (current == future) {
00130
00131 _error_message = STR_1007_ALREADY_BUILT;
00132 return false;
00133 }
00134
00135
00136 if (flags & DC_NO_RAIL_OVERLAP || HasSignals(tile)) {
00137
00138
00139 return future == TRACK_BIT_HORZ || future == TRACK_BIT_VERT;
00140 } else {
00141
00142 return true;
00143 }
00144 }
00145
00146
00148 static const TrackBits _valid_tracks_without_foundation[15] = {
00149 TRACK_BIT_ALL,
00150 TRACK_BIT_RIGHT,
00151 TRACK_BIT_UPPER,
00152 TRACK_BIT_X,
00153
00154 TRACK_BIT_LEFT,
00155 TRACK_BIT_NONE,
00156 TRACK_BIT_Y,
00157 TRACK_BIT_LOWER,
00158
00159 TRACK_BIT_LOWER,
00160 TRACK_BIT_Y,
00161 TRACK_BIT_NONE,
00162 TRACK_BIT_LEFT,
00163
00164 TRACK_BIT_X,
00165 TRACK_BIT_UPPER,
00166 TRACK_BIT_RIGHT,
00167 };
00168
00170 static const TrackBits _valid_tracks_on_leveled_foundation[15] = {
00171 TRACK_BIT_NONE,
00172 TRACK_BIT_LEFT,
00173 TRACK_BIT_LOWER,
00174 TRACK_BIT_Y | TRACK_BIT_LOWER | TRACK_BIT_LEFT,
00175
00176 TRACK_BIT_RIGHT,
00177 TRACK_BIT_ALL,
00178 TRACK_BIT_X | TRACK_BIT_LOWER | TRACK_BIT_RIGHT,
00179 TRACK_BIT_ALL,
00180
00181 TRACK_BIT_UPPER,
00182 TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_LEFT,
00183 TRACK_BIT_ALL,
00184 TRACK_BIT_ALL,
00185
00186 TRACK_BIT_Y | TRACK_BIT_UPPER | TRACK_BIT_RIGHT,
00187 TRACK_BIT_ALL,
00188 TRACK_BIT_ALL
00189 };
00190
00198 Foundation GetRailFoundation(Slope tileh, TrackBits bits)
00199 {
00200 if (bits == TRACK_BIT_NONE) return FOUNDATION_NONE;
00201
00202 if (IsSteepSlope(tileh)) {
00203
00204 if (bits == TRACK_BIT_X) return FOUNDATION_INCLINED_X;
00205 if (bits == TRACK_BIT_Y) return FOUNDATION_INCLINED_Y;
00206
00207
00208 Corner highest_corner = GetHighestSlopeCorner(tileh);
00209 TrackBits higher_track = CornerToTrackBits(highest_corner);
00210
00211
00212 if (bits == higher_track) return HalftileFoundation(highest_corner);
00213
00214
00215 if (TracksOverlap(bits | higher_track)) return FOUNDATION_INVALID;
00216
00217
00218 return ((bits & higher_track) != 0 ? FOUNDATION_STEEP_BOTH : FOUNDATION_STEEP_LOWER);
00219 } else {
00220 if ((~_valid_tracks_without_foundation[tileh] & bits) == 0) return FOUNDATION_NONE;
00221
00222 bool valid_on_leveled = ((~_valid_tracks_on_leveled_foundation[tileh] & bits) == 0);
00223
00224 Corner track_corner;
00225 switch (bits) {
00226 case TRACK_BIT_LEFT: track_corner = CORNER_W; break;
00227 case TRACK_BIT_LOWER: track_corner = CORNER_S; break;
00228 case TRACK_BIT_RIGHT: track_corner = CORNER_E; break;
00229 case TRACK_BIT_UPPER: track_corner = CORNER_N; break;
00230
00231 case TRACK_BIT_HORZ:
00232 if (tileh == SLOPE_N) return HalftileFoundation(CORNER_N);
00233 if (tileh == SLOPE_S) return HalftileFoundation(CORNER_S);
00234 return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
00235
00236 case TRACK_BIT_VERT:
00237 if (tileh == SLOPE_W) return HalftileFoundation(CORNER_W);
00238 if (tileh == SLOPE_E) return HalftileFoundation(CORNER_E);
00239 return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
00240
00241 case TRACK_BIT_X:
00242 if (IsSlopeWithOneCornerRaised(tileh)) return FOUNDATION_INCLINED_X;
00243 return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
00244
00245 case TRACK_BIT_Y:
00246 if (IsSlopeWithOneCornerRaised(tileh)) return FOUNDATION_INCLINED_Y;
00247 return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
00248
00249 default:
00250 return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
00251 }
00252
00253
00254
00255 if (!valid_on_leveled) return FOUNDATION_INVALID;
00256
00257
00258 if (IsSlopeWithThreeCornersRaised(tileh)) return FOUNDATION_LEVELED;
00259
00260
00261 if ((tileh & SlopeWithThreeCornersRaised(OppositeCorner(track_corner))) == SlopeWithOneCornerRaised(track_corner)) return HalftileFoundation(track_corner);
00262
00263
00264 return SpecialRailFoundation(track_corner);
00265 }
00266 }
00267
00268
00278 static CommandCost CheckRailSlope(Slope tileh, TrackBits rail_bits, TrackBits existing, TileIndex tile)
00279 {
00280
00281 if (IsTileType(tile, MP_WATER) || (IsTileType(tile, MP_RAILWAY) && (GetRailGroundType(tile) == RAIL_GROUND_WATER))) {
00282 if (!IsSteepSlope(tileh) && ((~_valid_tracks_on_leveled_foundation[tileh] & (rail_bits | existing)) != 0)) return_cmd_error(STR_3807_CAN_T_BUILD_ON_WATER);
00283 }
00284
00285 Foundation f_new = GetRailFoundation(tileh, rail_bits | existing);
00286
00287
00288 if ((f_new == FOUNDATION_INVALID) ||
00289 ((f_new != FOUNDATION_NONE) && (!_patches.build_on_slopes || _is_old_ai_player))
00290 ) return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
00291
00292 Foundation f_old = GetRailFoundation(tileh, existing);
00293 return CommandCost(EXPENSES_CONSTRUCTION, f_new != f_old ? _price.terraform : (Money)0);
00294 }
00295
00296
00297 static inline bool ValParamTrackOrientation(Track track) {return IsValidTrack(track);}
00298
00305 CommandCost CmdBuildSingleRail(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
00306 {
00307 Slope tileh;
00308 RailType railtype = (RailType)p1;
00309 Track track = (Track)p2;
00310 TrackBits trackbit;
00311 CommandCost cost(EXPENSES_CONSTRUCTION);
00312 CommandCost ret;
00313
00314 if (!ValParamRailtype(railtype) || !ValParamTrackOrientation(track)) return CMD_ERROR;
00315
00316 tileh = GetTileSlope(tile, NULL);
00317 trackbit = TrackToTrackBits(track);
00318
00319 switch (GetTileType(tile)) {
00320 case MP_RAILWAY:
00321 if (!CheckTrackCombination(tile, trackbit, flags) ||
00322 !EnsureNoTrainOnTrack(tile, track)) {
00323 return CMD_ERROR;
00324 }
00325 if (!IsTileOwner(tile, _current_player) ||
00326 !IsCompatibleRail(GetRailType(tile), railtype)) {
00327
00328 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00329 }
00330
00331 ret = CheckRailSlope(tileh, trackbit, GetTrackBits(tile), tile);
00332 if (CmdFailed(ret)) return ret;
00333 cost.AddCost(ret);
00334
00335
00336
00337 if (GetRailType(tile) != railtype && HasPowerOnRail(GetRailType(tile), railtype)) {
00338 ret = DoCommand(tile, tile, railtype, flags, CMD_CONVERT_RAIL);
00339 if (CmdFailed(ret)) return ret;
00340 cost.AddCost(ret);
00341 }
00342
00343 if (flags & DC_EXEC) {
00344 SetRailGroundType(tile, RAIL_GROUND_BARREN);
00345 SetTrackBits(tile, GetTrackBits(tile) | trackbit);
00346 }
00347 break;
00348
00349 case MP_ROAD:
00350 #define M(x) (1 << (x))
00351
00352 if (!HasBit(M(SLOPE_SEN) | M(SLOPE_ENW) | M(SLOPE_NWS) | M(SLOPE_NS) | M(SLOPE_WSE) | M(SLOPE_EW) | M(SLOPE_FLAT), tileh)) {
00353 return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
00354 }
00355 #undef M
00356
00357 if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
00358
00359 if (IsNormalRoad(tile)) {
00360 if (HasRoadWorks(tile)) return_cmd_error(STR_ROAD_WORKS_IN_PROGRESS);
00361
00362 if (GetDisallowedRoadDirections(tile) != DRD_NONE) return_cmd_error(STR_ERR_CROSSING_ON_ONEWAY_ROAD);
00363
00364 RoadTypes roadtypes = GetRoadTypes(tile);
00365 RoadBits road = GetRoadBits(tile, ROADTYPE_ROAD);
00366 RoadBits tram = GetRoadBits(tile, ROADTYPE_TRAM);
00367 switch (roadtypes) {
00368 default: break;
00369 case ROADTYPES_TRAM:
00370
00371 if (flags & DC_EXEC) SetRoadOwner(tile, ROADTYPE_ROAD, _current_player);
00372 roadtypes |= ROADTYPES_ROAD;
00373 break;
00374
00375 case ROADTYPES_ROADTRAM: if (road == tram) break;
00376
00377 case ROADTYPES_ROADHWAY:
00378 case ROADTYPES_TRAMHWAY:
00379 case ROADTYPES_ALL:
00380 return CMD_ERROR;
00381 }
00382
00383 road |= tram | GetRoadBits(tile, ROADTYPE_HWAY);
00384
00385 if ((track == TRACK_X && road == ROAD_Y) ||
00386 (track == TRACK_Y && road == ROAD_X)) {
00387 if (flags & DC_EXEC) {
00388 MakeRoadCrossing(tile, GetRoadOwner(tile, ROADTYPE_ROAD), GetRoadOwner(tile, ROADTYPE_TRAM), GetRoadOwner(tile, ROADTYPE_HWAY), _current_player, (track == TRACK_X ? AXIS_Y : AXIS_X), railtype, roadtypes, GetTownIndex(tile));
00389 UpdateLevelCrossing(tile, false);
00390 }
00391 break;
00392 }
00393 }
00394
00395 if (IsLevelCrossing(tile) && GetCrossingRailBits(tile) == trackbit) {
00396 return_cmd_error(STR_1007_ALREADY_BUILT);
00397 }
00398
00399
00400 default:
00401
00402 bool water_ground = IsTileType(tile, MP_WATER) && IsSlopeWithOneCornerRaised(tileh);
00403
00404 ret = CheckRailSlope(tileh, trackbit, TRACK_BIT_NONE, tile);
00405 if (CmdFailed(ret)) return ret;
00406 cost.AddCost(ret);
00407
00408 ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00409 if (CmdFailed(ret)) return ret;
00410 cost.AddCost(ret);
00411
00412 if (water_ground) {
00413 cost.AddCost(-_price.clear_water);
00414 cost.AddCost(_price.clear_roughland);
00415 }
00416
00417 if (flags & DC_EXEC) {
00418 MakeRailNormal(tile, _current_player, trackbit, railtype);
00419 if (water_ground) SetRailGroundType(tile, RAIL_GROUND_WATER);
00420 }
00421 break;
00422 }
00423
00424 if (flags & DC_EXEC) {
00425 MarkTileDirtyByTile(tile);
00426 AddTrackToSignalBuffer(tile, track, _current_player);
00427 YapfNotifyTrackLayoutChange(tile, track);
00428 }
00429
00430 return cost.AddCost(RailBuildCost(railtype));
00431 }
00432
00439 CommandCost CmdRemoveSingleRail(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
00440 {
00441 Track track = (Track)p2;
00442 TrackBits trackbit;
00443 CommandCost cost(EXPENSES_CONSTRUCTION, _price.remove_rail );
00444 bool crossing = false;
00445
00446 if (!ValParamTrackOrientation((Track)p2)) return CMD_ERROR;
00447 trackbit = TrackToTrackBits(track);
00448
00449
00450
00451
00452
00453 Owner owner = INVALID_OWNER;
00454
00455 switch (GetTileType(tile)) {
00456 case MP_ROAD: {
00457 if (!IsLevelCrossing(tile) ||
00458 GetCrossingRailBits(tile) != trackbit ||
00459 (_current_player != OWNER_WATER && !CheckTileOwnership(tile)) ||
00460 (!(flags & DC_BANKRUPT) && !EnsureNoVehicleOnGround(tile))) {
00461 return CMD_ERROR;
00462 }
00463
00464 if (flags & DC_EXEC) {
00465 owner = GetTileOwner(tile);
00466 MakeRoadNormal(tile, GetCrossingRoadBits(tile), GetRoadTypes(tile), GetTownIndex(tile), GetRoadOwner(tile, ROADTYPE_ROAD), GetRoadOwner(tile, ROADTYPE_TRAM), GetRoadOwner(tile, ROADTYPE_HWAY));
00467 }
00468 break;
00469 }
00470
00471 case MP_RAILWAY: {
00472 TrackBits present;
00473
00474 if (!IsPlainRailTile(tile) ||
00475 (_current_player != OWNER_WATER && !CheckTileOwnership(tile)) ||
00476 !EnsureNoTrainOnTrack(tile, track)) {
00477 return CMD_ERROR;
00478 }
00479
00480 present = GetTrackBits(tile);
00481 if ((present & trackbit) == 0) return CMD_ERROR;
00482 if (present == (TRACK_BIT_X | TRACK_BIT_Y)) crossing = true;
00483
00484
00485 if (HasSignalOnTrack(tile, track))
00486 cost.AddCost(DoCommand(tile, track, 0, flags, CMD_REMOVE_SIGNALS));
00487
00488 if (flags & DC_EXEC) {
00489 owner = GetTileOwner(tile);
00490 present ^= trackbit;
00491 if (present == 0) {
00492 Slope tileh = GetTileSlope(tile, NULL);
00493
00494 if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh)) {
00495 MakeShore(tile);
00496 } else {
00497 DoClearSquare(tile);
00498 }
00499 } else {
00500 SetTrackBits(tile, present);
00501 }
00502 }
00503 break;
00504 }
00505
00506 default: return CMD_ERROR;
00507 }
00508
00509 if (flags & DC_EXEC) {
00510
00511 assert(IsValidPlayer(owner));
00512
00513 MarkTileDirtyByTile(tile);
00514 if (crossing) {
00515
00516
00517
00518
00519 AddTrackToSignalBuffer(tile, TRACK_X, owner);
00520 AddTrackToSignalBuffer(tile, TRACK_Y, owner);
00521 YapfNotifyTrackLayoutChange(tile, TRACK_X);
00522 YapfNotifyTrackLayoutChange(tile, TRACK_Y);
00523 } else {
00524 AddTrackToSignalBuffer(tile, track, owner);
00525 YapfNotifyTrackLayoutChange(tile, track);
00526 }
00527 }
00528
00529 return cost;
00530 }
00531
00532
00540 bool FloodHalftile(TileIndex t)
00541 {
00542 bool flooded = false;
00543 if (GetRailGroundType(t) == RAIL_GROUND_WATER) return flooded;
00544
00545 Slope tileh = GetTileSlope(t, NULL);
00546 TrackBits rail_bits = GetTrackBits(t);
00547
00548 if (IsSlopeWithOneCornerRaised(tileh)) {
00549 TrackBits lower_track = CornerToTrackBits(OppositeCorner(GetHighestSlopeCorner(tileh)));
00550
00551 TrackBits to_remove = lower_track & rail_bits;
00552 if (to_remove != 0) {
00553 _current_player = OWNER_WATER;
00554 if (CmdFailed(DoCommand(t, 0, FIND_FIRST_BIT(to_remove), DC_EXEC, CMD_REMOVE_SINGLE_RAIL))) return flooded;
00555 flooded = true;
00556 rail_bits = rail_bits & ~to_remove;
00557 if (rail_bits == 0) {
00558 MakeShore(t);
00559 MarkTileDirtyByTile(t);
00560 return flooded;
00561 }
00562 }
00563
00564 if (IsNonContinuousFoundation(GetRailFoundation(tileh, rail_bits))) {
00565 flooded = true;
00566 SetRailGroundType(t, RAIL_GROUND_WATER);
00567 MarkTileDirtyByTile(t);
00568 }
00569 } else {
00570
00571 if (ApplyFoundationToSlope(GetRailFoundation(tileh, rail_bits), &tileh) == 0) {
00572 if (IsSteepSlope(tileh) || IsSlopeWithThreeCornersRaised(tileh)) {
00573 flooded = true;
00574 SetRailGroundType(t, RAIL_GROUND_WATER);
00575 MarkTileDirtyByTile(t);
00576 }
00577 }
00578 }
00579 return flooded;
00580 }
00581
00582 static const TileIndexDiffC _trackdelta[] = {
00583 { -1, 0 }, { 0, 1 }, { -1, 0 }, { 0, 1 }, { 1, 0 }, { 0, 1 },
00584 { 0, 0 },
00585 { 0, 0 },
00586 { 1, 0 }, { 0, -1 }, { 0, -1 }, { 1, 0 }, { 0, -1 }, { -1, 0 },
00587 { 0, 0 },
00588 { 0, 0 }
00589 };
00590
00591
00592 static CommandCost ValidateAutoDrag(Trackdir *trackdir, TileIndex start, TileIndex end)
00593 {
00594 int x = TileX(start);
00595 int y = TileY(start);
00596 int ex = TileX(end);
00597 int ey = TileY(end);
00598 int dx, dy, trdx, trdy;
00599
00600 if (!ValParamTrackOrientation(TrackdirToTrack(*trackdir))) return CMD_ERROR;
00601
00602
00603 dx = ex - x;
00604 dy = ey - y;
00605
00606
00607 trdx = _trackdelta[*trackdir].x;
00608 trdy = _trackdelta[*trackdir].y;
00609
00610 if (!IsDiagonalTrackdir(*trackdir)) {
00611 trdx += _trackdelta[*trackdir ^ 1].x;
00612 trdy += _trackdelta[*trackdir ^ 1].y;
00613 }
00614
00615
00616 while (
00617 (trdx <= 0 && dx > 0) ||
00618 (trdx >= 0 && dx < 0) ||
00619 (trdy <= 0 && dy > 0) ||
00620 (trdy >= 0 && dy < 0)
00621 ) {
00622 if (!HasBit(*trackdir, 3)) {
00623 SetBit(*trackdir, 3);
00624 trdx = -trdx;
00625 trdy = -trdy;
00626 } else {
00627 return CMD_ERROR;
00628 }
00629 }
00630
00631
00632
00633 if (!IsDiagonalTrackdir(*trackdir)) {
00634 trdx = _trackdelta[*trackdir].x;
00635 trdy = _trackdelta[*trackdir].y;
00636 if (abs(dx) != abs(dy) && abs(dx) + abs(trdy) != abs(dy) + abs(trdx))
00637 return CMD_ERROR;
00638 }
00639
00640 return CommandCost();
00641 }
00642
00652 static CommandCost CmdRailTrackHelper(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
00653 {
00654 CommandCost ret, total_cost(EXPENSES_CONSTRUCTION);
00655 Track track = (Track)GB(p2, 4, 3);
00656 Trackdir trackdir;
00657 byte mode = HasBit(p2, 7);
00658 RailType railtype = (RailType)GB(p2, 0, 4);
00659 TileIndex end_tile;
00660
00661 if (!ValParamRailtype(railtype) || !ValParamTrackOrientation(track)) return CMD_ERROR;
00662 if (p1 >= MapSize()) return CMD_ERROR;
00663 end_tile = p1;
00664 trackdir = TrackToTrackdir(track);
00665
00666 if (CmdFailed(ValidateAutoDrag(&trackdir, tile, end_tile))) return CMD_ERROR;
00667
00668 if (flags & DC_EXEC) SndPlayTileFx(SND_20_SPLAT_2, tile);
00669
00670 for (;;) {
00671 ret = DoCommand(tile, railtype, TrackdirToTrack(trackdir), flags, (mode == 0) ? CMD_BUILD_SINGLE_RAIL : CMD_REMOVE_SINGLE_RAIL);
00672
00673 if (CmdFailed(ret)) {
00674 if ((_error_message != STR_1007_ALREADY_BUILT) && (mode == 0)) break;
00675 _error_message = INVALID_STRING_ID;
00676 } else {
00677 total_cost.AddCost(ret);
00678 }
00679
00680 if (tile == end_tile) break;
00681
00682 tile += ToTileIndexDiff(_trackdelta[trackdir]);
00683
00684
00685 if (!IsDiagonalTrackdir(trackdir)) ToggleBit(trackdir, 0);
00686 }
00687
00688 return (total_cost.GetCost() == 0) ? CMD_ERROR : total_cost;
00689 }
00690
00702 CommandCost CmdBuildRailroadTrack(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
00703 {
00704 return CmdRailTrackHelper(tile, flags, p1, ClrBit(p2, 7));
00705 }
00706
00718 CommandCost CmdRemoveRailroadTrack(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
00719 {
00720 return CmdRailTrackHelper(tile, flags, p1, SetBit(p2, 7));
00721 }
00722
00732 CommandCost CmdBuildTrainDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
00733 {
00734 Slope tileh;
00735
00736
00737 if (!ValParamRailtype((RailType)p1)) return CMD_ERROR;
00738
00739 tileh = GetTileSlope(tile, NULL);
00740
00741 DiagDirection dir = Extract<DiagDirection, 0>(p2);
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751 if (tileh != SLOPE_FLAT && (
00752 _is_old_ai_player ||
00753 !_patches.build_on_slopes ||
00754 IsSteepSlope(tileh) ||
00755 !CanBuildDepotByTileh(dir, tileh)
00756 )) {
00757 return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
00758 }
00759
00760 CommandCost cost = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00761 if (CmdFailed(cost)) return CMD_ERROR;
00762
00763 if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
00764
00765 if (!Depot::CanAllocateItem()) return CMD_ERROR;
00766
00767 if (flags & DC_EXEC) {
00768 Depot *d = new Depot(tile);
00769 MakeRailDepot(tile, _current_player, dir, (RailType)p1);
00770 MarkTileDirtyByTile(tile);
00771
00772 d->town_index = ClosestTownFromTile(tile, (uint)-1)->index;
00773
00774 AddSideToSignalBuffer(tile, INVALID_DIAGDIR, _current_player);
00775 YapfNotifyTrackLayoutChange(tile, TrackdirToTrack(DiagdirToDiagTrackdir(dir)));
00776 }
00777
00778 return cost.AddCost(_price.build_train_depot);
00779 }
00780
00795 CommandCost CmdBuildSingleSignal(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
00796 {
00797 Track track = (Track)GB(p1, 0, 3);
00798 bool ctrl_pressed = HasBit(p1, 3);
00799 SignalVariant sigvar = (ctrl_pressed ^ HasBit(p1, 4)) ? SIG_SEMAPHORE : SIG_ELECTRIC;
00800 SignalType sigtype = (SignalType)GB(p1, 5, 2);
00801 bool convert_signal = HasBit(p1, 7);
00802 CommandCost cost;
00803
00804 if (!ValParamTrackOrientation(track) || !IsTileType(tile, MP_RAILWAY) || !EnsureNoTrainOnTrack(tile, track))
00805 return CMD_ERROR;
00806
00807
00808 if (p2 != 0 && (p2 & SignalOnTrack(track)) == 0) return CMD_ERROR;
00809
00810
00811 if (!IsPlainRailTile(tile) || !HasTrack(tile, track)) return CMD_ERROR;
00812
00813 if (!CheckTileOwnership(tile)) return CMD_ERROR;
00814
00815 {
00816
00817 TrackBits trackbits = GetTrackBits(tile);
00818 if (KillFirstBit(trackbits) != TRACK_BIT_NONE &&
00819 trackbits != TRACK_BIT_HORZ &&
00820 trackbits != TRACK_BIT_VERT) {
00821 return_cmd_error(STR_1005_NO_SUITABLE_RAILROAD_TRACK);
00822 }
00823 }
00824
00825
00826 if (convert_signal && !HasSignalOnTrack(tile, track)) return CMD_ERROR;
00827
00828 if (!HasSignalOnTrack(tile, track)) {
00829
00830 cost = CommandCost(EXPENSES_CONSTRUCTION, _price.build_signals);
00831 } else {
00832 if (p2 != 0 && sigvar != GetSignalVariant(tile, track)) {
00833
00834 cost = CommandCost(EXPENSES_CONSTRUCTION, _price.build_signals + _price.remove_signals);
00835
00836 } else if (convert_signal) {
00837
00838 if (ctrl_pressed || GetSignalVariant(tile, track) != sigvar) {
00839
00840 cost = CommandCost(EXPENSES_CONSTRUCTION, _price.build_signals + _price.remove_signals);
00841 } else {
00842
00843 cost = CommandCost();
00844 }
00845
00846 } else {
00847
00848 cost = CommandCost();
00849 }
00850 }
00851
00852 if (flags & DC_EXEC) {
00853 if (!HasSignals(tile)) {
00854
00855 SetHasSignals(tile, true);
00856 SetSignalStates(tile, 0xF);
00857 SetPresentSignals(tile, 0);
00858 SetSignalType(tile, track, sigtype);
00859 SetSignalVariant(tile, track, sigvar);
00860 }
00861
00862 if (p2 == 0) {
00863 if (!HasSignalOnTrack(tile, track)) {
00864
00865 SetPresentSignals(tile, GetPresentSignals(tile) | SignalOnTrack(track));
00866 SetSignalType(tile, track, sigtype);
00867 SetSignalVariant(tile, track, sigvar);
00868 } else {
00869 if (convert_signal) {
00870
00871 if (ctrl_pressed) {
00872
00873 SetSignalVariant(tile, track, (GetSignalVariant(tile, track) == SIG_ELECTRIC) ? SIG_SEMAPHORE : SIG_ELECTRIC);
00874
00875 } else {
00876
00877 SetSignalType(tile, track, sigtype);
00878 SetSignalVariant(tile, track, sigvar);
00879 }
00880
00881 } else if (ctrl_pressed) {
00882
00883 sigtype = GetSignalType(tile, track);
00884
00885 SetSignalType(tile, track, sigtype == SIGTYPE_COMBO ? SIGTYPE_NORMAL : (SignalType)(sigtype + 1));
00886 } else {
00887
00888 CycleSignalSide(tile, track);
00889 }
00890 }
00891 } else {
00892
00893
00894 SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | (p2 & SignalOnTrack(track)));
00895 SetSignalVariant(tile, track, sigvar);
00896 }
00897
00898 MarkTileDirtyByTile(tile);
00899 AddTrackToSignalBuffer(tile, track, _current_player);
00900 YapfNotifyTrackLayoutChange(tile, track);
00901 }
00902
00903 return cost;
00904 }
00905
00906 static bool CheckSignalAutoFill(TileIndex &tile, Trackdir &trackdir, int &signal_ctr, bool remove)
00907 {
00908 tile = AddTileIndexDiffCWrap(tile, _trackdelta[trackdir]);
00909 if (tile == INVALID_TILE) return false;
00910
00911
00912 TrackdirBits trackdirbits = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0));
00913
00914 if (TracksOverlap(TrackdirBitsToTrackBits(trackdirbits))) return false;
00915 trackdirbits &= TrackdirReachesTrackdirs(trackdir);
00916
00917
00918 if (trackdirbits == TRACKDIR_BIT_NONE) return false;
00919
00920
00921 trackdir = RemoveFirstTrackdir(&trackdirbits);
00922
00923
00924 if (trackdirbits != TRACKDIR_BIT_NONE) return false;
00925
00926 switch (GetTileType(tile)) {
00927 case MP_RAILWAY:
00928 if (IsRailDepot(tile)) return false;
00929 if (!remove && HasSignalOnTrack(tile, TrackdirToTrack(trackdir))) return false;
00930 signal_ctr++;
00931 if (IsDiagonalTrackdir(trackdir)) {
00932 signal_ctr++;
00933
00934 ClrBit(signal_ctr, 0);
00935 }
00936 return true;
00937
00938 case MP_ROAD:
00939 if (!IsLevelCrossing(tile)) return false;
00940 signal_ctr += 2;
00941 return true;
00942
00943 case MP_TUNNELBRIDGE: {
00944 TileIndex orig_tile = tile;
00945
00946 if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) return false;
00947 if (GetTunnelBridgeDirection(tile) != TrackdirToExitdir(trackdir)) return false;
00948
00949
00950
00951 tile = GetOtherTunnelBridgeEnd(tile);
00952
00953 signal_ctr += (GetTunnelBridgeLength(orig_tile, tile) + 2) * 2;
00954 return true;
00955 }
00956
00957 default: return false;
00958 }
00959 }
00960
00973 static CommandCost CmdSignalTrackHelper(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
00974 {
00975 CommandCost ret, total_cost(EXPENSES_CONSTRUCTION);
00976 int signal_ctr;
00977 byte signals;
00978 bool error = true;
00979 TileIndex end_tile;
00980 TileIndex start_tile = tile;
00981
00982 Track track = (Track)GB(p2, 0, 3);
00983 bool mode = HasBit(p2, 3);
00984 bool semaphores = HasBit(p2, 4);
00985 bool remove = HasBit(p2, 5);
00986 bool autofill = HasBit(p2, 6);
00987 Trackdir trackdir = TrackToTrackdir(track);
00988 byte signal_density = GB(p2, 24, 8);
00989
00990 if (p1 >= MapSize()) return CMD_ERROR;
00991 end_tile = p1;
00992 if (signal_density == 0 || signal_density > 20) return CMD_ERROR;
00993
00994 if (!IsTileType(tile, MP_RAILWAY)) return CMD_ERROR;
00995
00996
00997
00998 signal_density *= 2;
00999
01000 if (CmdFailed(ValidateAutoDrag(&trackdir, tile, end_tile))) return CMD_ERROR;
01001
01002 track = TrackdirToTrack(trackdir);
01003 Trackdir start_trackdir = trackdir;
01004
01005
01006 if (autofill && !HasTrack(tile, track)) return CMD_ERROR;
01007
01008
01009 if (HasSignals(tile)) {
01010 signals = GetPresentSignals(tile) & SignalOnTrack(track);
01011 if (signals == 0) signals = SignalOnTrack(track);
01012
01013
01014 semaphores = GetSignalVariant(tile, track) != SIG_ELECTRIC;
01015 } else {
01016 signals = SignalOnTrack(track);
01017 }
01018
01019 byte signal_dir = 0;
01020 if (signals & SignalAlongTrackdir(trackdir)) SetBit(signal_dir, 0);
01021 if (signals & SignalAgainstTrackdir(trackdir)) SetBit(signal_dir, 1);
01022
01023
01024
01025
01026
01027
01028
01029
01030
01031 signal_ctr = 0;
01032 for (;;) {
01033
01034 if ((remove && autofill) || signal_ctr % signal_density == 0) {
01035 uint32 p1 = GB(TrackdirToTrack(trackdir), 0, 3);
01036 SB(p1, 3, 1, mode);
01037 SB(p1, 4, 1, semaphores);
01038
01039
01040 signals = 0;
01041 if (HasBit(signal_dir, 0)) signals |= SignalAlongTrackdir(trackdir);
01042 if (HasBit(signal_dir, 1)) signals |= SignalAgainstTrackdir(trackdir);
01043
01044 ret = DoCommand(tile, p1, signals, flags, remove ? CMD_REMOVE_SIGNALS : CMD_BUILD_SIGNALS);
01045
01046
01047 if (CmdSucceeded(ret)) {
01048 error = false;
01049 total_cost.AddCost(ret);
01050 }
01051 }
01052
01053 if (autofill) {
01054 if (!CheckSignalAutoFill(tile, trackdir, signal_ctr, remove)) break;
01055
01056
01057 if (tile == start_tile && trackdir == start_trackdir) break;
01058 } else {
01059 if (tile == end_tile) break;
01060
01061 tile += ToTileIndexDiff(_trackdelta[trackdir]);
01062 signal_ctr++;
01063
01064
01065 if (IsDiagonalTrackdir(trackdir)) {
01066 signal_ctr++;
01067 } else {
01068 ToggleBit(trackdir, 0);
01069 }
01070 }
01071 }
01072
01073 return error ? CMD_ERROR : total_cost;
01074 }
01075
01090 CommandCost CmdBuildSignalTrack(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
01091 {
01092 return CmdSignalTrackHelper(tile, flags, p1, p2);
01093 }
01094
01104 CommandCost CmdRemoveSingleSignal(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
01105 {
01106 Track track = (Track)GB(p1, 0, 3);
01107
01108 if (!ValParamTrackOrientation(track) ||
01109 !IsTileType(tile, MP_RAILWAY) ||
01110 !HasTrack(tile, track) ||
01111 !EnsureNoTrainOnTrack(tile, track) ||
01112 !HasSignalOnTrack(tile, track)) {
01113 return CMD_ERROR;
01114 }
01115
01116
01117 if (_current_player != OWNER_WATER && !CheckTileOwnership(tile)) return CMD_ERROR;
01118
01119
01120 if (flags & DC_EXEC) {
01121 SetPresentSignals(tile, GetPresentSignals(tile) & ~SignalOnTrack(track));
01122
01123
01124 if (GetPresentSignals(tile) == 0) {
01125 SetSignalStates(tile, 0);
01126 SetHasSignals(tile, false);
01127 SetSignalVariant(tile, INVALID_TRACK, SIG_ELECTRIC);
01128 }
01129
01130 AddTrackToSignalBuffer(tile, track, GetTileOwner(tile));
01131 YapfNotifyTrackLayoutChange(tile, track);
01132
01133 MarkTileDirtyByTile(tile);
01134 }
01135
01136 return CommandCost(EXPENSES_CONSTRUCTION, _price.remove_signals);
01137 }
01138
01153 CommandCost CmdRemoveSignalTrack(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
01154 {
01155 return CmdSignalTrackHelper(tile, flags, p1, SetBit(p2, 5));
01156 }
01157
01159 void *UpdateTrainPowerProc(Vehicle *v, void *data)
01160 {
01161
01162
01163 if (v->type == VEH_TRAIN && !IsArticulatedPart(v)) {
01164 const RailVehicleInfo *rvi = RailVehInfo(v->engine_type);
01165 if (GetVehicleProperty(v, 0x0B, rvi->power) != 0) TrainPowerChanged(v->First());
01166 }
01167
01168 return NULL;
01169 }
01170
01178 CommandCost CmdConvertRail(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
01179 {
01180 CommandCost cost(EXPENSES_CONSTRUCTION);
01181 RailType totype = (RailType)p2;
01182
01183 if (!ValParamRailtype(totype)) return CMD_ERROR;
01184 if (p1 >= MapSize()) return CMD_ERROR;
01185
01186 uint ex = TileX(tile);
01187 uint ey = TileY(tile);
01188 uint sx = TileX(p1);
01189 uint sy = TileY(p1);
01190
01191
01192 if (ex < sx) Swap(ex, sx);
01193 if (ey < sy) Swap(ey, sy);
01194
01195 _error_message = STR_1005_NO_SUITABLE_RAILROAD_TRACK;
01196
01197 for (uint x = sx; x <= ex; ++x) {
01198 for (uint y = sy; y <= ey; ++y) {
01199 TileIndex tile = TileXY(x, y);
01200 TileType tt = GetTileType(tile);
01201
01202
01203 switch (tt) {
01204 case MP_RAILWAY:
01205 break;
01206 case MP_STATION:
01207 if (!IsRailwayStation(tile)) continue;
01208 break;
01209 case MP_ROAD:
01210 if (!IsLevelCrossing(tile)) continue;
01211 break;
01212 case MP_TUNNELBRIDGE:
01213 if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) continue;
01214 break;
01215 default: continue;
01216 }
01217
01218
01219 RailType type = GetRailType(tile);
01220
01221
01222 if (type == totype || (_patches.disable_elrails && totype == RAILTYPE_RAIL && type == RAILTYPE_ELECTRIC)) continue;
01223
01224
01225 if (!CheckTileOwnership(tile)) continue;
01226
01227
01228
01229 if (tt != MP_TUNNELBRIDGE) {
01230 if (!IsCompatibleRail(type, totype) && !EnsureNoVehicleOnGround(tile)) continue;
01231 if (flags & DC_EXEC) {
01232 SetRailType(tile, totype);
01233 MarkTileDirtyByTile(tile);
01234
01235 FindVehicleOnPos(tile, NULL, &UpdateTrainPowerProc);
01236 }
01237 }
01238
01239 switch (tt) {
01240 case MP_RAILWAY:
01241 switch (GetRailTileType(tile)) {
01242 case RAIL_TILE_WAYPOINT:
01243 if (flags & DC_EXEC) {
01244
01245 YapfNotifyTrackLayoutChange(tile, AxisToTrack(GetWaypointAxis(tile)));
01246 }
01247 cost.AddCost(RailConvertCost(type, totype));
01248 break;
01249
01250 case RAIL_TILE_DEPOT:
01251 if (flags & DC_EXEC) {
01252
01253 YapfNotifyTrackLayoutChange(tile, AxisToTrack(DiagDirToAxis(GetRailDepotDirection(tile))));
01254
01255
01256 InvalidateWindowData(WC_VEHICLE_DEPOT, tile);
01257 InvalidateWindowData(WC_BUILD_VEHICLE, tile);
01258 }
01259 cost.AddCost(RailConvertCost(type, totype));
01260 break;
01261
01262 default:
01263 if (flags & DC_EXEC) {
01264
01265 TrackBits tracks = GetTrackBits(tile);
01266 while (tracks != TRACK_BIT_NONE) {
01267 YapfNotifyTrackLayoutChange(tile, RemoveFirstTrack(&tracks));
01268 }
01269 }
01270 cost.AddCost(RailConvertCost(type, totype) * CountBits(GetTrackBits(tile)));
01271 break;
01272 }
01273 break;
01274
01275 case MP_TUNNELBRIDGE: {
01276 TileIndex endtile = GetOtherTunnelBridgeEnd(tile);
01277
01278
01279
01280 if (endtile < tile && TileX(endtile) >= sx && TileX(endtile) <= ex &&
01281 TileY(endtile) >= sy && TileY(endtile) <= ey) continue;
01282
01283
01284 if (!IsCompatibleRail(GetRailType(tile), totype) &&
01285 HasVehicleOnTunnelBridge(tile, endtile)) continue;
01286
01287 if (flags & DC_EXEC) {
01288 SetRailType(tile, totype);
01289 SetRailType(endtile, totype);
01290
01291 FindVehicleOnPos(tile, NULL, &UpdateTrainPowerProc);
01292 FindVehicleOnPos(endtile, NULL, &UpdateTrainPowerProc);
01293
01294 Track track = AxisToTrack(DiagDirToAxis(GetTunnelBridgeDirection(tile)));
01295
01296 YapfNotifyTrackLayoutChange(tile, track);
01297 YapfNotifyTrackLayoutChange(endtile, track);
01298
01299 MarkTileDirtyByTile(tile);
01300 MarkTileDirtyByTile(endtile);
01301
01302 if (IsBridge(tile)) {
01303 TileIndexDiff delta = TileOffsByDiagDir(GetTunnelBridgeDirection(tile));
01304 TileIndex t = tile + delta;
01305 for (; t != endtile; t += delta) MarkTileDirtyByTile(t);
01306 }
01307 }
01308
01309 cost.AddCost((GetTunnelBridgeLength(tile, endtile) + 2) * RailConvertCost(type, totype));
01310 } break;
01311
01312 default:
01313 if (flags & DC_EXEC) {
01314 Track track = ((tt == MP_STATION) ? GetRailStationTrack(tile) : GetCrossingRailTrack(tile));
01315 YapfNotifyTrackLayoutChange(tile, track);
01316 }
01317
01318 cost.AddCost(RailConvertCost(type, totype));
01319 break;
01320 }
01321 }
01322 }
01323
01324 return (cost.GetCost() == 0) ? CMD_ERROR : cost;
01325 }
01326
01327 static CommandCost RemoveTrainDepot(TileIndex tile, uint32 flags)
01328 {
01329 if (!CheckTileOwnership(tile) && _current_player != OWNER_WATER)
01330 return CMD_ERROR;
01331
01332 if (!EnsureNoVehicleOnGround(tile))
01333 return CMD_ERROR;
01334
01335 if (flags & DC_EXEC) {
01336
01337 DiagDirection dir = GetRailDepotDirection(tile);
01338 Owner owner = GetTileOwner(tile);
01339
01340 DoClearSquare(tile);
01341 delete GetDepotByTile(tile);
01342 AddSideToSignalBuffer(tile, dir, owner);
01343 YapfNotifyTrackLayoutChange(tile, TrackdirToTrack(DiagdirToDiagTrackdir(dir)));
01344 }
01345
01346 return CommandCost(EXPENSES_CONSTRUCTION, _price.remove_train_depot);
01347 }
01348
01349 static CommandCost ClearTile_Track(TileIndex tile, byte flags)
01350 {
01351 CommandCost cost(EXPENSES_CONSTRUCTION);
01352 CommandCost ret;
01353
01354 if (flags & DC_AUTO) {
01355 if (!IsTileOwner(tile, _current_player))
01356 return_cmd_error(STR_1024_AREA_IS_OWNED_BY_ANOTHER);
01357
01358 if (IsPlainRailTile(tile)) {
01359 return_cmd_error(STR_1008_MUST_REMOVE_RAILROAD_TRACK);
01360 } else {
01361 return_cmd_error(STR_2004_BUILDING_MUST_BE_DEMOLISHED);
01362 }
01363 }
01364
01365 switch (GetRailTileType(tile)) {
01366 case RAIL_TILE_SIGNALS:
01367 case RAIL_TILE_NORMAL: {
01368 Slope tileh = GetTileSlope(tile, NULL);
01369
01370 bool water_ground = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh));
01371
01372 TrackBits tracks = GetTrackBits(tile);
01373 while (tracks != TRACK_BIT_NONE) {
01374 Track track = RemoveFirstTrack(&tracks);
01375 ret = DoCommand(tile, 0, track, flags, CMD_REMOVE_SINGLE_RAIL);
01376 if (CmdFailed(ret)) return CMD_ERROR;
01377 cost.AddCost(ret);
01378 }
01379
01380
01381 if (water_ground && !(flags & DC_BANKRUPT)) {
01382 if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
01383
01384
01385 if (flags & DC_EXEC) DoClearSquare(tile);
01386 cost.AddCost(_price.clear_water);
01387 }
01388
01389 return cost;
01390 }
01391
01392 case RAIL_TILE_DEPOT:
01393 return RemoveTrainDepot(tile, flags);
01394
01395 case RAIL_TILE_WAYPOINT:
01396 return RemoveTrainWaypoint(tile, flags, false);
01397
01398 default:
01399 return CMD_ERROR;
01400 }
01401 }
01402
01407 static uint GetSaveSlopeZ(uint x, uint y, Track track)
01408 {
01409 switch (track) {
01410 case TRACK_UPPER: x &= ~0xF; y &= ~0xF; break;
01411 case TRACK_LOWER: x |= 0xF; y |= 0xF; break;
01412 case TRACK_LEFT: x |= 0xF; y &= ~0xF; break;
01413 case TRACK_RIGHT: x &= ~0xF; y |= 0xF; break;
01414 default: break;
01415 }
01416 return GetSlopeZ(x, y);
01417 }
01418
01419 static void DrawSingleSignal(TileIndex tile, Track track, byte condition, uint image, uint pos)
01420 {
01421 bool side = (_opt.road_side != 0) && _patches.signal_side;
01422 static const Point SignalPositions[2][12] = {
01423 {
01424
01425 { 8, 5}, {14, 1}, { 1, 14}, { 9, 11}, { 1, 0}, { 3, 10},
01426
01427 {11, 4}, {14, 14}, {11, 3}, { 4, 13}, { 3, 4}, {11, 13}
01428 }, {
01429
01430 {14, 1}, {12, 10}, { 4, 6}, { 1, 14}, {10, 4}, { 0, 1},
01431
01432 {14, 14}, { 5, 12}, {11, 13}, { 4, 3}, {13, 4}, { 3, 11}
01433 }
01434 };
01435
01436 uint x = TileX(tile) * TILE_SIZE + SignalPositions[side][pos].x;
01437 uint y = TileY(tile) * TILE_SIZE + SignalPositions[side][pos].y;
01438
01439 SpriteID sprite;
01440
01441 SignalType type = GetSignalType(tile, track);
01442 SignalVariant variant = GetSignalVariant(tile, track);
01443
01444 if (type == SIGTYPE_NORMAL && variant == SIG_ELECTRIC) {
01445
01446 sprite = SPR_ORIGINAL_SIGNALS_BASE + image + condition;
01447 } else {
01448
01449 sprite = SPR_SIGNALS_BASE + (type - 1) * 16 + variant * 64 + image + condition;
01450 }
01451
01452 AddSortableSpriteToDraw(sprite, PAL_NONE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, GetSaveSlopeZ(x, y, track));
01453 }
01454
01455 static uint32 _drawtile_track_palette;
01456
01457
01458 static void DrawTrackFence_NW(const TileInfo *ti)
01459 {
01460 SpriteID image = SPR_TRACK_FENCE_FLAT_X;
01461 if (ti->tileh != SLOPE_FLAT) image = (ti->tileh & SLOPE_S) ? SPR_TRACK_FENCE_SLOPE_SW : SPR_TRACK_FENCE_SLOPE_NE;
01462 AddSortableSpriteToDraw(image, _drawtile_track_palette,
01463 ti->x, ti->y + 1, 16, 1, 4, ti->z);
01464 }
01465
01466 static void DrawTrackFence_SE(const TileInfo *ti)
01467 {
01468 SpriteID image = SPR_TRACK_FENCE_FLAT_X;
01469 if (ti->tileh != SLOPE_FLAT) image = (ti->tileh & SLOPE_S) ? SPR_TRACK_FENCE_SLOPE_SW : SPR_TRACK_FENCE_SLOPE_NE;
01470 AddSortableSpriteToDraw(image, _drawtile_track_palette,
01471 ti->x, ti->y + TILE_SIZE - 1, 16, 1, 4, ti->z);
01472 }
01473
01474 static void DrawTrackFence_NW_SE(const TileInfo *ti)
01475 {
01476 DrawTrackFence_NW(ti);
01477 DrawTrackFence_SE(ti);
01478 }
01479
01480 static void DrawTrackFence_NE(const TileInfo *ti)
01481 {
01482 SpriteID image = SPR_TRACK_FENCE_FLAT_Y;
01483 if (ti->tileh != SLOPE_FLAT) image = (ti->tileh & SLOPE_S) ? SPR_TRACK_FENCE_SLOPE_SE : SPR_TRACK_FENCE_SLOPE_NW;
01484 AddSortableSpriteToDraw(image, _drawtile_track_palette,
01485 ti->x + 1, ti->y, 1, 16, 4, ti->z);
01486 }
01487
01488 static void DrawTrackFence_SW(const TileInfo *ti)
01489 {
01490 SpriteID image = SPR_TRACK_FENCE_FLAT_Y;
01491 if (ti->tileh != SLOPE_FLAT) image = (ti->tileh & SLOPE_S) ? SPR_TRACK_FENCE_SLOPE_SE : SPR_TRACK_FENCE_SLOPE_NW;
01492 AddSortableSpriteToDraw(image, _drawtile_track_palette,
01493 ti->x + TILE_SIZE - 1, ti->y, 1, 16, 4, ti->z);
01494 }
01495
01496 static void DrawTrackFence_NE_SW(const TileInfo *ti)
01497 {
01498 DrawTrackFence_NE(ti);
01499 DrawTrackFence_SW(ti);
01500 }
01501
01505 static void DrawTrackFence_NS_1(const TileInfo *ti)
01506 {
01507 uint z = ti->z + GetSlopeZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_W);
01508 AddSortableSpriteToDraw(SPR_TRACK_FENCE_FLAT_VERT, _drawtile_track_palette,
01509 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01510 }
01511
01515 static void DrawTrackFence_NS_2(const TileInfo *ti)
01516 {
01517 uint z = ti->z + GetSlopeZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_E);
01518 AddSortableSpriteToDraw(SPR_TRACK_FENCE_FLAT_VERT, _drawtile_track_palette,
01519 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01520 }
01521
01525 static void DrawTrackFence_WE_1(const TileInfo *ti)
01526 {
01527 uint z = ti->z + GetSlopeZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_N);
01528 AddSortableSpriteToDraw(SPR_TRACK_FENCE_FLAT_HORZ, _drawtile_track_palette,
01529 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01530 }
01531
01535 static void DrawTrackFence_WE_2(const TileInfo *ti)
01536 {
01537 uint z = ti->z + GetSlopeZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_S);
01538 AddSortableSpriteToDraw(SPR_TRACK_FENCE_FLAT_HORZ, _drawtile_track_palette,
01539 ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z);
01540 }
01541
01542
01543 static void DrawTrackDetails(const TileInfo* ti)
01544 {
01545 switch (GetRailGroundType(ti->tile)) {
01546 case RAIL_GROUND_FENCE_NW: DrawTrackFence_NW(ti); break;
01547 case RAIL_GROUND_FENCE_SE: DrawTrackFence_SE(ti); break;
01548 case RAIL_GROUND_FENCE_SENW: DrawTrackFence_NW_SE(ti); break;
01549 case RAIL_GROUND_FENCE_NE: DrawTrackFence_NE(ti); break;
01550 case RAIL_GROUND_FENCE_SW: DrawTrackFence_SW(ti); break;
01551 case RAIL_GROUND_FENCE_NESW: DrawTrackFence_NE_SW(ti); break;
01552 case RAIL_GROUND_FENCE_VERT1: DrawTrackFence_NS_1(ti); break;
01553 case RAIL_GROUND_FENCE_VERT2: DrawTrackFence_NS_2(ti); break;
01554 case RAIL_GROUND_FENCE_HORIZ1: DrawTrackFence_WE_1(ti); break;
01555 case RAIL_GROUND_FENCE_HORIZ2: DrawTrackFence_WE_2(ti); break;
01556 case RAIL_GROUND_WATER: {
01557 Corner track_corner;
01558 if (IsHalftileSlope(ti->tileh)) {
01559
01560 track_corner = GetHalftileSlopeCorner(ti->tileh);
01561 } else {
01562
01563 track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh)));
01564 }
01565 switch (track_corner) {
01566 case CORNER_W: DrawTrackFence_NS_1(ti); break;
01567 case CORNER_S: DrawTrackFence_WE_2(ti); break;
01568 case CORNER_E: DrawTrackFence_NS_2(ti); break;
01569 case CORNER_N: DrawTrackFence_WE_1(ti); break;
01570 default: NOT_REACHED();
01571 }
01572 break;
01573 }
01574 default: break;
01575 }
01576 }
01577
01578
01584 static void DrawTrackBits(TileInfo* ti, TrackBits track)
01585 {
01586
01587 static const int INF = 1000;
01588 static const SubSprite _halftile_sub_sprite[4] = {
01589 { -INF , -INF , 32 - 33, INF },
01590 { -INF , 0 + 7, INF , INF },
01591 { -31 + 33, -INF , INF , INF },
01592 { -INF , -INF , INF , 30 - 23 }
01593 };
01594
01595 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
01596 RailGroundType rgt = GetRailGroundType(ti->tile);
01597 Foundation f = GetRailFoundation(ti->tileh, track);
01598 Corner halftile_corner = CORNER_INVALID;
01599
01600 if (IsNonContinuousFoundation(f)) {
01601
01602 halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f));
01603
01604 track &= ~CornerToTrackBits(halftile_corner);
01605 f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE);
01606 }
01607
01608 DrawFoundation(ti, f);
01609
01610
01611 SpriteID image;
01612 SpriteID pal = PAL_NONE;
01613 const SubSprite *sub = NULL;
01614 bool junction = false;
01615
01616
01617 if (track == 0) {
01618
01619 if (rgt == RAIL_GROUND_WATER) {
01620 if (IsSteepSlope(ti->tileh)) {
01621 DrawShoreTile(ti->tileh);
01622 image = 0;
01623 } else {
01624 image = SPR_FLAT_WATER_TILE;
01625 }
01626 } else {
01627 switch (rgt) {
01628 case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
01629 case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOWY_TILE; break;
01630 default: image = SPR_FLAT_GRASS_TILE; break;
01631 }
01632 image += _tileh_to_sprite[ti->tileh];
01633 }
01634 } else {
01635 if (ti->tileh != SLOPE_FLAT) {
01636
01637 image = _track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.track_y;
01638 } else {
01639
01640 (image = rti->base_sprites.track_y, track == TRACK_BIT_Y) ||
01641 (image++, track == TRACK_BIT_X) ||
01642 (image++, track == TRACK_BIT_UPPER) ||
01643 (image++, track == TRACK_BIT_LOWER) ||
01644 (image++, track == TRACK_BIT_RIGHT) ||
01645 (image++, track == TRACK_BIT_LEFT) ||
01646 (image++, track == TRACK_BIT_CROSS) ||
01647
01648 (image = rti->base_sprites.track_ns, track == TRACK_BIT_HORZ) ||
01649 (image++, track == TRACK_BIT_VERT) ||
01650
01651 (junction = true, false) ||
01652 (image = rti->base_sprites.ground, (track & TRACK_BIT_3WAY_NE) == 0) ||
01653 (image++, (track & TRACK_BIT_3WAY_SW) == 0) ||
01654 (image++, (track & TRACK_BIT_3WAY_NW) == 0) ||
01655 (image++, (track & TRACK_BIT_3WAY_SE) == 0) ||
01656 (image++, true);
01657 }
01658
01659 switch (rgt) {
01660 case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
01661 case RAIL_GROUND_ICE_DESERT: image += rti->snow_offset; break;
01662 case RAIL_GROUND_WATER: {
01663
01664 DrawShoreTile(ti->tileh);
01665 Corner track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh)));
01666 sub = &(_halftile_sub_sprite[track_corner]);
01667 break;
01668 }
01669 default: break;
01670 }
01671 }
01672
01673 if (image != 0) DrawGroundSprite(image, pal, sub);
01674
01675
01676 if (junction) {
01677 if (track & TRACK_BIT_X) DrawGroundSprite(rti->base_sprites.single_y, PAL_NONE);
01678 if (track & TRACK_BIT_Y) DrawGroundSprite(rti->base_sprites.single_x, PAL_NONE);
01679 if (track & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PAL_NONE);
01680 if (track & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PAL_NONE);
01681 if (track & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PAL_NONE);
01682 if (track & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PAL_NONE);
01683 }
01684
01685 if (IsValidCorner(halftile_corner)) {
01686 DrawFoundation(ti, HalftileFoundation(halftile_corner));
01687
01688
01689 Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
01690 image = _track_sloped_sprites[fake_slope - 1] + rti->base_sprites.track_y;
01691 pal = PAL_NONE;
01692 switch (rgt) {
01693 case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
01694 case RAIL_GROUND_ICE_DESERT:
01695 case RAIL_GROUND_HALF_SNOW: image += rti->snow_offset; break;
01696 default: break;
01697 }
01698 DrawGroundSprite(image, pal, &(_halftile_sub_sprite[halftile_corner]));
01699 }
01700 }
01701
01707 enum {
01708 SIGNAL_TO_SOUTHWEST = 0,
01709 SIGNAL_TO_NORTHEAST = 2,
01710 SIGNAL_TO_SOUTHEAST = 4,
01711 SIGNAL_TO_NORTHWEST = 6,
01712 SIGNAL_TO_EAST = 8,
01713 SIGNAL_TO_WEST = 10,
01714 SIGNAL_TO_SOUTH = 12,
01715 SIGNAL_TO_NORTH = 14,
01716 };
01717
01718 static void DrawSignals(TileIndex tile, TrackBits rails)
01719 {
01720 #define MAYBE_DRAW_SIGNAL(x,y,z,t) if (IsSignalPresent(tile, x)) DrawSingleSignal(tile, t, GetSingleSignalState(tile, x), y, z)
01721
01722 if (!(rails & TRACK_BIT_Y)) {
01723 if (!(rails & TRACK_BIT_X)) {
01724 if (rails & TRACK_BIT_LEFT) {
01725 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTH, 0, TRACK_LEFT);
01726 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTH, 1, TRACK_LEFT);
01727 }
01728 if (rails & TRACK_BIT_RIGHT) {
01729 MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_NORTH, 2, TRACK_RIGHT);
01730 MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_SOUTH, 3, TRACK_RIGHT);
01731 }
01732 if (rails & TRACK_BIT_UPPER) {
01733 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_WEST, 4, TRACK_UPPER);
01734 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_EAST, 5, TRACK_UPPER);
01735 }
01736 if (rails & TRACK_BIT_LOWER) {
01737 MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_WEST, 6, TRACK_LOWER);
01738 MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_EAST, 7, TRACK_LOWER);
01739 }
01740 } else {
01741 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHWEST, 8, TRACK_X);
01742 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHEAST, 9, TRACK_X);
01743 }
01744 } else {
01745 MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHEAST, 10, TRACK_Y);
01746 MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHWEST, 11, TRACK_Y);
01747 }
01748 }
01749
01750 static void DrawTile_Track(TileInfo *ti)
01751 {
01752 const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
01753 SpriteID image;
01754
01755 _drawtile_track_palette = PLAYER_SPRITE_COLOR(GetTileOwner(ti->tile));
01756
01757 if (IsPlainRailTile(ti->tile)) {
01758 TrackBits rails = GetTrackBits(ti->tile);
01759
01760 DrawTrackBits(ti, rails);
01761
01762 if (HasBit(_display_opt, DO_FULL_DETAIL)) DrawTrackDetails(ti);
01763
01764 if (GetRailType(ti->tile) == RAILTYPE_ELECTRIC) DrawCatenary(ti);
01765
01766 if (HasSignals(ti->tile)) DrawSignals(ti->tile, rails);
01767 } else {
01768
01769 const DrawTileSprites* dts;
01770 const DrawTileSeqStruct* dtss;
01771 uint32 relocation;
01772
01773 if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
01774
01775 if (IsRailDepot(ti->tile)) {
01776 dts = &_depot_gfx_table[GetRailDepotDirection(ti->tile)];
01777
01778 relocation = rti->total_offset;
01779
01780 image = dts->ground.sprite;
01781 if (image != SPR_FLAT_GRASS_TILE) image += rti->total_offset;
01782
01783
01784
01785 if (IsSnowRailGround(ti->tile) && _opt.landscape == LT_TROPIC) {
01786 if (image != SPR_FLAT_GRASS_TILE) {
01787 image += rti->snow_offset;
01788 } else {
01789 image = SPR_FLAT_SNOWY_TILE;
01790 }
01791 }
01792 } else {
01793
01794 byte stat_id = GetWaypointByTile(ti->tile)->stat_id;
01795 const StationSpec *statspec = GetCustomStationSpec(STAT_CLASS_WAYP, stat_id);
01796
01797 if (statspec != NULL) {
01798
01799 const Station* st = ComposeWaypointStation(ti->tile);
01800 uint gfx = 2;
01801
01802 if (HasBit(statspec->callbackmask, CBM_STATION_SPRITE_LAYOUT)) {
01803 uint16 callback = GetStationCallback(CBID_STATION_SPRITE_LAYOUT, 0, 0, statspec, st, ti->tile);
01804 if (callback != CALLBACK_FAILED) gfx = callback;
01805 }
01806
01807 if (statspec->renderdata == NULL) {
01808 dts = GetStationTileLayout(STATION_RAIL, gfx);
01809 } else {
01810 dts = &statspec->renderdata[(gfx < statspec->tiles ? gfx : 0) + GetWaypointAxis(ti->tile)];
01811 }
01812
01813 if (dts != NULL && dts->seq != NULL) {
01814 relocation = GetCustomStationRelocation(statspec, st, ti->tile);
01815
01816 image = dts->ground.sprite;
01817 if (HasBit(image, SPRITE_MODIFIER_USE_OFFSET)) {
01818 image += GetCustomStationGroundRelocation(statspec, st, ti->tile);
01819 image += rti->custom_ground_offset;
01820 } else {
01821 image += rti->total_offset;
01822 }
01823 } else {
01824 goto default_waypoint;
01825 }
01826 } else {
01827 default_waypoint:
01828
01829 dts = &_waypoint_gfx_table[GetWaypointAxis(ti->tile)];
01830 relocation = 0;
01831 image = dts->ground.sprite + rti->total_offset;
01832 if (IsSnowRailGround(ti->tile)) image += rti->snow_offset;
01833 }
01834 }
01835
01836 DrawGroundSprite(image, PAL_NONE);
01837
01838 if (GetRailType(ti->tile) == RAILTYPE_ELECTRIC) DrawCatenary(ti);
01839
01840 foreach_draw_tile_seq(dtss, dts->seq) {
01841 SpriteID image = dtss->image.sprite;
01842 SpriteID pal;
01843
01844
01845
01846
01847 if (HasBit(image, SPRITE_MODIFIER_USE_OFFSET)) {
01848 image += rti->total_offset;
01849 } else {
01850 image += relocation;
01851 }
01852
01853 if (!(!HasBit(image, SPRITE_MODIFIER_OPAQUE) && IsTransparencySet(TO_BUILDINGS)) && HasBit(image, PALETTE_MODIFIER_COLOR)) {
01854 pal = _drawtile_track_palette;
01855 } else {
01856 pal = dtss->image.pal;
01857 }
01858
01859 if ((byte)dtss->delta_z != 0x80) {
01860 AddSortableSpriteToDraw(
01861 image, pal,
01862 ti->x + dtss->delta_x, ti->y + dtss->delta_y,
01863 dtss->size_x, dtss->size_y,
01864 dtss->size_z, ti->z + dtss->delta_z,
01865 !HasBit(image, SPRITE_MODIFIER_OPAQUE) && IsTransparencySet(TO_BUILDINGS)
01866 );
01867 } else {
01868 AddChildSpriteScreen(image, pal, dtss->delta_x, dtss->delta_y);
01869 }
01870 }
01871 }
01872 DrawBridgeMiddle(ti);
01873 }
01874
01875
01876 static void DrawTileSequence(int x, int y, SpriteID ground, const DrawTileSeqStruct* dtss, uint32 offset)
01877 {
01878 SpriteID palette = PLAYER_SPRITE_COLOR(_local_player);
01879
01880 DrawSprite(ground, PAL_NONE, x, y);
01881 for (; dtss->image.sprite != 0; dtss++) {
01882 Point pt = RemapCoords(dtss->delta_x, dtss->delta_y, dtss->delta_z);
01883 SpriteID image = dtss->image.sprite + offset;
01884
01885 DrawSprite(image, HasBit(image, PALETTE_MODIFIER_COLOR) ? palette : PAL_NONE, x + pt.x, y + pt.y);
01886 }
01887 }
01888
01889 void DrawTrainDepotSprite(int x, int y, int dir, RailType railtype)
01890 {
01891 const DrawTileSprites* dts = &_depot_gfx_table[dir];
01892 SpriteID image = dts->ground.sprite;
01893 uint32 offset = GetRailTypeInfo(railtype)->total_offset;
01894
01895 if (image != SPR_FLAT_GRASS_TILE) image += offset;
01896 DrawTileSequence(x + 33, y + 17, image, dts->seq, offset);
01897 }
01898
01899 void DrawDefaultWaypointSprite(int x, int y, RailType railtype)
01900 {
01901 uint32 offset = GetRailTypeInfo(railtype)->total_offset;
01902 const DrawTileSprites* dts = &_waypoint_gfx_table[AXIS_X];
01903
01904 DrawTileSequence(x, y, dts->ground.sprite + offset, dts->seq, 0);
01905 }
01906
01907 static uint GetSlopeZ_Track(TileIndex tile, uint x, uint y)
01908 {
01909 uint z;
01910 Slope tileh = GetTileSlope(tile, &z);
01911
01912 if (tileh == SLOPE_FLAT) return z;
01913 if (IsPlainRailTile(tile)) {
01914 z += ApplyFoundationToSlope(GetRailFoundation(tileh, GetTrackBits(tile)), &tileh);
01915 return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
01916 } else {
01917 return z + TILE_HEIGHT;
01918 }
01919 }
01920
01921 static Foundation GetFoundation_Track(TileIndex tile, Slope tileh)
01922 {
01923 return IsPlainRailTile(tile) ? GetRailFoundation(tileh, GetTrackBits(tile)) : FlatteningFoundation(tileh);
01924 }
01925
01926 static void GetAcceptedCargo_Track(TileIndex tile, AcceptedCargo ac)
01927 {
01928
01929 }
01930
01931 static void AnimateTile_Track(TileIndex tile)
01932 {
01933
01934 }
01935
01936 static void TileLoop_Track(TileIndex tile)
01937 {
01938 RailGroundType old_ground = GetRailGroundType(tile);
01939 RailGroundType new_ground;
01940
01941 if (old_ground == RAIL_GROUND_WATER) {
01942 TileLoop_Water(tile);
01943 return;
01944 }
01945
01946 switch (_opt.landscape) {
01947 case LT_ARCTIC: {
01948 uint z;
01949 Slope slope = GetTileSlope(tile, &z);
01950 bool half = false;
01951
01952
01953
01954 if (IsPlainRailTile(tile)) {
01955 TrackBits track = GetTrackBits(tile);
01956 Foundation f = GetRailFoundation(slope, track);
01957
01958 switch (f) {
01959 case FOUNDATION_NONE:
01960
01961 if (IsSlopeWithThreeCornersRaised(slope)) z += TILE_HEIGHT;
01962 break;
01963
01964 case FOUNDATION_INCLINED_X:
01965 case FOUNDATION_INCLINED_Y:
01966
01967 if (IsSteepSlope(slope)) z += TILE_HEIGHT;
01968 break;
01969
01970 case FOUNDATION_STEEP_LOWER:
01971
01972 z += TILE_HEIGHT;
01973 break;
01974
01975 default:
01976
01977 if (IsSteepSlope(slope)) z += TILE_HEIGHT;
01978 z += TILE_HEIGHT;
01979 break;
01980 }
01981
01982 half = IsInsideMM(f, FOUNDATION_STEEP_BOTH, FOUNDATION_HALFTILE_N + 1);
01983 } else {
01984
01985 if (slope != SLOPE_FLAT) z += TILE_HEIGHT;
01986 }
01987
01988
01989
01990
01991
01992 if (z > GetSnowLine()) {
01993 if (half && z - GetSnowLine() == TILE_HEIGHT) {
01994
01995 new_ground = RAIL_GROUND_HALF_SNOW;
01996 } else {
01997 new_ground = RAIL_GROUND_ICE_DESERT;
01998 }
01999 goto set_ground;
02000 }
02001 break;
02002 }
02003
02004 case LT_TROPIC:
02005 if (GetTropicZone(tile) == TROPICZONE_DESERT) {
02006 new_ground = RAIL_GROUND_ICE_DESERT;
02007 goto set_ground;
02008 }
02009 break;
02010 }
02011
02012 if (!IsPlainRailTile(tile)) return;
02013
02014 new_ground = RAIL_GROUND_GRASS;
02015
02016 if (old_ground != RAIL_GROUND_BARREN) {
02017
02018 TrackBits rail = GetTrackBits(tile);
02019
02020 switch (rail) {
02021 case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break;
02022 case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break;
02023 case TRACK_BIT_LEFT: new_ground = RAIL_GROUND_FENCE_VERT1; break;
02024 case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2; break;
02025
02026 default: {
02027 PlayerID owner = GetTileOwner(tile);
02028
02029 if (rail == (TRACK_BIT_LOWER | TRACK_BIT_RIGHT) || (
02030 (rail & TRACK_BIT_3WAY_NW) == 0 &&
02031 (rail & TRACK_BIT_X)
02032 )) {
02033 TileIndex n = tile + TileDiffXY(0, -1);
02034 TrackBits nrail = GetTrackBits(n);
02035
02036 if (!IsTileType(n, MP_RAILWAY) ||
02037 !IsTileOwner(n, owner) ||
02038 nrail == TRACK_BIT_UPPER ||
02039 nrail == TRACK_BIT_LEFT) {
02040 new_ground = RAIL_GROUND_FENCE_NW;
02041 }
02042 }
02043
02044 if (rail == (TRACK_BIT_UPPER | TRACK_BIT_LEFT) || (
02045 (rail & TRACK_BIT_3WAY_SE) == 0 &&
02046 (rail & TRACK_BIT_X)
02047 )) {
02048 TileIndex n = tile + TileDiffXY(0, 1);
02049 TrackBits nrail = GetTrackBits(n);
02050
02051 if (!IsTileType(n, MP_RAILWAY) ||
02052 !IsTileOwner(n, owner) ||
02053 nrail == TRACK_BIT_LOWER ||
02054 nrail == TRACK_BIT_RIGHT) {
02055 new_ground = (new_ground == RAIL_GROUND_FENCE_NW) ?
02056 RAIL_GROUND_FENCE_SENW : RAIL_GROUND_FENCE_SE;
02057 }
02058 }
02059
02060 if (rail == (TRACK_BIT_LOWER | TRACK_BIT_LEFT) || (
02061 (rail & TRACK_BIT_3WAY_NE) == 0 &&
02062 (rail & TRACK_BIT_Y)
02063 )) {
02064 TileIndex n = tile + TileDiffXY(-1, 0);
02065 TrackBits nrail = GetTrackBits(n);
02066
02067 if (!IsTileType(n, MP_RAILWAY) ||
02068 !IsTileOwner(n, owner) ||
02069 nrail == TRACK_BIT_UPPER ||
02070 nrail == TRACK_BIT_RIGHT) {
02071 new_ground = RAIL_GROUND_FENCE_NE;
02072 }
02073 }
02074
02075 if (rail == (TRACK_BIT_UPPER | TRACK_BIT_RIGHT) || (
02076 (rail & TRACK_BIT_3WAY_SW) == 0 &&
02077 (rail & TRACK_BIT_Y)
02078 )) {
02079 TileIndex n = tile + TileDiffXY(1, 0);
02080 TrackBits nrail = GetTrackBits(n);
02081
02082 if (!IsTileType(n, MP_RAILWAY) ||
02083 !IsTileOwner(n, owner) ||
02084 nrail == TRACK_BIT_LOWER ||
02085 nrail == TRACK_BIT_LEFT) {
02086 new_ground = (new_ground == RAIL_GROUND_FENCE_NE) ?
02087 RAIL_GROUND_FENCE_NESW : RAIL_GROUND_FENCE_SW;
02088 }
02089 }
02090 break;
02091 }
02092 }
02093 }
02094
02095 set_ground:
02096 if (old_ground != new_ground) {
02097 SetRailGroundType(tile, new_ground);
02098 MarkTileDirtyByTile(tile);
02099 }
02100 }
02101
02102
02103 static TrackStatus GetTileTrackStatus_Track(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
02104 {
02105
02106 if (mode == TRANSPORT_WATER && IsPlainRailTile(tile) && GetRailGroundType(tile) == RAIL_GROUND_WATER) {
02107 TrackBits tb = GetTrackBits(tile);
02108 switch (tb) {
02109 default: NOT_REACHED();
02110 case TRACK_BIT_UPPER: tb = TRACK_BIT_LOWER; break;
02111 case TRACK_BIT_LOWER: tb = TRACK_BIT_UPPER; break;
02112 case TRACK_BIT_LEFT: tb = TRACK_BIT_RIGHT; break;
02113 case TRACK_BIT_RIGHT: tb = TRACK_BIT_LEFT; break;
02114 }
02115 return CombineTrackStatus(TrackBitsToTrackdirBits(tb), TRACKDIR_BIT_NONE);
02116 }
02117
02118 if (mode != TRANSPORT_RAIL) return 0;
02119
02120 TrackBits trackbits = TRACK_BIT_NONE;
02121 TrackdirBits red_signals = TRACKDIR_BIT_NONE;
02122
02123 switch (GetRailTileType(tile)) {
02124 default: NOT_REACHED();
02125 case RAIL_TILE_NORMAL:
02126 trackbits = GetTrackBits(tile);
02127 break;
02128
02129 case RAIL_TILE_SIGNALS: {
02130 trackbits = GetTrackBits(tile);
02131 byte a = GetPresentSignals(tile);
02132 uint b = GetSignalStates(tile);
02133
02134 b &= a;
02135
02136
02137
02138
02139
02140 if ((a & 0xC) == 0) b |= 0xC;
02141 if ((a & 0x3) == 0) b |= 0x3;
02142
02143 if ((b & 0x8) == 0) red_signals |= (TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_X_NE | TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_UPPER_E);
02144 if ((b & 0x4) == 0) red_signals |= (TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_X_SW | TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_UPPER_W);
02145 if ((b & 0x2) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_LOWER_E);
02146 if ((b & 0x1) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_S | TRACKDIR_BIT_LOWER_W);
02147
02148 break;
02149 }
02150
02151 case RAIL_TILE_DEPOT: {
02152 DiagDirection dir = GetRailDepotDirection(tile);
02153
02154 if (side != INVALID_DIAGDIR && side != dir) break;
02155
02156 trackbits = AxisToTrackBits(DiagDirToAxis(dir));
02157 break;
02158 }
02159
02160 case RAIL_TILE_WAYPOINT:
02161 trackbits = GetRailWaypointBits(tile);
02162 break;
02163 }
02164
02165 return CombineTrackStatus(TrackBitsToTrackdirBits(trackbits), red_signals);
02166 }
02167
02168 static void ClickTile_Track(TileIndex tile)
02169 {
02170 switch (GetRailTileType(tile)) {
02171 case RAIL_TILE_DEPOT: ShowDepotWindow(tile, VEH_TRAIN); break;
02172 case RAIL_TILE_WAYPOINT: ShowRenameWaypointWindow(GetWaypointByTile(tile)); break;
02173 default: break;
02174 }
02175 }
02176
02177 static void GetTileDesc_Track(TileIndex tile, TileDesc *td)
02178 {
02179 td->owner = GetTileOwner(tile);
02180 switch (GetRailTileType(tile)) {
02181 case RAIL_TILE_NORMAL:
02182 td->str = STR_1021_RAILROAD_TRACK;
02183 break;
02184
02185 case RAIL_TILE_SIGNALS: {
02186 const StringID signal_type[4][4] = {
02187 {
02188 STR_RAILROAD_TRACK_WITH_NORMAL_SIGNALS,
02189 STR_RAILROAD_TRACK_WITH_NORMAL_PRESIGNALS,
02190 STR_RAILROAD_TRACK_WITH_NORMAL_EXITSIGNALS,
02191 STR_RAILROAD_TRACK_WITH_NORMAL_COMBOSIGNALS
02192 },
02193 {
02194 STR_RAILROAD_TRACK_WITH_NORMAL_PRESIGNALS,
02195 STR_RAILROAD_TRACK_WITH_PRESIGNALS,
02196 STR_RAILROAD_TRACK_WITH_PRE_EXITSIGNALS,
02197 STR_RAILROAD_TRACK_WITH_PRE_COMBOSIGNALS
02198 },
02199 {
02200 STR_RAILROAD_TRACK_WITH_NORMAL_EXITSIGNALS,
02201 STR_RAILROAD_TRACK_WITH_PRE_EXITSIGNALS,
02202 STR_RAILROAD_TRACK_WITH_EXITSIGNALS,
02203 STR_RAILROAD_TRACK_WITH_EXIT_COMBOSIGNALS
02204 },
02205 {
02206 STR_RAILROAD_TRACK_WITH_NORMAL_COMBOSIGNALS,
02207 STR_RAILROAD_TRACK_WITH_PRE_COMBOSIGNALS,
02208 STR_RAILROAD_TRACK_WITH_EXIT_COMBOSIGNALS,
02209 STR_RAILROAD_TRACK_WITH_COMBOSIGNALS
02210 }
02211 };
02212
02213 td->str = signal_type[GetSignalType(tile, TRACK_UPPER)][GetSignalType(tile, TRACK_LOWER)];
02214 break;
02215 }
02216
02217 case RAIL_TILE_DEPOT:
02218 td->str = STR_1023_RAILROAD_TRAIN_DEPOT;
02219 break;
02220
02221 case RAIL_TILE_WAYPOINT:
02222 default:
02223 td->str = STR_LANDINFO_WAYPOINT;
02224 break;
02225 }
02226 }
02227
02228 static void ChangeTileOwner_Track(TileIndex tile, PlayerID old_player, PlayerID new_player)
02229 {
02230 if (!IsTileOwner(tile, old_player)) return;
02231
02232 if (new_player != PLAYER_SPECTATOR) {
02233 SetTileOwner(tile, new_player);
02234 } else {
02235 DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
02236 }
02237 }
02238
02239 static const byte _fractcoords_behind[4] = { 0x8F, 0x8, 0x80, 0xF8 };
02240 static const byte _fractcoords_enter[4] = { 0x8A, 0x48, 0x84, 0xA8 };
02241 static const signed char _deltacoord_leaveoffset[8] = {
02242 -1, 0, 1, 0,
02243 0, 1, 0, -1
02244 };
02245
02246
02252 int TicksToLeaveDepot(const Vehicle *v)
02253 {
02254 DiagDirection dir = GetRailDepotDirection(v->tile);
02255 int length = v->u.rail.cached_veh_length;
02256
02257 switch (dir) {
02258 case DIAGDIR_NE: return ((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) - (length + 1)));
02259 case DIAGDIR_SE: return -((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) + (length + 1)));
02260 case DIAGDIR_SW: return -((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) + (length + 1)));
02261 default:
02262 case DIAGDIR_NW: return ((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) - (length + 1)));
02263 }
02264
02265 return 0;
02266 }
02267
02268
02269 static VehicleEnterTileStatus VehicleEnter_Track(Vehicle *v, TileIndex tile, int x, int y)
02270 {
02271 byte fract_coord;
02272 byte fract_coord_leave;
02273 DiagDirection dir;
02274 int length;
02275
02276
02277 if (v->type != VEH_TRAIN || !IsTileDepotType(tile, TRANSPORT_RAIL)) return VETSB_CONTINUE;
02278
02279
02280 dir = GetRailDepotDirection(tile);
02281
02282
02283
02284 length = v->u.rail.cached_veh_length;
02285
02286 fract_coord_leave =
02287 ((_fractcoords_enter[dir] & 0x0F) +
02288 (length + 1) * _deltacoord_leaveoffset[dir]) +
02289 (((_fractcoords_enter[dir] >> 4) +
02290 ((length + 1) * _deltacoord_leaveoffset[dir+4])) << 4);
02291
02292 fract_coord = (x & 0xF) + ((y & 0xF) << 4);
02293
02294 if (_fractcoords_behind[dir] == fract_coord) {
02295
02296 return VETSB_CANNOT_ENTER;
02297 } else if (_fractcoords_enter[dir] == fract_coord) {
02298 if (DiagDirToDir(ReverseDiagDir(dir)) == v->direction) {
02299
02300 v->u.rail.track = TRACK_BIT_DEPOT,
02301 v->vehstatus |= VS_HIDDEN;
02302 v->direction = ReverseDir(v->direction);
02303 if (v->Next() == NULL) VehicleEnterDepot(v);
02304 v->tile = tile;
02305
02306 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
02307 return VETSB_ENTERED_WORMHOLE;
02308 }
02309 } else if (fract_coord_leave == fract_coord) {
02310 if (DiagDirToDir(dir) == v->direction) {
02311
02312 if ((v = v->Next()) != NULL) {
02313 v->vehstatus &= ~VS_HIDDEN;
02314 v->u.rail.track = (DiagDirToAxis(dir) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y);
02315 }
02316 }
02317 }
02318
02319 return VETSB_CONTINUE;
02320 }
02321
02333 static CommandCost TestAutoslopeOnRailTile(TileIndex tile, uint flags, uint z_old, Slope tileh_old, uint z_new, Slope tileh_new, TrackBits rail_bits)
02334 {
02335 if (!_patches.build_on_slopes || !AutoslopeEnabled()) return CMD_ERROR;
02336
02337
02338 if (CmdFailed(CheckRailSlope(tileh_new, rail_bits, TRACK_BIT_NONE, tile))) return CMD_ERROR;
02339
02340
02341 z_old += ApplyFoundationToSlope(GetRailFoundation(tileh_old, rail_bits), &tileh_old);
02342 z_new += ApplyFoundationToSlope(GetRailFoundation(tileh_new, rail_bits), &tileh_new);
02343
02344 Corner track_corner;
02345 switch (rail_bits) {
02346 case TRACK_BIT_LEFT: track_corner = CORNER_W; break;
02347 case TRACK_BIT_LOWER: track_corner = CORNER_S; break;
02348 case TRACK_BIT_RIGHT: track_corner = CORNER_E; break;
02349 case TRACK_BIT_UPPER: track_corner = CORNER_N; break;
02350
02351
02352 default: return (((z_old != z_new) || (tileh_old != tileh_new)) ? CMD_ERROR : CommandCost(EXPENSES_CONSTRUCTION, _price.terraform));
02353 }
02354
02355
02356 z_old += GetSlopeZInCorner(RemoveHalftileSlope(tileh_old), track_corner);
02357 z_new += GetSlopeZInCorner(RemoveHalftileSlope(tileh_new), track_corner);
02358 if (z_old != z_new) return CMD_ERROR;
02359
02360 CommandCost cost = CommandCost(EXPENSES_CONSTRUCTION, _price.terraform);
02361
02362 if (tileh_old != tileh_new) {
02363
02364 if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old)) cost.AddCost(_price.clear_water);
02365 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
02366 }
02367 return cost;
02368 }
02369
02370 static CommandCost TerraformTile_Track(TileIndex tile, uint32 flags, uint z_new, Slope tileh_new)
02371 {
02372 uint z_old;
02373 Slope tileh_old = GetTileSlope(tile, &z_old);
02374 if (IsPlainRailTile(tile)) {
02375 TrackBits rail_bits = GetTrackBits(tile);
02376
02377 bool was_water = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old));
02378
02379 _error_message = STR_1008_MUST_REMOVE_RAILROAD_TRACK;
02380
02381
02382 CommandCost autoslope_result = TestAutoslopeOnRailTile(tile, flags, z_old, tileh_old, z_new, tileh_new, rail_bits);
02383
02384
02385 Corner allowed_corner;
02386 switch (rail_bits) {
02387 case TRACK_BIT_RIGHT: allowed_corner = CORNER_W; break;
02388 case TRACK_BIT_UPPER: allowed_corner = CORNER_S; break;
02389 case TRACK_BIT_LEFT: allowed_corner = CORNER_E; break;
02390 case TRACK_BIT_LOWER: allowed_corner = CORNER_N; break;
02391 default: return autoslope_result;
02392 }
02393
02394 Foundation f_old = GetRailFoundation(tileh_old, rail_bits);
02395
02396
02397 if (tileh_old != SLOPE_NS && tileh_old != SLOPE_EW && IsSpecialRailFoundation(f_old)) return autoslope_result;
02398
02399
02400 for (Corner corner = (Corner)0; corner < CORNER_END; corner = (Corner)(corner + 1)) {
02401 if (allowed_corner == corner) continue;
02402 if (z_old + GetSlopeZInCorner(tileh_old, corner) != z_new + GetSlopeZInCorner(tileh_new, corner)) return autoslope_result;
02403 }
02404
02405
02406 if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN);
02407
02408
02409 return CommandCost(EXPENSES_CONSTRUCTION, was_water ? _price.clear_water : (Money)0);
02410 } else {
02411 if (_patches.build_on_slopes && AutoslopeEnabled()) {
02412 switch (GetRailTileType(tile)) {
02413 case RAIL_TILE_WAYPOINT: {
02414 CommandCost cost = TestAutoslopeOnRailTile(tile, flags, z_old, tileh_old, z_new, tileh_new, GetRailWaypointBits(tile));
02415 if (!CmdFailed(cost)) return cost;
02416 break;
02417 }
02418
02419 case RAIL_TILE_DEPOT:
02420 if (AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetRailDepotDirection(tile))) return CommandCost(EXPENSES_CONSTRUCTION, _price.terraform);
02421 break;
02422
02423 default: NOT_REACHED();
02424 }
02425 }
02426 }
02427 return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
02428 }
02429
02430
02431 extern const TileTypeProcs _tile_type_rail_procs = {
02432 DrawTile_Track,
02433 GetSlopeZ_Track,
02434 ClearTile_Track,
02435 GetAcceptedCargo_Track,
02436 GetTileDesc_Track,
02437 GetTileTrackStatus_Track,
02438 ClickTile_Track,
02439 AnimateTile_Track,
02440 TileLoop_Track,
02441 ChangeTileOwner_Track,
02442 NULL,
02443 VehicleEnter_Track,
02444 GetFoundation_Track,
02445 TerraformTile_Track,
02446 };