10
#include "bridge_map.h"
11
10
#include "rail_map.h"
14
11
#include "landscape.h"
15
#include "tunnel_map.h"
16
12
#include "unmovable_map.h"
17
13
#include "viewport_func.h"
18
14
#include "command_func.h"
20
16
#include "variables.h"
23
18
#include "water_map.h"
24
19
#include "yapf/yapf.h"
25
20
#include "newgrf_sound.h"
26
21
#include "autoslope.h"
27
#include "transparency.h"
28
22
#include "tunnelbridge_map.h"
29
23
#include "strings_func.h"
30
24
#include "date_func.h"
31
25
#include "functions.h"
32
26
#include "vehicle_func.h"
33
27
#include "sound_func.h"
34
#include "signal_func.h"
35
28
#include "tunnelbridge.h"
36
#include "player_base.h"
29
#include "engine_base.h"
30
#include "cheat_type.h"
31
#include "elrail_func.h"
32
#include "landscape_type.h"
38
34
#include "table/sprites.h"
39
35
#include "table/strings.h"
40
36
#include "table/bridge_land.h"
42
38
BridgeSpec _bridge[MAX_BRIDGES];
39
TileIndex _build_tunnel_endtile;
44
41
/** Reset the data been eventually changed by the grf loaded. */
45
42
void ResetBridges()
98
95
return (tileh != SLOPE_FLAT);
101
static inline const PalSpriteID *GetBridgeSpriteTable(int index, byte table)
98
static inline const PalSpriteID *GetBridgeSpriteTable(int index, BridgePieces table)
103
100
const BridgeSpec *bridge = GetBridgeSpec(index);
101
assert(table < BRIDGE_PIECE_INVALID);
105
102
if (bridge->sprite_table == NULL || bridge->sprite_table[table] == NULL) {
106
103
return _bridge_sprite_table[index][table];
152
149
return CommandCost(EXPENSES_CONSTRUCTION, _price.terraform);
155
bool CheckBridge_Stuff(BridgeType bridge_type, uint bridge_len, uint32 flags)
152
bool CheckBridge_Stuff(BridgeType bridge_type, uint bridge_len, DoCommandFlag flags)
157
154
if (flags & DC_QUERY_COST) {
158
return bridge_len <= (_patches.longbridges ? 100U : 16U);
155
return bridge_len <= (_settings_game.construction.longbridges ? 100U : 16U);
161
158
if (bridge_type >= MAX_BRIDGES) return false;
174
171
* @param flags type of operation
175
172
* @param p1 packed start tile coords (~ dx)
176
173
* @param p2 various bitstuffed elements
177
* - p2 = (bit 0- 7) - bridge type (hi bh)
178
* - p2 = (bit 8-..) - rail type or road types.
179
* - p2 = (bit 15 ) - set means road bridge.
174
* - p2 = (bit 0- 7) - bridge type (hi bh)
175
* - p2 = (bit 8-14) - rail type or road types.
176
* - p2 = (bit 15-16) - transport type.
181
CommandCost CmdBuildBridge(TileIndex end_tile, uint32 flags, uint32 p1, uint32 p2)
178
CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
183
180
BridgeType bridge_type;
184
181
RailType railtype = INVALID_RAILTYPE;
213
210
/* type of bridge */
214
211
switch (transport_type) {
215
212
case TRANSPORT_ROAD:
216
roadtypes = (RoadTypes)GB(p2, 8, 3);
217
if (!AreValidRoadTypes(roadtypes) || !HasRoadTypesAvail(_current_player, roadtypes)) return CMD_ERROR;
213
roadtypes = (RoadTypes)GB(p2, 8, 2);
214
if (!AreValidRoadTypes(roadtypes) || !HasRoadTypesAvail(_current_company, roadtypes)) return CMD_ERROR;
220
217
case TRANSPORT_RAIL:
221
railtype = (RailType)GB(p2, 8, 8);
218
railtype = (RailType)GB(p2, 8, 7);
222
219
if (!ValParamRailtype(railtype)) return CMD_ERROR;
222
case TRANSPORT_WATER:
226
/* For now, only TRANSPORT_RAIL and TRANSPORT_ROAD are allowed.
227
* But let not this stops us for preparing the future */
226
/* Airports don't have tunnels. */
228
227
return CMD_ERROR;
245
244
return_cmd_error(STR_500A_START_AND_END_MUST_BE_IN);
248
/* set and test bridge length, availability */
249
247
bridge_len = sx + sy - x - y - 1;
250
if (!CheckBridge_Stuff(bridge_type, bridge_len, flags)) return_cmd_error(STR_5015_CAN_T_BUILD_BRIDGE_HERE);
248
if (transport_type != TRANSPORT_WATER) {
249
/* set and test bridge length, availability */
250
if (!CheckBridge_Stuff(bridge_type, bridge_len, flags)) return_cmd_error(STR_5015_CAN_T_BUILD_BRIDGE_HERE);
252
253
/* retrieve landscape height and ensure it's on land */
253
254
tile_start = TileXY(x, y);
292
293
return_cmd_error(STR_1007_ALREADY_BUILT);
295
/* Do not allow replacing another player's bridges. */
296
if (!IsTileOwner(tile_start, _current_player) && !IsTileOwner(tile_start, OWNER_TOWN)) {
296
/* Do not allow replacing another company's bridges. */
297
if (!IsTileOwner(tile_start, _current_company) && !IsTileOwner(tile_start, OWNER_TOWN)) {
297
298
return_cmd_error(STR_1024_AREA_IS_OWNED_BY_ANOTHER);
307
308
/* Build a new bridge. */
309
bool allow_on_slopes = (!_is_old_ai_player && _patches.build_on_slopes);
310
bool allow_on_slopes = (_settings_game.construction.build_on_slopes && transport_type != TRANSPORT_WATER);
311
312
/* Try and clear the start landscape */
312
313
ret = DoCommand(tile_start, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
426
433
if (flags & DC_EXEC && transport_type == TRANSPORT_RAIL) {
427
434
Track track = AxisToTrack(direction);
428
AddSideToSignalBuffer(tile_start, INVALID_DIAGDIR, _current_player);
435
AddSideToSignalBuffer(tile_start, INVALID_DIAGDIR, _current_company);
429
436
YapfNotifyTrackLayoutChange(tile_start, track);
433
440
* It's unnecessary to execute this command every time for every bridge. So it is done only
434
441
* and cost is computed in "bridge_gui.c". For AI, Towns this has to be of course calculated
436
if (!(flags & DC_QUERY_COST) || (IsValidPlayer(_current_player) && GetPlayer(_current_player)->is_ai)) {
443
if (!(flags & DC_QUERY_COST) || (IsValidCompanyID(_current_company) && GetCompany(_current_company)->is_ai)) {
437
444
bridge_len += 2; // begin and end tiles/ramps
439
if (IsValidPlayer(_current_player) && !_is_old_ai_player)
446
if (IsValidCompanyID(_current_company))
440
447
bridge_len = CalcBridgeLenCostFactor(bridge_len);
442
449
cost.AddCost((int64)bridge_len * _price.build_bridge * GetBridgeSpec(bridge_type)->price >> 8);
451
/* Aqueducts are a little more expensive. */
452
if (transport_type == TRANSPORT_WATER) cost.AddCost((int64)bridge_len * _price.clear_water);
469
479
if (transport_type == TRANSPORT_RAIL) {
470
480
if (!ValParamRailtype((RailType)p1)) return CMD_ERROR;
472
const RoadTypes rts = (RoadTypes)GB(p1, 0, 3);
473
if (!AreValidRoadTypes(rts) || !HasRoadTypesAvail(_current_player, rts)) return CMD_ERROR;
482
const RoadTypes rts = (RoadTypes)GB(p1, 0, 2);
483
if (!AreValidRoadTypes(rts) || !HasRoadTypesAvail(_current_company, rts)) return CMD_ERROR;
476
486
start_tileh = GetTileSlope(start_tile, &start_z);
536
547
/* slope of end tile must be complementary to the slope of the start tile */
537
548
if (end_tileh != ComplementSlope(start_tileh)) {
538
/* Check if there is a structure on the terraformed tile. Do not add the cost, that will be done by the terraforming */
549
/* Check if there is a structure on the terraformed tile. Do not add the cost, that will be done by the terraforming
550
* Note: Currently the town rating is also affected by this clearing-test. So effectivly the player is punished twice for clearing
551
* the tree on end_tile.
539
553
ret = DoCommand(end_tile, 0, 0, DC_AUTO, CMD_LANDSCAPE_CLEAR);
540
554
if (CmdFailed(ret)) return_cmd_error(STR_5005_UNABLE_TO_EXCAVATE_LAND);
551
565
if (flags & DC_EXEC) {
552
566
if (transport_type == TRANSPORT_RAIL) {
553
MakeRailTunnel(start_tile, _current_player, direction, (RailType)GB(p1, 0, 4));
554
MakeRailTunnel(end_tile, _current_player, ReverseDiagDir(direction), (RailType)GB(p1, 0, 4));
555
AddSideToSignalBuffer(start_tile, INVALID_DIAGDIR, _current_player);
556
YapfNotifyTrackLayoutChange(start_tile, AxisToTrack(DiagDirToAxis(direction)));
567
MakeRailTunnel(start_tile, _current_company, direction, (RailType)GB(p1, 0, 4));
568
MakeRailTunnel(end_tile, _current_company, ReverseDiagDir(direction), (RailType)GB(p1, 0, 4));
569
AddSideToSignalBuffer(start_tile, INVALID_DIAGDIR, _current_company);
570
YapfNotifyTrackLayoutChange(start_tile, DiagDirToDiagTrack(direction));
558
MakeRoadTunnel(start_tile, _current_player, direction, (RoadTypes)GB(p1, 0, 3));
559
MakeRoadTunnel(end_tile, _current_player, ReverseDiagDir(direction), (RoadTypes)GB(p1, 0, 3));
572
MakeRoadTunnel(start_tile, _current_company, direction, (RoadTypes)GB(p1, 0, 2));
573
MakeRoadTunnel(end_tile, _current_company, ReverseDiagDir(direction), (RoadTypes)GB(p1, 0, 2));
567
581
static inline bool CheckAllowRemoveTunnelBridge(TileIndex tile)
569
583
/* Floods can remove anything as well as the scenario editor */
570
if (_current_player == OWNER_WATER || _game_mode == GM_EDITOR) return true;
571
/* Obviously if the bridge/tunnel belongs to us, or no-one, we can remove it */
572
if (CheckTileOwnership(tile) || IsTileOwner(tile, OWNER_NONE)) return true;
573
/* Otherwise we can only remove town-owned stuff with extra patch-settings, or cheat */
574
if (IsTileOwner(tile, OWNER_TOWN) && (_patches.extra_dynamite || _cheats.magic_bulldozer.value)) return true;
584
if (_current_company == OWNER_WATER || _game_mode == GM_EDITOR) return true;
586
switch (GetTunnelBridgeTransportType(tile)) {
587
case TRANSPORT_ROAD: {
588
RoadTypes rts = GetRoadTypes(tile);
589
Owner road_owner = _current_company;
590
Owner tram_owner = _current_company;
592
if (HasBit(rts, ROADTYPE_ROAD)) road_owner = GetRoadOwner(tile, ROADTYPE_ROAD);
593
if (HasBit(rts, ROADTYPE_TRAM)) tram_owner = GetRoadOwner(tile, ROADTYPE_TRAM);
595
/* We can remove unowned road and if the town allows it */
596
if (road_owner == OWNER_TOWN && !(_settings_game.construction.extra_dynamite || _cheats.magic_bulldozer.value)) return CheckTileOwnership(tile);
597
if (road_owner == OWNER_NONE || road_owner == OWNER_TOWN) road_owner = _current_company;
598
if (tram_owner == OWNER_NONE) tram_owner = _current_company;
600
return CheckOwnership(road_owner) && CheckOwnership(tram_owner);
604
case TRANSPORT_WATER:
605
return CheckOwnership(GetTileOwner(tile));
607
default: NOT_REACHED();
578
static CommandCost DoClearTunnel(TileIndex tile, uint32 flags)
611
static CommandCost DoClearTunnel(TileIndex tile, DoCommandFlag flags)
581
614
TileIndex endtile;
589
622
_build_tunnel_endtile = endtile;
591
624
if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) {
592
t = ClosestTownFromTile(tile, (uint)-1); // town penalty rating
625
t = ClosestTownFromTile(tile, UINT_MAX); // town penalty rating
594
627
/* Check if you are allowed to remove the tunnel owned by a town
595
628
* Removal depends on difficulty settings */
602
635
/* checks if the owner is town then decrease town rating by RATING_TUNNEL_BRIDGE_DOWN_STEP until
603
636
* you have a "Poor" (0) town rating */
604
637
if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) {
605
ChangeTownRating(t, RATING_TUNNEL_BRIDGE_DOWN_STEP, RATING_TUNNEL_BRIDGE_MINIMUM);
638
ChangeTownRating(t, RATING_TUNNEL_BRIDGE_DOWN_STEP, RATING_TUNNEL_BRIDGE_MINIMUM, flags);
608
641
if (flags & DC_EXEC) {
609
642
if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) {
610
643
/* We first need to request values before calling DoClearSquare */
611
644
DiagDirection dir = GetTunnelBridgeDirection(tile);
645
Track track = DiagDirToDiagTrack(dir);
612
646
Owner owner = GetTileOwner(tile);
649
if (GetTunnelBridgeReservation(tile)) {
650
v = GetTrainForReservation(tile, track);
651
if (v != NULL) FreeTrainTrackReservation(v);
614
654
DoClearSquare(tile);
615
655
DoClearSquare(endtile);
618
658
AddSideToSignalBuffer(tile, ReverseDiagDir(dir), owner);
619
659
AddSideToSignalBuffer(endtile, dir, owner);
621
Track track = AxisToTrack(DiagDirToAxis(dir));
622
661
YapfNotifyTrackLayoutChange(tile, track);
623
662
YapfNotifyTrackLayoutChange(endtile, track);
664
if (v != NULL) TryPathReserve(v);
625
666
DoClearSquare(tile);
626
667
DoClearSquare(endtile);
647
688
delta = TileOffsByDiagDir(direction);
649
690
if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) {
650
t = ClosestTownFromTile(tile, (uint)-1); // town penalty rating
691
t = ClosestTownFromTile(tile, UINT_MAX); // town penalty rating
652
693
/* Check if you are allowed to remove the bridge owned by a town
653
694
* Removal depends on difficulty settings */
660
701
/* checks if the owner is town then decrease town rating by RATING_TUNNEL_BRIDGE_DOWN_STEP until
661
702
* you have a "Poor" (0) town rating */
662
703
if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) {
663
ChangeTownRating(t, RATING_TUNNEL_BRIDGE_DOWN_STEP, RATING_TUNNEL_BRIDGE_MINIMUM);
704
ChangeTownRating(t, RATING_TUNNEL_BRIDGE_DOWN_STEP, RATING_TUNNEL_BRIDGE_MINIMUM, flags);
666
707
if (flags & DC_EXEC) {
686
733
AddSideToSignalBuffer(tile, ReverseDiagDir(direction), owner);
687
734
AddSideToSignalBuffer(endtile, direction, owner);
689
Track track = AxisToTrack(DiagDirToAxis(direction));
736
Track track = DiagDirToDiagTrack(direction);
690
737
YapfNotifyTrackLayoutChange(tile, track);
691
738
YapfNotifyTrackLayoutChange(endtile, track);
740
if (v != NULL) TryPathReserve(v, true);
695
744
return CommandCost(EXPENSES_CONSTRUCTION, (GetTunnelBridgeLength(tile, endtile) + 2) * _price.clear_bridge);
698
static CommandCost ClearTile_TunnelBridge(TileIndex tile, byte flags)
747
static CommandCost ClearTile_TunnelBridge(TileIndex tile, DoCommandFlag flags)
700
749
if (IsTunnel(tile)) {
701
750
if (flags & DC_AUTO) return_cmd_error(STR_5006_MUST_DEMOLISH_TUNNEL_FIRST);
719
768
* @param y Sprite Y position of front pillar.
720
769
* @param z_bridge Absolute height of bridge bottom.
722
static void DrawBridgePillars(const PalSpriteID *psid, const TileInfo* ti, Axis axis, BridgeType type, int x, int y, int z_bridge)
771
static void DrawBridgePillars(const PalSpriteID *psid, const TileInfo *ti, Axis axis, bool drawfarpillar, int x, int y, int z_bridge)
773
/* Do not draw bridge pillars if they are invisible */
774
if (IsInvisibilitySet(TO_BRIDGES)) return;
724
776
SpriteID image = psid->sprite;
725
778
if (image != 0) {
726
bool drawfarpillar = !HasBit(GetBridgeSpec(type)->flags, 0);
728
779
/* "side" specifies the side the pillars stand on.
729
780
* The length of the pillars is then set to the height of the bridge over the corners of this edge.
773
824
* @param z the z of the bridge
774
825
* @param offset number representing whether to level or sloped and the direction
775
826
* @param overlay do we want to still see the road?
827
* @param head are we drawing bridge head?
777
static void DrawBridgeTramBits(int x, int y, byte z, int offset, bool overlay)
829
static void DrawBridgeTramBits(int x, int y, byte z, int offset, bool overlay, bool head)
779
831
static const SpriteID tram_offsets[2][6] = { { 107, 108, 109, 110, 111, 112 }, { 4, 5, 15, 16, 17, 18 } };
780
832
static const SpriteID back_offsets[6] = { 95, 96, 99, 102, 100, 101 };
788
840
/* The sprites under the vehicles are drawn as SpriteCombine. StartSpriteCombine() has already been called
789
841
* The bounding boxes here are the same as for bridge front/roof */
790
AddSortableSpriteToDraw(SPR_TRAMWAY_BASE + tram_offsets[overlay][offset], PAL_NONE, x, y, size_x[offset], size_y[offset], 0x28, z, IsTransparencySet(TO_BRIDGES));
842
if (head || !IsInvisibilitySet(TO_BRIDGES)) {
843
AddSortableSpriteToDraw(SPR_TRAMWAY_BASE + tram_offsets[overlay][offset], PAL_NONE,
844
x, y, size_x[offset], size_y[offset], 0x28, z,
845
!head && IsTransparencySet(TO_BRIDGES));
792
AddSortableSpriteToDraw(SPR_TRAMWAY_BASE + back_offsets[offset], PAL_NONE, x, y, size_x[offset], size_y[offset], 0x28, z, IsTransparencySet(TO_CATENARY));
848
/* Do not draw catenary if it is set invisible */
849
if (!IsInvisibilitySet(TO_CATENARY)) {
850
AddSortableSpriteToDraw(SPR_TRAMWAY_BASE + back_offsets[offset], PAL_NONE,
851
x, y, size_x[offset], size_y[offset], 0x28, z,
852
IsTransparencySet(TO_CATENARY));
794
855
/* Start a new SpriteCombine for the front part */
795
856
EndSpriteCombine();
796
857
StartSpriteCombine();
798
859
/* For sloped sprites the bounding box needs to be higher, as the pylons stop on a higher point */
799
AddSortableSpriteToDraw(SPR_TRAMWAY_BASE + front_offsets[offset], PAL_NONE, x, y, size_x[offset] + front_bb_offset_x[offset], size_y[offset] + front_bb_offset_y[offset], 0x28, z, IsTransparencySet(TO_CATENARY), front_bb_offset_x[offset], front_bb_offset_y[offset]);
860
if (!IsInvisibilitySet(TO_CATENARY)) {
861
AddSortableSpriteToDraw(SPR_TRAMWAY_BASE + front_offsets[offset], PAL_NONE,
862
x, y, size_x[offset] + front_bb_offset_x[offset], size_y[offset] + front_bb_offset_y[offset], 0x28, z,
863
IsTransparencySet(TO_CATENARY), front_bb_offset_x[offset], front_bb_offset_y[offset]);
851
916
image += tunnelbridge_direction * 2;
852
917
DrawGroundSprite(image, PAL_NONE);
919
/* PBS debugging, draw reserved tracks darker */
920
if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && (transport_type == TRANSPORT_RAIL && GetTunnelBridgeReservation(ti->tile))) {
921
const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
922
DrawGroundSprite(DiagDirToAxis(tunnelbridge_direction) == AXIS_X ? rti->base_sprites.single_y : rti->base_sprites.single_x, PALETTE_CRASH);
853
925
if (transport_type == TRANSPORT_ROAD) {
854
926
RoadTypes rts = GetRoadTypes(ti->tile);
859
931
DrawGroundSprite(SPR_TRAMWAY_BASE + tunnel_sprites[rts - ROADTYPES_TRAM][tunnelbridge_direction], PAL_NONE);
862
StartSpriteCombine();
863
AddSortableSpriteToDraw(SPR_TRAMWAY_TUNNEL_WIRES + tunnelbridge_direction, PAL_NONE, ti->x, ti->y, BB_data[10], BB_data[11], TILE_HEIGHT, ti->z, IsTransparencySet(TO_CATENARY), BB_data[8], BB_data[9], BB_Z_SEPARATOR);
933
/* Do not draw wires if they are invisible */
934
if (!IsInvisibilitySet(TO_CATENARY)) {
936
StartSpriteCombine();
937
AddSortableSpriteToDraw(SPR_TRAMWAY_TUNNEL_WIRES + tunnelbridge_direction, PAL_NONE, ti->x, ti->y, BB_data[10], BB_data[11], TILE_HEIGHT, ti->z, IsTransparencySet(TO_CATENARY), BB_data[8], BB_data[9], BB_Z_SEPARATOR);
865
} else if (GetRailType(ti->tile) == RAILTYPE_ELECTRIC) {
940
} else if (HasCatenaryDrawn(GetRailType(ti->tile))) {
941
/* Maybe draw pylons on the entry side */
866
942
DrawCatenary(ti);
869
945
StartSpriteCombine();
946
/* Draw wire above the ramp */
870
947
DrawCatenaryOnTunnel(ti);
902
979
if (ti->tileh == SLOPE_FLAT) base_offset += 4; // sloped bridge head
904
/* Table number 6 always refers to the bridge heads for any bridge type */
905
psid = &GetBridgeSpriteTable(GetBridgeType(ti->tile), 6)[base_offset];
981
/* Table number BRIDGE_PIECE_HEAD always refers to the bridge heads for any bridge type */
982
if (transport_type != TRANSPORT_WATER) {
983
psid = &GetBridgeSpriteTable(GetBridgeType(ti->tile), BRIDGE_PIECE_HEAD)[base_offset];
985
psid = _aqueduct_sprites + base_offset;
908
989
DrawClearLandTile(ti, 3);
918
999
/* HACK set the height of the BB of a sloped ramp to 1 so a vehicle on
919
1000
* it doesn't disappear behind it
921
AddSortableSpriteToDraw(
922
psid->sprite, psid->pal, ti->x, ti->y, 16, 16, ti->tileh == SLOPE_FLAT ? 0 : 8, ti->z, IsTransparencySet(TO_BRIDGES)
1002
/* Bridge heads are drawn solid no matter how invisibility/transparency is set */
1003
AddSortableSpriteToDraw(psid->sprite, psid->pal, ti->x, ti->y, 16, 16, ti->tileh == SLOPE_FLAT ? 0 : 8, ti->z);
1005
if (_settings_client.gui.show_track_reservation && transport_type == TRANSPORT_RAIL && GetTunnelBridgeReservation(ti->tile)) {
1006
const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
1007
if (HasBridgeFlatRamp(ti->tileh, DiagDirToAxis(tunnelbridge_direction))) {
1008
AddSortableSpriteToDraw(DiagDirToAxis(tunnelbridge_direction) == AXIS_X ? rti->base_sprites.single_y : rti->base_sprites.single_x, PALETTE_CRASH, ti->x, ti->y, 16, 16, 0, ti->z + 8);
1010
AddSortableSpriteToDraw(rti->base_sprites.single_sloped + tunnelbridge_direction, PALETTE_CRASH, ti->x, ti->y, 16, 16, 8, ti->z);
925
1014
if (transport_type == TRANSPORT_ROAD) {
926
1015
RoadTypes rts = GetRoadTypes(ti->tile);
937
1026
/* DrawBridgeTramBits() calls EndSpriteCombine() and StartSpriteCombine() */
938
DrawBridgeTramBits(ti->x, ti->y, z, offset, HasBit(rts, ROADTYPE_ROAD));
1027
DrawBridgeTramBits(ti->x, ti->y, z, offset, HasBit(rts, ROADTYPE_ROAD), true);
940
1029
EndSpriteCombine();
941
} else if (GetRailType(ti->tile) == RAILTYPE_ELECTRIC) {
1030
} else if (transport_type == TRANSPORT_RAIL) {
1031
if (HasCatenaryDrawn(GetRailType(ti->tile))) {
945
1036
DrawBridgeMiddle(ti);
950
1041
/** Compute bridge piece. Computes the bridge piece to display depending on the position inside the bridge.
951
* bridges pieces sequence (middle parts)
954
* bridge len 3: 0 4 1
955
* bridge len 4: 0 2 3 1
956
* bridge len 5: 0 2 5 3 1
957
* bridge len 6: 0 2 3 2 3 1
958
* bridge len 7: 0 2 3 4 2 3 1
1042
* bridges pieces sequence (middle parts).
1043
* Note that it is not covering the bridge heads, which are always referenced by the same sprite table.
1044
* bridge len 1: BRIDGE_PIECE_NORTH
1045
* bridge len 2: BRIDGE_PIECE_NORTH BRIDGE_PIECE_SOUTH
1046
* bridge len 3: BRIDGE_PIECE_NORTH BRIDGE_PIECE_MIDDLE_ODD BRIDGE_PIECE_SOUTH
1047
* bridge len 4: BRIDGE_PIECE_NORTH BRIDGE_PIECE_INNER_NORTH BRIDGE_PIECE_INNER_SOUTH BRIDGE_PIECE_SOUTH
1048
* bridge len 5: BRIDGE_PIECE_NORTH BRIDGE_PIECE_INNER_NORTH BRIDGE_PIECE_MIDDLE_EVEN BRIDGE_PIECE_INNER_SOUTH BRIDGE_PIECE_SOUTH
1049
* bridge len 6: BRIDGE_PIECE_NORTH BRIDGE_PIECE_INNER_NORTH BRIDGE_PIECE_INNER_SOUTH BRIDGE_PIECE_INNER_NORTH BRIDGE_PIECE_INNER_SOUTH BRIDGE_PIECE_SOUTH
1050
* bridge len 7: BRIDGE_PIECE_NORTH BRIDGE_PIECE_INNER_NORTH BRIDGE_PIECE_INNER_SOUTH BRIDGE_PIECE_MIDDLE_ODD BRIDGE_PIECE_INNER_NORTH BRIDGE_PIECE_INNER_SOUTH BRIDGE_PIECE_SOUTH
959
1051
* #0 - always as first, #1 - always as last (if len>1)
960
1052
* #2,#3 are to pair in order
961
1053
* for odd bridges: #5 is going in the bridge middle if on even position, #4 on odd (counting from 0)
963
1055
* @param south Southernmost tile of bridge
964
1056
* @return Index of bridge piece
966
static uint CalcBridgePiece(uint north, uint south)
1058
static BridgePieces CalcBridgePiece(uint north, uint south)
968
1060
if (north == 1) {
1061
return BRIDGE_PIECE_NORTH;
970
1062
} else if (south == 1) {
1063
return BRIDGE_PIECE_SOUTH;
972
1064
} else if (north < south) {
973
return north & 1 ? 3 : 2;
1065
return north & 1 ? BRIDGE_PIECE_INNER_SOUTH : BRIDGE_PIECE_INNER_NORTH;
974
1066
} else if (north > south) {
975
return south & 1 ? 2 : 3;
1067
return south & 1 ? BRIDGE_PIECE_INNER_NORTH : BRIDGE_PIECE_INNER_SOUTH;
977
return north & 1 ? 5 : 4;
1069
return north & 1 ? BRIDGE_PIECE_MIDDLE_EVEN : BRIDGE_PIECE_MIDDLE_ODD;
982
void DrawBridgeMiddle(const TileInfo* ti)
1074
void DrawBridgeMiddle(const TileInfo *ti)
984
1076
/* Sectional view of bridge bounding boxes:
1000
1092
/* Z position of the bridge sprites relative to bridge height (downwards) */
1001
1093
static const int BRIDGE_Z_START = 3;
1003
const PalSpriteID* psid;
1005
TileIndex rampnorth;
1006
TileIndex rampsouth;
1007
TransportType transport_type;
1015
1095
if (!IsBridgeAbove(ti->tile)) return;
1017
rampnorth = GetNorthernBridgeEnd(ti->tile);
1018
rampsouth = GetSouthernBridgeEnd(ti->tile);
1019
transport_type = GetTunnelBridgeTransportType(rampsouth);
1097
TileIndex rampnorth = GetNorthernBridgeEnd(ti->tile);
1098
TileIndex rampsouth = GetSouthernBridgeEnd(ti->tile);
1099
TransportType transport_type = GetTunnelBridgeTransportType(rampsouth);
1021
axis = GetBridgeAxis(ti->tile);
1022
piece = CalcBridgePiece(
1101
Axis axis = GetBridgeAxis(ti->tile);
1102
BridgePieces piece = CalcBridgePiece(
1023
1103
GetTunnelBridgeLength(ti->tile, rampnorth) + 1,
1024
1104
GetTunnelBridgeLength(ti->tile, rampsouth) + 1
1026
type = GetBridgeType(rampsouth);
1028
if (transport_type == TRANSPORT_RAIL) {
1029
base_offset = GetRailTypeInfo(GetRailType(rampsouth))->bridge_offset;
1107
const PalSpriteID *psid;
1109
if (transport_type != TRANSPORT_WATER) {
1110
BridgeType type = GetBridgeType(rampsouth);
1111
drawfarpillar = !HasBit(GetBridgeSpec(type)->flags, 0);
1114
if (transport_type == TRANSPORT_RAIL) {
1115
base_offset = GetRailTypeInfo(GetRailType(rampsouth))->bridge_offset;
1120
psid = base_offset + GetBridgeSpriteTable(type, piece);
1122
drawfarpillar = true;
1123
psid = _aqueduct_sprites;
1034
psid = base_offset + GetBridgeSpriteTable(type, piece);
1035
1126
if (axis != AXIS_X) psid += 4;
1039
1130
uint bridge_z = GetBridgeHeight(rampsouth);
1040
z = bridge_z - BRIDGE_Z_START;
1131
uint z = bridge_z - BRIDGE_Z_START;
1042
1133
/* Add a bounding box, that separates the bridge from things below it. */
1043
1134
AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, x, y, 16, 16, 1, bridge_z - TILE_HEIGHT + BB_Z_SEPARATOR);
1046
1137
if (transport_type == TRANSPORT_ROAD) StartSpriteCombine();
1048
1139
/* Draw floor and far part of bridge*/
1049
if (axis == AXIS_X) {
1050
AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, 16, 1, 0x28, z, IsTransparencySet(TO_BRIDGES), 0, 0, BRIDGE_Z_START);
1052
AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, 1, 16, 0x28, z, IsTransparencySet(TO_BRIDGES), 0, 0, BRIDGE_Z_START);
1140
if (!IsInvisibilitySet(TO_BRIDGES)) {
1141
if (axis == AXIS_X) {
1142
AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, 16, 1, 0x28, z, IsTransparencySet(TO_BRIDGES), 0, 0, BRIDGE_Z_START);
1144
AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, 1, 16, 0x28, z, IsTransparencySet(TO_BRIDGES), 0, 0, BRIDGE_Z_START);
1060
1153
if (HasBit(rts, ROADTYPE_TRAM)) {
1061
1154
/* DrawBridgeTramBits() calls EndSpriteCombine() and StartSpriteCombine() */
1062
DrawBridgeTramBits(x, y, bridge_z, axis ^ 1, HasBit(rts, ROADTYPE_ROAD));
1155
DrawBridgeTramBits(x, y, bridge_z, axis ^ 1, HasBit(rts, ROADTYPE_ROAD), false);
1064
1157
EndSpriteCombine();
1065
1158
StartSpriteCombine();
1067
} else if (GetRailType(rampsouth) == RAILTYPE_ELECTRIC) {
1160
} else if (transport_type == TRANSPORT_RAIL) {
1161
if (HasCatenaryDrawn(GetRailType(rampsouth))) {
1162
DrawCatenaryOnBridge(ti);
1071
1166
/* draw roof, the component of the bridge which is logically between the vehicle and the camera */
1072
if (axis == AXIS_X) {
1074
if (psid->sprite & SPRITE_MASK) AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, 16, 4, 0x28, z, IsTransparencySet(TO_BRIDGES), 0, 3, BRIDGE_Z_START);
1077
if (psid->sprite & SPRITE_MASK) AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, 4, 16, 0x28, z, IsTransparencySet(TO_BRIDGES), 3, 0, BRIDGE_Z_START);
1167
if (!IsInvisibilitySet(TO_BRIDGES)) {
1168
if (axis == AXIS_X) {
1170
if (psid->sprite & SPRITE_MASK) AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, 16, 4, 0x28, z, IsTransparencySet(TO_BRIDGES), 0, 3, BRIDGE_Z_START);
1173
if (psid->sprite & SPRITE_MASK) AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, 4, 16, 0x28, z, IsTransparencySet(TO_BRIDGES), 3, 0, BRIDGE_Z_START);
1080
1177
/* Draw TramFront as SpriteCombine */
1081
1178
if (transport_type == TRANSPORT_ROAD) EndSpriteCombine();
1180
/* Do not draw anything more if bridges are invisible */
1181
if (IsInvisibilitySet(TO_BRIDGES)) return;
1084
1184
if (ti->z + 5 == z) {
1085
1185
/* draw poles below for small bridges */
1094
1194
DrawGroundSpriteAt(image, pal, x, y, z);
1096
} else if (_patches.bridge_pillars) {
1196
} else if (_settings_client.gui.bridge_pillars) {
1097
1197
/* draw pillars below for high bridges */
1098
DrawBridgePillars(psid, ti, axis, type, x, y, z);
1198
DrawBridgePillars(psid, ti, axis, drawfarpillar, x, y, z);
1153
1253
static void GetTileDesc_TunnelBridge(TileIndex tile, TileDesc *td)
1255
TransportType tt = GetTunnelBridgeTransportType(tile);
1155
1257
if (IsTunnel(tile)) {
1156
td->str = (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) ?
1157
STR_5017_RAILROAD_TUNNEL : STR_5018_ROAD_TUNNEL;
1158
} else { //so it must be a bridge
1159
td->str = GetBridgeSpec(GetBridgeType(tile))->transport_name[GetTunnelBridgeTransportType(tile)];
1161
td->owner = GetTileOwner(tile);
1258
td->str = (tt == TRANSPORT_RAIL) ? STR_5017_RAILROAD_TUNNEL : STR_5018_ROAD_TUNNEL;
1259
} else { // IsBridge(tile)
1260
td->str = (tt == TRANSPORT_WATER) ? STR_AQUEDUCT : GetBridgeSpec(GetBridgeType(tile))->transport_name[tt];
1262
td->owner[0] = GetTileOwner(tile);
1264
Owner road_owner = INVALID_OWNER;
1265
Owner tram_owner = INVALID_OWNER;
1266
RoadTypes rts = GetRoadTypes(tile);
1267
if (HasBit(rts, ROADTYPE_ROAD)) road_owner = GetRoadOwner(tile, ROADTYPE_ROAD);
1268
if (HasBit(rts, ROADTYPE_TRAM)) tram_owner = GetRoadOwner(tile, ROADTYPE_TRAM);
1270
/* Is there a mix of owners? */
1271
if ((tram_owner != INVALID_OWNER && tram_owner != td->owner[0]) ||
1272
(road_owner != INVALID_OWNER && road_owner != td->owner[0])) {
1274
if (road_owner != INVALID_OWNER) {
1275
td->owner_type[i] = STR_ROAD_OWNER;
1276
td->owner[i] = road_owner;
1279
if (tram_owner != INVALID_OWNER) {
1280
td->owner_type[i] = STR_TRAM_OWNER;
1281
td->owner[i] = tram_owner;
1204
1327
DiagDirection dir = GetTunnelBridgeDirection(tile);
1205
1328
if (side != INVALID_DIAGDIR && side != ReverseDiagDir(dir)) return 0;
1206
return CombineTrackStatus(TrackBitsToTrackdirBits(AxisToTrackBits(DiagDirToAxis(dir))), TRACKDIR_BIT_NONE);
1329
return CombineTrackStatus(TrackBitsToTrackdirBits(DiagDirToDiagTrackBits(dir)), TRACKDIR_BIT_NONE);
1209
static void ChangeTileOwner_TunnelBridge(TileIndex tile, PlayerID old_player, PlayerID new_player)
1332
static void ChangeTileOwner_TunnelBridge(TileIndex tile, Owner old_owner, Owner new_owner)
1211
if (!IsTileOwner(tile, old_player)) return;
1213
if (new_player != PLAYER_SPECTATOR) {
1214
SetTileOwner(tile, new_player);
1334
for (RoadType rt = ROADTYPE_ROAD; rt < ROADTYPE_END; rt++) {
1335
/* Update all roadtypes, no matter if they are present */
1336
if (GetRoadOwner(tile, rt) == old_owner) {
1337
SetRoadOwner(tile, rt, new_owner == INVALID_OWNER ? OWNER_NONE : new_owner);
1341
if (!IsTileOwner(tile, old_owner)) return;
1343
if (new_owner != INVALID_OWNER) {
1344
SetTileOwner(tile, new_owner);
1216
1346
if (CmdFailed(DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR))) {
1217
1347
/* When clearing the bridge/tunnel failed there are still vehicles on/in
1218
1348
* the bridge/tunnel. As all *our* vehicles are already removed, they
1219
* must be of another owner. Therefor this must be a road bridge/tunnel.
1349
* must be of another owner. Therefore this can't be rail tunnel/bridge.
1220
1350
* In that case we can safely reassign the ownership to OWNER_NONE. */
1221
assert(GetTunnelBridgeTransportType(tile) == TRANSPORT_ROAD);
1351
assert(GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL);
1222
1352
SetTileOwner(tile, OWNER_NONE);
1328
1458
case DIAGDIR_SW: if ((x & 0xF) != TILE_SIZE - 1) return VETSB_CONTINUE; break;
1329
1459
case DIAGDIR_NW: if ((y & 0xF) != 0) return VETSB_CONTINUE; break;
1331
if (v->type == VEH_TRAIN) {
1332
v->u.rail.track = TRACK_BIT_WORMHOLE;
1333
ClrBit(v->u.rail.flags, VRF_GOINGUP);
1334
ClrBit(v->u.rail.flags, VRF_GOINGDOWN);
1336
v->u.road.state = RVSB_WORMHOLE;
1463
v->u.rail.track = TRACK_BIT_WORMHOLE;
1464
ClrBit(v->u.rail.flags, VRF_GOINGUP);
1465
ClrBit(v->u.rail.flags, VRF_GOINGDOWN);
1469
v->u.road.state = RVSB_WORMHOLE;
1473
v->u.ship.state = TRACK_BIT_WORMHOLE;
1476
default: NOT_REACHED();
1338
1478
return VETSB_ENTERED_WORMHOLE;
1339
1479
} else if (DirToDiagDir(v->direction) == ReverseDiagDir(dir)) {
1340
1480
v->tile = tile;
1341
if (v->type == VEH_TRAIN) {
1342
if (v->u.rail.track == TRACK_BIT_WORMHOLE) {
1343
v->u.rail.track = (DiagDirToAxis(dir) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y);
1344
return VETSB_ENTERED_WORMHOLE;
1347
if (v->u.road.state == RVSB_WORMHOLE) {
1348
v->u.road.state = _road_exit_tunnel_state[dir];
1349
v->u.road.frame = 0;
1350
return VETSB_ENTERED_WORMHOLE;
1483
if (v->u.rail.track == TRACK_BIT_WORMHOLE) {
1484
v->u.rail.track = (DiagDirToAxis(dir) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y);
1485
return VETSB_ENTERED_WORMHOLE;
1490
if (v->u.road.state == RVSB_WORMHOLE) {
1491
v->u.road.state = _road_exit_tunnel_state[dir];
1492
v->u.road.frame = 0;
1493
return VETSB_ENTERED_WORMHOLE;
1498
if (v->u.ship.state == TRACK_BIT_WORMHOLE) {
1499
v->u.ship.state = (DiagDirToAxis(dir) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y);
1500
return VETSB_ENTERED_WORMHOLE;
1504
default: NOT_REACHED();
1353
return VETSB_CONTINUE;
1356
1508
return VETSB_CONTINUE;
1359
static CommandCost TerraformTile_TunnelBridge(TileIndex tile, uint32 flags, uint z_new, Slope tileh_new)
1511
static CommandCost TerraformTile_TunnelBridge(TileIndex tile, DoCommandFlag flags, uint z_new, Slope tileh_new)
1361
if (_patches.build_on_slopes && AutoslopeEnabled() && IsBridge(tile)) {
1513
if (_settings_game.construction.build_on_slopes && AutoslopeEnabled() && IsBridge(tile) && GetTunnelBridgeTransportType(tile) != TRANSPORT_WATER) {
1362
1514
DiagDirection direction = GetTunnelBridgeDirection(tile);
1363
1515
Axis axis = DiagDirToAxis(direction);
1364
1516
CommandCost res;
1366
1518
Slope tileh_old = GetTileSlope(tile, &z_old);
1368
/* Check if new slope is valid for bridges in general (so we can savely call GetBridgeFoundation()) */
1520
/* Check if new slope is valid for bridges in general (so we can safely call GetBridgeFoundation()) */
1369
1521
if ((direction == DIAGDIR_NW) || (direction == DIAGDIR_NE)) {
1370
1522
CheckBridgeSlopeSouth(axis, &tileh_old, &z_old);
1371
1523
res = CheckBridgeSlopeSouth(axis, &tileh_new, &z_new);
1384
1536
extern const TileTypeProcs _tile_type_tunnelbridge_procs = {
1385
DrawTile_TunnelBridge, /* draw_tile_proc */
1386
GetSlopeZ_TunnelBridge, /* get_slope_z_proc */
1387
ClearTile_TunnelBridge, /* clear_tile_proc */
1388
GetAcceptedCargo_TunnelBridge, /* get_accepted_cargo_proc */
1389
GetTileDesc_TunnelBridge, /* get_tile_desc_proc */
1390
GetTileTrackStatus_TunnelBridge, /* get_tile_track_status_proc */
1391
ClickTile_TunnelBridge, /* click_tile_proc */
1392
AnimateTile_TunnelBridge, /* animate_tile_proc */
1393
TileLoop_TunnelBridge, /* tile_loop_clear */
1394
ChangeTileOwner_TunnelBridge, /* change_tile_owner_clear */
1395
NULL, /* get_produced_cargo_proc */
1396
VehicleEnter_TunnelBridge, /* vehicle_enter_tile_proc */
1397
GetFoundation_TunnelBridge, /* get_foundation_proc */
1398
TerraformTile_TunnelBridge, /* terraform_tile_proc */
1537
DrawTile_TunnelBridge, // draw_tile_proc
1538
GetSlopeZ_TunnelBridge, // get_slope_z_proc
1539
ClearTile_TunnelBridge, // clear_tile_proc
1540
GetAcceptedCargo_TunnelBridge, // get_accepted_cargo_proc
1541
GetTileDesc_TunnelBridge, // get_tile_desc_proc
1542
GetTileTrackStatus_TunnelBridge, // get_tile_track_status_proc
1543
ClickTile_TunnelBridge, // click_tile_proc
1544
AnimateTile_TunnelBridge, // animate_tile_proc
1545
TileLoop_TunnelBridge, // tile_loop_clear
1546
ChangeTileOwner_TunnelBridge, // change_tile_owner_clear
1547
NULL, // get_produced_cargo_proc
1548
VehicleEnter_TunnelBridge, // vehicle_enter_tile_proc
1549
GetFoundation_TunnelBridge, // get_foundation_proc
1550
TerraformTile_TunnelBridge, // terraform_tile_proc