OpenTTD Source 20260711-master-g3fb3006dff
tunnelbridge_cmd.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
12
13#include "stdafx.h"
14#include "viewport_func.h"
15#include "command_func.h"
16#include "town.h"
17#include "train.h"
18#include "ship.h"
19#include "roadveh.h"
21#include "newgrf_sound.h"
22#include "autoslope.h"
23#include "tunnelbridge_map.h"
24#include "strings_func.h"
26#include "clear_func.h"
27#include "vehicle_func.h"
28#include "sound_func.h"
29#include "tunnelbridge.h"
30#include "cheat_type.h"
31#include "elrail_func.h"
32#include "pbs.h"
33#include "company_base.h"
34#include "newgrf_railtype.h"
35#include "newgrf_roadtype.h"
36#include "object_base.h"
37#include "water.h"
38#include "company_gui.h"
39#include "tunnelbridge_cmd.h"
40#include "landscape_cmd.h"
41#include "terraform_cmd.h"
42
43#include "table/strings.h"
44#include "table/bridge_land.h"
45
46#include "safeguards.h"
47
50
52static const int BRIDGE_Z_START = 3;
53
54
63void MarkBridgeDirty(TileIndex begin, TileIndex end, DiagDirection direction, uint bridge_height)
64{
65 TileIndexDiff delta = TileOffsByDiagDir(direction);
66 for (TileIndex t = begin; t != end; t += delta) {
67 MarkTileDirtyByTile(t, bridge_height - TileHeight(t));
68 }
70}
71
80
83{
84 std::ranges::copy(_orig_bridge, std::begin(_bridge));
85}
86
94{
95 if (length < 2) return length;
96
97 length -= 2;
98 int sum = 2;
99 for (int delta = 1;; delta++) {
100 for (int count = 0; count < delta; count++) {
101 if (length == 0) return sum;
102 sum += delta;
103 length--;
104 }
105 }
106}
107
115{
116 if (tileh == SLOPE_FLAT ||
117 ((tileh == SLOPE_NE || tileh == SLOPE_SW) && axis == Axis::X) ||
118 ((tileh == SLOPE_NW || tileh == SLOPE_SE) && axis == Axis::Y)) return Foundation::None;
119
120 return (HasSlopeHighestCorner(tileh) ? InclinedFoundation(axis) : FlatteningFoundation(tileh));
121}
122
130bool HasBridgeFlatRamp(Slope tileh, Axis axis)
131{
132 ApplyFoundationToSlope(GetBridgeFoundation(tileh, axis), tileh);
133 /* If the foundation slope is flat the bridge has a non-flat ramp and vice versa. */
134 return (tileh != SLOPE_FLAT);
135}
136
144{
145 assert(piece < NUM_BRIDGE_PIECES);
146 const BridgeSpec *bridge = GetBridgeSpec(bridge_type);
147 return piece < bridge->sprite_table.size() && !bridge->sprite_table[piece].empty();
148}
149
156static std::span<const PalSpriteID> GetBridgeSpriteTable(BridgeType bridge_type, BridgePieces piece)
157{
158 assert(piece < NUM_BRIDGE_PIECES);
159
160 const BridgeSpec *bridge = GetBridgeSpec(bridge_type);
161 if (piece < bridge->sprite_table.size() && !bridge->sprite_table[piece].empty()) return bridge->sprite_table[piece];
162
163 return _bridge_sprite_table[bridge_type][piece];
164}
165
172static uint8_t GetBridgeSpriteTableBaseOffset(TransportType transport_type, TileIndex ramp)
173{
174 switch (transport_type) {
176 case TransportType::Road: return 8;
177 default: NOT_REACHED();
178 }
179}
180
187{
188 /* Bridge ramps are ordered SW, SE, NE, NW instead of NE, SE, SW, NW. */
189 static constexpr DiagDirectionIndexArray<uint8_t> ramp_offsets{2, 1, 0, 3};
190 return ramp_offsets[diagdir];
191}
192
199{
200 return axis == Axis::X ? 0 : 4;
201}
202
212static CommandCost CheckBridgeSlope(BridgePieces bridge_piece, Axis axis, Slope &tileh, int &z)
213{
214 assert(bridge_piece == BRIDGE_PIECE_NORTH || bridge_piece == BRIDGE_PIECE_SOUTH);
215
216 Foundation f = GetBridgeFoundation(tileh, axis);
217 z += ApplyFoundationToSlope(f, tileh);
218
219 Slope valid_inclined;
220 if (bridge_piece == BRIDGE_PIECE_NORTH) {
221 valid_inclined = (axis == Axis::X ? SLOPE_NE : SLOPE_NW);
222 } else {
223 valid_inclined = (axis == Axis::X ? SLOPE_SW : SLOPE_SE);
224 }
225 if ((tileh != SLOPE_FLAT) && (tileh != valid_inclined)) return CMD_ERROR;
226
227 if (f == Foundation::None) return CommandCost();
228
230}
231
240{
241 if (flags.Test(DoCommandFlag::QueryCost)) {
242 if (bridge_len <= _settings_game.construction.max_bridge_length) return CommandCost();
243 return CommandCost(STR_ERROR_BRIDGE_TOO_LONG);
244 }
245
246 if (bridge_type >= MAX_BRIDGES) return CMD_ERROR;
247
248 const BridgeSpec *b = GetBridgeSpec(bridge_type);
250
251 uint max = std::min(b->max_length, _settings_game.construction.max_bridge_length);
252
253 if (b->min_length > bridge_len) return CMD_ERROR;
254 if (bridge_len <= max) return CommandCost();
255 return CommandCost(STR_ERROR_BRIDGE_TOO_LONG);
256}
257
264static Money TunnelBridgeClearCost(TileIndex tile, Price base_price)
265{
266 Money base_cost = _price[base_price];
267
268 /* Add the cost of the transport that is on the tunnel/bridge. */
269 switch (GetTunnelBridgeTransportType(tile)) {
270 case TransportType::Road: {
271 RoadType road_rt = GetRoadTypeRoad(tile);
272 RoadType tram_rt = GetRoadTypeTram(tile);
273
274 if (road_rt != INVALID_ROADTYPE) {
275 base_cost += 2 * RoadClearCost(road_rt);
276 }
277 if (tram_rt != INVALID_ROADTYPE) {
278 base_cost += 2 * RoadClearCost(tram_rt);
279 }
280 } break;
281
282 case TransportType::Rail: base_cost += RailClearCost(GetRailType(tile)); break;
283 /* Aqueducts have their own clear price. */
284 case TransportType::Water: base_cost = _price[Price::ClearAqueduct]; break;
285 default: break;
286 }
287
288 return base_cost;
289}
290
291static CommandCost CheckBuildAbove(TileIndex tile, DoCommandFlags flags, Axis axis, int height)
292{
293 if (_tile_type_procs[GetTileType(tile)]->check_build_above_proc != nullptr) {
294 return _tile_type_procs[GetTileType(tile)]->check_build_above_proc(tile, flags, axis, height);
295 }
296 /* A tile without a handler must be cleared. */
297 return Command<Commands::LandscapeClear>::Do(flags, tile);
298}
299
311CommandCost CmdBuildBridge(DoCommandFlags flags, TileIndex tile_end, TileIndex tile_start, TransportType transport_type, BridgeType bridge_type, RailType railtype, RoadType roadtype)
312{
313 CompanyID company = _current_company;
314
315 for (TileIndex t : {tile_start, tile_end}) {
316 if (!IsValidTile(t)) return CommandCost(STR_ERROR_BRIDGE_THROUGH_MAP_BORDER);
317 /* User cannot modify height of tiles with one coordinate equal to zero, they are always at the sea level, and you can't build bridge in the sea.
318 * Furthermore, they are void tiles unless map is infinite water. If we don't return for them here, we will still fail as their slope is invalid. */
319 if (TileX(t) == 0 || TileY(t) == 0) return CommandCost(transport_type == TransportType::Water ? STR_ERROR_BRIDGE_THROUGH_MAP_BORDER : STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP);
320 }
321
322 /* type of bridge */
323 switch (transport_type) {
325 if (!ValParamRoadType(roadtype)) return CMD_ERROR;
326 break;
327
329 if (!ValParamRailType(railtype)) return CMD_ERROR;
330 break;
331
333 break;
334
335 default:
336 /* Airports don't have bridges. */
337 return CMD_ERROR;
338 }
339
340 if (company == OWNER_DEITY) {
341 if (transport_type != TransportType::Road) return CMD_ERROR;
342 const Town *town = CalcClosestTownFromTile(tile_start);
343
344 company = OWNER_TOWN;
345
346 /* If we are not within a town, we are not owned by the town */
347 if (town == nullptr || DistanceSquare(tile_start, town->xy) > town->cache.squared_town_zone_radius[to_underlying(HouseZone::TownEdge)]) {
348 company = OWNER_NONE;
349 }
350 }
351
352 if (tile_start == tile_end) {
353 return CommandCost(STR_ERROR_CAN_T_START_AND_END_ON);
354 }
355
356 Axis direction;
357 if (TileX(tile_start) == TileX(tile_end)) {
358 direction = Axis::Y;
359 } else if (TileY(tile_start) == TileY(tile_end)) {
360 direction = Axis::X;
361 } else {
362 return CommandCost(STR_ERROR_START_AND_END_MUST_BE_IN);
363 }
364
365 if (tile_end < tile_start) std::swap(tile_start, tile_end);
366
367 uint bridge_len = GetTunnelBridgeLength(tile_start, tile_end);
368 if (transport_type != TransportType::Water) {
369 /* set and test bridge length, availability */
370 CommandCost ret = CheckBridgeAvailability(bridge_type, bridge_len, flags);
371 if (ret.Failed()) return ret;
372 } else {
373 if (bridge_len > _settings_game.construction.max_bridge_length) return CommandCost(STR_ERROR_BRIDGE_TOO_LONG);
374 }
375 bridge_len += 2; // begin and end tiles/ramps
376
377 auto [tileh_start, z_start] = GetTileSlopeZ(tile_start);
378 auto [tileh_end, z_end] = GetTileSlopeZ(tile_end);
379 bool pbs_reservation = false;
380
381 CommandCost terraform_cost_north = CheckBridgeSlope(BRIDGE_PIECE_NORTH, direction, tileh_start, z_start);
382 CommandCost terraform_cost_south = CheckBridgeSlope(BRIDGE_PIECE_SOUTH, direction, tileh_end, z_end);
383
384 /* Aqueducts can't be built of flat land. */
385 if (transport_type == TransportType::Water && (tileh_start == SLOPE_FLAT || tileh_end == SLOPE_FLAT)) return CommandCost(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
386 if (z_start != z_end) return CommandCost(STR_ERROR_BRIDGEHEADS_NOT_SAME_HEIGHT);
387
389 Owner owner;
390 bool is_new_owner;
391 RoadType road_rt = INVALID_ROADTYPE;
392 RoadType tram_rt = INVALID_ROADTYPE;
393 if (IsBridgeTile(tile_start) && IsBridgeTile(tile_end) &&
394 GetOtherBridgeEnd(tile_start) == tile_end &&
395 GetTunnelBridgeTransportType(tile_start) == transport_type) {
396 /* Replace a current bridge. */
397
398 switch (transport_type) {
400 /* Keep the reservation, the path stays valid. */
401 pbs_reservation = HasTunnelBridgeReservation(tile_start);
402 break;
403
405 /* Do not remove road types when upgrading a bridge */
406 road_rt = GetRoadTypeRoad(tile_start);
407 tram_rt = GetRoadTypeTram(tile_start);
408 break;
409
410 default: break;
411 }
412
413 /* If this is a railway bridge, make sure the railtypes match. */
414 if (transport_type == TransportType::Rail && GetRailType(tile_start) != railtype) {
415 return CommandCost(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
416 }
417
418 /* If this is a road bridge, make sure the roadtype matches. */
419 if (transport_type == TransportType::Road) {
420 RoadType existing_rt = RoadTypeIsRoad(roadtype) ? road_rt : tram_rt;
421 if (existing_rt != roadtype && existing_rt != INVALID_ROADTYPE) {
422 return CommandCost(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
423 }
424 }
425
426 if (!flags.Test(DoCommandFlag::QueryCost)) {
427 /* Do not replace the bridge with the same bridge type. */
428 if ((bridge_type == GetBridgeType(tile_start)) && (transport_type != TransportType::Road || road_rt == roadtype || tram_rt == roadtype)) {
429 return CommandCost(STR_ERROR_ALREADY_BUILT);
430 }
431
432 /* Do not replace town bridges with lower speed bridges, unless in scenario editor. */
433 if (IsTileOwner(tile_start, OWNER_TOWN) && _game_mode != GameMode::Editor) {
434 Town *t = ClosestTownFromTile(tile_start, UINT_MAX);
435 if (t == nullptr) return CMD_ERROR;
436
437 if (GetBridgeSpec(bridge_type)->speed < GetBridgeSpec(GetBridgeType(tile_start))->speed) {
438 return CommandCostWithParam(STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS, t->index);
439 } else {
440 ChangeTownRating(t, RATING_TUNNEL_BRIDGE_UP_STEP, RATING_MAXIMUM, flags);
441 }
442 }
443 }
444
445 /* Do not allow replacing another company's bridges. */
446 if (!IsTileOwner(tile_start, company) && !IsTileOwner(tile_start, OWNER_TOWN) && !IsTileOwner(tile_start, OWNER_NONE)) {
447 return CommandCost(STR_ERROR_AREA_IS_OWNED_BY_ANOTHER);
448 }
449
450 /* The cost of clearing the current bridge. */
451 cost.AddCost(bridge_len * TunnelBridgeClearCost(tile_start, Price::ClearBridge));
452 owner = GetTileOwner(tile_start);
453
454 /* If bridge belonged to bankrupt company, it has a new owner now */
455 is_new_owner = (owner == OWNER_NONE);
456 if (is_new_owner) owner = company;
457
458 /* Check if the new bridge is compatible with tiles underneath. */
459 TileIndexDiff delta = (direction == Axis::X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
460 for (TileIndex tile = tile_start + delta; tile != tile_end; tile += delta) {
461 CommandCost ret = CheckBuildAbove(tile, flags, direction, z_start + 1);
462 if (ret.Failed()) return ret;
463 cost.AddCost(ret.GetCost());
464 }
465 } else {
466 /* Build a new bridge. */
467
468 bool allow_on_slopes = (_settings_game.construction.build_on_slopes && transport_type != TransportType::Water);
469
470 /* Try and clear the start landscape */
471 CommandCost ret = Command<Commands::LandscapeClear>::Do(flags, tile_start);
472 if (ret.Failed()) return ret;
473 cost = ret;
474
475 if (terraform_cost_north.Failed() || (terraform_cost_north.GetCost() != 0 && !allow_on_slopes)) return CommandCost(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
476 cost.AddCost(terraform_cost_north.GetCost());
477
478 /* Try and clear the end landscape */
479 ret = Command<Commands::LandscapeClear>::Do(flags, tile_end);
480 if (ret.Failed()) return ret;
481 cost.AddCost(ret.GetCost());
482
483 /* false - end tile slope check */
484 if (terraform_cost_south.Failed() || (terraform_cost_south.GetCost() != 0 && !allow_on_slopes)) return CommandCost(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
485 cost.AddCost(terraform_cost_south.GetCost());
486
487 /* Check for bridges above the bridge ramps. */
488 for (TileIndex tile : {tile_start, tile_end}) {
489 if (!IsBridgeAbove(tile)) continue;
490
491 if (direction == GetBridgeAxis(tile)) return CommandCost(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
492
493 if (z_start + 1 == GetBridgeHeight(GetNorthernBridgeEnd(tile))) return CommandCost(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
494 }
495
496 TileIndexDiff delta = TileOffsByAxis(direction);
497 for (TileIndex tile = tile_start + delta; tile != tile_end; tile += delta) {
498 if (GetTileMaxZ(tile) > z_start) return CommandCost(STR_ERROR_BRIDGE_TOO_LOW_FOR_TERRAIN);
499
500 if (z_start >= (GetTileZ(tile) + _settings_game.construction.max_bridge_height)) {
501 /*
502 * Disallow too high bridges.
503 * Properly rendering a map where very high bridges (might) exist is expensive.
504 * See http://www.tt-forums.net/viewtopic.php?f=33&t=40844&start=980#p1131762
505 * for a detailed discussion. z_start here is one heightlevel below the bridge level.
506 */
507 return CommandCost(STR_ERROR_BRIDGE_TOO_HIGH_FOR_TERRAIN);
508 }
509
510 if (IsBridgeAbove(tile)) {
511 /* Disallow crossing bridges for the time being */
512 return CommandCost(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
513 }
514
515 ret = CheckBuildAbove(tile, flags, direction, z_start + 1);
516 if (ret.Failed()) return ret;
517 cost.AddCost(ret.GetCost());
518
519 if (flags.Test(DoCommandFlag::Execute)) {
520 /* We do this here because when replacing a bridge with another
521 * type calling SetBridgeMiddle isn't needed. After all, the
522 * tile already has the has_bridge_above bits set. */
523 SetBridgeMiddle(tile, direction);
524 }
525 }
526
527 owner = company;
528 is_new_owner = true;
529 }
530
531 bool hasroad = road_rt != INVALID_ROADTYPE;
532 bool hastram = tram_rt != INVALID_ROADTYPE;
533 if (transport_type == TransportType::Road) {
534 if (RoadTypeIsRoad(roadtype)) road_rt = roadtype;
535 if (RoadTypeIsTram(roadtype)) tram_rt = roadtype;
536 }
537
538 /* do the drill? */
539 if (flags.Test(DoCommandFlag::Execute)) {
540 DiagDirection dir = AxisToDiagDir(direction);
541
542 Company *c = Company::GetIfValid(company);
543 switch (transport_type) {
545 /* Add to company infrastructure count if required. */
546 if (is_new_owner && c != nullptr) c->infrastructure.rail[railtype] += bridge_len * TUNNELBRIDGE_TRACKBIT_FACTOR;
547 MakeRailBridgeRamp(tile_start, owner, bridge_type, dir, railtype);
548 MakeRailBridgeRamp(tile_end, owner, bridge_type, ReverseDiagDir(dir), railtype);
549 SetTunnelBridgeReservation(tile_start, pbs_reservation);
550 SetTunnelBridgeReservation(tile_end, pbs_reservation);
551 break;
552
553 case TransportType::Road: {
554 if (is_new_owner) {
555 /* Also give unowned present roadtypes to new owner */
556 if (hasroad && GetRoadOwner(tile_start, RoadTramType::Road) == OWNER_NONE) hasroad = false;
557 if (hastram && GetRoadOwner(tile_start, RoadTramType::Tram) == OWNER_NONE) hastram = false;
558 }
559 if (c != nullptr) {
560 /* Add all new road types to the company infrastructure counter. */
561 if (!hasroad && road_rt != INVALID_ROADTYPE) {
562 /* A full diagonal road tile has two road bits. */
563 c->infrastructure.road[road_rt] += bridge_len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR;
564 }
565 if (!hastram && tram_rt != INVALID_ROADTYPE) {
566 /* A full diagonal road tile has two road bits. */
567 c->infrastructure.road[tram_rt] += bridge_len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR;
568 }
569 }
570 Owner owner_road = hasroad ? GetRoadOwner(tile_start, RoadTramType::Road) : company;
571 Owner owner_tram = hastram ? GetRoadOwner(tile_start, RoadTramType::Tram) : company;
572 MakeRoadBridgeRamp(tile_start, owner, owner_road, owner_tram, bridge_type, dir, road_rt, tram_rt);
573 MakeRoadBridgeRamp(tile_end, owner, owner_road, owner_tram, bridge_type, ReverseDiagDir(dir), road_rt, tram_rt);
574 break;
575 }
576
578 if (is_new_owner && c != nullptr) c->infrastructure.water += bridge_len * TUNNELBRIDGE_TRACKBIT_FACTOR;
579 MakeAqueductBridgeRamp(tile_start, owner, dir);
580 MakeAqueductBridgeRamp(tile_end, owner, ReverseDiagDir(dir));
581 CheckForDockingTile(tile_start);
582 CheckForDockingTile(tile_end);
583 break;
584
585 default:
586 NOT_REACHED();
587 }
588
589 /* Mark all tiles dirty */
590 MarkBridgeDirty(tile_start, tile_end, AxisToDiagDir(direction), z_start);
592 }
593
594 if (flags.Test(DoCommandFlag::Execute) && transport_type == TransportType::Rail) {
595 Track track = AxisToTrack(direction);
596 AddSideToSignalBuffer(tile_start, DiagDirection::Invalid, company);
597 YapfNotifyTrackLayoutChange(tile_start, track);
598 }
599
600 /* Human players that build bridges get a selection to choose from (DoCommandFlag::QueryCost)
601 * It's unnecessary to execute this command every time for every bridge.
602 * So it is done only for humans and cost is computed in bridge_gui.cpp.
603 * For (non-spectated) AI, Towns this has to be of course calculated. */
604 Company *c = Company::GetIfValid(company);
605 if (!flags.Test(DoCommandFlag::QueryCost) || (c != nullptr && c->is_ai && company != _local_company)) {
606 switch (transport_type) {
608 if (road_rt != INVALID_ROADTYPE) {
609 cost.AddCost(bridge_len * 2 * RoadBuildCost(road_rt));
610 }
611 if (tram_rt != INVALID_ROADTYPE) {
612 cost.AddCost(bridge_len * 2 * RoadBuildCost(tram_rt));
613 }
614 break;
615
616 case TransportType::Rail: cost.AddCost(bridge_len * RailBuildCost(railtype)); break;
617 default: break;
618 }
619
620 if (c != nullptr) bridge_len = CalcBridgeLenCostFactor(bridge_len);
621
622 if (transport_type != TransportType::Water) {
623 cost.AddCost((int64_t)bridge_len * _price[Price::BuildBridge] * GetBridgeSpec(bridge_type)->price >> 8);
624 } else {
625 /* Aqueducts use a separate base cost. */
626 cost.AddCost((int64_t)bridge_len * _price[Price::BuildAqueduct]);
627 }
628
629 }
630
631 return cost;
632}
633
634
644CommandCost CmdBuildTunnel(DoCommandFlags flags, TileIndex start_tile, TransportType transport_type, RailType railtype, RoadType roadtype)
645{
646 CompanyID company = _current_company;
647
649 switch (transport_type) {
651 if (!ValParamRailType(railtype)) return CMD_ERROR;
652 break;
653
655 if (!ValParamRoadType(roadtype)) return CMD_ERROR;
656 break;
657
658 default: return CMD_ERROR;
659 }
660
661 if (company == OWNER_DEITY) {
662 if (transport_type != TransportType::Road) return CMD_ERROR;
663 const Town *town = CalcClosestTownFromTile(start_tile);
664
665 company = OWNER_TOWN;
666
667 /* If we are not within a town, we are not owned by the town */
668 if (town == nullptr || DistanceSquare(start_tile, town->xy) > town->cache.squared_town_zone_radius[to_underlying(HouseZone::TownEdge)]) {
669 company = OWNER_NONE;
670 }
671 }
672
673 auto [start_tileh, start_z] = GetTileSlopeZ(start_tile);
674 DiagDirection direction = GetInclinedSlopeDirection(start_tileh);
675 if (direction == DiagDirection::Invalid) return CommandCost(STR_ERROR_SITE_UNSUITABLE_FOR_TUNNEL);
676
677 if (HasTileWaterGround(start_tile)) return CommandCost(STR_ERROR_CAN_T_BUILD_ON_WATER);
678
679 CommandCost ret = Command<Commands::LandscapeClear>::Do(flags, start_tile);
680 if (ret.Failed()) return ret;
681
682 /* XXX - do NOT change 'ret' in the loop, as it is used as the price
683 * for the clearing of the entrance of the tunnel. Assigning it to
684 * cost before the loop will yield different costs depending on start-
685 * position, because of increased-cost-by-length: 'cost += cost >> 3' */
686
687 TileIndexDiff delta = TileOffsByDiagDir(direction);
688 DiagDirection tunnel_in_way_dir;
689 if (DiagDirToAxis(direction) == Axis::Y) {
690 tunnel_in_way_dir = (TileX(start_tile) < (Map::MaxX() / 2)) ? DiagDirection::SW : DiagDirection::NE;
691 } else {
692 tunnel_in_way_dir = (TileY(start_tile) < (Map::MaxX() / 2)) ? DiagDirection::SE : DiagDirection::NW;
693 }
694
695 TileIndex end_tile = start_tile;
696
697 /* Tile shift coefficient. Will decrease for very long tunnels to avoid exponential growth of price*/
698 int tiles_coef = 3;
699 /* Number of tiles from start of tunnel */
700 int tiles = 0;
701 /* Number of tiles at which the cost increase coefficient per tile is halved */
702 int tiles_bump = 25;
703
705 Slope end_tileh;
706 int end_z;
707 for (;;) {
708 end_tile += delta;
709 if (!IsValidTile(end_tile)) return CommandCost(STR_ERROR_TUNNEL_THROUGH_MAP_BORDER);
710 std::tie(end_tileh, end_z) = GetTileSlopeZ(end_tile);
711
712 if (start_z == end_z) break;
713
714 if (!_cheats.crossing_tunnels.value && IsTunnelInWayDir(end_tile, start_z, tunnel_in_way_dir)) {
715 return CommandCost(STR_ERROR_ANOTHER_TUNNEL_IN_THE_WAY);
716 }
717
718 tiles++;
719 if (tiles == tiles_bump) {
720 tiles_coef++;
721 tiles_bump *= 2;
722 }
723
725 cost.AddCost(cost.GetCost() >> tiles_coef); // add a multiplier for longer tunnels
726 }
727
728 /* Add the cost of the entrance */
730 cost.AddCost(ret.GetCost());
731
732 /* if the command fails from here on we want the end tile to be highlighted */
733 _build_tunnel_endtile = end_tile;
734
735 if (tiles > _settings_game.construction.max_tunnel_length) return CommandCost(STR_ERROR_TUNNEL_TOO_LONG);
736
737 if (HasTileWaterGround(end_tile)) return CommandCost(STR_ERROR_CAN_T_BUILD_ON_WATER);
738
739 /* Clear the tile in any case */
740 ret = Command<Commands::LandscapeClear>::Do(flags, end_tile);
741 if (ret.Failed()) return CommandCost(STR_ERROR_UNABLE_TO_EXCAVATE_LAND);
742 cost.AddCost(ret.GetCost());
743
744 /* slope of end tile must be complementary to the slope of the start tile */
745 if (end_tileh != ComplementSlope(start_tileh)) {
746 /* Mark the tile as already cleared for the terraform command.
747 * Do this for all tiles (like trees), not only objects. */
748 ClearedObjectArea *coa = FindClearedObject(end_tile);
749 if (coa == nullptr) {
750 coa = &_cleared_object_areas.emplace_back(end_tile, TileArea(end_tile, 1, 1));
751 }
752
753 /* Hide the tile from the terraforming command */
754 TileIndex old_first_tile = coa->first_tile;
756
757 /* Commands::TerraformLand may append further items to _cleared_object_areas,
758 * however it will never erase or re-order existing items.
759 * _cleared_object_areas is a value-type self-resizing vector, therefore appending items
760 * may result in a backing-store re-allocation, which would invalidate the coa pointer.
761 * The index of the coa pointer into the _cleared_object_areas vector remains valid,
762 * and can be used safely after the Commands::TerraformLand operation.
763 * Deliberately clear the coa pointer to avoid leaving dangling pointers which could
764 * inadvertently be dereferenced.
765 */
766 ClearedObjectArea *begin = _cleared_object_areas.data();
767 assert(coa >= begin && coa < begin + _cleared_object_areas.size());
768 size_t coa_index = coa - begin;
769 assert(coa_index < UINT_MAX); // more than 2**32 cleared areas would be a bug in itself
770 coa = nullptr;
771
772 ret = ExtractCommandCost(Command<Commands::TerraformLand>::Do(flags, end_tile, end_tileh & start_tileh, false));
773 _cleared_object_areas[(uint)coa_index].first_tile = old_first_tile;
774 if (ret.Failed()) return CommandCost(STR_ERROR_UNABLE_TO_EXCAVATE_LAND);
775 cost.AddCost(ret.GetCost());
776 }
778
779 /* Pay for the rail/road in the tunnel including entrances */
780 switch (transport_type) {
781 case TransportType::Road: cost.AddCost((tiles + 2) * RoadBuildCost(roadtype) * 2); break;
782 case TransportType::Rail: cost.AddCost((tiles + 2) * RailBuildCost(railtype)); break;
783 default: NOT_REACHED();
784 }
785
786 if (flags.Test(DoCommandFlag::Execute)) {
787 Company *c = Company::GetIfValid(company);
788 uint num_pieces = (tiles + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR;
789 if (transport_type == TransportType::Rail) {
790 if (c != nullptr) c->infrastructure.rail[railtype] += num_pieces;
791 MakeRailTunnel(start_tile, company, direction, railtype);
792 MakeRailTunnel(end_tile, company, ReverseDiagDir(direction), railtype);
793 AddSideToSignalBuffer(start_tile, DiagDirection::Invalid, company);
794 YapfNotifyTrackLayoutChange(start_tile, DiagDirToDiagTrack(direction));
795 } else {
796 if (c != nullptr) c->infrastructure.road[roadtype] += num_pieces * 2; // A full diagonal road has two road bits.
797 RoadType road_rt = RoadTypeIsRoad(roadtype) ? roadtype : INVALID_ROADTYPE;
798 RoadType tram_rt = RoadTypeIsTram(roadtype) ? roadtype : INVALID_ROADTYPE;
799 MakeRoadTunnel(start_tile, company, direction, road_rt, tram_rt);
800 MakeRoadTunnel(end_tile, company, ReverseDiagDir(direction), road_rt, tram_rt);
801 }
803 }
804
805 return cost;
806}
807
808
815{
816 /* Floods can remove anything as well as the scenario editor */
817 if (_current_company == OWNER_WATER || _game_mode == GameMode::Editor) return CommandCost();
818
819 switch (GetTunnelBridgeTransportType(tile)) {
820 case TransportType::Road: {
821 RoadType road_rt = GetRoadTypeRoad(tile);
822 RoadType tram_rt = GetRoadTypeTram(tile);
823 Owner road_owner = _current_company;
824 Owner tram_owner = _current_company;
825
826 if (road_rt != INVALID_ROADTYPE) road_owner = GetRoadOwner(tile, RoadTramType::Road);
827 if (tram_rt != INVALID_ROADTYPE) tram_owner = GetRoadOwner(tile, RoadTramType::Tram);
828
829 /* We can remove unowned road and if the town allows it */
830 if (road_owner == OWNER_TOWN && _current_company != OWNER_TOWN && !(_settings_game.construction.extra_dynamite || _cheats.magic_bulldozer.value)) {
831 /* Town does not allow */
832 return CheckTileOwnership(tile);
833 }
834 if (road_owner == OWNER_NONE || road_owner == OWNER_TOWN) road_owner = _current_company;
835 if (tram_owner == OWNER_NONE) tram_owner = _current_company;
836
837 CommandCost ret = CheckOwnership(road_owner, tile);
838 if (ret.Succeeded()) ret = CheckOwnership(tram_owner, tile);
839 return ret;
840 }
841
843 return CheckOwnership(GetTileOwner(tile));
844
846 /* Always allow to remove aqueducts without owner. */
847 Owner aqueduct_owner = GetTileOwner(tile);
848 if (aqueduct_owner == OWNER_NONE) aqueduct_owner = _current_company;
849 return CheckOwnership(aqueduct_owner);
850 }
851
852 default: NOT_REACHED();
853 }
854}
855
863{
865 if (ret.Failed()) return ret;
866
867 TileIndex endtile = GetOtherTunnelEnd(tile);
868
869 ret = TunnelBridgeIsFree(tile, endtile);
870 if (ret.Failed()) return ret;
871
872 _build_tunnel_endtile = endtile;
873
874 Town *t = nullptr;
875 if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GameMode::Editor) {
876 t = ClosestTownFromTile(tile, UINT_MAX); // town penalty rating
877
878 /* Check if you are allowed to remove the tunnel owned by a town
879 * Removal depends on difficulty settings */
881 if (ret.Failed()) return ret;
882 }
883
884 /* checks if the owner is town then decrease town rating by RATING_TUNNEL_BRIDGE_DOWN_STEP until
885 * you have a "Poor" (0) town rating */
886 if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GameMode::Editor) {
888 }
889
890 Money base_cost = TunnelBridgeClearCost(tile, Price::ClearTunnel);
891 uint len = GetTunnelBridgeLength(tile, endtile) + 2; // Don't forget the end tiles.
892
893 if (flags.Test(DoCommandFlag::Execute)) {
895 /* We first need to request values before calling DoClearSquare */
897 Track track = DiagDirToDiagTrack(dir);
898 Owner owner = GetTileOwner(tile);
899
900 Train *v = nullptr;
901 if (HasTunnelBridgeReservation(tile)) {
902 v = GetTrainForReservation(tile, track);
903 if (v != nullptr) FreeTrainTrackReservation(v);
904 }
905
906 if (Company::IsValidID(owner)) {
907 Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= len * TUNNELBRIDGE_TRACKBIT_FACTOR;
909 }
910
911 DoClearSquare(tile);
912 DoClearSquare(endtile);
913
914 /* cannot use DiagDirection::Invalid for signal update because the tunnel doesn't exist anymore */
915 AddSideToSignalBuffer(tile, ReverseDiagDir(dir), owner);
916 AddSideToSignalBuffer(endtile, dir, owner);
917
918 YapfNotifyTrackLayoutChange(tile, track);
919 YapfNotifyTrackLayoutChange(endtile, track);
920
921 if (v != nullptr) TryPathReserve(v);
922 } else {
923 /* A full diagonal road tile has two road bits. */
926
927 DoClearSquare(tile);
928 DoClearSquare(endtile);
929 }
930 }
931
932 return CommandCost(ExpensesType::Construction, len * base_cost);
933}
934
935
943{
945 if (ret.Failed()) return ret;
946
947 TileIndex endtile = GetOtherBridgeEnd(tile);
948
949 ret = TunnelBridgeIsFree(tile, endtile);
950 if (ret.Failed()) return ret;
951
952 DiagDirection direction = GetTunnelBridgeDirection(tile);
953 TileIndexDiff delta = TileOffsByDiagDir(direction);
954
955 Town *t = nullptr;
956 if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GameMode::Editor) {
957 t = ClosestTownFromTile(tile, UINT_MAX); // town penalty rating
958
959 /* Check if you are allowed to remove the bridge owned by a town
960 * Removal depends on difficulty settings */
962 if (ret.Failed()) return ret;
963 }
964
965 /* checks if the owner is town then decrease town rating by RATING_TUNNEL_BRIDGE_DOWN_STEP until
966 * you have a "Poor" (0) town rating */
967 if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GameMode::Editor) {
969 }
970
971 Money base_cost = TunnelBridgeClearCost(tile, Price::ClearBridge);
972 uint len = GetTunnelBridgeLength(tile, endtile) + 2; // Don't forget the end tiles.
973
974 if (flags.Test(DoCommandFlag::Execute)) {
975 /* read this value before actual removal of bridge */
977 Owner owner = GetTileOwner(tile);
978 int height = GetBridgeHeight(tile);
979 Train *v = nullptr;
980
981 if (rail && HasTunnelBridgeReservation(tile)) {
982 v = GetTrainForReservation(tile, DiagDirToDiagTrack(direction));
983 if (v != nullptr) FreeTrainTrackReservation(v);
984 }
985
986 /* Update company infrastructure counts. */
987 if (rail) {
988 if (Company::IsValidID(owner)) Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= len * TUNNELBRIDGE_TRACKBIT_FACTOR;
990 /* A full diagonal road tile has two road bits. */
993 } else { // Aqueduct
994 if (Company::IsValidID(owner)) Company::Get(owner)->infrastructure.water -= len * TUNNELBRIDGE_TRACKBIT_FACTOR;
995 }
997
998 DoClearSquare(tile);
999 DoClearSquare(endtile);
1000
1001 for (TileIndex c = tile + delta; c != endtile; c += delta) {
1002 /* do not let trees appear from 'nowhere' after removing bridge */
1004 int minz = GetTileMaxZ(c) + 3;
1005 if (height < minz) SetRoadside(c, Roadside::Paved);
1006 }
1008 MarkTileDirtyByTile(c, height - TileHeight(c));
1009 }
1010
1011 if (rail) {
1012 /* cannot use DiagDirection::Invalid for signal update because the bridge doesn't exist anymore */
1013 AddSideToSignalBuffer(tile, ReverseDiagDir(direction), owner);
1014 AddSideToSignalBuffer(endtile, direction, owner);
1015
1016 Track track = DiagDirToDiagTrack(direction);
1017 YapfNotifyTrackLayoutChange(tile, track);
1018 YapfNotifyTrackLayoutChange(endtile, track);
1019
1020 if (v != nullptr) TryPathReserve(v, true);
1021 }
1022 }
1023
1024 return CommandCost(ExpensesType::Construction, len * base_cost);
1025}
1026
1029{
1030 if (IsTunnel(tile)) {
1031 if (flags.Test(DoCommandFlag::Auto)) return CommandCost(STR_ERROR_MUST_DEMOLISH_TUNNEL_FIRST);
1032 return DoClearTunnel(tile, flags);
1033 } else { // IsBridge(tile)
1034 if (flags.Test(DoCommandFlag::Auto)) return CommandCost(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
1035 return DoClearBridge(tile, flags);
1036 }
1037}
1038
1049static inline void DrawPillar(const PalSpriteID &psid, int x, int y, int z, uint8_t w, uint8_t h, const SubSprite *subsprite)
1050{
1051 static const int PILLAR_Z_OFFSET = TILE_HEIGHT - BRIDGE_Z_START;
1052 AddSortableSpriteToDraw(psid.sprite, psid.pal, x, y, z, {{0, 0, -PILLAR_Z_OFFSET}, {w, h, BB_HEIGHT_UNDER_BRIDGE}, {0, 0, PILLAR_Z_OFFSET}}, IsTransparencySet(TransparencyOption::Bridges), subsprite);
1053}
1054
1066static int DrawPillarColumn(int z_bottom, int z_top, const PalSpriteID &psid, int x, int y, int w, int h)
1067{
1068 int cur_z;
1069 for (cur_z = z_top; cur_z >= z_bottom; cur_z -= TILE_HEIGHT) {
1070 DrawPillar(psid, x, y, cur_z, w, h, nullptr);
1071 }
1072 return cur_z;
1073}
1074
1086static void DrawBridgePillars(const PalSpriteID &psid, const TileInfo *ti, Axis axis, bool drawfarpillar, int x, int y, int z_bridge)
1087{
1088 static constexpr AxisIndexArray<int> bounding_box_size{16, 2};
1089 static constexpr AxisIndexArray<int> back_pillar_offset{0, 9};
1090
1091 static const int INF = 1000;
1092 static constexpr AxisIndexArray<std::array<SubSprite, 2>> half_pillar_sub_sprite{{{
1093 {{ { -14, -INF, INF, INF }, { -INF, -INF, -15, INF } }}, // X axis, north and south
1094 {{ { -INF, -INF, 15, INF }, { 16, -INF, INF, INF } }}, // Y axis, north and south
1095 }}};
1096
1097 if (psid.sprite == 0) return;
1098
1099 /* Determine ground height under pillars */
1100 DiagDirection south_dir = AxisToDiagDir(axis);
1101 int z_front_north = ti->z;
1102 int z_back_north = ti->z;
1103 int z_front_south = ti->z;
1104 int z_back_south = ti->z;
1105 GetSlopePixelZOnEdge(ti->tileh, south_dir, z_front_south, z_back_south);
1106 GetSlopePixelZOnEdge(ti->tileh, ReverseDiagDir(south_dir), z_front_north, z_back_north);
1107
1108 /* Shared height of pillars */
1109 int z_front = std::max(z_front_north, z_front_south);
1110 int z_back = std::max(z_back_north, z_back_south);
1111
1112 /* x and y size of bounding-box of pillars */
1113 int w = bounding_box_size[axis];
1114 int h = bounding_box_size[OtherAxis(axis)];
1115 /* sprite position of back facing pillar */
1116 int x_back = x - back_pillar_offset[axis];
1117 int y_back = y - back_pillar_offset[OtherAxis(axis)];
1118
1119 /* Draw front pillars */
1120 int bottom_z = DrawPillarColumn(z_front, z_bridge, psid, x, y, w, h);
1121 if (z_front_north < z_front) DrawPillar(psid, x, y, bottom_z, w, h, &half_pillar_sub_sprite[axis][0]);
1122 if (z_front_south < z_front) DrawPillar(psid, x, y, bottom_z, w, h, &half_pillar_sub_sprite[axis][1]);
1123
1124 /* Draw back pillars, skip top two parts, which are hidden by the bridge */
1125 int z_bridge_back = z_bridge - 2 * (int)TILE_HEIGHT;
1126 if (drawfarpillar && (z_back_north <= z_bridge_back || z_back_south <= z_bridge_back)) {
1127 bottom_z = DrawPillarColumn(z_back, z_bridge_back, psid, x_back, y_back, w, h);
1128 if (z_back_north < z_back) DrawPillar(psid, x_back, y_back, bottom_z, w, h, &half_pillar_sub_sprite[axis][0]);
1129 if (z_back_south < z_back) DrawPillar(psid, x_back, y_back, bottom_z, w, h, &half_pillar_sub_sprite[axis][1]);
1130 }
1131}
1132
1142static void GetBridgeRoadCatenary(const RoadTypeInfo *rti, TileIndex head_tile, int offset, bool head, SpriteID &spr_back, SpriteID &spr_front)
1143{
1144 static const SpriteID back_offsets[6] = { 95, 96, 99, 102, 100, 101 };
1145 static const SpriteID front_offsets[6] = { 97, 98, 103, 106, 104, 105 };
1146
1147 /* Simplified from DrawRoadTypeCatenary() to remove all the special cases required for regular ground road */
1150 if (spr_back == 0 && spr_front == 0) {
1151 spr_back = SPR_TRAMWAY_BASE + back_offsets[offset];
1152 spr_front = SPR_TRAMWAY_BASE + front_offsets[offset];
1153 } else {
1154 if (spr_back != 0) spr_back += 23 + offset;
1155 if (spr_front != 0) spr_front += 23 + offset;
1156 }
1157}
1158
1169static void DrawBridgeRoadBits(TileIndex head_tile, int x, int y, int z, int offset, bool head, bool is_custom_layout)
1170{
1171 RoadType road_rt = GetRoadTypeRoad(head_tile);
1172 RoadType tram_rt = GetRoadTypeTram(head_tile);
1173 const RoadTypeInfo *road_rti = road_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(road_rt);
1174 const RoadTypeInfo *tram_rti = tram_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(tram_rt);
1175
1176 SpriteID seq_back[5] = { 0 };
1177 bool trans_back[5] = { false };
1178 SpriteID seq_front[4] = { 0 };
1179 bool trans_front[4] = { false };
1180
1181 static const SpriteID overlay_offsets[6] = { 0, 1, 11, 12, 13, 14 };
1183 /* Road underlay takes precedence over tram */
1184 trans_back[0] = !head && IsTransparencySet(TransparencyOption::Bridges);
1185 if (road_rti != nullptr) {
1186 if (road_rti->UsesOverlay()) {
1187 seq_back[0] = GetCustomRoadSprite(road_rti, head_tile, RoadSpriteType::Bridge, head ? TileContext::Normal : TileContext::OnBridge) + offset;
1188 } else if (is_custom_layout) {
1189 /* For custom layouts draw a custom bridge deck. */
1190 seq_back[0] = SPR_BRIDGE_DECKS_ROAD + offset;
1191 }
1192 } else if (tram_rti != nullptr) {
1193 if (tram_rti->UsesOverlay()) {
1194 seq_back[0] = GetCustomRoadSprite(tram_rti, head_tile, RoadSpriteType::Bridge, head ? TileContext::Normal : TileContext::OnBridge) + offset;
1195 } else {
1196 seq_back[0] = SPR_TRAMWAY_BRIDGE + offset;
1197 }
1198 }
1199
1200 /* Draw road overlay */
1201 trans_back[1] = !head && IsTransparencySet(TransparencyOption::Bridges);
1202 if (road_rti != nullptr) {
1203 if (road_rti->UsesOverlay()) {
1204 seq_back[1] = GetCustomRoadSprite(road_rti, head_tile, RoadSpriteType::Overlay, head ? TileContext::Normal : TileContext::OnBridge);
1205 if (seq_back[1] != 0) seq_back[1] += overlay_offsets[offset];
1206 }
1207 }
1208
1209 /* Draw tram overlay */
1210 trans_back[2] = !head && IsTransparencySet(TransparencyOption::Bridges);
1211 if (tram_rti != nullptr) {
1212 if (tram_rti->UsesOverlay()) {
1213 seq_back[2] = GetCustomRoadSprite(tram_rti, head_tile, RoadSpriteType::Overlay, head ? TileContext::Normal : TileContext::OnBridge);
1214 if (seq_back[2] != 0) seq_back[2] += overlay_offsets[offset];
1215 } else if (road_rti != nullptr) {
1216 seq_back[2] = SPR_TRAMWAY_OVERLAY + overlay_offsets[offset];
1217 }
1218 }
1219
1220 /* Both the road and tram catenary sprites need to be on their own layers so they can both be drawn */
1225
1226 if (road_rti != nullptr && HasRoadCatenaryDrawn(road_rt)) {
1227 GetBridgeRoadCatenary(road_rti, head_tile, offset, head, seq_back[3], seq_front[0]);
1228 }
1229
1230 if (tram_rti != nullptr && HasRoadCatenaryDrawn(tram_rt)) {
1231 GetBridgeRoadCatenary(tram_rti, head_tile, offset, head, seq_back[4], seq_front[1]);
1232 }
1233 }
1234
1235 static constexpr SpriteBounds back_bounds[6] = {
1236 {{}, {0, TILE_SIZE, 40}, {}},
1237 {{}, {TILE_SIZE, 0, 40}, {}},
1238 {{}, {TILE_SIZE, 0, 40}, {}},
1239 {{}, {0, TILE_SIZE, 40}, {}},
1240 {{}, {TILE_SIZE, 0, 40}, {}},
1241 {{}, {0, TILE_SIZE, 40}, {}},
1242 };
1243
1244 /* The sprites under the vehicles are drawn as SpriteCombine. StartSpriteCombine() has already been called
1245 * The bounding boxes here are the same as for bridge front/roof */
1246 for (uint i = 0; i < lengthof(seq_back); ++i) {
1247 if (seq_back[i] != 0) {
1248 AddSortableSpriteToDraw(seq_back[i], PAL_NONE, x, y, z, back_bounds[offset], trans_back[i]);
1249 }
1250 }
1251
1252 /* Start a new SpriteCombine for the front part */
1255
1256 static constexpr SpriteBounds front_bounds[6] = {
1257 {{15, 0, 0}, {0, TILE_SIZE, 40}, {-15, 0, 0}},
1258 {{0, 15, 0}, {TILE_SIZE, 0, 40}, {0, -15, 0}},
1259 {{0, 15, 0}, {TILE_SIZE, 0, 40}, {0, -15, 0}},
1260 {{15, 0, 0}, {0, TILE_SIZE, 40}, {-15, 0, 0}},
1261 {{0, 15, 0}, {TILE_SIZE, 0, 40}, {0, -15, 0}},
1262 {{15, 0, 0}, {0, TILE_SIZE, 40}, {-15, 0, 0}},
1263 };
1264
1265 for (uint i = 0; i < lengthof(seq_front); ++i) {
1266 if (seq_front[i] != 0) {
1267 AddSortableSpriteToDraw(seq_front[i], PAL_NONE, x, y, z, front_bounds[offset], trans_front[i]);
1268 }
1269 }
1270}
1271
1287{
1288 TransportType transport_type = GetTunnelBridgeTransportType(ti->tile);
1289 DiagDirection tunnelbridge_direction = GetTunnelBridgeDirection(ti->tile);
1290
1291 if (IsTunnel(ti->tile)) {
1292 /* Front view of tunnel bounding boxes:
1293 *
1294 * 122223 <- BB_Z_SEPARATOR
1295 * 1 3
1296 * 1 3 1,3 = empty helper BB
1297 * 1 3 2 = SpriteCombine of tunnel-roof and catenary (tram & elrail)
1298 *
1299 */
1300
1301 /* Tunnel sprites are positioned at 15,15, but the bounding box covers most of the tile. */
1302 static constexpr DiagDirectionIndexArray<SpriteBounds> roof_bounds{{{
1303 {{0, 1, BB_Z_SEPARATOR}, {TILE_SIZE, TILE_SIZE - 1, 1}, {TILE_SIZE - 1, TILE_SIZE - 2, -BB_Z_SEPARATOR}}, // NE
1304 {{1, 0, BB_Z_SEPARATOR}, {TILE_SIZE - 1, TILE_SIZE, 1}, {TILE_SIZE - 2, TILE_SIZE - 1, -BB_Z_SEPARATOR}}, // SE
1305 {{0, 1, BB_Z_SEPARATOR}, {TILE_SIZE, TILE_SIZE - 1, 1}, {TILE_SIZE - 1, TILE_SIZE - 2, -BB_Z_SEPARATOR}}, // SW
1306 {{1, 0, BB_Z_SEPARATOR}, {TILE_SIZE - 1, TILE_SIZE, 1}, {TILE_SIZE - 2, TILE_SIZE - 1, -BB_Z_SEPARATOR}}, // NW
1307 }}};
1308
1309 /* Catenary sprites are positioned at 0,0, with the same bounding box as above. */
1310 static constexpr DiagDirectionIndexArray<SpriteBounds> catenary_bounds{{{
1311 {{0, 1, BB_Z_SEPARATOR}, {TILE_SIZE, TILE_SIZE - 1, 1}, {0, -1, -BB_Z_SEPARATOR}}, // NE
1312 {{1, 0, BB_Z_SEPARATOR}, {TILE_SIZE - 1, TILE_SIZE, 1}, {-1, 0, -BB_Z_SEPARATOR}}, // SE
1313 {{0, 1, BB_Z_SEPARATOR}, {TILE_SIZE, TILE_SIZE - 1, 1}, {0, -1, -BB_Z_SEPARATOR}}, // SW
1314 {{1, 0, BB_Z_SEPARATOR}, {TILE_SIZE - 1, TILE_SIZE, 1}, {-1, 0, -BB_Z_SEPARATOR}}, // NW
1315 }}};
1316
1317 static constexpr DiagDirectionIndexArray<SpriteBounds> rear_sep{{{
1318 {{}, {TILE_SIZE, 1, TILE_HEIGHT}, {}}, // NE
1319 {{}, {1, TILE_SIZE, TILE_HEIGHT}, {}}, // SE
1320 {{}, {TILE_SIZE, 1, TILE_HEIGHT}, {}}, // SW
1321 {{}, {1, TILE_SIZE, TILE_HEIGHT}, {}}, // NW
1322 }}};
1323
1324 static constexpr DiagDirectionIndexArray<SpriteBounds> front_sep{{{
1325 {{0, TILE_SIZE - 1, 0}, {TILE_SIZE, 1, TILE_HEIGHT}, {}}, // NE
1326 {{TILE_SIZE - 1, 0, 0}, {1, TILE_SIZE, TILE_HEIGHT}, {}}, // SE
1327 {{0, TILE_SIZE - 1, 0}, {TILE_SIZE, 1, TILE_HEIGHT}, {}}, // SW
1328 {{TILE_SIZE - 1, 0, 0}, {1, TILE_SIZE, TILE_HEIGHT}, {}}, // NW
1329 }}};
1330
1331 bool catenary = false;
1332
1333 SpriteID image;
1334 SpriteID railtype_overlay = 0;
1335 if (transport_type == TransportType::Rail) {
1336 const RailTypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
1337 image = rti->base_sprites.tunnel;
1338 if (rti->UsesOverlay()) {
1339 /* Check if the railtype has custom tunnel portals. */
1340 railtype_overlay = GetCustomRailSprite(rti, ti->tile, RailSpriteType::TunnelPortal);
1341 if (railtype_overlay != 0) image = SPR_RAILTYPE_TUNNEL_BASE; // Draw blank grass tunnel base.
1342 }
1343 } else {
1345 }
1346
1347 if (HasTunnelBridgeSnowOrDesert(ti->tile)) image += railtype_overlay != 0 ? 8 : 32;
1348
1349 image += to_underlying(tunnelbridge_direction) * 2;
1350 DrawGroundSprite(image, PAL_NONE);
1351
1352 if (transport_type == TransportType::Road) {
1353 RoadType road_rt = GetRoadTypeRoad(ti->tile);
1354 RoadType tram_rt = GetRoadTypeTram(ti->tile);
1355 const RoadTypeInfo *road_rti = road_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(road_rt);
1356 const RoadTypeInfo *tram_rti = tram_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(tram_rt);
1357 uint sprite_offset = DiagDirToAxis(tunnelbridge_direction) == Axis::X ? 1 : 0;
1358 bool draw_underlay = true;
1359
1360 /* Road underlay takes precedence over tram */
1361 if (road_rti != nullptr) {
1362 if (road_rti->UsesOverlay()) {
1364 if (ground != 0) {
1365 DrawGroundSprite(ground + to_underlying(tunnelbridge_direction), PAL_NONE);
1366 draw_underlay = false;
1367 }
1368 }
1369 } else {
1370 if (tram_rti->UsesOverlay()) {
1372 if (ground != 0) {
1373 DrawGroundSprite(ground + to_underlying(tunnelbridge_direction), PAL_NONE);
1374 draw_underlay = false;
1375 }
1376 }
1377 }
1378
1379 DrawRoadOverlays(ti, PAL_NONE, road_rti, tram_rti, sprite_offset, sprite_offset, draw_underlay);
1380
1381 /* Road catenary takes precedence over tram */
1382 SpriteID catenary_sprite_base = 0;
1383 if (road_rti != nullptr && HasRoadCatenaryDrawn(road_rt)) {
1384 catenary_sprite_base = GetCustomRoadSprite(road_rti, ti->tile, RoadSpriteType::CatenaryFront);
1385 if (catenary_sprite_base == 0) {
1386 catenary_sprite_base = SPR_TRAMWAY_TUNNEL_WIRES;
1387 } else {
1388 catenary_sprite_base += 19;
1389 }
1390 } else if (tram_rti != nullptr && HasRoadCatenaryDrawn(tram_rt)) {
1391 catenary_sprite_base = GetCustomRoadSprite(tram_rti, ti->tile, RoadSpriteType::CatenaryFront);
1392 if (catenary_sprite_base == 0) {
1393 catenary_sprite_base = SPR_TRAMWAY_TUNNEL_WIRES;
1394 } else {
1395 catenary_sprite_base += 19;
1396 }
1397 }
1398
1399 if (catenary_sprite_base != 0) {
1400 catenary = true;
1402 AddSortableSpriteToDraw(catenary_sprite_base + to_underlying(tunnelbridge_direction), PAL_NONE, *ti, catenary_bounds[tunnelbridge_direction], IsTransparencySet(TransparencyOption::Catenary));
1403 }
1404 } else {
1405 const RailTypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
1406 if (rti->UsesOverlay()) {
1408 if (surface != 0) DrawGroundSprite(surface + to_underlying(tunnelbridge_direction), PAL_NONE);
1409 }
1410
1411 /* PBS debugging, draw reserved tracks darker */
1412 if (_game_mode != GameMode::Menu && _settings_client.gui.show_track_reservation && HasTunnelBridgeReservation(ti->tile)) {
1413 if (rti->UsesOverlay()) {
1415 DrawGroundSprite(overlay + RTO_X + to_underlying(DiagDirToAxis(tunnelbridge_direction)), PALETTE_CRASH);
1416 } else {
1418 }
1419 }
1420
1422 /* Maybe draw pylons on the entry side */
1423 DrawRailCatenary(ti);
1424
1425 catenary = true;
1427 /* Draw wire above the ramp */
1429 }
1430 }
1431
1432 if (railtype_overlay != 0 && !catenary) StartSpriteCombine();
1433
1434 AddSortableSpriteToDraw(image + 1, PAL_NONE, *ti, roof_bounds[tunnelbridge_direction], false);
1435 /* Draw railtype tunnel portal overlay if defined. */
1436 if (railtype_overlay != 0) AddSortableSpriteToDraw(railtype_overlay + to_underlying(tunnelbridge_direction), PAL_NONE, *ti, roof_bounds[tunnelbridge_direction], false);
1437
1438 if (catenary || railtype_overlay != 0) EndSpriteCombine();
1439
1440 /* Add helper BB for sprite sorting that separates the tunnel from things beside of it. */
1441 AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, *ti, rear_sep[tunnelbridge_direction]);
1442 AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, *ti, front_sep[tunnelbridge_direction]);
1443
1444 DrawBridgeMiddle(ti, BridgePillarFlag::EdgeNE + tunnelbridge_direction);
1445 } else { // IsBridge(ti->tile)
1446 DrawFoundation(ti, GetBridgeFoundation(ti->tileh, DiagDirToAxis(tunnelbridge_direction)));
1447 bool is_custom_layout = false; // Set if rail/road bridge uses a custom layout.
1448
1449 uint base_offset = GetBridgeRampDirectionBaseOffset(tunnelbridge_direction);
1450 std::span<const PalSpriteID> psid;
1451 if (transport_type != TransportType::Water) {
1452 BridgeType bridge_type = GetBridgeType(ti->tile);
1453 if (ti->tileh == SLOPE_FLAT) base_offset += 4; // sloped bridge head
1454 base_offset += GetBridgeSpriteTableBaseOffset(transport_type, ti->tile);
1455 psid = GetBridgeSpriteTable(bridge_type, BRIDGE_PIECE_HEAD);
1456 is_custom_layout = BridgeHasCustomSpriteTable(bridge_type, BRIDGE_PIECE_HEAD);
1457 } else {
1459 }
1460 psid = psid.subspan(base_offset, 1);
1461
1463 TileIndex next = ti->tile + TileOffsByDiagDir(tunnelbridge_direction);
1464 if (ti->tileh != SLOPE_FLAT && ti->z == 0 && HasTileWaterClass(next) && GetWaterClass(next) == WaterClass::Sea) {
1465 DrawShoreTile(ti->tileh);
1466 } else {
1467 DrawClearLandTile(ti, 3);
1468 }
1469 } else {
1471 }
1472
1473 /* draw ramp */
1474
1475 /* Draw Trambits and PBS Reservation as SpriteCombine */
1476 if (transport_type == TransportType::Road || transport_type == TransportType::Rail) StartSpriteCombine();
1477
1478 /* HACK set the height of the BB of a sloped ramp to 1 so a vehicle on
1479 * it doesn't disappear behind it
1480 */
1481 /* Bridge heads are drawn solid no matter how invisibility/transparency is set */
1482 AddSortableSpriteToDraw(psid[0].sprite, psid[0].pal, *ti, {{}, {TILE_SIZE, TILE_SIZE, static_cast<uint8_t>(ti->tileh == SLOPE_FLAT ? 0 : TILE_HEIGHT)}, {}});
1483
1484 if (transport_type == TransportType::Road) {
1485 uint offset = to_underlying(tunnelbridge_direction);
1486 int z = ti->z;
1487 if (ti->tileh != SLOPE_FLAT) {
1488 offset = (offset + 1) & 1;
1489 z += TILE_HEIGHT;
1490 } else {
1491 offset += 2;
1492 }
1493
1494 /* DrawBridgeRoadBits() calls EndSpriteCombine() and StartSpriteCombine() */
1495 DrawBridgeRoadBits(ti->tile, ti->x, ti->y, z, offset, true, is_custom_layout);
1496
1498 } else if (transport_type == TransportType::Rail) {
1499 const RailTypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
1500 if (is_custom_layout || rti->UsesOverlay()) {
1501 SpriteID surface = rti->UsesOverlay() ? GetCustomRailSprite(rti, ti->tile, RailSpriteType::Bridge) : rti->base_sprites.bridge_deck;
1502 if (surface != 0) {
1503 if (HasBridgeFlatRamp(ti->tileh, DiagDirToAxis(tunnelbridge_direction))) {
1504 AddSortableSpriteToDraw(surface + ((DiagDirToAxis(tunnelbridge_direction) == Axis::X) ? RTBO_X : RTBO_Y), PAL_NONE, *ti, {{0, 0, TILE_HEIGHT}, {TILE_SIZE, TILE_SIZE, 0}, {}});
1505 } else {
1506 AddSortableSpriteToDraw(surface + RTBO_SLOPE + to_underlying(tunnelbridge_direction), PAL_NONE, *ti, {{}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT}, {}});
1507 }
1508 }
1509 }
1510
1511 /* PBS debugging, draw reserved tracks darker */
1512 if (_game_mode != GameMode::Menu && _settings_client.gui.show_track_reservation && HasTunnelBridgeReservation(ti->tile)) {
1513 if (rti->UsesOverlay()) {
1515 if (HasBridgeFlatRamp(ti->tileh, DiagDirToAxis(tunnelbridge_direction))) {
1516 AddSortableSpriteToDraw(overlay + RTO_X + to_underlying(DiagDirToAxis(tunnelbridge_direction)), PALETTE_CRASH, *ti, {{0, 0, TILE_HEIGHT}, {TILE_SIZE, TILE_SIZE, 0}, {}});
1517 } else {
1518 AddSortableSpriteToDraw(overlay + RTO_SLOPE_NE + to_underlying(tunnelbridge_direction), PALETTE_CRASH, *ti, {{}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT}, {}});
1519 }
1520 } else {
1521 if (HasBridgeFlatRamp(ti->tileh, DiagDirToAxis(tunnelbridge_direction))) {
1522 AddSortableSpriteToDraw(DiagDirToAxis(tunnelbridge_direction) == Axis::X ? rti->base_sprites.single_x : rti->base_sprites.single_y, PALETTE_CRASH, *ti, {{0, 0, TILE_HEIGHT}, {TILE_SIZE, TILE_SIZE, 0}, {}});
1523 } else {
1525 }
1526 }
1527 }
1528
1531 DrawRailCatenary(ti);
1532 }
1533 }
1534
1535 BridgePillarFlags blocked_pillars;
1536 if (DiagDirToAxis(tunnelbridge_direction) == Axis::X) {
1538 } else {
1540 }
1541 DrawBridgeMiddle(ti, blocked_pillars);
1542 }
1543}
1544
1545
1564static BridgePieces CalcBridgePiece(uint north, uint south)
1565{
1566 if (north == 1) {
1567 return BRIDGE_PIECE_NORTH;
1568 } else if (south == 1) {
1569 return BRIDGE_PIECE_SOUTH;
1570 } else if (north < south) {
1571 return north & 1 ? BRIDGE_PIECE_INNER_SOUTH : BRIDGE_PIECE_INNER_NORTH;
1572 } else if (north > south) {
1573 return south & 1 ? BRIDGE_PIECE_INNER_NORTH : BRIDGE_PIECE_INNER_SOUTH;
1574 } else {
1575 return north & 1 ? BRIDGE_PIECE_MIDDLE_EVEN : BRIDGE_PIECE_MIDDLE_ODD;
1576 }
1577}
1578
1589{
1590 if (transport_type == TransportType::Water) return BRIDGEPILLARFLAGS_ALL_CORNERS;
1591
1592 const BridgeSpec *spec = GetBridgeSpec(type);
1594 BridgePieces piece = CalcBridgePiece(GetTunnelBridgeLength(tile, rampnorth) + 1, GetTunnelBridgeLength(tile, rampsouth) + 1);
1595 Axis axis = TileX(rampnorth) == TileX(rampsouth) ? Axis::Y : Axis::X;
1596
1597 return spec->pillar_flags[piece][axis];
1598 }
1599
1600 return BRIDGEPILLARFLAGS_ALL_CORNERS;
1601}
1602
1608void DrawBridgeMiddle(const TileInfo *ti, BridgePillarFlags blocked_pillars)
1609{
1610 /* Sectional view of bridge bounding boxes:
1611 *
1612 * 1 2 1,2 = SpriteCombine of Bridge front/(back&floor) and RoadCatenary
1613 * 1 2 3 = empty helper BB
1614 * 1 7 2 4,5 = pillars under higher bridges
1615 * 1 6 88888 6 2 6 = elrail-pylons
1616 * 1 6 88888 6 2 7 = elrail-wire
1617 * 1 6 88888 6 2 <- TILE_HEIGHT 8 = rail-vehicle on bridge
1618 * 3333333333333 <- BB_Z_SEPARATOR
1619 * <- unused
1620 * 4 5 <- BB_HEIGHT_UNDER_BRIDGE
1621 * 4 5
1622 * 4 5
1623 *
1624 */
1625
1626 if (!IsBridgeAbove(ti->tile)) return;
1627
1628 TileIndex rampnorth = GetNorthernBridgeEnd(ti->tile);
1629 TileIndex rampsouth = GetSouthernBridgeEnd(ti->tile);
1630 TransportType transport_type = GetTunnelBridgeTransportType(rampsouth);
1631 Axis axis = GetBridgeAxis(ti->tile);
1632 BridgePillarFlags pillars;
1633 bool is_custom_layout; // Set if rail/road bridge uses a custom layout.
1634
1635 uint base_offset = GetBridgeMiddleAxisBaseOffset(axis);
1636 std::span<const PalSpriteID> psid;
1637 bool drawfarpillar;
1638 if (transport_type != TransportType::Water) {
1639 BridgeType bridge_type = GetBridgeType(rampsouth);
1640 BridgePieces bridge_piece = CalcBridgePiece(GetTunnelBridgeLength(ti->tile, rampnorth) + 1, GetTunnelBridgeLength(ti->tile, rampsouth) + 1);
1641 drawfarpillar = !HasBit(GetBridgeSpec(bridge_type)->flags, 0);
1642 base_offset += GetBridgeSpriteTableBaseOffset(transport_type, rampsouth);
1643 psid = GetBridgeSpriteTable(bridge_type, bridge_piece);
1644 pillars = GetBridgeTilePillarFlags(ti->tile, rampnorth, rampsouth, bridge_type, transport_type);
1645 is_custom_layout = BridgeHasCustomSpriteTable(bridge_type, bridge_piece);
1646 } else {
1647 drawfarpillar = true;
1649 pillars = BRIDGEPILLARFLAGS_ALL_CORNERS;
1650 }
1651 psid = psid.subspan(base_offset, 3);
1652
1653 int x = ti->x;
1654 int y = ti->y;
1655 uint bridge_z = GetBridgePixelHeight(rampsouth);
1656 int z = bridge_z - BRIDGE_Z_START;
1657
1658 /* Add a bounding box that separates the bridge from things below it. */
1659 AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, x, y, bridge_z - TILE_HEIGHT + BB_Z_SEPARATOR, {{}, {TILE_SIZE, TILE_SIZE, 1}, {}});
1660
1661 /* Draw Trambits as SpriteCombine */
1662 if (transport_type == TransportType::Road || transport_type == TransportType::Rail) StartSpriteCombine();
1663
1664 /* Draw floor and far part of bridge*/
1666 if (axis == Axis::X) {
1667 AddSortableSpriteToDraw(psid[0].sprite, psid[0].pal, x, y, z, {{0, 0, BRIDGE_Z_START}, {TILE_SIZE, 1, 40}, {0, 0, -BRIDGE_Z_START}}, IsTransparencySet(TransparencyOption::Bridges));
1668 } else {
1669 AddSortableSpriteToDraw(psid[0].sprite, psid[0].pal, x, y, z, {{0, 0, BRIDGE_Z_START}, {1, TILE_SIZE, 40}, {0, 0, -BRIDGE_Z_START}}, IsTransparencySet(TransparencyOption::Bridges));
1670 }
1671 }
1672
1673 if (transport_type == TransportType::Road) {
1674 /* DrawBridgeRoadBits() calls EndSpriteCombine() and StartSpriteCombine() */
1675 DrawBridgeRoadBits(rampsouth, x, y, bridge_z, to_underlying(OtherAxis(axis)), false, is_custom_layout);
1676 } else if (transport_type == TransportType::Rail) {
1677 const RailTypeInfo *rti = GetRailTypeInfo(GetRailType(rampsouth));
1678 if ((is_custom_layout || rti->UsesOverlay()) && !IsInvisibilitySet(TransparencyOption::Bridges)) {
1679 SpriteID surface = rti->UsesOverlay() ? GetCustomRailSprite(rti, rampsouth, RailSpriteType::Bridge, TileContext::OnBridge) : rti->base_sprites.bridge_deck;
1680 if (surface != 0) {
1681 AddSortableSpriteToDraw(surface + to_underlying(axis), PAL_NONE, x, y, bridge_z, {{}, {TILE_SIZE, TILE_SIZE, 0}, {}}, IsTransparencySet(TransparencyOption::Bridges));
1682 }
1683 }
1684
1685 if (_game_mode != GameMode::Menu && _settings_client.gui.show_track_reservation && !IsInvisibilitySet(TransparencyOption::Bridges) && HasTunnelBridgeReservation(rampnorth)) {
1686 if (rti->UsesOverlay()) {
1688 AddSortableSpriteToDraw(overlay + RTO_X + to_underlying(axis), PALETTE_CRASH, ti->x, ti->y, bridge_z, {{}, {TILE_SIZE, TILE_SIZE, 0}, {}}, IsTransparencySet(TransparencyOption::Bridges));
1689 } else {
1690 AddSortableSpriteToDraw(axis == Axis::X ? rti->base_sprites.single_x : rti->base_sprites.single_y, PALETTE_CRASH, ti->x, ti->y, bridge_z, {{}, {TILE_SIZE, TILE_SIZE, 0}, {}}, IsTransparencySet(TransparencyOption::Bridges));
1691 }
1692 }
1693
1695
1696 if (HasRailCatenaryDrawn(GetRailType(rampsouth))) {
1698 }
1699 }
1700
1701 /* draw roof, the component of the bridge which is logically between the vehicle and the camera */
1703 if (axis == Axis::X) {
1704 y += 12;
1705 if (psid[1].sprite & SPRITE_MASK) AddSortableSpriteToDraw(psid[1].sprite, psid[1].pal, x, y, z, {{0, 3, BRIDGE_Z_START}, {TILE_SIZE, 1, 40}, {0, -3, -BRIDGE_Z_START}}, IsTransparencySet(TransparencyOption::Bridges));
1706 } else {
1707 x += 12;
1708 if (psid[1].sprite & SPRITE_MASK) AddSortableSpriteToDraw(psid[1].sprite, psid[1].pal, x, y, z, {{3, 0, BRIDGE_Z_START}, {1, TILE_SIZE, 40}, {-3, 0, -BRIDGE_Z_START}}, IsTransparencySet(TransparencyOption::Bridges));
1709 }
1710 }
1711
1712 /* Draw TramFront as SpriteCombine */
1713 if (transport_type == TransportType::Road) EndSpriteCombine();
1714
1715 /* Do not draw anything more if bridges are invisible */
1717
1718 if (blocked_pillars.Any(pillars)) return;
1719 DrawBridgePillars(psid[2], ti, axis, drawfarpillar, x, y, z);
1720}
1721
1722
1724static int GetSlopePixelZ_TunnelBridge(TileIndex tile, uint x, uint y, bool ground_vehicle)
1725{
1726 auto [tileh, z] = GetTilePixelSlope(tile);
1727
1728 x &= 0xF;
1729 y &= 0xF;
1730
1731 if (IsTunnel(tile)) {
1732 /* In the tunnel entrance? */
1733 if (ground_vehicle) return z;
1734 } else { // IsBridge(tile)
1737
1738 /* On the bridge ramp? */
1739 if (ground_vehicle) {
1740 if (tileh != SLOPE_FLAT) return z + TILE_HEIGHT;
1741
1742 switch (dir) {
1743 default: NOT_REACHED();
1744 case DiagDirection::NE: tileh = SLOPE_NE; break;
1745 case DiagDirection::SE: tileh = SLOPE_SE; break;
1746 case DiagDirection::SW: tileh = SLOPE_SW; break;
1747 case DiagDirection::NW: tileh = SLOPE_NW; break;
1748 }
1749 }
1750 }
1751
1752 return z + GetPartialPixelZ(x, y, tileh);
1753}
1754
1760
1763{
1765
1766 if (IsTunnel(tile)) {
1767 td.str = (tt == TransportType::Rail) ? STR_LAI_TUNNEL_DESCRIPTION_RAILROAD : STR_LAI_TUNNEL_DESCRIPTION_ROAD;
1768 } else { // IsBridge(tile)
1769 td.str = (tt == TransportType::Water) ? STR_LAI_BRIDGE_DESCRIPTION_AQUEDUCT : GetBridgeSpec(GetBridgeType(tile))->transport_name[to_underlying(tt)];
1770 }
1771 td.owner[0] = GetTileOwner(tile);
1772
1773 Owner road_owner = INVALID_OWNER;
1774 Owner tram_owner = INVALID_OWNER;
1777 if (road_rt != INVALID_ROADTYPE) {
1778 const RoadTypeInfo *rti = GetRoadTypeInfo(road_rt);
1779 td.roadtype = rti->strings.name;
1780 td.road_speed = rti->max_speed / 2;
1781 road_owner = GetRoadOwner(tile, RoadTramType::Road);
1782 }
1783 if (tram_rt != INVALID_ROADTYPE) {
1784 const RoadTypeInfo *rti = GetRoadTypeInfo(tram_rt);
1785 td.tramtype = rti->strings.name;
1786 td.tram_speed = rti->max_speed / 2;
1787 tram_owner = GetRoadOwner(tile, RoadTramType::Tram);
1788 }
1789
1790 /* Is there a mix of owners? */
1791 if ((tram_owner != INVALID_OWNER && tram_owner != td.owner[0]) ||
1792 (road_owner != INVALID_OWNER && road_owner != td.owner[0])) {
1793 uint i = 1;
1794 if (road_owner != INVALID_OWNER) {
1795 td.owner_type[i] = STR_LAND_AREA_INFORMATION_ROAD_OWNER;
1796 td.owner[i] = road_owner;
1797 i++;
1798 }
1799 if (tram_owner != INVALID_OWNER) {
1800 td.owner_type[i] = STR_LAND_AREA_INFORMATION_TRAM_OWNER;
1801 td.owner[i] = tram_owner;
1802 }
1803 }
1804
1805 if (tt == TransportType::Rail) {
1806 const RailTypeInfo *rti = GetRailTypeInfo(GetRailType(tile));
1807 td.rail_speed = rti->max_speed;
1808 td.railtype = rti->strings.name;
1809
1810 if (!IsTunnel(tile)) {
1811 uint16_t spd = GetBridgeSpec(GetBridgeType(tile))->speed;
1812 /* rail speed special-cases 0 as unlimited, hides display of limit etc. */
1813 if (spd == UINT16_MAX) spd = 0;
1814 if (td.rail_speed == 0 || spd < td.rail_speed) {
1815 td.rail_speed = spd;
1816 }
1817 }
1818 } else if (tt == TransportType::Road && !IsTunnel(tile)) {
1819 uint16_t spd = GetBridgeSpec(GetBridgeType(tile))->speed;
1820 /* road speed special-cases 0 as unlimited, hides display of limit etc. */
1821 if (spd == UINT16_MAX) spd = 0;
1822 if (road_rt != INVALID_ROADTYPE && (td.road_speed == 0 || spd < td.road_speed)) td.road_speed = spd;
1823 if (tram_rt != INVALID_ROADTYPE && (td.tram_speed == 0 || spd < td.tram_speed)) td.tram_speed = spd;
1824 }
1825}
1826
1827
1830{
1831 bool snow_or_desert = HasTunnelBridgeSnowOrDesert(tile);
1832 switch (_settings_game.game_creation.landscape) {
1833 case LandscapeType::Arctic: {
1834 /* As long as we do not have a snow density, we want to use the density
1835 * from the entry edge. For tunnels this is the lowest point for bridges the highest point.
1836 * (Independent of foundations) */
1837 int z = IsBridge(tile) ? GetTileMaxZ(tile) : GetTileZ(tile);
1838 if (snow_or_desert != (z > GetSnowLine())) {
1839 SetTunnelBridgeSnowOrDesert(tile, !snow_or_desert);
1840 MarkTileDirtyByTile(tile);
1841 }
1842 break;
1843 }
1844
1846 if (GetTropicZone(tile) == TropicZone::Desert && !snow_or_desert) {
1847 SetTunnelBridgeSnowOrDesert(tile, true);
1848 MarkTileDirtyByTile(tile);
1849 }
1850 break;
1851
1852 default:
1853 break;
1854 }
1855}
1856
1859{
1860 TransportType transport_type = GetTunnelBridgeTransportType(tile);
1861 if (transport_type != mode || (transport_type == TransportType::Road && !HasTileRoadType(tile, (RoadTramType)sub_mode))) return {};
1862
1864 if (side != DiagDirection::Invalid && side != ReverseDiagDir(dir)) return {};
1866}
1867
1869static void ChangeTileOwner_TunnelBridge(TileIndex tile, Owner old_owner, Owner new_owner)
1870{
1871 TileIndex other_end = GetOtherTunnelBridgeEnd(tile);
1872 /* Set number of pieces to zero if it's the southern tile as we
1873 * don't want to update the infrastructure counts twice. */
1874 uint num_pieces = tile < other_end ? (GetTunnelBridgeLength(tile, other_end) + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR : 0;
1875
1877
1878 if (tt == TransportType::Road) {
1879 for (RoadTramType rtt : ROADTRAMTYPES_ALL) {
1880 /* Update all roadtypes, no matter if they are present */
1881 if (GetRoadOwner(tile, rtt) == old_owner) {
1882 RoadType rt = GetRoadType(tile, rtt);
1883 if (rt != INVALID_ROADTYPE) {
1884 /* Update company infrastructure counts. A full diagonal road tile has two road bits.
1885 * No need to dirty windows here, we'll redraw the whole screen anyway. */
1886 Company::Get(old_owner)->infrastructure.road[rt] -= num_pieces * 2;
1887 if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.road[rt] += num_pieces * 2;
1888 }
1889
1890 SetRoadOwner(tile, rtt, new_owner == INVALID_OWNER ? OWNER_NONE : new_owner);
1891 }
1892 }
1893 }
1894
1895 if (!IsTileOwner(tile, old_owner)) return;
1896
1897 /* Update company infrastructure counts for rail and water as well.
1898 * No need to dirty windows here, we'll redraw the whole screen anyway. */
1899 Company *old = Company::Get(old_owner);
1900 if (tt == TransportType::Rail) {
1901 old->infrastructure.rail[GetRailType(tile)] -= num_pieces;
1902 if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.rail[GetRailType(tile)] += num_pieces;
1903 } else if (tt == TransportType::Water) {
1904 old->infrastructure.water -= num_pieces;
1905 if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.water += num_pieces;
1906 }
1907
1908 if (new_owner != INVALID_OWNER) {
1909 SetTileOwner(tile, new_owner);
1910 } else {
1911 if (tt == TransportType::Rail) {
1912 /* Since all of our vehicles have been removed, it is safe to remove the rail
1913 * bridge / tunnel. */
1914 [[maybe_unused]] CommandCost ret = Command<Commands::LandscapeClear>::Do({DoCommandFlag::Execute, DoCommandFlag::Bankrupt}, tile);
1915 assert(ret.Succeeded());
1916 } else {
1917 /* In any other case, we can safely reassign the ownership to OWNER_NONE. */
1918 SetTileOwner(tile, OWNER_NONE);
1919 }
1920 }
1921}
1922
1935template <typename T>
1936static void PrepareToEnterBridge(T *gv)
1937{
1938 if (gv->gv_flags.Test(GroundVehicleFlag::GoingUp)) {
1939 gv->z_pos++;
1940 gv->gv_flags.Reset(GroundVehicleFlag::GoingUp);
1941 } else {
1942 gv->gv_flags.Reset(GroundVehicleFlag::GoingDown);
1943 }
1944}
1945
1951static const uint8_t TUNNEL_SOUND_FRAME = 1;
1952
1962
1965{
1966 int z = GetSlopePixelZ(x, y, true) - v->z_pos;
1967
1968 if (abs(z) > 2) return VehicleEnterTileState::CannotEnter;
1969 /* Direction into the wormhole */
1970 const DiagDirection dir = GetTunnelBridgeDirection(tile);
1971 /* Direction of the vehicle */
1973 /* New position of the vehicle on the tile */
1974 uint8_t pos = (DiagDirToAxis(vdir) == Axis::X ? x : y) & TILE_UNIT_MASK;
1975 /* Number of units moved by the vehicle since entering the tile */
1976 uint8_t frame = (vdir == DiagDirection::NE || vdir == DiagDirection::NW) ? TILE_SIZE - 1 - pos : pos;
1977
1978 if (IsTunnel(tile)) {
1979 if (v->type == VehicleType::Train) {
1980 Train *t = Train::From(v);
1981
1982 if (t->track != Track::Wormhole && dir == vdir) {
1983 if (t->IsMovingFront() && frame == TUNNEL_SOUND_FRAME) {
1984 if (!PlayVehicleSound(t, VSE_TUNNEL) && RailVehInfo(t->engine_type)->engclass == EngineClass::Steam) {
1985 SndPlayVehicleFx(SND_05_TRAIN_THROUGH_TUNNEL, v);
1986 }
1987 return {};
1988 }
1989 if (frame == _tunnel_visibility_frame[dir]) {
1990 t->tile = tile;
1994 }
1995 }
1996
1997 if (dir == ReverseDiagDir(vdir) && frame == TILE_SIZE - _tunnel_visibility_frame[dir] && z == 0) {
1998 /* We're at the tunnel exit ?? */
1999 t->tile = tile;
2000 t->track = DiagDirToDiagTrack(vdir);
2001 assert(t->track.Any());
2004 }
2005 } else if (v->type == VehicleType::Road) {
2007
2008 /* Enter tunnel? */
2009 if (rv->state != RVSB_WORMHOLE && dir == vdir) {
2010 if (frame == _tunnel_visibility_frame[dir]) {
2011 /* Frame should be equal to the next frame number in the RV's movement */
2012 assert(frame == rv->frame + 1);
2013 rv->tile = tile;
2014 rv->state = RVSB_WORMHOLE;
2017 } else {
2018 return {};
2019 }
2020 }
2021
2022 /* We're at the tunnel exit ?? */
2023 if (dir == ReverseDiagDir(vdir) && frame == TILE_SIZE - _tunnel_visibility_frame[dir] && z == 0) {
2024 rv->tile = tile;
2026 rv->frame = frame;
2029 }
2030 }
2031 } else { // IsBridge(tile)
2032 if (v->type != VehicleType::Ship) {
2033 /* modify speed of vehicle */
2034 uint16_t spd = GetBridgeSpec(GetBridgeType(tile))->speed;
2035
2036 if (v->type == VehicleType::Road) spd *= 2;
2037 Vehicle *first = v->First();
2038 first->cur_speed = std::min(first->cur_speed, spd);
2039 }
2040
2041 if (vdir == dir) {
2042 /* Vehicle enters bridge at the last frame inside this tile. */
2043 if (frame != TILE_SIZE - 1) return {};
2044 switch (v->type) {
2045 case VehicleType::Train: {
2046 Train *t = Train::From(v);
2049 break;
2050 }
2051
2052 case VehicleType::Road: {
2054 rv->state = RVSB_WORMHOLE;
2056 break;
2057 }
2058
2059 case VehicleType::Ship:
2061 break;
2062
2063 default: NOT_REACHED();
2064 }
2066 } else if (vdir == ReverseDiagDir(dir)) {
2067 v->tile = tile;
2068 switch (v->type) {
2069 case VehicleType::Train: {
2070 Train *t = Train::From(v);
2071 if (t->track == Track::Wormhole) {
2072 t->track = DiagDirToDiagTrack(vdir);
2074 }
2075 break;
2076 }
2077
2078 case VehicleType::Road: {
2080 if (rv->state == RVSB_WORMHOLE) {
2082 rv->frame = 0;
2084 }
2085 break;
2086 }
2087
2088 case VehicleType::Ship: {
2089 Ship *ship = Ship::From(v);
2090 if (ship->state == Track::Wormhole) {
2091 ship->state = DiagDirToDiagTrack(vdir);
2093 }
2094 break;
2095 }
2096
2097 default: NOT_REACHED();
2098 }
2099 }
2100 }
2101 return {};
2102}
2103
2106{
2107 if (_settings_game.construction.build_on_slopes && AutoslopeEnabled() && IsBridge(tile) && GetTunnelBridgeTransportType(tile) != TransportType::Water) {
2108 DiagDirection direction = GetTunnelBridgeDirection(tile);
2109 Axis axis = DiagDirToAxis(direction);
2110 CommandCost res;
2111 auto [tileh_old, z_old] = GetTileSlopeZ(tile);
2112
2113 /* Check if new slope is valid for bridges in general (so we can safely call GetBridgeFoundation()) */
2114 if ((direction == DiagDirection::NW) || (direction == DiagDirection::NE)) {
2115 CheckBridgeSlope(BRIDGE_PIECE_SOUTH, axis, tileh_old, z_old);
2116 res = CheckBridgeSlope(BRIDGE_PIECE_SOUTH, axis, tileh_new, z_new);
2117 } else {
2118 CheckBridgeSlope(BRIDGE_PIECE_NORTH, axis, tileh_old, z_old);
2119 res = CheckBridgeSlope(BRIDGE_PIECE_NORTH, axis, tileh_new, z_new);
2120 }
2121
2122 /* Surface slope is valid and remains unchanged? */
2123 if (res.Succeeded() && (z_old == z_new) && (tileh_old == tileh_new)) return CommandCost(ExpensesType::Construction, _price[Price::BuildFoundation]);
2124 }
2125
2126 return Command<Commands::LandscapeClear>::Do(flags, tile);
2127}
2128
2131{
2132 if (IsTunnel(tile)) return CommandCost();
2133
2134 if (axis != DiagDirToAxis(GetTunnelBridgeDirection(tile)) && height > GetBridgeHeight(tile)) {
2135 return CommandCost();
2136 }
2137
2138 return Command<Commands::LandscapeClear>::Do(flags, tile);
2139}
2140
2143 .draw_tile_proc = DrawTile_TunnelBridge,
2144 .get_slope_pixel_z_proc = GetSlopePixelZ_TunnelBridge,
2145 .clear_tile_proc = ClearTile_TunnelBridge,
2146 .get_tile_desc_proc = GetTileDesc_TunnelBridge,
2147 .get_tile_track_status_proc = GetTileTrackStatus_TunnelBridge,
2148 .tile_loop_proc = TileLoop_TunnelBridge,
2149 .change_tile_owner_proc = ChangeTileOwner_TunnelBridge,
2150 .vehicle_enter_tile_proc = VehicleEnterTile_TunnelBridge,
2151 .get_foundation_proc = GetFoundation_TunnelBridge,
2152 .terraform_tile_proc = TerraformTile_TunnelBridge,
2153 .check_build_above_proc = CheckBuildAbove_TunnelBridge,
2154};
Functions related to autoslope.
bool AutoslopeEnabled()
Tests if autoslope is enabled for _current_company.
Definition autoslope.h:65
constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
const BridgeSpec * GetBridgeSpec(BridgeType i)
Get the specification of a bridge type.
Definition bridge.h:62
static const uint MAX_BRIDGES
Maximal number of available bridge specs.
Definition bridge.h:18
BridgeSpec _bridge[MAX_BRIDGES]
The specification of all bridges.
This file contains all the sprites for bridges.
static const PalSpriteID _aqueduct_sprite_table_middle[]
Sprite table for middle part of aqueduct.
Definition bridge_land.h:41
static const PalSpriteID _aqueduct_sprite_table_heads[]
Sprite table for head part of aqueduct.
Definition bridge_land.h:47
TileIndex GetSouthernBridgeEnd(TileIndex t)
Finds the southern end of a bridge starting at a middle tile.
TileIndex GetOtherBridgeEnd(TileIndex tile)
Starting at one bridge end finds the other bridge end.
TileIndex GetNorthernBridgeEnd(TileIndex t)
Finds the northern end of a bridge starting at a middle tile.
int GetBridgeHeight(TileIndex t)
Get the height ('z') of a bridge.
void SetBridgeMiddle(Tile t, Axis a)
Set that there is a bridge over the given axis.
Definition bridge_map.h:114
void MakeAqueductBridgeRamp(Tile t, Owner o, DiagDirection d)
Make a bridge ramp for aqueducts.
Definition bridge_map.h:182
bool IsBridgeTile(Tile t)
checks if there is a bridge on this tile
Definition bridge_map.h:35
void MakeRailBridgeRamp(Tile t, Owner o, BridgeType bridgetype, DiagDirection d, RailType rt)
Make a bridge ramp for rails.
Definition bridge_map.h:170
int GetBridgePixelHeight(TileIndex tile)
Get the height ('z') of a bridge in pixels.
Definition bridge_map.h:84
void ClearBridgeMiddle(Tile t)
Removes bridges from the given, that is bridges along the X and Y axis.
Definition bridge_map.h:103
void MakeRoadBridgeRamp(Tile t, Owner o, Owner owner_road, Owner owner_tram, BridgeType bridgetype, DiagDirection d, RoadType road_rt, RoadType tram_rt)
Make a bridge ramp for roads.
Definition bridge_map.h:154
BridgeType GetBridgeType(Tile t)
Determines the type of bridge on a tile.
Definition bridge_map.h:56
bool IsBridgeAbove(Tile t)
checks if a bridge is set above the ground of this tile
Definition bridge_map.h:45
Axis GetBridgeAxis(Tile t)
Get the axis of the bridge that goes over the tile.
Definition bridge_map.h:68
bool IsBridge(Tile t)
Checks if this is a bridge, instead of a tunnel.
Definition bridge_map.h:24
EnumBitSet< BridgePillarFlag, uint8_t > BridgePillarFlags
Bitset of BridgePillarFlag elements.
Definition bridge_type.h:53
BridgePieces
This enum is related to the definition of bridge pieces, which is used to determine the proper sprite...
Definition bridge_type.h:22
@ EdgeNE
Northeast edge is obstructed.
Definition bridge_type.h:46
@ EdgeSW
Southwest edge is obstructed.
Definition bridge_type.h:48
@ EdgeNW
Northwest edge is obstructed.
Definition bridge_type.h:49
@ EdgeSE
Southeast edge is obstructed.
Definition bridge_type.h:47
uint BridgeType
Bridge spec number.
Definition bridge_type.h:15
Cheats _cheats
All the cheats.
Definition cheat.cpp:16
Types related to cheating.
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr Timpl & Reset()
Reset all bits.
constexpr Timpl & Set()
Set all bits.
constexpr bool Any(const Timpl &other) const
Test if any of the given values are set.
Common return value for all commands.
bool Succeeded() const
Did this command succeed?
void AddCost(const Money &cost)
Adds the given cost to the cost of the command.
Money GetCost() const
The costs as made up to this moment.
bool Failed() const
Did this command fail?
This struct contains all the info that is needed to draw and construct tracks.
Definition rail.h:117
SpriteID single_x
single piece of rail in X direction, without ground
Definition rail.h:127
uint16_t max_speed
Maximum speed for vehicles travelling on this rail type.
Definition rail.h:222
struct RailTypeInfo::@157247141350136173143103254227157213063052244122 strings
Strings associated with the rail type.
SpriteID bridge_deck
bridge deck sprites base
Definition rail.h:136
SpriteID single_y
single piece of rail in Y direction, without ground
Definition rail.h:128
StringID name
Name of this rail type.
Definition rail.h:167
uint8_t bridge_offset
Bridge offset.
Definition rail.h:187
struct RailTypeInfo::@332027037331076264023214171276243307073252216167 base_sprites
Struct containing the main sprites.
SpriteID tunnel
tunnel sprites base
Definition rail.h:135
SpriteID single_sloped
single piece of rail for slopes
Definition rail.h:133
uint16_t max_speed
Maximum speed for vehicles travelling on this road type.
Definition road.h:118
struct RoadTypeInfo::@070000167274302256150317022075324310363002361255 strings
Strings associated with the rail type.
StringID name
Name of this rail type.
Definition road.h:79
static Year year
Current year, starting at 0.
void DrawClearLandTile(const TileInfo *ti, uint8_t density)
Draw a ClearGround::Grass tile.
Definition clear_cmd.cpp:61
Functions related to clear (TileType::Clear) land.
CommandCost CommandCostWithParam(StringID str, uint64_t value)
Return an error status, with string and parameter.
Definition command.cpp:416
Functions related to commands.
CommandCost & ExtractCommandCost(Tret &ret)
Extract the CommandCost from a command proc result.
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
@ Auto
don't allow building on structures
@ QueryCost
query cost only, don't build.
@ Execute
execute the given command
@ Bankrupt
company bankrupts, skip money check, skip vehicle on tile check in some cases
EnumBitSet< DoCommandFlag, uint16_t > DoCommandFlags
Bitset of DoCommandFlag elements.
Definition of stuff that is very close to a company, like the company struct itself.
CommandCost CheckTileOwnership(TileIndex tile)
Check whether the current owner owns the stuff on the given tile.
CommandCost CheckOwnership(Owner owner, TileIndex tile)
Check whether the current owner owns something.
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
CompanyID _current_company
Company currently doing an action.
void DirtyCompanyInfrastructureWindows(CompanyID company)
Redraw all windows with company infrastructure counts.
GUI Functions related to companies.
static constexpr Owner OWNER_DEITY
The object is owned by a superuser / goal script.
static constexpr Owner OWNER_TOWN
A town owns the tile, or a town is expanding.
static constexpr Owner OWNER_NONE
The tile has no ownership.
static constexpr Owner INVALID_OWNER
An invalid owner.
static constexpr Owner OWNER_WATER
The tile/execution is done by "water".
DiagDirection ReverseDiagDir(DiagDirection d)
Returns the reverse direction of the given DiagDirection.
DiagDirection AxisToDiagDir(Axis a)
Converts an Axis to a DiagDirection.
Axis OtherAxis(Axis a)
Select the other axis as provided.
Axis DiagDirToAxis(DiagDirection d)
Convert a DiagDirection to the axis.
DiagDirection DirToDiagDir(Direction dir)
Convert a Direction to a DiagDirection.
EnumIndexArray< T, Axis, Axis::End > AxisIndexArray
Array with Axis as index.
EnumIndexArray< T, DiagDirection, DiagDirection::End > DiagDirectionIndexArray
Array with DiagDirection as index.
Axis
Enumeration for the two axis X and Y.
@ X
The X axis.
@ Y
The y axis.
DiagDirection
Enumeration for diagonal directions.
@ Invalid
Flag for an invalid DiagDirection.
@ SW
Southwest.
@ NW
Northwest.
@ NE
Northeast, upper right on your monitor.
@ SE
Southeast.
Prices _price
Prices and also the fractional part.
Definition economy.cpp:106
@ Construction
Construction costs.
static const uint TUNNELBRIDGE_TRACKBIT_FACTOR
Multiplier for how many regular track bits a tunnel/bridge counts.
Price
Enumeration of all base prices for use with Prices.
@ ClearTunnel
Price for destroying tunnels.
@ BuildFoundation
Price for building foundation under other constructions e.g. roads, rails, depots,...
@ ClearAqueduct
Price for destroying aqueducts.
@ BuildAqueduct
Price for building new aqueducts.
@ BuildTunnel
Price for building tunnels.
@ BuildBridge
Price for building bridges.
@ ClearBridge
Price for destroying bridges.
void DrawRailCatenaryOnBridge(const TileInfo *ti)
Draws wires on a tunnel tile.
Definition elrail.cpp:493
void DrawRailCatenaryOnTunnel(const TileInfo *ti)
Draws wires on a tunnel tile.
Definition elrail.cpp:259
void DrawRailCatenary(const TileInfo *ti)
Draws overhead wires and pylons for electric railways.
Definition elrail.cpp:553
Header file for electrified rail specific functions.
bool HasRailCatenaryDrawn(RailType rt)
Test if we should draw rail catenary.
Definition elrail_func.h:32
@ Steam
Steam rail engine.
Definition engine_type.h:39
#define T
Climate temperate.
Definition engines.h:91
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23).
Definition enum_type.hpp:21
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:17
uint8_t GetSnowLine()
Get the current snow line, either variable or static.
void MarkTileDirtyByTile(TileIndex tile, int bridge_level_offset, int tile_height_override)
Mark a tile given by its index dirty for repaint.
@ TownEdge
Edge of the town; roads without pavement.
Definition house.h:60
uint GetPartialPixelZ(int x, int y, Slope corners)
Determines height at given coordinate of a slope.
void DrawFoundation(TileInfo *ti, Foundation f)
Draw foundation f at tile ti.
const TileTypeProcs _tile_type_tunnelbridge_procs
TileTypeProcs definitions for TileType::TunnelBridge tiles.
Definition landscape.cpp:61
void GetSlopePixelZOnEdge(Slope tileh, DiagDirection edge, int &z1, int &z2)
Determine the Z height of the corners of a specific tile edge.
uint ApplyFoundationToSlope(Foundation f, Slope &s)
Applies a foundation to a slope.
const EnumIndexArray< const TileTypeProcs *, TileType, TileType::MaxSize > _tile_type_procs
Tile callback functions for each type of tile.
Definition landscape.cpp:69
int GetSlopePixelZ(int x, int y, bool ground_vehicle)
Return world Z coordinate of a given point of a tile.
uint ApplyPixelFoundationToSlope(Foundation f, Slope &s)
Applies a foundation to a slope.
Definition landscape.h:128
Command definitions related to landscape (slopes etc.).
@ Arctic
Landscape with snow levels.
@ Tropic
Landscape with distinct rainforests and deserts,.
uint DistanceSquare(TileIndex t0, TileIndex t1)
Gets the 'Square' distance between the two given tiles.
Definition map.cpp:186
TileIndexDiff TileDiffXY(int x, int y)
Calculates an offset for the given coordinate(-offset).
Definition map_func.h:392
TileIndexDiff TileOffsByAxis(Axis axis)
Convert an Axis to a TileIndexDiff.
Definition map_func.h:559
static uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition map_func.h:429
static uint TileX(TileIndex tile)
Get the X component of a tile.
Definition map_func.h:419
TileIndexDiff TileOffsByDiagDir(DiagDirection dir)
Convert a DiagDirection to a TileIndexDiff.
Definition map_func.h:574
int32_t TileIndexDiff
An offset value between two tiles.
Definition map_type.h:23
constexpr T abs(const T a)
Returns the absolute value of (scalar) variable.
Definition math_func.hpp:23
@ Normal
Nothing special.
@ OnBridge
Querying information about stuff on the bridge (via some bridgehead).
SpriteID GetCustomRailSprite(const RailTypeInfo *rti, TileIndex tile, RailSpriteType rtsg, TileContext context, uint *num_results)
Get the sprite to draw for the given tile.
NewGRF handling of rail types.
SpriteID GetCustomRoadSprite(const RoadTypeInfo *rti, TileIndex tile, RoadSpriteType rtsg, TileContext context, uint *num_results)
Get the sprite to draw for the given tile.
NewGRF handling of road types.
bool PlayVehicleSound(const Vehicle *v, VehicleSoundEvent event, bool force)
Checks whether a NewGRF wants to play a different vehicle sound effect.
Functions related to NewGRF provided sounds.
@ VSE_TUNNEL
Train entering a tunnel.
Base for all objects.
ClearedObjectArea * FindClearedObject(TileIndex tile)
Find the entry in _cleared_object_areas which occupies a certain tile.
@ Editor
In the scenario editor.
Definition openttd.h:21
@ Menu
In the main menu.
Definition openttd.h:19
Train * GetTrainForReservation(TileIndex tile, Track track)
Find the train which has reserved a specific path.
Definition pbs.cpp:345
PBS support routines.
bool ValParamRailType(const RailType rail)
Validate functions for rail building.
Definition rail.cpp:92
@ RTBO_Y
Piece of rail in Y direction.
Definition rail.h:87
@ RTBO_X
Piece of rail in X direction.
Definition rail.h:86
@ RTBO_SLOPE
Sloped rail pieces, in order NE, SE, SW, NW.
Definition rail.h:88
@ TunnelPortal
Tunnel portal overlay.
Definition rail.h:53
@ Overlay
Images for overlaying track.
Definition rail.h:44
@ Bridge
Bridge surface images.
Definition rail.h:49
@ Tunnel
Main group of ground images for snow or desert.
Definition rail.h:46
Money RailClearCost(RailType railtype)
Returns the 'cost' of clearing the specified railtype.
Definition rail.h:442
Money RailBuildCost(RailType railtype)
Returns the cost of building the specified railtype.
Definition rail.h:431
const RailTypeInfo * GetRailTypeInfo(RailType railtype)
Returns a pointer to the Railtype information for a given railtype.
Definition rail.h:303
@ RTO_SLOPE_NE
Piece of rail on slope with north-east raised.
Definition rail.h:70
@ RTO_X
Piece of rail in X direction.
Definition rail.h:64
static const int INF
Big number compared to tilesprite size.
RailType GetRailType(Tile t)
Gets the rail type of the given tile.
Definition rail_map.h:115
RailType
Enumeration for all possible railtypes.
Definition rail_type.h:25
bool ValParamRoadType(RoadType roadtype)
Validate functions for rail building.
Definition road.cpp:165
Money RoadClearCost(RoadType roadtype)
Returns the cost of clearing the specified roadtype.
Definition road.h:253
const RoadTypeInfo * GetRoadTypeInfo(RoadType roadtype)
Returns a pointer to the Roadtype information for a given roadtype.
Definition road.h:217
@ CatenaryFront
Optional: Catenary front.
Definition road.h:43
@ Overlay
Optional: Images for overlaying track.
Definition road.h:40
@ CatenaryRear
Optional: Catenary back.
Definition road.h:44
@ Bridge
Required: Bridge surface images.
Definition road.h:45
@ Tunnel
Optional: Ground images for tunnels.
Definition road.h:42
Money RoadBuildCost(RoadType roadtype)
Returns the cost of building the specified roadtype.
Definition road.h:242
void UpdateCompanyRoadInfrastructure(RoadType rt, Owner o, int count)
Update road infrastructure counts for a company.
Definition road_cmd.cpp:183
void DrawRoadOverlays(const TileInfo *ti, PaletteID pal, const RoadTypeInfo *road_rti, const RoadTypeInfo *tram_rti, uint road_offset, uint tram_offset, bool draw_underlay)
Draw road underlay and overlay sprites.
bool HasRoadCatenaryDrawn(RoadType roadtype)
Test if we should draw road catenary.
Definition road_func.h:129
void SetRoadOwner(Tile t, RoadTramType rtt, Owner o)
Set the owner of a specific road type.
Definition road_map.h:261
RoadType GetRoadTypeRoad(Tile t)
Get the road type for RoadTramType being RoadTramType::Road.
Definition road_map.h:152
bool HasTileRoadType(Tile t, RoadTramType rtt)
Check if a tile has a road or a tram road type.
Definition road_map.h:221
RoadType GetRoadTypeTram(Tile t)
Get the road type for RoadTramType being RoadTramType::Tram.
Definition road_map.h:163
Roadside GetRoadside(Tile tile)
Get the decorations of a road.
Definition road_map.h:488
RoadType GetRoadType(Tile t, RoadTramType rtt)
Get the road type for the given RoadTramType.
Definition road_map.h:175
static bool IsNormalRoadTile(Tile t)
Return whether a tile is a normal road tile.
Definition road_map.h:58
Owner GetRoadOwner(Tile t, RoadTramType rtt)
Get the owner of a specific road type.
Definition road_map.h:244
void SetRoadside(Tile tile, Roadside s)
Set the decorations of a road.
Definition road_map.h:498
@ Paved
Road with paved sidewalks.
Definition road_map.h:475
@ Trees
Road with trees on paved sidewalks.
Definition road_map.h:478
static constexpr RoadTramTypes ROADTRAMTYPES_ALL
All possible RoadTramTypes.
Definition road_type.h:48
RoadType
The different roadtypes we support.
Definition road_type.h:23
@ INVALID_ROADTYPE
flag for invalid roadtype
Definition road_type.h:28
RoadTramType
The different types of road type.
Definition road_type.h:37
@ Tram
Tram type.
Definition road_type.h:39
@ Road
Road type.
Definition road_type.h:38
Road vehicle states.
@ RVSB_WORMHOLE
The vehicle is in a tunnel and/or bridge.
Definition roadveh.h:39
A number of safeguards to prevent using unsafe methods.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:61
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:60
Base for ships.
void AddSideToSignalBuffer(TileIndex tile, DiagDirection side, Owner owner)
Add side of tile to signal update buffer.
Definition signal.cpp:630
uint SlopeToSpriteOffset(Slope s)
Returns the Sprite offset for a given Slope.
Definition slope_func.h:423
bool HasSlopeHighestCorner(Slope s)
Tests if a slope has a highest corner (i.e.
Definition slope_func.h:123
Foundation FlatteningFoundation(Slope s)
Returns the foundation needed to flatten a slope.
Definition slope_func.h:377
DiagDirection GetInclinedSlopeDirection(Slope s)
Returns the direction of an inclined slope.
Definition slope_func.h:249
Foundation InclinedFoundation(Axis axis)
Returns the along a specific axis inclined foundation.
Definition slope_func.h:388
Slope ComplementSlope(Slope s)
Return the complement of a slope.
Definition slope_func.h:86
Slope
Enumeration for the slope-type.
Definition slope_type.h:53
@ SLOPE_SW
south and west corner are raised
Definition slope_type.h:61
@ SLOPE_FLAT
a flat tile
Definition slope_type.h:54
@ SLOPE_NE
north and east corner are raised
Definition slope_type.h:63
@ SLOPE_SE
south and east corner are raised
Definition slope_type.h:62
@ SLOPE_NW
north and west corner are raised
Definition slope_type.h:60
Foundation
Enumeration for Foundations.
Definition slope_type.h:98
@ None
The tile has no foundation, the slope remains unchanged.
Definition slope_type.h:99
Functions related to sound.
@ SND_05_TRAIN_THROUGH_TUNNEL
3 == 0x03 Train enters tunnel: steam engine
Definition sound_type.h:51
static const SpriteID SPR_BRIDGE_DECKS_ROAD
Definition sprites.h:371
static const SpriteID SPR_TRAMWAY_BRIDGE
Definition sprites.h:317
static constexpr uint32_t SPRITE_MASK
The mask to for the main sprite.
Definition sprites.h:1737
static const SpriteID SPR_TUNNEL_ENTRY_REAR_ROAD
Definition sprites.h:766
static const PaletteID PALETTE_CRASH
Recolour sprite greying of crashed vehicles.
Definition sprites.h:1788
static const SpriteID SPR_FLAT_SNOW_DESERT_TILE
Definition sprites.h:683
static const SpriteID SPR_TRAMWAY_OVERLAY
Definition sprites.h:302
static const SpriteID SPR_RAILTYPE_TUNNEL_BASE
Definition sprites.h:332
static const SpriteID SPR_TRAMWAY_BASE
Definition sprites.h:301
static const SpriteID SPR_TRAMWAY_TUNNEL_WIRES
Definition sprites.h:316
static const SpriteID SPR_EMPTY_BOUNDING_BOX
Definition sprites.h:338
Definition of base types and functions in a cross-platform compatible way.
#define lengthof(array)
Return the length of an fixed size array.
Definition stdafx.h:271
Functions related to OTTD's strings.
VehicleType type
Type of vehicle.
Struct containing information about a single bridge type.
Definition bridge.h:27
ControlFlags ctrl_flags
control flags
Definition bridge.h:48
@ InvalidPillarFlags
Bridge pillar flags are not valid, i.e. only the tile layout has been modified.
Definition bridge.h:31
uint8_t min_length
the minimum length (not counting start and end tile)
Definition bridge.h:38
BridgeMiddlePillarFlags pillar_flags
bridge pillar flags.
Definition bridge.h:49
std::vector< std::vector< PalSpriteID > > sprite_table
table of sprites for drawing the bridge
Definition bridge.h:46
TimerGameCalendar::Year avail_year
the year where it becomes available
Definition bridge.h:37
StringID transport_name[2]
description of the bridge, when built for road or rail
Definition bridge.h:45
uint16_t speed
maximum travel speed (1 unit = 1/1.6 mph = 1 km-ish/h)
Definition bridge.h:41
uint16_t max_length
the maximum length (not counting start and end tile)
Definition bridge.h:39
Keeps track of removed objects during execution/testruns of commands.
Definition object_base.h:87
TileIndex first_tile
The first tile being cleared, which then causes the whole object to be cleared.
Definition object_base.h:88
std::array< uint32_t, ROADTYPE_END > road
Count of company owned track bits for each road type.
std::array< uint32_t, RAILTYPE_END > rail
Count of company owned track bits for each rail type.
uint32_t water
Count of company owned track bits for canals.
bool is_ai
If true, the company is (also) controlled by the computer (a NoAI program).
CompanyInfrastructure infrastructure
NOSAVE: Counts of company owned infrastructure.
T x
X coordinate.
T y
Y coordinate.
T z
Z coordinate.
static uint MaxX()
Gets the maximum X coordinate within the map, including TileType::Void.
Definition map_func.h:289
Combination of a palette sprite and a 'real' sprite.
Definition gfx_type.h:22
SpriteID sprite
The 'real' sprite.
Definition gfx_type.h:23
PaletteID pal
The palette (use PAL_NONE) if not needed).
Definition gfx_type.h:24
static Company * Get(auto index)
static Company * GetIfValid(auto index)
Buses, trucks and trams belong to this class.
Definition roadveh.h:105
uint8_t state
Definition roadveh.h:107
All ships have this type.
Definition ship.h:32
TrackBits state
The "track" the ship is following.
Definition ship.h:34
static Train * From(Vehicle *v)
Used to only draw a part of the sprite.
Definition gfx_type.h:278
Tile description for the 'land area information' tool.
Definition tile_cmd.h:40
uint16_t rail_speed
Speed limit of rail (bridges and track).
Definition tile_cmd.h:53
StringID str
Description of the tile.
Definition tile_cmd.h:41
std::array< Owner, 4 > owner
Name of the owner(s).
Definition tile_cmd.h:43
uint16_t tram_speed
Speed limit of tram (bridges and track).
Definition tile_cmd.h:57
StringID roadtype
Type of road on the tile.
Definition tile_cmd.h:54
StringID tramtype
Type of tram on the tile.
Definition tile_cmd.h:56
StringID railtype
Type of rail on the tile.
Definition tile_cmd.h:52
uint16_t road_speed
Speed limit of road (bridges and track).
Definition tile_cmd.h:55
std::array< StringID, 4 > owner_type
Type of each owner.
Definition tile_cmd.h:44
Tile information, used while rendering the tile.
Definition tile_cmd.h:34
Slope tileh
Slope of the tile.
Definition tile_cmd.h:35
TileIndex tile
Tile index.
Definition tile_cmd.h:36
Set of callback functions for performing tile operations of a given tile type.
Definition tile_cmd.h:214
std::array< uint32_t, NUM_HOUSE_ZONES > squared_town_zone_radius
UpdateTownRadius updates this given the house count.
Definition town.h:57
Town data structure.
Definition town.h:64
TileIndex xy
town center tile
Definition town.h:65
TownCache cache
Container for all cacheable data.
Definition town.h:67
Track status of a tile.
Definition track_type.h:105
'Train' is either a loco or a wagon.
Definition train.h:97
TrackBits track
On which track the train currently is.
Definition train.h:110
Vehicle data structure.
EngineID engine_type
The type of engine used for this vehicle.
int32_t z_pos
z coordinate.
Direction GetMovingDirection() const
Get the moving direction of this vehicle chain.
bool IsMovingFront() const
Is this vehicle the moving front of the vehicle chain?
VehStates vehstatus
Status.
Vehicle * First() const
Get the first vehicle of this vehicle chain.
uint16_t cur_speed
current speed
TileIndex tile
Current tile index.
Command definitions related to terraforming.
@ CannotEnter
The vehicle cannot enter the tile.
Definition tile_cmd.h:27
@ EnteredWormhole
The vehicle either entered a bridge, tunnel or depot tile (this includes the last tile of the bridge/...
Definition tile_cmd.h:26
EnumBitSet< VehicleEnterTileState, uint8_t > VehicleEnterTileStates
Bitset of VehicleEnterTileState elements.
Definition tile_cmd.h:31
std::tuple< Slope, int > GetTileSlopeZ(TileIndex tile)
Return the slope of a given tile inside the map.
Definition tile_map.cpp:55
int GetTileMaxZ(TileIndex t)
Get top height of the tile inside the map.
Definition tile_map.cpp:135
int GetTileZ(TileIndex tile)
Get bottom height of the tile.
Definition tile_map.cpp:115
static uint TileHeight(Tile tile)
Returns the height of a tile.
Definition tile_map.h:29
bool IsTileOwner(Tile tile, Owner owner)
Checks if a tile belongs to the given owner.
Definition tile_map.h:214
Owner GetTileOwner(Tile tile)
Returns the owner of a tile.
Definition tile_map.h:178
void SetTileOwner(Tile tile, Owner owner)
Sets the owner of a tile.
Definition tile_map.h:198
std::tuple< Slope, int > GetTilePixelSlope(TileIndex tile)
Return the slope of a given tile.
Definition tile_map.h:289
bool IsValidTile(Tile tile)
Checks if a tile is valid.
Definition tile_map.h:161
TropicZone GetTropicZone(Tile tile)
Get the tropic zone.
Definition tile_map.h:238
static TileType GetTileType(Tile tile)
Get the tiletype of a given tile.
Definition tile_map.h:96
static constexpr uint TILE_UNIT_MASK
For masking in/out the inner-tile world coordinate units.
Definition tile_type.h:16
StrongType::Typedef< uint32_t, struct TileIndexTag, StrongType::Compare, StrongType::Integer, StrongType::Compatible< int32_t >, StrongType::Compatible< int64_t > > TileIndex
The index/ID of a Tile.
Definition tile_type.h:92
@ Desert
Tile is desert.
Definition tile_type.h:83
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:100
static constexpr uint TILE_SIZE
Tile size in world coordinates.
Definition tile_type.h:15
static constexpr uint TILE_HEIGHT
Height of a height level in world coordinate AND in pixels in ZOOM_BASE.
Definition tile_type.h:18
OrthogonalTileArea TileArea
Shorthand for the much more common orthogonal tile area.
Definition of the game-calendar-timer.
Base of the town class.
void ChangeTownRating(Town *t, int add, int max, DoCommandFlags flags)
Changes town rating of the current company.
@ TunnelBridgeRemove
Removal of a tunnel or bridge owned by the town.
Definition town.h:276
Town * ClosestTownFromTile(TileIndex tile, uint threshold)
Return the town closest (in distance or ownership) to a given tile, within a given threshold.
Town * CalcClosestTownFromTile(TileIndex tile, uint threshold=UINT_MAX)
Return the town closest to the given tile within threshold.
CommandCost CheckforTownRating(DoCommandFlags flags, Town *t, TownRatingCheckType type)
Does the town authority allow the (destructive) action of the current company?
static constexpr int RATING_TUNNEL_BRIDGE_UP_STEP
rating increase for improving a town-owned bridge
Definition town_type.h:57
static constexpr int RATING_TUNNEL_BRIDGE_MINIMUM
minimum rating after removing tunnel or bridge
Definition town_type.h:59
static constexpr int RATING_TUNNEL_BRIDGE_DOWN_STEP
penalty for removing town owned tunnel or bridge
Definition town_type.h:58
TrackdirBits TrackBitsToTrackdirBits(TrackBits bits)
Converts TrackBits to TrackdirBits while allowing both directions.
Definition track_func.h:292
Trackdir DiagDirToDiagTrackdir(DiagDirection diagdir)
Maps a (4-way) direction to the diagonal trackdir that runs in that direction.
Definition track_func.h:432
Track AxisToTrack(Axis a)
Convert an Axis to the corresponding Track Axis::X -> Track::X Axis::Y -> Track::Y Uses the fact that...
Definition track_func.h:62
Track DiagDirToDiagTrack(DiagDirection diagdir)
Maps a DiagDirection to the associated diagonal Track.
Definition track_func.h:419
Track
These are used to specify a single track.
Definition track_type.h:19
@ Wormhole
Special flag indicating vehicle is inside a bridge or tunnel.
Definition track_type.h:29
Base for the train class.
bool TryPathReserve(Train *v, bool mark_as_stuck=false, bool first_tile_okay=false)
Try to reserve a path to a safe position.
void FreeTrainTrackReservation(const Train *v)
Free the reserved path in front of a vehicle.
bool IsTransparencySet(TransparencyOption to)
Check if the transparency option bit is set and if we aren't in the game menu (there's never transpar...
bool IsInvisibilitySet(TransparencyOption to)
Check if the invisibility option bit is set and if we aren't in the game menu (there's never transpar...
TransportType
Available types of transport.
@ Water
Transport over water.
@ Rail
Transport by train.
@ Road
Transport by road vehicle.
bool IsTunnelInWayDir(TileIndex tile, int z, DiagDirection dir)
Is there a tunnel in the way in the given direction?
TileIndex GetOtherTunnelEnd(TileIndex tile)
Gets the other end of the tunnel.
void MakeRailTunnel(Tile t, Owner o, DiagDirection d, RailType r)
Makes a rail tunnel entrance.
Definition tunnel_map.h:74
bool IsTunnel(Tile t)
Is this a tunnel (entrance)?
Definition tunnel_map.h:23
void MakeRoadTunnel(Tile t, Owner o, DiagDirection d, RoadType road_rt, RoadType tram_rt)
Makes a road tunnel entrance.
Definition tunnel_map.h:51
Header file for things common for tunnels and bridges.
uint GetTunnelBridgeLength(TileIndex begin, TileIndex end)
Calculates the length of a tunnel or a bridge (without end tiles).
TileIndex _build_tunnel_endtile
The end of a tunnel; as hidden return from the tunnel build command for GUI purposes.
static Foundation GetFoundation_TunnelBridge(TileIndex tile, Slope tileh)
Tile callback function signature for getting the foundation of a tile.
static void GetTileDesc_TunnelBridge(TileIndex tile, TileDesc &td)
Tile callback function signature for obtaining a tile description.
CommandCost CmdBuildBridge(DoCommandFlags flags, TileIndex tile_end, TileIndex tile_start, TransportType transport_type, BridgeType bridge_type, RailType railtype, RoadType roadtype)
Build a Bridge.
static CommandCost ClearTile_TunnelBridge(TileIndex tile, DoCommandFlags flags)
Tile callback function signature for clearing a tile.
CommandCost CmdBuildTunnel(DoCommandFlags flags, TileIndex start_tile, TransportType transport_type, RailType railtype, RoadType roadtype)
Build Tunnel.
static void DrawBridgePillars(const PalSpriteID &psid, const TileInfo *ti, Axis axis, bool drawfarpillar, int x, int y, int z_bridge)
Draws the pillars under high bridges.
static BridgePieces CalcBridgePiece(uint north, uint south)
Compute bridge piece.
static bool BridgeHasCustomSpriteTable(BridgeType bridge_type, BridgePieces piece)
Test if bridge piece uses a custom sprite table.
const DiagDirectionIndexArray< uint8_t > _tunnel_visibility_frame
Frame when a vehicle should be hidden in a tunnel with a certain direction.
static CommandCost CheckAllowRemoveTunnelBridge(TileIndex tile)
Are we allowed to remove the tunnel or bridge at tile?
static Money TunnelBridgeClearCost(TileIndex tile, Price base_price)
Calculate the base cost of clearing a tunnel/bridge per tile.
Foundation GetBridgeFoundation(Slope tileh, Axis axis)
Get the foundation for a bridge.
static int GetSlopePixelZ_TunnelBridge(TileIndex tile, uint x, uint y, bool ground_vehicle)
Tile callback function signature for obtaining the world Z coordinate of a given point of a tile.
static void ChangeTileOwner_TunnelBridge(TileIndex tile, Owner old_owner, Owner new_owner)
Tile callback function signature for changing the owner of a tile.
static CommandCost DoClearTunnel(TileIndex tile, DoCommandFlags flags)
Remove a tunnel from the game, update town rating, etc.
static CommandCost DoClearBridge(TileIndex tile, DoCommandFlags flags)
Remove a bridge from the game, update town rating, etc.
static CommandCost CheckBuildAbove_TunnelBridge(TileIndex tile, DoCommandFlags flags, Axis axis, int height)
Tile callback function signature to test if a bridge can be built above a tile.
static VehicleEnterTileStates VehicleEnterTile_TunnelBridge(Vehicle *v, TileIndex tile, int x, int y)
Tile callback function for a vehicle entering a tile.
static int DrawPillarColumn(int z_bottom, int z_top, const PalSpriteID &psid, int x, int y, int w, int h)
Draw two bridge pillars (north and south).
static BridgePillarFlags GetBridgeTilePillarFlags(TileIndex tile, TileIndex rampnorth, TileIndex rampsouth, BridgeType type, TransportType transport_type)
Get pillar information for a bridge middle tile.
static void DrawPillar(const PalSpriteID &psid, int x, int y, int z, uint8_t w, uint8_t h, const SubSprite *subsprite)
Draw a single pillar sprite.
static uint8_t GetBridgeRampDirectionBaseOffset(DiagDirection diagdir)
Get bridge sprite table base offset for the ramp part of bridge.
CommandCost CheckBridgeAvailability(BridgeType bridge_type, uint bridge_len, DoCommandFlags flags)
Is a bridge of the specified type and length available?
void MarkBridgeDirty(TileIndex begin, TileIndex end, DiagDirection direction, uint bridge_height)
Mark bridge tiles dirty.
static TrackStatus GetTileTrackStatus_TunnelBridge(TileIndex tile, TransportType mode, RoadTramType sub_mode, DiagDirection side)
Tile callback function signature for getting the possible tracks that can be taken on a given tile by...
bool HasBridgeFlatRamp(Slope tileh, Axis axis)
Determines if the track on a bridge ramp is flat or goes up/down.
static void DrawTile_TunnelBridge(TileInfo *ti)
Tile callback function signature for drawing a tile and its contents to the screen.
void DrawBridgeMiddle(const TileInfo *ti, BridgePillarFlags blocked_pillars)
Draw the middle bits of a bridge.
static std::span< const PalSpriteID > GetBridgeSpriteTable(BridgeType bridge_type, BridgePieces piece)
Get the sprite table for a rail/road bridge piece.
static const int BRIDGE_Z_START
Z position of the bridge sprites relative to bridge height (downwards).
static CommandCost TerraformTile_TunnelBridge(TileIndex tile, DoCommandFlags flags, int z_new, Slope tileh_new)
Tile callback function signature of the terraforming callback.
static uint8_t GetBridgeMiddleAxisBaseOffset(Axis axis)
Get bridge sprite table base offset for the middle part of bridge.
static void GetBridgeRoadCatenary(const RoadTypeInfo *rti, TileIndex head_tile, int offset, bool head, SpriteID &spr_back, SpriteID &spr_front)
Retrieve the sprites required for catenary on a road/tram bridge.
int CalcBridgeLenCostFactor(int length)
Calculate the price factor for building a long bridge.
static void PrepareToEnterBridge(T *gv)
Helper to prepare the ground vehicle when entering a bridge.
static uint8_t GetBridgeSpriteTableBaseOffset(TransportType transport_type, TileIndex ramp)
Get the sprite table transport type base offset for a rail/road bridge.
void ResetBridges()
Reset the data been eventually changed by the grf loaded.
static void TileLoop_TunnelBridge(TileIndex tile)
Tile callback function signature for running periodic tile updates.
static CommandCost CheckBridgeSlope(BridgePieces bridge_piece, Axis axis, Slope &tileh, int &z)
Determines the foundation for the bridge head, and tests if the resulting slope is valid.
static void DrawBridgeRoadBits(TileIndex head_tile, int x, int y, int z, int offset, bool head, bool is_custom_layout)
Draws the road and trambits over an already drawn (lower end) of a bridge.
static const uint8_t TUNNEL_SOUND_FRAME
Frame when the 'enter tunnel' sound should be played.
Command definitions related to tunnels and bridges.
Functions that have tunnels and bridges in common.
void SetTunnelBridgeSnowOrDesert(Tile t, bool snow_or_desert)
Tunnel: Places this tunnel entrance in a snowy or desert area, or takes it out of there.
DiagDirection GetTunnelBridgeDirection(Tile t)
Get the direction pointing to the other end.
bool HasTunnelBridgeSnowOrDesert(Tile t)
Tunnel: Is this tunnel entrance in a snowy or desert area?
bool HasTunnelBridgeReservation(Tile t)
Get the reservation state of the rail tunnel/bridge.
TransportType GetTunnelBridgeTransportType(Tile t)
Tunnel: Get the transport type of the tunnel (road or rail) Bridge: Get the transport type of the bri...
TileIndex GetOtherTunnelBridgeEnd(Tile t)
Determines type of the wormhole and returns its other end.
void SetTunnelBridgeReservation(Tile t, bool b)
Set the reservation state of the rail tunnel/bridge.
CommandCost TunnelBridgeIsFree(TileIndex tile, TileIndex endtile, const Vehicle *ignore)
Finds vehicle in tunnel / bridge.
Definition vehicle.cpp:581
@ Hidden
Vehicle is not visible.
Functions related to vehicles.
@ Ship
Ship vehicle type.
@ Road
Road vehicle type.
@ Train
Train vehicle type.
@ GoingUp
Vehicle is currently going uphill. (Cached track information for acceleration).
@ GoingDown
Vehicle is currently going downhill. (Cached track information for acceleration).
void StartSpriteCombine()
Starts a block of sprites, which are "combined" into a single bounding box.
Definition viewport.cpp:765
void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int z, const SpriteBounds &bounds, bool transparent, const SubSprite *sub)
Draw a (transparent) sprite at given coordinates with a given bounding box.
Definition viewport.cpp:664
void EndSpriteCombine()
Terminates a block of sprites started by StartSpriteCombine.
Definition viewport.cpp:775
void DrawGroundSprite(SpriteID image, PaletteID pal, const SubSprite *sub, int extra_offs_x, int extra_offs_y)
Draws a ground sprite for the current tile.
Definition viewport.cpp:579
Functions related to (drawing on) viewports.
static constexpr int BB_Z_SEPARATOR
Separates the bridge/tunnel from the things under/above it.
Functions related to water management.
void CheckForDockingTile(TileIndex t)
Mark the supplied tile as a docking tile if it is suitable for docking.
bool HasTileWaterGround(Tile t)
Checks whether the tile has water at the ground.
Definition water_map.h:353
@ Sea
Sea.
Definition water_map.h:40
bool HasTileWaterClass(Tile t)
Checks whether the tile has an waterclass associated.
Definition water_map.h:103
WaterClass GetWaterClass(Tile t)
Get the water class at a tile.
Definition water_map.h:114
Entry point for OpenTTD to YAPF's cache.
void YapfNotifyTrackLayoutChange(TileIndex tile, Track track)
Use this function to notify YAPF that track layout (or signal configuration) has change.