OpenTTD Source 20260420-master-ga6db99765a
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 TRANSPORT_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 uint8_t ramp_offsets[DIAGDIR_END] = {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
239CommandCost CheckBridgeAvailability(BridgeType bridge_type, uint bridge_len, DoCommandFlags flags)
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 TRANSPORT_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 TRANSPORT_RAIL: base_cost += RailClearCost(GetRailType(tile)); break;
283 /* Aqueducts have their own clear price. */
284 case TRANSPORT_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 == TRANSPORT_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) {
324 case TRANSPORT_ROAD:
325 if (!ValParamRoadType(roadtype)) return CMD_ERROR;
326 break;
327
328 case TRANSPORT_RAIL:
329 if (!ValParamRailType(railtype)) return CMD_ERROR;
330 break;
331
332 case TRANSPORT_WATER:
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 != TRANSPORT_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 != TRANSPORT_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 == TRANSPORT_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) {
399 case TRANSPORT_RAIL:
400 /* Keep the reservation, the path stays valid. */
401 pbs_reservation = HasTunnelBridgeReservation(tile_start);
402 break;
403
404 case TRANSPORT_ROAD:
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 == TRANSPORT_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 == TRANSPORT_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 != TRANSPORT_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 != GM_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 != TRANSPORT_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 == TRANSPORT_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) {
544 case TRANSPORT_RAIL:
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 TRANSPORT_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
577 case TRANSPORT_WATER:
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 == TRANSPORT_RAIL) {
595 Track track = AxisToTrack(direction);
596 AddSideToSignalBuffer(tile_start, INVALID_DIAGDIR, 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) {
607 case TRANSPORT_ROAD:
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 TRANSPORT_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 != TRANSPORT_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) {
650 case TRANSPORT_RAIL:
651 if (!ValParamRailType(railtype)) return CMD_ERROR;
652 break;
653
654 case TRANSPORT_ROAD:
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 != TRANSPORT_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 == INVALID_DIAGDIR) 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)) ? DIAGDIR_SW : DIAGDIR_NE;
691 } else {
692 tunnel_in_way_dir = (TileY(start_tile) < (Map::MaxX() / 2)) ? DIAGDIR_SE : DIAGDIR_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 = std::get<0>(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 TRANSPORT_ROAD: cost.AddCost((tiles + 2) * RoadBuildCost(roadtype) * 2); break;
782 case TRANSPORT_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 == TRANSPORT_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, INVALID_DIAGDIR, 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 == GM_EDITOR) return CommandCost();
818
819 switch (GetTunnelBridgeTransportType(tile)) {
820 case TRANSPORT_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
842 case TRANSPORT_RAIL:
843 return CheckOwnership(GetTileOwner(tile));
844
845 case TRANSPORT_WATER: {
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
862static CommandCost DoClearTunnel(TileIndex tile, DoCommandFlags flags)
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 != GM_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 != GM_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 INVALID_DIAGDIR 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(EXPENSES_CONSTRUCTION, len * base_cost);
933}
934
935
942static CommandCost DoClearBridge(TileIndex tile, DoCommandFlags flags)
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 != GM_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 != GM_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 */
976 bool rail = GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL;
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;
989 } else if (GetTunnelBridgeTransportType(tile) == TRANSPORT_ROAD) {
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 INVALID_DIAGDIR 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(EXPENSES_CONSTRUCTION, len * base_cost);
1025}
1026
1028static CommandCost ClearTile_TunnelBridge(TileIndex tile, DoCommandFlags flags)
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(TO_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 const int bounding_box_size[2] = {16, 2};
1089 static const int back_pillar_offset[2] = { 0, 9};
1090
1091 static const int INF = 1000;
1092 static const SubSprite half_pillar_sub_sprite[2][2] = {
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 */
1148 spr_back = GetCustomRoadSprite(rti, head_tile, RoadSpriteType::CatenaryRear, head ? TCX_NORMAL : TCX_ON_BRIDGE);
1149 spr_front = GetCustomRoadSprite(rti, head_tile, RoadSpriteType::CatenaryFront, head ? TCX_NORMAL : TCX_ON_BRIDGE);
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[4] = { 0 };
1177 bool trans_back[4] = { 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 };
1182 if (head || !IsInvisibilitySet(TO_BRIDGES)) {
1183 /* Road underlay takes precedence over tram */
1184 trans_back[0] = !head && IsTransparencySet(TO_BRIDGES);
1185 if (road_rti != nullptr) {
1186 if (road_rti->UsesOverlay()) {
1187 seq_back[0] = GetCustomRoadSprite(road_rti, head_tile, RoadSpriteType::Bridge, head ? TCX_NORMAL : TCX_ON_BRIDGE) + 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 ? TCX_NORMAL : TCX_ON_BRIDGE) + offset;
1195 } else {
1196 seq_back[0] = SPR_TRAMWAY_BRIDGE + offset;
1197 }
1198 }
1199
1200 /* Draw road overlay */
1201 trans_back[1] = !head && IsTransparencySet(TO_BRIDGES);
1202 if (road_rti != nullptr) {
1203 if (road_rti->UsesOverlay()) {
1204 seq_back[1] = GetCustomRoadSprite(road_rti, head_tile, RoadSpriteType::Overlay, head ? TCX_NORMAL : TCX_ON_BRIDGE);
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(TO_BRIDGES);
1211 if (tram_rti != nullptr) {
1212 if (tram_rti->UsesOverlay()) {
1213 seq_back[2] = GetCustomRoadSprite(tram_rti, head_tile, RoadSpriteType::Overlay, head ? TCX_NORMAL : TCX_ON_BRIDGE);
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 /* Road catenary takes precedence over tram */
1221 trans_back[3] = IsTransparencySet(TO_CATENARY);
1222 trans_front[0] = IsTransparencySet(TO_CATENARY);
1223 if (road_rti != nullptr && HasRoadCatenaryDrawn(road_rt)) {
1224 GetBridgeRoadCatenary(road_rti, head_tile, offset, head, seq_back[3], seq_front[0]);
1225 } else if (tram_rti != nullptr && HasRoadCatenaryDrawn(tram_rt)) {
1226 GetBridgeRoadCatenary(tram_rti, head_tile, offset, head, seq_back[3], seq_front[0]);
1227 }
1228 }
1229
1230 static constexpr SpriteBounds back_bounds[6] = {
1231 {{}, {0, TILE_SIZE, 40}, {}},
1232 {{}, {TILE_SIZE, 0, 40}, {}},
1233 {{}, {TILE_SIZE, 0, 40}, {}},
1234 {{}, {0, TILE_SIZE, 40}, {}},
1235 {{}, {TILE_SIZE, 0, 40}, {}},
1236 {{}, {0, TILE_SIZE, 40}, {}},
1237 };
1238
1239 /* The sprites under the vehicles are drawn as SpriteCombine. StartSpriteCombine() has already been called
1240 * The bounding boxes here are the same as for bridge front/roof */
1241 for (uint i = 0; i < lengthof(seq_back); ++i) {
1242 if (seq_back[i] != 0) {
1243 AddSortableSpriteToDraw(seq_back[i], PAL_NONE, x, y, z, back_bounds[offset], trans_back[i]);
1244 }
1245 }
1246
1247 /* Start a new SpriteCombine for the front part */
1250
1251 static constexpr SpriteBounds front_bounds[6] = {
1252 {{15, 0, 0}, {0, TILE_SIZE, 40}, {-15, 0, 0}},
1253 {{0, 15, 0}, {TILE_SIZE, 0, 40}, {0, -15, 0}},
1254 {{0, 15, 0}, {TILE_SIZE, 0, 40}, {0, -15, 0}},
1255 {{15, 0, 0}, {0, TILE_SIZE, 40}, {-15, 0, 0}},
1256 {{0, 15, 0}, {TILE_SIZE, 0, 40}, {0, -15, 0}},
1257 {{15, 0, 0}, {0, TILE_SIZE, 40}, {-15, 0, 0}},
1258 };
1259
1260 for (uint i = 0; i < lengthof(seq_front); ++i) {
1261 if (seq_front[i] != 0) {
1262 AddSortableSpriteToDraw(seq_front[i], PAL_NONE, x, y, z, front_bounds[offset], trans_front[i]);
1263 }
1264 }
1265}
1266
1282{
1283 TransportType transport_type = GetTunnelBridgeTransportType(ti->tile);
1284 DiagDirection tunnelbridge_direction = GetTunnelBridgeDirection(ti->tile);
1285
1286 if (IsTunnel(ti->tile)) {
1287 /* Front view of tunnel bounding boxes:
1288 *
1289 * 122223 <- BB_Z_SEPARATOR
1290 * 1 3
1291 * 1 3 1,3 = empty helper BB
1292 * 1 3 2 = SpriteCombine of tunnel-roof and catenary (tram & elrail)
1293 *
1294 */
1295
1296 /* Tunnel sprites are positioned at 15,15, but the bounding box covers most of the tile. */
1297 static constexpr SpriteBounds roof_bounds[DIAGDIR_END] = {
1298 {{0, 1, BB_Z_SEPARATOR}, {TILE_SIZE, TILE_SIZE - 1, 1}, {TILE_SIZE - 1, TILE_SIZE - 2, -BB_Z_SEPARATOR}}, // NE
1299 {{1, 0, BB_Z_SEPARATOR}, {TILE_SIZE - 1, TILE_SIZE, 1}, {TILE_SIZE - 2, TILE_SIZE - 1, -BB_Z_SEPARATOR}}, // SE
1300 {{0, 1, BB_Z_SEPARATOR}, {TILE_SIZE, TILE_SIZE - 1, 1}, {TILE_SIZE - 1, TILE_SIZE - 2, -BB_Z_SEPARATOR}}, // SW
1301 {{1, 0, BB_Z_SEPARATOR}, {TILE_SIZE - 1, TILE_SIZE, 1}, {TILE_SIZE - 2, TILE_SIZE - 1, -BB_Z_SEPARATOR}}, // NW
1302 };
1303
1304 /* Catenary sprites are positioned at 0,0, with the same bounding box as above. */
1305 static constexpr SpriteBounds catenary_bounds[DIAGDIR_END] = {
1306 {{0, 1, BB_Z_SEPARATOR}, {TILE_SIZE, TILE_SIZE - 1, 1}, {0, -1, -BB_Z_SEPARATOR}}, // NE
1307 {{1, 0, BB_Z_SEPARATOR}, {TILE_SIZE - 1, TILE_SIZE, 1}, {-1, 0, -BB_Z_SEPARATOR}}, // SE
1308 {{0, 1, BB_Z_SEPARATOR}, {TILE_SIZE, TILE_SIZE - 1, 1}, {0, -1, -BB_Z_SEPARATOR}}, // SW
1309 {{1, 0, BB_Z_SEPARATOR}, {TILE_SIZE - 1, TILE_SIZE, 1}, {-1, 0, -BB_Z_SEPARATOR}}, // NW
1310 };
1311
1312 static constexpr SpriteBounds rear_sep[DIAGDIR_END] = {
1313 {{}, {TILE_SIZE, 1, TILE_HEIGHT}, {}}, // NE
1314 {{}, {1, TILE_SIZE, TILE_HEIGHT}, {}}, // SE
1315 {{}, {TILE_SIZE, 1, TILE_HEIGHT}, {}}, // SW
1316 {{}, {1, TILE_SIZE, TILE_HEIGHT}, {}}, // NW
1317 };
1318
1319 static constexpr SpriteBounds front_sep[DIAGDIR_END] = {
1320 {{0, TILE_SIZE - 1, 0}, {TILE_SIZE, 1, TILE_HEIGHT}, {}}, // NE
1321 {{TILE_SIZE - 1, 0, 0}, {1, TILE_SIZE, TILE_HEIGHT}, {}}, // SE
1322 {{0, TILE_SIZE - 1, 0}, {TILE_SIZE, 1, TILE_HEIGHT}, {}}, // SW
1323 {{TILE_SIZE - 1, 0, 0}, {1, TILE_SIZE, TILE_HEIGHT}, {}}, // NW
1324 };
1325
1326 bool catenary = false;
1327
1328 SpriteID image;
1329 SpriteID railtype_overlay = 0;
1330 if (transport_type == TRANSPORT_RAIL) {
1331 const RailTypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
1332 image = rti->base_sprites.tunnel;
1333 if (rti->UsesOverlay()) {
1334 /* Check if the railtype has custom tunnel portals. */
1335 railtype_overlay = GetCustomRailSprite(rti, ti->tile, RailSpriteType::TunnelPortal);
1336 if (railtype_overlay != 0) image = SPR_RAILTYPE_TUNNEL_BASE; // Draw blank grass tunnel base.
1337 }
1338 } else {
1339 image = SPR_TUNNEL_ENTRY_REAR_ROAD;
1340 }
1341
1342 if (HasTunnelBridgeSnowOrDesert(ti->tile)) image += railtype_overlay != 0 ? 8 : 32;
1343
1344 image += tunnelbridge_direction * 2;
1345 DrawGroundSprite(image, PAL_NONE);
1346
1347 if (transport_type == TRANSPORT_ROAD) {
1348 RoadType road_rt = GetRoadTypeRoad(ti->tile);
1349 RoadType tram_rt = GetRoadTypeTram(ti->tile);
1350 const RoadTypeInfo *road_rti = road_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(road_rt);
1351 const RoadTypeInfo *tram_rti = tram_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(tram_rt);
1352 uint sprite_offset = DiagDirToAxis(tunnelbridge_direction) == AXIS_X ? 1 : 0;
1353 bool draw_underlay = true;
1354
1355 /* Road underlay takes precedence over tram */
1356 if (road_rti != nullptr) {
1357 if (road_rti->UsesOverlay()) {
1359 if (ground != 0) {
1360 DrawGroundSprite(ground + tunnelbridge_direction, PAL_NONE);
1361 draw_underlay = false;
1362 }
1363 }
1364 } else {
1365 if (tram_rti->UsesOverlay()) {
1367 if (ground != 0) {
1368 DrawGroundSprite(ground + tunnelbridge_direction, PAL_NONE);
1369 draw_underlay = false;
1370 }
1371 }
1372 }
1373
1374 DrawRoadOverlays(ti, PAL_NONE, road_rti, tram_rti, sprite_offset, sprite_offset, draw_underlay);
1375
1376 /* Road catenary takes precedence over tram */
1377 SpriteID catenary_sprite_base = 0;
1378 if (road_rti != nullptr && HasRoadCatenaryDrawn(road_rt)) {
1379 catenary_sprite_base = GetCustomRoadSprite(road_rti, ti->tile, RoadSpriteType::CatenaryFront);
1380 if (catenary_sprite_base == 0) {
1381 catenary_sprite_base = SPR_TRAMWAY_TUNNEL_WIRES;
1382 } else {
1383 catenary_sprite_base += 19;
1384 }
1385 } else if (tram_rti != nullptr && HasRoadCatenaryDrawn(tram_rt)) {
1386 catenary_sprite_base = GetCustomRoadSprite(tram_rti, ti->tile, RoadSpriteType::CatenaryFront);
1387 if (catenary_sprite_base == 0) {
1388 catenary_sprite_base = SPR_TRAMWAY_TUNNEL_WIRES;
1389 } else {
1390 catenary_sprite_base += 19;
1391 }
1392 }
1393
1394 if (catenary_sprite_base != 0) {
1395 catenary = true;
1397 AddSortableSpriteToDraw(catenary_sprite_base + tunnelbridge_direction, PAL_NONE, *ti, catenary_bounds[tunnelbridge_direction], IsTransparencySet(TO_CATENARY));
1398 }
1399 } else {
1400 const RailTypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
1401 if (rti->UsesOverlay()) {
1403 if (surface != 0) DrawGroundSprite(surface + tunnelbridge_direction, PAL_NONE);
1404 }
1405
1406 /* PBS debugging, draw reserved tracks darker */
1407 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasTunnelBridgeReservation(ti->tile)) {
1408 if (rti->UsesOverlay()) {
1410 DrawGroundSprite(overlay + RTO_X + DiagDirToAxis(tunnelbridge_direction), PALETTE_CRASH);
1411 } else {
1413 }
1414 }
1415
1417 /* Maybe draw pylons on the entry side */
1418 DrawRailCatenary(ti);
1419
1420 catenary = true;
1422 /* Draw wire above the ramp */
1424 }
1425 }
1426
1427 if (railtype_overlay != 0 && !catenary) StartSpriteCombine();
1428
1429 AddSortableSpriteToDraw(image + 1, PAL_NONE, *ti, roof_bounds[tunnelbridge_direction], false);
1430 /* Draw railtype tunnel portal overlay if defined. */
1431 if (railtype_overlay != 0) AddSortableSpriteToDraw(railtype_overlay + tunnelbridge_direction, PAL_NONE, *ti, roof_bounds[tunnelbridge_direction], false);
1432
1433 if (catenary || railtype_overlay != 0) EndSpriteCombine();
1434
1435 /* Add helper BB for sprite sorting that separates the tunnel from things beside of it. */
1436 AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, *ti, rear_sep[tunnelbridge_direction]);
1437 AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, *ti, front_sep[tunnelbridge_direction]);
1438
1439 DrawBridgeMiddle(ti, BridgePillarFlag::EdgeNE + tunnelbridge_direction);
1440 } else { // IsBridge(ti->tile)
1441 DrawFoundation(ti, GetBridgeFoundation(ti->tileh, DiagDirToAxis(tunnelbridge_direction)));
1442 bool is_custom_layout = false; // Set if rail/road bridge uses a custom layout.
1443
1444 uint base_offset = GetBridgeRampDirectionBaseOffset(tunnelbridge_direction);
1445 std::span<const PalSpriteID> psid;
1446 if (transport_type != TRANSPORT_WATER) {
1447 BridgeType bridge_type = GetBridgeType(ti->tile);
1448 if (ti->tileh == SLOPE_FLAT) base_offset += 4; // sloped bridge head
1449 base_offset += GetBridgeSpriteTableBaseOffset(transport_type, ti->tile);
1450 psid = GetBridgeSpriteTable(bridge_type, BRIDGE_PIECE_HEAD);
1451 is_custom_layout = BridgeHasCustomSpriteTable(bridge_type, BRIDGE_PIECE_HEAD);
1452 } else {
1454 }
1455 psid = psid.subspan(base_offset, 1);
1456
1458 TileIndex next = ti->tile + TileOffsByDiagDir(tunnelbridge_direction);
1459 if (ti->tileh != SLOPE_FLAT && ti->z == 0 && HasTileWaterClass(next) && GetWaterClass(next) == WaterClass::Sea) {
1460 DrawShoreTile(ti->tileh);
1461 } else {
1462 DrawClearLandTile(ti, 3);
1463 }
1464 } else {
1465 DrawGroundSprite(SPR_FLAT_SNOW_DESERT_TILE + SlopeToSpriteOffset(ti->tileh), PAL_NONE);
1466 }
1467
1468 /* draw ramp */
1469
1470 /* Draw Trambits and PBS Reservation as SpriteCombine */
1471 if (transport_type == TRANSPORT_ROAD || transport_type == TRANSPORT_RAIL) StartSpriteCombine();
1472
1473 /* HACK set the height of the BB of a sloped ramp to 1 so a vehicle on
1474 * it doesn't disappear behind it
1475 */
1476 /* Bridge heads are drawn solid no matter how invisibility/transparency is set */
1477 AddSortableSpriteToDraw(psid[0].sprite, psid[0].pal, *ti, {{}, {TILE_SIZE, TILE_SIZE, static_cast<uint8_t>(ti->tileh == SLOPE_FLAT ? 0 : TILE_HEIGHT)}, {}});
1478
1479 if (transport_type == TRANSPORT_ROAD) {
1480 uint offset = tunnelbridge_direction;
1481 int z = ti->z;
1482 if (ti->tileh != SLOPE_FLAT) {
1483 offset = (offset + 1) & 1;
1484 z += TILE_HEIGHT;
1485 } else {
1486 offset += 2;
1487 }
1488
1489 /* DrawBridgeRoadBits() calls EndSpriteCombine() and StartSpriteCombine() */
1490 DrawBridgeRoadBits(ti->tile, ti->x, ti->y, z, offset, true, is_custom_layout);
1491
1493 } else if (transport_type == TRANSPORT_RAIL) {
1494 const RailTypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
1495 if (is_custom_layout || rti->UsesOverlay()) {
1496 SpriteID surface = rti->UsesOverlay() ? GetCustomRailSprite(rti, ti->tile, RailSpriteType::Bridge) : rti->base_sprites.bridge_deck;
1497 if (surface != 0) {
1498 if (HasBridgeFlatRamp(ti->tileh, DiagDirToAxis(tunnelbridge_direction))) {
1499 AddSortableSpriteToDraw(surface + ((DiagDirToAxis(tunnelbridge_direction) == AXIS_X) ? RTBO_X : RTBO_Y), PAL_NONE, *ti, {{0, 0, TILE_HEIGHT}, {TILE_SIZE, TILE_SIZE, 0}, {}});
1500 } else {
1501 AddSortableSpriteToDraw(surface + RTBO_SLOPE + tunnelbridge_direction, PAL_NONE, *ti, {{}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT}, {}});
1502 }
1503 }
1504 }
1505
1506 /* PBS debugging, draw reserved tracks darker */
1507 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasTunnelBridgeReservation(ti->tile)) {
1508 if (rti->UsesOverlay()) {
1510 if (HasBridgeFlatRamp(ti->tileh, DiagDirToAxis(tunnelbridge_direction))) {
1511 AddSortableSpriteToDraw(overlay + RTO_X + DiagDirToAxis(tunnelbridge_direction), PALETTE_CRASH, *ti, {{0, 0, TILE_HEIGHT}, {TILE_SIZE, TILE_SIZE, 0}, {}});
1512 } else {
1513 AddSortableSpriteToDraw(overlay + RTO_SLOPE_NE + tunnelbridge_direction, PALETTE_CRASH, *ti, {{}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT}, {}});
1514 }
1515 } else {
1516 if (HasBridgeFlatRamp(ti->tileh, DiagDirToAxis(tunnelbridge_direction))) {
1517 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}, {}});
1518 } else {
1519 AddSortableSpriteToDraw(rti->base_sprites.single_sloped + tunnelbridge_direction, PALETTE_CRASH, *ti, {{}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT}, {}});
1520 }
1521 }
1522 }
1523
1526 DrawRailCatenary(ti);
1527 }
1528 }
1529
1530 BridgePillarFlags blocked_pillars;
1531 if (DiagDirToAxis(tunnelbridge_direction) == AXIS_X) {
1533 } else {
1535 }
1536 DrawBridgeMiddle(ti, blocked_pillars);
1537 }
1538}
1539
1540
1559static BridgePieces CalcBridgePiece(uint north, uint south)
1560{
1561 if (north == 1) {
1562 return BRIDGE_PIECE_NORTH;
1563 } else if (south == 1) {
1564 return BRIDGE_PIECE_SOUTH;
1565 } else if (north < south) {
1566 return north & 1 ? BRIDGE_PIECE_INNER_SOUTH : BRIDGE_PIECE_INNER_NORTH;
1567 } else if (north > south) {
1568 return south & 1 ? BRIDGE_PIECE_INNER_NORTH : BRIDGE_PIECE_INNER_SOUTH;
1569 } else {
1570 return north & 1 ? BRIDGE_PIECE_MIDDLE_EVEN : BRIDGE_PIECE_MIDDLE_ODD;
1571 }
1572}
1573
1583static BridgePillarFlags GetBridgeTilePillarFlags(TileIndex tile, TileIndex rampnorth, TileIndex rampsouth, BridgeType type, TransportType transport_type)
1584{
1585 if (transport_type == TRANSPORT_WATER) return BRIDGEPILLARFLAGS_ALL_CORNERS;
1586
1587 const BridgeSpec *spec = GetBridgeSpec(type);
1589 BridgePieces piece = CalcBridgePiece(GetTunnelBridgeLength(tile, rampnorth) + 1, GetTunnelBridgeLength(tile, rampsouth) + 1);
1590 Axis axis = TileX(rampnorth) == TileX(rampsouth) ? AXIS_Y : AXIS_X;
1591
1592 return spec->pillar_flags[piece][axis == AXIS_Y ? 1 : 0];
1593 }
1594
1595 return BRIDGEPILLARFLAGS_ALL_CORNERS;
1596}
1597
1603void DrawBridgeMiddle(const TileInfo *ti, BridgePillarFlags blocked_pillars)
1604{
1605 /* Sectional view of bridge bounding boxes:
1606 *
1607 * 1 2 1,2 = SpriteCombine of Bridge front/(back&floor) and RoadCatenary
1608 * 1 2 3 = empty helper BB
1609 * 1 7 2 4,5 = pillars under higher bridges
1610 * 1 6 88888 6 2 6 = elrail-pylons
1611 * 1 6 88888 6 2 7 = elrail-wire
1612 * 1 6 88888 6 2 <- TILE_HEIGHT 8 = rail-vehicle on bridge
1613 * 3333333333333 <- BB_Z_SEPARATOR
1614 * <- unused
1615 * 4 5 <- BB_HEIGHT_UNDER_BRIDGE
1616 * 4 5
1617 * 4 5
1618 *
1619 */
1620
1621 if (!IsBridgeAbove(ti->tile)) return;
1622
1623 TileIndex rampnorth = GetNorthernBridgeEnd(ti->tile);
1624 TileIndex rampsouth = GetSouthernBridgeEnd(ti->tile);
1625 TransportType transport_type = GetTunnelBridgeTransportType(rampsouth);
1626 Axis axis = GetBridgeAxis(ti->tile);
1627 BridgePillarFlags pillars;
1628 bool is_custom_layout; // Set if rail/road bridge uses a custom layout.
1629
1630 uint base_offset = GetBridgeMiddleAxisBaseOffset(axis);
1631 std::span<const PalSpriteID> psid;
1632 bool drawfarpillar;
1633 if (transport_type != TRANSPORT_WATER) {
1634 BridgeType bridge_type = GetBridgeType(rampsouth);
1635 BridgePieces bridge_piece = CalcBridgePiece(GetTunnelBridgeLength(ti->tile, rampnorth) + 1, GetTunnelBridgeLength(ti->tile, rampsouth) + 1);
1636 drawfarpillar = !HasBit(GetBridgeSpec(bridge_type)->flags, 0);
1637 base_offset += GetBridgeSpriteTableBaseOffset(transport_type, rampsouth);
1638 psid = GetBridgeSpriteTable(bridge_type, bridge_piece);
1639 pillars = GetBridgeTilePillarFlags(ti->tile, rampnorth, rampsouth, bridge_type, transport_type);
1640 is_custom_layout = BridgeHasCustomSpriteTable(bridge_type, bridge_piece);
1641 } else {
1642 drawfarpillar = true;
1644 pillars = BRIDGEPILLARFLAGS_ALL_CORNERS;
1645 }
1646 psid = psid.subspan(base_offset, 3);
1647
1648 int x = ti->x;
1649 int y = ti->y;
1650 uint bridge_z = GetBridgePixelHeight(rampsouth);
1651 int z = bridge_z - BRIDGE_Z_START;
1652
1653 /* Add a bounding box that separates the bridge from things below it. */
1654 AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, x, y, bridge_z - TILE_HEIGHT + BB_Z_SEPARATOR, {{}, {TILE_SIZE, TILE_SIZE, 1}, {}});
1655
1656 /* Draw Trambits as SpriteCombine */
1657 if (transport_type == TRANSPORT_ROAD || transport_type == TRANSPORT_RAIL) StartSpriteCombine();
1658
1659 /* Draw floor and far part of bridge*/
1661 if (axis == AXIS_X) {
1662 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(TO_BRIDGES));
1663 } else {
1664 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(TO_BRIDGES));
1665 }
1666 }
1667
1668 if (transport_type == TRANSPORT_ROAD) {
1669 /* DrawBridgeRoadBits() calls EndSpriteCombine() and StartSpriteCombine() */
1670 DrawBridgeRoadBits(rampsouth, x, y, bridge_z, axis ^ 1, false, is_custom_layout);
1671 } else if (transport_type == TRANSPORT_RAIL) {
1672 const RailTypeInfo *rti = GetRailTypeInfo(GetRailType(rampsouth));
1673 if ((is_custom_layout || rti->UsesOverlay()) && !IsInvisibilitySet(TO_BRIDGES)) {
1674 SpriteID surface = rti->UsesOverlay() ? GetCustomRailSprite(rti, rampsouth, RailSpriteType::Bridge, TCX_ON_BRIDGE) : rti->base_sprites.bridge_deck;
1675 if (surface != 0) {
1676 AddSortableSpriteToDraw(surface + axis, PAL_NONE, x, y, bridge_z, {{}, {TILE_SIZE, TILE_SIZE, 0}, {}}, IsTransparencySet(TO_BRIDGES));
1677 }
1678 }
1679
1680 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && !IsInvisibilitySet(TO_BRIDGES) && HasTunnelBridgeReservation(rampnorth)) {
1681 if (rti->UsesOverlay()) {
1683 AddSortableSpriteToDraw(overlay + RTO_X + axis, PALETTE_CRASH, ti->x, ti->y, bridge_z, {{}, {TILE_SIZE, TILE_SIZE, 0}, {}}, IsTransparencySet(TO_BRIDGES));
1684 } else {
1685 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(TO_BRIDGES));
1686 }
1687 }
1688
1690
1691 if (HasRailCatenaryDrawn(GetRailType(rampsouth))) {
1693 }
1694 }
1695
1696 /* draw roof, the component of the bridge which is logically between the vehicle and the camera */
1698 if (axis == AXIS_X) {
1699 y += 12;
1700 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(TO_BRIDGES));
1701 } else {
1702 x += 12;
1703 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(TO_BRIDGES));
1704 }
1705 }
1706
1707 /* Draw TramFront as SpriteCombine */
1708 if (transport_type == TRANSPORT_ROAD) EndSpriteCombine();
1709
1710 /* Do not draw anything more if bridges are invisible */
1711 if (IsInvisibilitySet(TO_BRIDGES)) return;
1712
1713 if (blocked_pillars.Any(pillars)) return;
1714 DrawBridgePillars(psid[2], ti, axis, drawfarpillar, x, y, z);
1715}
1716
1717
1719static int GetSlopePixelZ_TunnelBridge(TileIndex tile, uint x, uint y, bool ground_vehicle)
1720{
1721 auto [tileh, z] = GetTilePixelSlope(tile);
1722
1723 x &= 0xF;
1724 y &= 0xF;
1725
1726 if (IsTunnel(tile)) {
1727 /* In the tunnel entrance? */
1728 if (ground_vehicle) return z;
1729 } else { // IsBridge(tile)
1732
1733 /* On the bridge ramp? */
1734 if (ground_vehicle) {
1735 if (tileh != SLOPE_FLAT) return z + TILE_HEIGHT;
1736
1737 switch (dir) {
1738 default: NOT_REACHED();
1739 case DIAGDIR_NE: tileh = SLOPE_NE; break;
1740 case DIAGDIR_SE: tileh = SLOPE_SE; break;
1741 case DIAGDIR_SW: tileh = SLOPE_SW; break;
1742 case DIAGDIR_NW: tileh = SLOPE_NW; break;
1743 }
1744 }
1745 }
1746
1747 return z + GetPartialPixelZ(x, y, tileh);
1748}
1749
1755
1758{
1760
1761 if (IsTunnel(tile)) {
1762 td.str = (tt == TRANSPORT_RAIL) ? STR_LAI_TUNNEL_DESCRIPTION_RAILROAD : STR_LAI_TUNNEL_DESCRIPTION_ROAD;
1763 } else { // IsBridge(tile)
1764 td.str = (tt == TRANSPORT_WATER) ? STR_LAI_BRIDGE_DESCRIPTION_AQUEDUCT : GetBridgeSpec(GetBridgeType(tile))->transport_name[tt];
1765 }
1766 td.owner[0] = GetTileOwner(tile);
1767
1768 Owner road_owner = INVALID_OWNER;
1769 Owner tram_owner = INVALID_OWNER;
1770 RoadType road_rt = (tt == TRANSPORT_ROAD) ? GetRoadTypeRoad(tile) : INVALID_ROADTYPE;
1771 RoadType tram_rt = (tt == TRANSPORT_ROAD) ? GetRoadTypeTram(tile) : INVALID_ROADTYPE;
1772 if (road_rt != INVALID_ROADTYPE) {
1773 const RoadTypeInfo *rti = GetRoadTypeInfo(road_rt);
1774 td.roadtype = rti->strings.name;
1775 td.road_speed = rti->max_speed / 2;
1776 road_owner = GetRoadOwner(tile, RoadTramType::Road);
1777 }
1778 if (tram_rt != INVALID_ROADTYPE) {
1779 const RoadTypeInfo *rti = GetRoadTypeInfo(tram_rt);
1780 td.tramtype = rti->strings.name;
1781 td.tram_speed = rti->max_speed / 2;
1782 tram_owner = GetRoadOwner(tile, RoadTramType::Tram);
1783 }
1784
1785 /* Is there a mix of owners? */
1786 if ((tram_owner != INVALID_OWNER && tram_owner != td.owner[0]) ||
1787 (road_owner != INVALID_OWNER && road_owner != td.owner[0])) {
1788 uint i = 1;
1789 if (road_owner != INVALID_OWNER) {
1790 td.owner_type[i] = STR_LAND_AREA_INFORMATION_ROAD_OWNER;
1791 td.owner[i] = road_owner;
1792 i++;
1793 }
1794 if (tram_owner != INVALID_OWNER) {
1795 td.owner_type[i] = STR_LAND_AREA_INFORMATION_TRAM_OWNER;
1796 td.owner[i] = tram_owner;
1797 }
1798 }
1799
1800 if (tt == TRANSPORT_RAIL) {
1801 const RailTypeInfo *rti = GetRailTypeInfo(GetRailType(tile));
1802 td.rail_speed = rti->max_speed;
1803 td.railtype = rti->strings.name;
1804
1805 if (!IsTunnel(tile)) {
1806 uint16_t spd = GetBridgeSpec(GetBridgeType(tile))->speed;
1807 /* rail speed special-cases 0 as unlimited, hides display of limit etc. */
1808 if (spd == UINT16_MAX) spd = 0;
1809 if (td.rail_speed == 0 || spd < td.rail_speed) {
1810 td.rail_speed = spd;
1811 }
1812 }
1813 } else if (tt == TRANSPORT_ROAD && !IsTunnel(tile)) {
1814 uint16_t spd = GetBridgeSpec(GetBridgeType(tile))->speed;
1815 /* road speed special-cases 0 as unlimited, hides display of limit etc. */
1816 if (spd == UINT16_MAX) spd = 0;
1817 if (road_rt != INVALID_ROADTYPE && (td.road_speed == 0 || spd < td.road_speed)) td.road_speed = spd;
1818 if (tram_rt != INVALID_ROADTYPE && (td.tram_speed == 0 || spd < td.tram_speed)) td.tram_speed = spd;
1819 }
1820}
1821
1822
1825{
1826 bool snow_or_desert = HasTunnelBridgeSnowOrDesert(tile);
1827 switch (_settings_game.game_creation.landscape) {
1828 case LandscapeType::Arctic: {
1829 /* As long as we do not have a snow density, we want to use the density
1830 * from the entry edge. For tunnels this is the lowest point for bridges the highest point.
1831 * (Independent of foundations) */
1832 int z = IsBridge(tile) ? GetTileMaxZ(tile) : GetTileZ(tile);
1833 if (snow_or_desert != (z > GetSnowLine())) {
1834 SetTunnelBridgeSnowOrDesert(tile, !snow_or_desert);
1835 MarkTileDirtyByTile(tile);
1836 }
1837 break;
1838 }
1839
1841 if (GetTropicZone(tile) == TropicZone::Desert && !snow_or_desert) {
1842 SetTunnelBridgeSnowOrDesert(tile, true);
1843 MarkTileDirtyByTile(tile);
1844 }
1845 break;
1846
1847 default:
1848 break;
1849 }
1850}
1851
1854{
1855 TransportType transport_type = GetTunnelBridgeTransportType(tile);
1856 if (transport_type != mode || (transport_type == TRANSPORT_ROAD && !HasTileRoadType(tile, (RoadTramType)sub_mode))) return 0;
1857
1859 if (side != INVALID_DIAGDIR && side != ReverseDiagDir(dir)) return 0;
1861}
1862
1864static void ChangeTileOwner_TunnelBridge(TileIndex tile, Owner old_owner, Owner new_owner)
1865{
1866 TileIndex other_end = GetOtherTunnelBridgeEnd(tile);
1867 /* Set number of pieces to zero if it's the southern tile as we
1868 * don't want to update the infrastructure counts twice. */
1869 uint num_pieces = tile < other_end ? (GetTunnelBridgeLength(tile, other_end) + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR : 0;
1870
1872
1873 if (tt == TRANSPORT_ROAD) {
1874 for (RoadTramType rtt : ROADTRAMTYPES_ALL) {
1875 /* Update all roadtypes, no matter if they are present */
1876 if (GetRoadOwner(tile, rtt) == old_owner) {
1877 RoadType rt = GetRoadType(tile, rtt);
1878 if (rt != INVALID_ROADTYPE) {
1879 /* Update company infrastructure counts. A full diagonal road tile has two road bits.
1880 * No need to dirty windows here, we'll redraw the whole screen anyway. */
1881 Company::Get(old_owner)->infrastructure.road[rt] -= num_pieces * 2;
1882 if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.road[rt] += num_pieces * 2;
1883 }
1884
1885 SetRoadOwner(tile, rtt, new_owner == INVALID_OWNER ? OWNER_NONE : new_owner);
1886 }
1887 }
1888 }
1889
1890 if (!IsTileOwner(tile, old_owner)) return;
1891
1892 /* Update company infrastructure counts for rail and water as well.
1893 * No need to dirty windows here, we'll redraw the whole screen anyway. */
1894 Company *old = Company::Get(old_owner);
1895 if (tt == TRANSPORT_RAIL) {
1896 old->infrastructure.rail[GetRailType(tile)] -= num_pieces;
1897 if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.rail[GetRailType(tile)] += num_pieces;
1898 } else if (tt == TRANSPORT_WATER) {
1899 old->infrastructure.water -= num_pieces;
1900 if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.water += num_pieces;
1901 }
1902
1903 if (new_owner != INVALID_OWNER) {
1904 SetTileOwner(tile, new_owner);
1905 } else {
1906 if (tt == TRANSPORT_RAIL) {
1907 /* Since all of our vehicles have been removed, it is safe to remove the rail
1908 * bridge / tunnel. */
1909 [[maybe_unused]] CommandCost ret = Command<Commands::LandscapeClear>::Do({DoCommandFlag::Execute, DoCommandFlag::Bankrupt}, tile);
1910 assert(ret.Succeeded());
1911 } else {
1912 /* In any other case, we can safely reassign the ownership to OWNER_NONE. */
1913 SetTileOwner(tile, OWNER_NONE);
1914 }
1915 }
1916}
1917
1930template <typename T>
1931static void PrepareToEnterBridge(T *gv)
1932{
1933 if (HasBit(gv->gv_flags, GVF_GOINGUP_BIT)) {
1934 gv->z_pos++;
1935 ClrBit(gv->gv_flags, GVF_GOINGUP_BIT);
1936 } else {
1937 ClrBit(gv->gv_flags, GVF_GOINGDOWN_BIT);
1938 }
1939}
1940
1946static const uint8_t TUNNEL_SOUND_FRAME = 1;
1947
1956extern const uint8_t _tunnel_visibility_frame[DIAGDIR_END] = {12, 8, 8, 12};
1957
1959static VehicleEnterTileStates VehicleEnterTile_TunnelBridge(Vehicle *v, TileIndex tile, int x, int y)
1960{
1961 int z = GetSlopePixelZ(x, y, true) - v->z_pos;
1962
1963 if (abs(z) > 2) return VehicleEnterTileState::CannotEnter;
1964 /* Direction into the wormhole */
1965 const DiagDirection dir = GetTunnelBridgeDirection(tile);
1966 /* Direction of the vehicle */
1968 /* New position of the vehicle on the tile */
1969 uint8_t pos = (DiagDirToAxis(vdir) == AXIS_X ? x : y) & TILE_UNIT_MASK;
1970 /* Number of units moved by the vehicle since entering the tile */
1971 uint8_t frame = (vdir == DIAGDIR_NE || vdir == DIAGDIR_NW) ? TILE_SIZE - 1 - pos : pos;
1972
1973 if (IsTunnel(tile)) {
1974 if (v->type == VEH_TRAIN) {
1975 Train *t = Train::From(v);
1976
1977 if (t->track != TRACK_BIT_WORMHOLE && dir == vdir) {
1978 if (t->IsMovingFront() && frame == TUNNEL_SOUND_FRAME) {
1979 if (!PlayVehicleSound(t, VSE_TUNNEL) && RailVehInfo(t->engine_type)->engclass == 0) {
1980 SndPlayVehicleFx(SND_05_TRAIN_THROUGH_TUNNEL, v);
1981 }
1982 return {};
1983 }
1984 if (frame == _tunnel_visibility_frame[dir]) {
1985 t->tile = tile;
1989 }
1990 }
1991
1992 if (dir == ReverseDiagDir(vdir) && frame == TILE_SIZE - _tunnel_visibility_frame[dir] && z == 0) {
1993 /* We're at the tunnel exit ?? */
1994 t->tile = tile;
1995 t->track = DiagDirToDiagTrackBits(vdir);
1996 assert(t->track);
1999 }
2000 } else if (v->type == VEH_ROAD) {
2002
2003 /* Enter tunnel? */
2004 if (rv->state != RVSB_WORMHOLE && dir == vdir) {
2005 if (frame == _tunnel_visibility_frame[dir]) {
2006 /* Frame should be equal to the next frame number in the RV's movement */
2007 assert(frame == rv->frame + 1);
2008 rv->tile = tile;
2009 rv->state = RVSB_WORMHOLE;
2012 } else {
2013 return {};
2014 }
2015 }
2016
2017 /* We're at the tunnel exit ?? */
2018 if (dir == ReverseDiagDir(vdir) && frame == TILE_SIZE - _tunnel_visibility_frame[dir] && z == 0) {
2019 rv->tile = tile;
2020 rv->state = DiagDirToDiagTrackdir(vdir);
2021 rv->frame = frame;
2024 }
2025 }
2026 } else { // IsBridge(tile)
2027 if (v->type != VEH_SHIP) {
2028 /* modify speed of vehicle */
2029 uint16_t spd = GetBridgeSpec(GetBridgeType(tile))->speed;
2030
2031 if (v->type == VEH_ROAD) spd *= 2;
2032 Vehicle *first = v->First();
2033 first->cur_speed = std::min(first->cur_speed, spd);
2034 }
2035
2036 if (vdir == dir) {
2037 /* Vehicle enters bridge at the last frame inside this tile. */
2038 if (frame != TILE_SIZE - 1) return {};
2039 switch (v->type) {
2040 case VEH_TRAIN: {
2041 Train *t = Train::From(v);
2044 break;
2045 }
2046
2047 case VEH_ROAD: {
2049 rv->state = RVSB_WORMHOLE;
2051 break;
2052 }
2053
2054 case VEH_SHIP:
2056 break;
2057
2058 default: NOT_REACHED();
2059 }
2061 } else if (vdir == ReverseDiagDir(dir)) {
2062 v->tile = tile;
2063 switch (v->type) {
2064 case VEH_TRAIN: {
2065 Train *t = Train::From(v);
2066 if (t->track == TRACK_BIT_WORMHOLE) {
2067 t->track = DiagDirToDiagTrackBits(vdir);
2069 }
2070 break;
2071 }
2072
2073 case VEH_ROAD: {
2075 if (rv->state == RVSB_WORMHOLE) {
2076 rv->state = DiagDirToDiagTrackdir(vdir);
2077 rv->frame = 0;
2079 }
2080 break;
2081 }
2082
2083 case VEH_SHIP: {
2084 Ship *ship = Ship::From(v);
2085 if (ship->state == TRACK_BIT_WORMHOLE) {
2086 ship->state = DiagDirToDiagTrackBits(vdir);
2088 }
2089 break;
2090 }
2091
2092 default: NOT_REACHED();
2093 }
2094 }
2095 }
2096 return {};
2097}
2098
2100static CommandCost TerraformTile_TunnelBridge(TileIndex tile, DoCommandFlags flags, int z_new, Slope tileh_new)
2101{
2102 if (_settings_game.construction.build_on_slopes && AutoslopeEnabled() && IsBridge(tile) && GetTunnelBridgeTransportType(tile) != TRANSPORT_WATER) {
2103 DiagDirection direction = GetTunnelBridgeDirection(tile);
2104 Axis axis = DiagDirToAxis(direction);
2105 CommandCost res;
2106 auto [tileh_old, z_old] = GetTileSlopeZ(tile);
2107
2108 /* Check if new slope is valid for bridges in general (so we can safely call GetBridgeFoundation()) */
2109 if ((direction == DIAGDIR_NW) || (direction == DIAGDIR_NE)) {
2110 CheckBridgeSlope(BRIDGE_PIECE_SOUTH, axis, tileh_old, z_old);
2111 res = CheckBridgeSlope(BRIDGE_PIECE_SOUTH, axis, tileh_new, z_new);
2112 } else {
2113 CheckBridgeSlope(BRIDGE_PIECE_NORTH, axis, tileh_old, z_old);
2114 res = CheckBridgeSlope(BRIDGE_PIECE_NORTH, axis, tileh_new, z_new);
2115 }
2116
2117 /* Surface slope is valid and remains unchanged? */
2118 if (res.Succeeded() && (z_old == z_new) && (tileh_old == tileh_new)) return CommandCost(EXPENSES_CONSTRUCTION, _price[Price::BuildFoundation]);
2119 }
2120
2121 return Command<Commands::LandscapeClear>::Do(flags, tile);
2122}
2123
2125static CommandCost CheckBuildAbove_TunnelBridge(TileIndex tile, DoCommandFlags flags, Axis axis, int height)
2126{
2127 if (IsTunnel(tile)) return CommandCost();
2128
2129 if (axis != DiagDirToAxis(GetTunnelBridgeDirection(tile)) && height > GetBridgeHeight(tile)) {
2130 return CommandCost();
2131 }
2132
2133 return Command<Commands::LandscapeClear>::Do(flags, tile);
2134}
2135
2138 .draw_tile_proc = DrawTile_TunnelBridge,
2139 .get_slope_pixel_z_proc = GetSlopePixelZ_TunnelBridge,
2140 .clear_tile_proc = ClearTile_TunnelBridge,
2141 .get_tile_desc_proc = GetTileDesc_TunnelBridge,
2142 .get_tile_track_status_proc = GetTileTrackStatus_TunnelBridge,
2143 .tile_loop_proc = TileLoop_TunnelBridge,
2144 .change_tile_owner_proc = ChangeTileOwner_TunnelBridge,
2145 .vehicle_enter_tile_proc = VehicleEnterTile_TunnelBridge,
2146 .get_foundation_proc = GetFoundation_TunnelBridge,
2147 .terraform_tile_proc = TerraformTile_TunnelBridge,
2148 .check_build_above_proc = CheckBuildAbove_TunnelBridge,
2149};
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.
constexpr T ClrBit(T &x, const uint8_t y)
Clears a bit in a variable.
const BridgeSpec * GetBridgeSpec(BridgeType i)
Get the specification of a bridge type.
Definition bridge.h:60
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
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:115
SpriteID single_x
single piece of rail in X direction, without ground
Definition rail.h:125
uint16_t max_speed
Maximum speed for vehicles travelling on this rail type.
Definition rail.h:220
struct RailTypeInfo::@157247141350136173143103254227157213063052244122 strings
Strings associated with the rail type.
SpriteID bridge_deck
bridge deck sprites base
Definition rail.h:134
SpriteID single_y
single piece of rail in Y direction, without ground
Definition rail.h:126
StringID name
Name of this rail type.
Definition rail.h:165
uint8_t bridge_offset
Bridge offset.
Definition rail.h:185
struct RailTypeInfo::@332027037331076264023214171276243307073252216167 base_sprites
Struct containing the main sprites.
SpriteID tunnel
tunnel sprites base
Definition rail.h:133
SpriteID single_sloped
single piece of rail for slopes
Definition rail.h:131
uint16_t max_speed
Maximum speed for vehicles travelling on this road type.
Definition road.h:116
struct RoadTypeInfo::@070000167274302256150317022075324310363002361255 strings
Strings associated with the rail type.
StringID name
Name of this rail type.
Definition road.h:77
static Year year
Current year, starting at 0.
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.
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
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.
Axis
Allow incrementing of DiagDirDiff variables.
@ AXIS_X
The X axis.
@ AXIS_Y
The y axis.
DiagDirection
Enumeration for diagonal directions.
@ DIAGDIR_NE
Northeast, upper right on your monitor.
@ DIAGDIR_NW
Northwest.
@ DIAGDIR_SE
Southeast.
@ DIAGDIR_END
Used for iterations.
@ INVALID_DIAGDIR
Flag for an invalid DiagDirection.
@ DIAGDIR_SW
Southwest.
Prices _price
Prices and also the fractional part.
Definition economy.cpp:106
@ EXPENSES_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:499
void DrawRailCatenaryOnTunnel(const TileInfo *ti)
Draws wires on a tunnel tile.
Definition elrail.cpp:258
void DrawRailCatenary(const TileInfo *ti)
Draws overhead wires and pylons for electric railways.
Definition elrail.cpp:559
Header file for electrified rail specific functions.
bool HasRailCatenaryDrawn(RailType rt)
Test if we should draw rail catenary.
Definition elrail_func.h:32
#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
@ GVF_GOINGDOWN_BIT
Vehicle is currently going downhill. (Cached track information for acceleration).
@ GVF_GOINGUP_BIT
Vehicle is currently going uphill. (Cached track information for acceleration).
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:58
uint GetPartialPixelZ(int x, int y, Slope corners)
Determines height at given coordinate of a slope.
const EnumClassIndexContainer< std::array< const TileTypeProcs *, to_underlying(TileType::MaxSize)>, TileType > _tile_type_procs
Tile callback functions for each type of tile.
Definition landscape.cpp:69
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.
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
@ TCX_ON_BRIDGE
Querying information about stuff on the bridge (via some bridgehead).
@ TCX_NORMAL
Nothing special.
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.
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:85
@ RTBO_X
Piece of rail in X direction.
Definition rail.h:84
@ RTBO_SLOPE
Sloped rail pieces, in order NE, SE, SW, NW.
Definition rail.h:86
@ TunnelPortal
Tunnel portal overlay.
Definition rail.h:51
@ Overlay
Images for overlaying track.
Definition rail.h:42
@ Bridge
Bridge surface images.
Definition rail.h:47
@ Tunnel
Main group of ground images for snow or desert.
Definition rail.h:44
Money RailClearCost(RailType railtype)
Returns the 'cost' of clearing the specified railtype.
Definition rail.h:440
Money RailBuildCost(RailType railtype)
Returns the cost of building the specified railtype.
Definition rail.h:429
const RailTypeInfo * GetRailTypeInfo(RailType railtype)
Returns a pointer to the Railtype information for a given railtype.
Definition rail.h:301
@ RTO_SLOPE_NE
Piece of rail on slope with north-east raised.
Definition rail.h:68
@ RTO_X
Piece of rail in X direction.
Definition rail.h:62
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:251
const RoadTypeInfo * GetRoadTypeInfo(RoadType roadtype)
Returns a pointer to the Roadtype information for a given roadtype.
Definition road.h:215
@ CatenaryFront
Optional: Catenary front.
Definition road.h:41
@ Overlay
Optional: Images for overlaying track.
Definition road.h:38
@ CatenaryRear
Optional: Catenary back.
Definition road.h:42
@ Bridge
Required: Bridge surface images.
Definition road.h:43
@ Tunnel
Optional: Ground images for tunnels.
Definition road.h:40
Money RoadBuildCost(RoadType roadtype)
Returns the cost of building the specified roadtype.
Definition road.h:240
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:147
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:499
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:509
@ Paved
Road with paved sidewalks.
Definition road_map.h:486
@ Trees
Road with trees on paved sidewalks.
Definition road_map.h:489
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:628
uint SlopeToSpriteOffset(Slope s)
Returns the Sprite offset for a given Slope.
Definition slope_func.h:415
bool HasSlopeHighestCorner(Slope s)
Tests if a slope has a highest corner (i.e.
Definition slope_func.h:113
Foundation FlatteningFoundation(Slope s)
Returns the foundation needed to flatten a slope.
Definition slope_func.h:369
DiagDirection GetInclinedSlopeDirection(Slope s)
Returns the direction of an inclined slope.
Definition slope_func.h:239
Foundation InclinedFoundation(Axis axis)
Returns the along a specific axis inclined foundation.
Definition slope_func.h:380
Slope ComplementSlope(Slope s)
Return the complement of a slope.
Definition slope_func.h:76
Slope
Enumeration for the slope-type.
Definition slope_type.h:47
@ SLOPE_SW
south and west corner are raised
Definition slope_type.h:55
@ SLOPE_FLAT
a flat tile
Definition slope_type.h:48
@ SLOPE_NE
north and east corner are raised
Definition slope_type.h:57
@ SLOPE_SE
south and east corner are raised
Definition slope_type.h:56
@ SLOPE_NW
north and west corner are raised
Definition slope_type.h:54
Foundation
Enumeration for Foundations.
Definition slope_type.h:92
@ FOUNDATION_NONE
The tile has no foundation, the slope remains unchanged.
Definition slope_type.h:93
Functions related to sound.
@ SND_05_TRAIN_THROUGH_TUNNEL
3 == 0x03 Train enters tunnel: steam engine
Definition sound_type.h:51
static constexpr uint32_t SPRITE_MASK
The mask to for the main sprite.
Definition sprites.h:1570
static const PaletteID PALETTE_CRASH
Recolour sprite greying of crashed vehicles.
Definition sprites.h:1619
static const SpriteID SPR_RAILTYPE_TUNNEL_BASE
Tunnel sprites with grass only for custom railtype tunnel.
Definition sprites.h:301
static const SpriteID SPR_TRAMWAY_BASE
Tramway sprites.
Definition sprites.h:274
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:46
@ 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:36
BridgeMiddlePillarFlags pillar_flags
bridge pillar flags.
Definition bridge.h:47
std::vector< std::vector< PalSpriteID > > sprite_table
table of sprites for drawing the bridge
Definition bridge.h:44
TimerGameCalendar::Year avail_year
the year where it becomes available
Definition bridge.h:35
StringID transport_name[2]
description of the bridge, when built for road or rail
Definition bridge.h:43
uint16_t speed
maximum travel speed (1 unit = 1/1.6 mph = 1 km-ish/h)
Definition bridge.h:39
uint16_t max_length
the maximum length (not counting start and end tile)
Definition bridge.h:37
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:39
uint16_t rail_speed
Speed limit of rail (bridges and track).
Definition tile_cmd.h:52
StringID str
Description of the tile.
Definition tile_cmd.h:40
std::array< Owner, 4 > owner
Name of the owner(s).
Definition tile_cmd.h:42
uint16_t tram_speed
Speed limit of tram (bridges and track).
Definition tile_cmd.h:56
StringID roadtype
Type of road on the tile.
Definition tile_cmd.h:53
StringID tramtype
Type of tram on the tile.
Definition tile_cmd.h:55
StringID railtype
Type of rail on the tile.
Definition tile_cmd.h:51
uint16_t road_speed
Speed limit of road (bridges and track).
Definition tile_cmd.h:54
std::array< StringID, 4 > owner_type
Type of each owner.
Definition tile_cmd.h:43
Tile information, used while rendering the tile.
Definition tile_cmd.h:33
Slope tileh
Slope of the tile.
Definition tile_cmd.h:34
TileIndex tile
Tile index.
Definition tile_cmd.h:35
Set of callback functions for performing tile operations of a given tile type.
Definition tile_cmd.h:213
std::array< uint32_t, NUM_HOUSE_ZONES > squared_town_zone_radius
UpdateTownRadius updates this given the house count.
Definition town.h:56
Town data structure.
Definition town.h:63
TileIndex xy
town center tile
Definition town.h:64
TownCache cache
Container for all cacheable data.
Definition town.h:66
'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
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:275
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:58
static constexpr int RATING_TUNNEL_BRIDGE_MINIMUM
minimum rating after removing tunnel or bridge
Definition town_type.h:60
static constexpr int RATING_TUNNEL_BRIDGE_DOWN_STEP
penalty for removing town owned tunnel or bridge
Definition town_type.h:59
TrackdirBits TrackBitsToTrackdirBits(TrackBits bits)
Converts TrackBits to TrackdirBits while allowing both directions.
Definition track_func.h:319
TrackStatus CombineTrackStatus(TrackdirBits trackdirbits, TrackdirBits red_signals)
Builds a TrackStatus.
Definition track_func.h:390
TrackBits DiagDirToDiagTrackBits(DiagDirection diagdir)
Maps a (4-way) direction to the diagonal track bits incidating with that diagdir.
Definition track_func.h:529
Trackdir DiagDirToDiagTrackdir(DiagDirection diagdir)
Maps a (4-way) direction to the diagonal trackdir that runs in that direction.
Definition track_func.h:542
Track AxisToTrack(Axis a)
Convert an Axis to the corresponding Track AXIS_X -> TRACK_X AXIS_Y -> TRACK_Y Uses the fact that the...
Definition track_func.h:66
Track DiagDirToDiagTrack(DiagDirection diagdir)
Maps a (4-way) direction to the diagonal track incidating with that diagdir.
Definition track_func.h:517
@ TRACK_BIT_WORMHOLE
Bitflag for a wormhole (used for tunnels).
Definition track_type.h:52
@ TRACKDIR_BIT_NONE
No track build.
Definition track_type.h:98
Track
These are used to specify a single track.
Definition track_type.h:19
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...
@ TO_BRIDGES
bridges
@ TO_CATENARY
catenary
TransportType
Available types of transport.
@ TRANSPORT_RAIL
Transport by train.
@ TRANSPORT_ROAD
Transport by road vehicle.
@ TRANSPORT_WATER
Transport over water.
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.
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.
const uint8_t _tunnel_visibility_frame[DIAGDIR_END]
Frame when a vehicle should be hidden in a tunnel with a certain direction.
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.
@ VEH_ROAD
Road vehicle type.
@ VEH_SHIP
Ship vehicle type.
@ VEH_TRAIN
Train vehicle type.
void StartSpriteCombine()
Starts a block of sprites, which are "combined" into a single bounding box.
Definition viewport.cpp:759
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:658
void EndSpriteCombine()
Terminates a block of sprites started by StartSpriteCombine.
Definition viewport.cpp:769
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.