OpenTTD Source 20250905-master-g122023be8d
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 <http://www.gnu.org/licenses/>.
6 */
7
14#include "stdafx.h"
15#include "viewport_func.h"
16#include "command_func.h"
17#include "town.h"
18#include "train.h"
19#include "ship.h"
20#include "roadveh.h"
22#include "newgrf_sound.h"
23#include "autoslope.h"
24#include "tunnelbridge_map.h"
25#include "strings_func.h"
27#include "clear_func.h"
28#include "vehicle_func.h"
29#include "sound_func.h"
30#include "tunnelbridge.h"
31#include "cheat_type.h"
32#include "elrail_func.h"
33#include "pbs.h"
34#include "company_base.h"
35#include "newgrf_railtype.h"
36#include "newgrf_roadtype.h"
37#include "object_base.h"
38#include "water.h"
39#include "company_gui.h"
40#include "tunnelbridge_cmd.h"
41#include "landscape_cmd.h"
42#include "terraform_cmd.h"
43
44#include "table/strings.h"
45#include "table/bridge_land.h"
46
47#include "safeguards.h"
48
51
53static const int BRIDGE_Z_START = 3;
54
55
64void MarkBridgeDirty(TileIndex begin, TileIndex end, DiagDirection direction, uint bridge_height)
65{
66 TileIndexDiff delta = TileOffsByDiagDir(direction);
67 for (TileIndex t = begin; t != end; t += delta) {
68 MarkTileDirtyByTile(t, bridge_height - TileHeight(t));
69 }
71}
72
81
84{
85 std::ranges::copy(_orig_bridge, std::begin(_bridge));
86}
87
95{
96 if (length < 2) return length;
97
98 length -= 2;
99 int sum = 2;
100 for (int delta = 1;; delta++) {
101 for (int count = 0; count < delta; count++) {
102 if (length == 0) return sum;
103 sum += delta;
104 length--;
105 }
106 }
107}
108
116{
117 if (tileh == SLOPE_FLAT ||
118 ((tileh == SLOPE_NE || tileh == SLOPE_SW) && axis == AXIS_X) ||
119 ((tileh == SLOPE_NW || tileh == SLOPE_SE) && axis == AXIS_Y)) return FOUNDATION_NONE;
120
121 return (HasSlopeHighestCorner(tileh) ? InclinedFoundation(axis) : FlatteningFoundation(tileh));
122}
123
131bool HasBridgeFlatRamp(Slope tileh, Axis axis)
132{
133 ApplyFoundationToSlope(GetBridgeFoundation(tileh, axis), tileh);
134 /* If the foundation slope is flat the bridge has a non-flat ramp and vice versa. */
135 return (tileh != SLOPE_FLAT);
136}
137
144static std::span<const PalSpriteID> GetBridgeSpriteTable(BridgeType bridge_type, BridgePieces piece)
145{
146 assert(piece < NUM_BRIDGE_PIECES);
147
148 const BridgeSpec *bridge = GetBridgeSpec(bridge_type);
149 if (piece < bridge->sprite_table.size() && !bridge->sprite_table[piece].empty()) return bridge->sprite_table[piece];
150
151 return _bridge_sprite_table[bridge_type][piece];
152}
153
160static uint8_t GetBridgeSpriteTableBaseOffset(TransportType transport_type, TileIndex ramp)
161{
162 switch (transport_type) {
164 case TRANSPORT_ROAD: return 8;
165 default: NOT_REACHED();
166 }
167}
168
175{
176 /* Bridge ramps are ordered SW, SE, NE, NW instead of NE, SE, SW, NW. */
177 static constexpr uint8_t ramp_offsets[DIAGDIR_END] = {2, 1, 0, 3};
178 return ramp_offsets[diagdir];
179}
180
187{
188 return axis == AXIS_X ? 0 : 4;
189}
190
200static CommandCost CheckBridgeSlope(BridgePieces bridge_piece, Axis axis, Slope &tileh, int &z)
201{
202 assert(bridge_piece == BRIDGE_PIECE_NORTH || bridge_piece == BRIDGE_PIECE_SOUTH);
203
204 Foundation f = GetBridgeFoundation(tileh, axis);
205 z += ApplyFoundationToSlope(f, tileh);
206
207 Slope valid_inclined;
208 if (bridge_piece == BRIDGE_PIECE_NORTH) {
209 valid_inclined = (axis == AXIS_X ? SLOPE_NE : SLOPE_NW);
210 } else {
211 valid_inclined = (axis == AXIS_X ? SLOPE_SW : SLOPE_SE);
212 }
213 if ((tileh != SLOPE_FLAT) && (tileh != valid_inclined)) return CMD_ERROR;
214
215 if (f == FOUNDATION_NONE) return CommandCost();
216
217 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
218}
219
228{
229 if (flags.Test(DoCommandFlag::QueryCost)) {
230 if (bridge_len <= _settings_game.construction.max_bridge_length) return CommandCost();
231 return CommandCost(STR_ERROR_BRIDGE_TOO_LONG);
232 }
233
234 if (bridge_type >= MAX_BRIDGES) return CMD_ERROR;
235
236 const BridgeSpec *b = GetBridgeSpec(bridge_type);
238
240
241 if (b->min_length > bridge_len) return CMD_ERROR;
242 if (bridge_len <= max) return CommandCost();
243 return CommandCost(STR_ERROR_BRIDGE_TOO_LONG);
244}
245
252{
253 Money base_cost = _price[base_price];
254
255 /* Add the cost of the transport that is on the tunnel/bridge. */
256 switch (GetTunnelBridgeTransportType(tile)) {
257 case TRANSPORT_ROAD: {
258 RoadType road_rt = GetRoadTypeRoad(tile);
259 RoadType tram_rt = GetRoadTypeTram(tile);
260
261 if (road_rt != INVALID_ROADTYPE) {
262 base_cost += 2 * RoadClearCost(road_rt);
263 }
264 if (tram_rt != INVALID_ROADTYPE) {
265 base_cost += 2 * RoadClearCost(tram_rt);
266 }
267 } break;
268
269 case TRANSPORT_RAIL: base_cost += RailClearCost(GetRailType(tile)); break;
270 /* Aqueducts have their own clear price. */
271 case TRANSPORT_WATER: base_cost = _price[PR_CLEAR_AQUEDUCT]; break;
272 default: break;
273 }
274
275 return base_cost;
276}
277
278static CommandCost CheckBuildAbove(TileIndex tile, DoCommandFlags flags, Axis axis, int height)
279{
280 if (_tile_type_procs[GetTileType(tile)]->check_build_above_proc != nullptr) {
281 return _tile_type_procs[GetTileType(tile)]->check_build_above_proc(tile, flags, axis, height);
282 }
283 /* A tile without a handler must be cleared. */
284 return Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile);
285}
286
297CommandCost CmdBuildBridge(DoCommandFlags flags, TileIndex tile_end, TileIndex tile_start, TransportType transport_type, BridgeType bridge_type, uint8_t road_rail_type)
298{
299 CompanyID company = _current_company;
300
301 RailType railtype = INVALID_RAILTYPE;
302 RoadType roadtype = INVALID_ROADTYPE;
303
304 if (!IsValidTile(tile_start)) return CommandCost(STR_ERROR_BRIDGE_THROUGH_MAP_BORDER);
305
306 /* type of bridge */
307 switch (transport_type) {
308 case TRANSPORT_ROAD:
309 roadtype = (RoadType)road_rail_type;
310 if (!ValParamRoadType(roadtype)) return CMD_ERROR;
311 break;
312
313 case TRANSPORT_RAIL:
314 railtype = (RailType)road_rail_type;
315 if (!ValParamRailType(railtype)) return CMD_ERROR;
316 break;
317
318 case TRANSPORT_WATER:
319 break;
320
321 default:
322 /* Airports don't have bridges. */
323 return CMD_ERROR;
324 }
325
326 if (company == OWNER_DEITY) {
327 if (transport_type != TRANSPORT_ROAD) return CMD_ERROR;
328 const Town *town = CalcClosestTownFromTile(tile_start);
329
330 company = OWNER_TOWN;
331
332 /* If we are not within a town, we are not owned by the town */
333 if (town == nullptr || DistanceSquare(tile_start, town->xy) > town->cache.squared_town_zone_radius[to_underlying(HouseZone::TownEdge)]) {
334 company = OWNER_NONE;
335 }
336 }
337
338 if (tile_start == tile_end) {
339 return CommandCost(STR_ERROR_CAN_T_START_AND_END_ON);
340 }
341
342 Axis direction;
343 if (TileX(tile_start) == TileX(tile_end)) {
344 direction = AXIS_Y;
345 } else if (TileY(tile_start) == TileY(tile_end)) {
346 direction = AXIS_X;
347 } else {
348 return CommandCost(STR_ERROR_START_AND_END_MUST_BE_IN);
349 }
350
351 if (tile_end < tile_start) std::swap(tile_start, tile_end);
352
353 uint bridge_len = GetTunnelBridgeLength(tile_start, tile_end);
354 if (transport_type != TRANSPORT_WATER) {
355 /* set and test bridge length, availability */
356 CommandCost ret = CheckBridgeAvailability(bridge_type, bridge_len, flags);
357 if (ret.Failed()) return ret;
358 } else {
359 if (bridge_len > _settings_game.construction.max_bridge_length) return CommandCost(STR_ERROR_BRIDGE_TOO_LONG);
360 }
361 bridge_len += 2; // begin and end tiles/ramps
362
363 auto [tileh_start, z_start] = GetTileSlopeZ(tile_start);
364 auto [tileh_end, z_end] = GetTileSlopeZ(tile_end);
365 bool pbs_reservation = false;
366
367 CommandCost terraform_cost_north = CheckBridgeSlope(BRIDGE_PIECE_NORTH, direction, tileh_start, z_start);
368 CommandCost terraform_cost_south = CheckBridgeSlope(BRIDGE_PIECE_SOUTH, direction, tileh_end, z_end);
369
370 /* Aqueducts can't be built of flat land. */
371 if (transport_type == TRANSPORT_WATER && (tileh_start == SLOPE_FLAT || tileh_end == SLOPE_FLAT)) return CommandCost(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
372 if (z_start != z_end) return CommandCost(STR_ERROR_BRIDGEHEADS_NOT_SAME_HEIGHT);
373
375 Owner owner;
376 bool is_new_owner;
377 RoadType road_rt = INVALID_ROADTYPE;
378 RoadType tram_rt = INVALID_ROADTYPE;
379 if (IsBridgeTile(tile_start) && IsBridgeTile(tile_end) &&
380 GetOtherBridgeEnd(tile_start) == tile_end &&
381 GetTunnelBridgeTransportType(tile_start) == transport_type) {
382 /* Replace a current bridge. */
383
384 switch (transport_type) {
385 case TRANSPORT_RAIL:
386 /* Keep the reservation, the path stays valid. */
387 pbs_reservation = HasTunnelBridgeReservation(tile_start);
388 break;
389
390 case TRANSPORT_ROAD:
391 /* Do not remove road types when upgrading a bridge */
392 road_rt = GetRoadTypeRoad(tile_start);
393 tram_rt = GetRoadTypeTram(tile_start);
394 break;
395
396 default: break;
397 }
398
399 /* If this is a railway bridge, make sure the railtypes match. */
400 if (transport_type == TRANSPORT_RAIL && GetRailType(tile_start) != railtype) {
401 return CommandCost(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
402 }
403
404 /* If this is a road bridge, make sure the roadtype matches. */
405 if (transport_type == TRANSPORT_ROAD) {
406 RoadType existing_rt = RoadTypeIsRoad(roadtype) ? road_rt : tram_rt;
407 if (existing_rt != roadtype && existing_rt != INVALID_ROADTYPE) {
408 return CommandCost(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
409 }
410 }
411
412 if (!flags.Test(DoCommandFlag::QueryCost)) {
413 /* Do not replace the bridge with the same bridge type. */
414 if ((bridge_type == GetBridgeType(tile_start)) && (transport_type != TRANSPORT_ROAD || road_rt == roadtype || tram_rt == roadtype)) {
415 return CommandCost(STR_ERROR_ALREADY_BUILT);
416 }
417
418 /* Do not replace town bridges with lower speed bridges, unless in scenario editor. */
419 if (IsTileOwner(tile_start, OWNER_TOWN) && _game_mode != GM_EDITOR) {
420 Town *t = ClosestTownFromTile(tile_start, UINT_MAX);
421 if (t == nullptr) return CMD_ERROR;
422
423 if (GetBridgeSpec(bridge_type)->speed < GetBridgeSpec(GetBridgeType(tile_start))->speed) {
424 return CommandCostWithParam(STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS, t->index);
425 } else {
426 ChangeTownRating(t, RATING_TUNNEL_BRIDGE_UP_STEP, RATING_MAXIMUM, flags);
427 }
428 }
429 }
430
431 /* Do not allow replacing another company's bridges. */
432 if (!IsTileOwner(tile_start, company) && !IsTileOwner(tile_start, OWNER_TOWN) && !IsTileOwner(tile_start, OWNER_NONE)) {
433 return CommandCost(STR_ERROR_AREA_IS_OWNED_BY_ANOTHER);
434 }
435
436 /* The cost of clearing the current bridge. */
437 cost.AddCost(bridge_len * TunnelBridgeClearCost(tile_start, PR_CLEAR_BRIDGE));
438 owner = GetTileOwner(tile_start);
439
440 /* If bridge belonged to bankrupt company, it has a new owner now */
441 is_new_owner = (owner == OWNER_NONE);
442 if (is_new_owner) owner = company;
443
444 /* Check if the new bridge is compatible with tiles underneath. */
445 TileIndexDiff delta = (direction == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
446 for (TileIndex tile = tile_start + delta; tile != tile_end; tile += delta) {
447 CommandCost ret = CheckBuildAbove(tile, flags, direction, z_start + 1);
448 if (ret.Failed()) return ret;
449 cost.AddCost(ret.GetCost());
450 }
451 } else {
452 /* Build a new bridge. */
453
454 bool allow_on_slopes = (_settings_game.construction.build_on_slopes && transport_type != TRANSPORT_WATER);
455
456 /* Try and clear the start landscape */
457 CommandCost ret = Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile_start);
458 if (ret.Failed()) return ret;
459 cost = ret;
460
461 if (terraform_cost_north.Failed() || (terraform_cost_north.GetCost() != 0 && !allow_on_slopes)) return CommandCost(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
462 cost.AddCost(terraform_cost_north.GetCost());
463
464 /* Try and clear the end landscape */
465 ret = Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile_end);
466 if (ret.Failed()) return ret;
467 cost.AddCost(ret.GetCost());
468
469 /* false - end tile slope check */
470 if (terraform_cost_south.Failed() || (terraform_cost_south.GetCost() != 0 && !allow_on_slopes)) return CommandCost(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
471 cost.AddCost(terraform_cost_south.GetCost());
472
473 /* Check for bridges above the bridge ramps. */
474 for (TileIndex tile : {tile_start, tile_end}) {
475 if (!IsBridgeAbove(tile)) continue;
476
477 if (direction == GetBridgeAxis(tile)) return CommandCost(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
478
479 if (z_start + 1 == GetBridgeHeight(GetNorthernBridgeEnd(tile))) return CommandCost(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
480 }
481
482 TileIndexDiff delta = TileOffsByAxis(direction);
483 for (TileIndex tile = tile_start + delta; tile != tile_end; tile += delta) {
484 if (GetTileMaxZ(tile) > z_start) return CommandCost(STR_ERROR_BRIDGE_TOO_LOW_FOR_TERRAIN);
485
486 if (z_start >= (GetTileZ(tile) + _settings_game.construction.max_bridge_height)) {
487 /*
488 * Disallow too high bridges.
489 * Properly rendering a map where very high bridges (might) exist is expensive.
490 * See http://www.tt-forums.net/viewtopic.php?f=33&t=40844&start=980#p1131762
491 * for a detailed discussion. z_start here is one heightlevel below the bridge level.
492 */
493 return CommandCost(STR_ERROR_BRIDGE_TOO_HIGH_FOR_TERRAIN);
494 }
495
496 if (IsBridgeAbove(tile)) {
497 /* Disallow crossing bridges for the time being */
498 return CommandCost(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
499 }
500
501 ret = CheckBuildAbove(tile, flags, direction, z_start + 1);
502 if (ret.Failed()) return ret;
503 cost.AddCost(ret.GetCost());
504
505 if (flags.Test(DoCommandFlag::Execute)) {
506 /* We do this here because when replacing a bridge with another
507 * type calling SetBridgeMiddle isn't needed. After all, the
508 * tile already has the has_bridge_above bits set. */
509 SetBridgeMiddle(tile, direction);
510 }
511 }
512
513 owner = company;
514 is_new_owner = true;
515 }
516
517 bool hasroad = road_rt != INVALID_ROADTYPE;
518 bool hastram = tram_rt != INVALID_ROADTYPE;
519 if (transport_type == TRANSPORT_ROAD) {
520 if (RoadTypeIsRoad(roadtype)) road_rt = roadtype;
521 if (RoadTypeIsTram(roadtype)) tram_rt = roadtype;
522 }
523
524 /* do the drill? */
525 if (flags.Test(DoCommandFlag::Execute)) {
526 DiagDirection dir = AxisToDiagDir(direction);
527
528 Company *c = Company::GetIfValid(company);
529 switch (transport_type) {
530 case TRANSPORT_RAIL:
531 /* Add to company infrastructure count if required. */
532 if (is_new_owner && c != nullptr) c->infrastructure.rail[railtype] += bridge_len * TUNNELBRIDGE_TRACKBIT_FACTOR;
533 MakeRailBridgeRamp(tile_start, owner, bridge_type, dir, railtype);
534 MakeRailBridgeRamp(tile_end, owner, bridge_type, ReverseDiagDir(dir), railtype);
535 SetTunnelBridgeReservation(tile_start, pbs_reservation);
536 SetTunnelBridgeReservation(tile_end, pbs_reservation);
537 break;
538
539 case TRANSPORT_ROAD: {
540 if (is_new_owner) {
541 /* Also give unowned present roadtypes to new owner */
542 if (hasroad && GetRoadOwner(tile_start, RTT_ROAD) == OWNER_NONE) hasroad = false;
543 if (hastram && GetRoadOwner(tile_start, RTT_TRAM) == OWNER_NONE) hastram = false;
544 }
545 if (c != nullptr) {
546 /* Add all new road types to the company infrastructure counter. */
547 if (!hasroad && road_rt != INVALID_ROADTYPE) {
548 /* A full diagonal road tile has two road bits. */
549 c->infrastructure.road[road_rt] += bridge_len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR;
550 }
551 if (!hastram && tram_rt != INVALID_ROADTYPE) {
552 /* A full diagonal road tile has two road bits. */
553 c->infrastructure.road[tram_rt] += bridge_len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR;
554 }
555 }
556 Owner owner_road = hasroad ? GetRoadOwner(tile_start, RTT_ROAD) : company;
557 Owner owner_tram = hastram ? GetRoadOwner(tile_start, RTT_TRAM) : company;
558 MakeRoadBridgeRamp(tile_start, owner, owner_road, owner_tram, bridge_type, dir, road_rt, tram_rt);
559 MakeRoadBridgeRamp(tile_end, owner, owner_road, owner_tram, bridge_type, ReverseDiagDir(dir), road_rt, tram_rt);
560 break;
561 }
562
563 case TRANSPORT_WATER:
564 if (is_new_owner && c != nullptr) c->infrastructure.water += bridge_len * TUNNELBRIDGE_TRACKBIT_FACTOR;
565 MakeAqueductBridgeRamp(tile_start, owner, dir);
566 MakeAqueductBridgeRamp(tile_end, owner, ReverseDiagDir(dir));
567 CheckForDockingTile(tile_start);
568 CheckForDockingTile(tile_end);
569 break;
570
571 default:
572 NOT_REACHED();
573 }
574
575 /* Mark all tiles dirty */
576 MarkBridgeDirty(tile_start, tile_end, AxisToDiagDir(direction), z_start);
578 }
579
580 if (flags.Test(DoCommandFlag::Execute) && transport_type == TRANSPORT_RAIL) {
581 Track track = AxisToTrack(direction);
582 AddSideToSignalBuffer(tile_start, INVALID_DIAGDIR, company);
583 YapfNotifyTrackLayoutChange(tile_start, track);
584 }
585
586 /* Human players that build bridges get a selection to choose from (DoCommandFlag::QueryCost)
587 * It's unnecessary to execute this command every time for every bridge.
588 * So it is done only for humans and cost is computed in bridge_gui.cpp.
589 * For (non-spectated) AI, Towns this has to be of course calculated. */
590 Company *c = Company::GetIfValid(company);
591 if (!flags.Test(DoCommandFlag::QueryCost) || (c != nullptr && c->is_ai && company != _local_company)) {
592 switch (transport_type) {
593 case TRANSPORT_ROAD:
594 if (road_rt != INVALID_ROADTYPE) {
595 cost.AddCost(bridge_len * 2 * RoadBuildCost(road_rt));
596 }
597 if (tram_rt != INVALID_ROADTYPE) {
598 cost.AddCost(bridge_len * 2 * RoadBuildCost(tram_rt));
599 }
600 break;
601
602 case TRANSPORT_RAIL: cost.AddCost(bridge_len * RailBuildCost(railtype)); break;
603 default: break;
604 }
605
606 if (c != nullptr) bridge_len = CalcBridgeLenCostFactor(bridge_len);
607
608 if (transport_type != TRANSPORT_WATER) {
609 cost.AddCost((int64_t)bridge_len * _price[PR_BUILD_BRIDGE] * GetBridgeSpec(bridge_type)->price >> 8);
610 } else {
611 /* Aqueducts use a separate base cost. */
612 cost.AddCost((int64_t)bridge_len * _price[PR_BUILD_AQUEDUCT]);
613 }
614
615 }
616
617 return cost;
618}
619
620
629CommandCost CmdBuildTunnel(DoCommandFlags flags, TileIndex start_tile, TransportType transport_type, uint8_t road_rail_type)
630{
631 CompanyID company = _current_company;
632
633 RailType railtype = INVALID_RAILTYPE;
634 RoadType roadtype = INVALID_ROADTYPE;
636 switch (transport_type) {
637 case TRANSPORT_RAIL:
638 railtype = (RailType)road_rail_type;
639 if (!ValParamRailType(railtype)) return CMD_ERROR;
640 break;
641
642 case TRANSPORT_ROAD:
643 roadtype = (RoadType)road_rail_type;
644 if (!ValParamRoadType(roadtype)) return CMD_ERROR;
645 break;
646
647 default: return CMD_ERROR;
648 }
649
650 if (company == OWNER_DEITY) {
651 if (transport_type != TRANSPORT_ROAD) return CMD_ERROR;
652 const Town *town = CalcClosestTownFromTile(start_tile);
653
654 company = OWNER_TOWN;
655
656 /* If we are not within a town, we are not owned by the town */
657 if (town == nullptr || DistanceSquare(start_tile, town->xy) > town->cache.squared_town_zone_radius[to_underlying(HouseZone::TownEdge)]) {
658 company = OWNER_NONE;
659 }
660 }
661
662 auto [start_tileh, start_z] = GetTileSlopeZ(start_tile);
663 DiagDirection direction = GetInclinedSlopeDirection(start_tileh);
664 if (direction == INVALID_DIAGDIR) return CommandCost(STR_ERROR_SITE_UNSUITABLE_FOR_TUNNEL);
665
666 if (HasTileWaterGround(start_tile)) return CommandCost(STR_ERROR_CAN_T_BUILD_ON_WATER);
667
668 CommandCost ret = Command<CMD_LANDSCAPE_CLEAR>::Do(flags, start_tile);
669 if (ret.Failed()) return ret;
670
671 /* XXX - do NOT change 'ret' in the loop, as it is used as the price
672 * for the clearing of the entrance of the tunnel. Assigning it to
673 * cost before the loop will yield different costs depending on start-
674 * position, because of increased-cost-by-length: 'cost += cost >> 3' */
675
676 TileIndexDiff delta = TileOffsByDiagDir(direction);
677 DiagDirection tunnel_in_way_dir;
678 if (DiagDirToAxis(direction) == AXIS_Y) {
679 tunnel_in_way_dir = (TileX(start_tile) < (Map::MaxX() / 2)) ? DIAGDIR_SW : DIAGDIR_NE;
680 } else {
681 tunnel_in_way_dir = (TileY(start_tile) < (Map::MaxX() / 2)) ? DIAGDIR_SE : DIAGDIR_NW;
682 }
683
684 TileIndex end_tile = start_tile;
685
686 /* Tile shift coefficient. Will decrease for very long tunnels to avoid exponential growth of price*/
687 int tiles_coef = 3;
688 /* Number of tiles from start of tunnel */
689 int tiles = 0;
690 /* Number of tiles at which the cost increase coefficient per tile is halved */
691 int tiles_bump = 25;
692
694 Slope end_tileh;
695 int end_z;
696 for (;;) {
697 end_tile += delta;
698 if (!IsValidTile(end_tile)) return CommandCost(STR_ERROR_TUNNEL_THROUGH_MAP_BORDER);
699 std::tie(end_tileh, end_z) = GetTileSlopeZ(end_tile);
700
701 if (start_z == end_z) break;
702
703 if (!_cheats.crossing_tunnels.value && IsTunnelInWayDir(end_tile, start_z, tunnel_in_way_dir)) {
704 return CommandCost(STR_ERROR_ANOTHER_TUNNEL_IN_THE_WAY);
705 }
706
707 tiles++;
708 if (tiles == tiles_bump) {
709 tiles_coef++;
710 tiles_bump *= 2;
711 }
712
713 cost.AddCost(_price[PR_BUILD_TUNNEL]);
714 cost.AddCost(cost.GetCost() >> tiles_coef); // add a multiplier for longer tunnels
715 }
716
717 /* Add the cost of the entrance */
718 cost.AddCost(_price[PR_BUILD_TUNNEL]);
719 cost.AddCost(ret.GetCost());
720
721 /* if the command fails from here on we want the end tile to be highlighted */
722 _build_tunnel_endtile = end_tile;
723
724 if (tiles > _settings_game.construction.max_tunnel_length) return CommandCost(STR_ERROR_TUNNEL_TOO_LONG);
725
726 if (HasTileWaterGround(end_tile)) return CommandCost(STR_ERROR_CAN_T_BUILD_ON_WATER);
727
728 /* Clear the tile in any case */
729 ret = Command<CMD_LANDSCAPE_CLEAR>::Do(flags, end_tile);
730 if (ret.Failed()) return CommandCost(STR_ERROR_UNABLE_TO_EXCAVATE_LAND);
731 cost.AddCost(ret.GetCost());
732
733 /* slope of end tile must be complementary to the slope of the start tile */
734 if (end_tileh != ComplementSlope(start_tileh)) {
735 /* Mark the tile as already cleared for the terraform command.
736 * Do this for all tiles (like trees), not only objects. */
737 ClearedObjectArea *coa = FindClearedObject(end_tile);
738 if (coa == nullptr) {
739 coa = &_cleared_object_areas.emplace_back(end_tile, TileArea(end_tile, 1, 1));
740 }
741
742 /* Hide the tile from the terraforming command */
743 TileIndex old_first_tile = coa->first_tile;
745
746 /* CMD_TERRAFORM_LAND may append further items to _cleared_object_areas,
747 * however it will never erase or re-order existing items.
748 * _cleared_object_areas is a value-type self-resizing vector, therefore appending items
749 * may result in a backing-store re-allocation, which would invalidate the coa pointer.
750 * The index of the coa pointer into the _cleared_object_areas vector remains valid,
751 * and can be used safely after the CMD_TERRAFORM_LAND operation.
752 * Deliberately clear the coa pointer to avoid leaving dangling pointers which could
753 * inadvertently be dereferenced.
754 */
755 ClearedObjectArea *begin = _cleared_object_areas.data();
756 assert(coa >= begin && coa < begin + _cleared_object_areas.size());
757 size_t coa_index = coa - begin;
758 assert(coa_index < UINT_MAX); // more than 2**32 cleared areas would be a bug in itself
759 coa = nullptr;
760
761 ret = std::get<0>(Command<CMD_TERRAFORM_LAND>::Do(flags, end_tile, end_tileh & start_tileh, false));
762 _cleared_object_areas[(uint)coa_index].first_tile = old_first_tile;
763 if (ret.Failed()) return CommandCost(STR_ERROR_UNABLE_TO_EXCAVATE_LAND);
764 cost.AddCost(ret.GetCost());
765 }
766 cost.AddCost(_price[PR_BUILD_TUNNEL]);
767
768 /* Pay for the rail/road in the tunnel including entrances */
769 switch (transport_type) {
770 case TRANSPORT_ROAD: cost.AddCost((tiles + 2) * RoadBuildCost(roadtype) * 2); break;
771 case TRANSPORT_RAIL: cost.AddCost((tiles + 2) * RailBuildCost(railtype)); break;
772 default: NOT_REACHED();
773 }
774
775 if (flags.Test(DoCommandFlag::Execute)) {
776 Company *c = Company::GetIfValid(company);
777 uint num_pieces = (tiles + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR;
778 if (transport_type == TRANSPORT_RAIL) {
779 if (c != nullptr) c->infrastructure.rail[railtype] += num_pieces;
780 MakeRailTunnel(start_tile, company, direction, railtype);
781 MakeRailTunnel(end_tile, company, ReverseDiagDir(direction), railtype);
782 AddSideToSignalBuffer(start_tile, INVALID_DIAGDIR, company);
783 YapfNotifyTrackLayoutChange(start_tile, DiagDirToDiagTrack(direction));
784 } else {
785 if (c != nullptr) c->infrastructure.road[roadtype] += num_pieces * 2; // A full diagonal road has two road bits.
786 RoadType road_rt = RoadTypeIsRoad(roadtype) ? roadtype : INVALID_ROADTYPE;
787 RoadType tram_rt = RoadTypeIsTram(roadtype) ? roadtype : INVALID_ROADTYPE;
788 MakeRoadTunnel(start_tile, company, direction, road_rt, tram_rt);
789 MakeRoadTunnel(end_tile, company, ReverseDiagDir(direction), road_rt, tram_rt);
790 }
792 }
793
794 return cost;
795}
796
797
804{
805 /* Floods can remove anything as well as the scenario editor */
806 if (_current_company == OWNER_WATER || _game_mode == GM_EDITOR) return CommandCost();
807
808 switch (GetTunnelBridgeTransportType(tile)) {
809 case TRANSPORT_ROAD: {
810 RoadType road_rt = GetRoadTypeRoad(tile);
811 RoadType tram_rt = GetRoadTypeTram(tile);
812 Owner road_owner = _current_company;
813 Owner tram_owner = _current_company;
814
815 if (road_rt != INVALID_ROADTYPE) road_owner = GetRoadOwner(tile, RTT_ROAD);
816 if (tram_rt != INVALID_ROADTYPE) tram_owner = GetRoadOwner(tile, RTT_TRAM);
817
818 /* We can remove unowned road and if the town allows it */
820 /* Town does not allow */
821 return CheckTileOwnership(tile);
822 }
823 if (road_owner == OWNER_NONE || road_owner == OWNER_TOWN) road_owner = _current_company;
824 if (tram_owner == OWNER_NONE) tram_owner = _current_company;
825
826 CommandCost ret = CheckOwnership(road_owner, tile);
827 if (ret.Succeeded()) ret = CheckOwnership(tram_owner, tile);
828 return ret;
829 }
830
831 case TRANSPORT_RAIL:
832 return CheckOwnership(GetTileOwner(tile));
833
834 case TRANSPORT_WATER: {
835 /* Always allow to remove aqueducts without owner. */
836 Owner aqueduct_owner = GetTileOwner(tile);
837 if (aqueduct_owner == OWNER_NONE) aqueduct_owner = _current_company;
838 return CheckOwnership(aqueduct_owner);
839 }
840
841 default: NOT_REACHED();
842 }
843}
844
852{
854 if (ret.Failed()) return ret;
855
856 TileIndex endtile = GetOtherTunnelEnd(tile);
857
858 ret = TunnelBridgeIsFree(tile, endtile);
859 if (ret.Failed()) return ret;
860
861 _build_tunnel_endtile = endtile;
862
863 Town *t = nullptr;
864 if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) {
865 t = ClosestTownFromTile(tile, UINT_MAX); // town penalty rating
866
867 /* Check if you are allowed to remove the tunnel owned by a town
868 * Removal depends on difficulty settings */
870 if (ret.Failed()) return ret;
871 }
872
873 /* checks if the owner is town then decrease town rating by RATING_TUNNEL_BRIDGE_DOWN_STEP until
874 * you have a "Poor" (0) town rating */
875 if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) {
877 }
878
879 Money base_cost = TunnelBridgeClearCost(tile, PR_CLEAR_TUNNEL);
880 uint len = GetTunnelBridgeLength(tile, endtile) + 2; // Don't forget the end tiles.
881
882 if (flags.Test(DoCommandFlag::Execute)) {
884 /* We first need to request values before calling DoClearSquare */
886 Track track = DiagDirToDiagTrack(dir);
887 Owner owner = GetTileOwner(tile);
888
889 Train *v = nullptr;
890 if (HasTunnelBridgeReservation(tile)) {
891 v = GetTrainForReservation(tile, track);
892 if (v != nullptr) FreeTrainTrackReservation(v);
893 }
894
895 if (Company::IsValidID(owner)) {
896 Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= len * TUNNELBRIDGE_TRACKBIT_FACTOR;
898 }
899
900 DoClearSquare(tile);
901 DoClearSquare(endtile);
902
903 /* cannot use INVALID_DIAGDIR for signal update because the tunnel doesn't exist anymore */
904 AddSideToSignalBuffer(tile, ReverseDiagDir(dir), owner);
905 AddSideToSignalBuffer(endtile, dir, owner);
906
907 YapfNotifyTrackLayoutChange(tile, track);
908 YapfNotifyTrackLayoutChange(endtile, track);
909
910 if (v != nullptr) TryPathReserve(v);
911 } else {
912 /* A full diagonal road tile has two road bits. */
913 UpdateCompanyRoadInfrastructure(GetRoadTypeRoad(tile), GetRoadOwner(tile, RTT_ROAD), -(int)(len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR));
914 UpdateCompanyRoadInfrastructure(GetRoadTypeTram(tile), GetRoadOwner(tile, RTT_TRAM), -(int)(len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR));
915
916 DoClearSquare(tile);
917 DoClearSquare(endtile);
918 }
919 }
920
921 return CommandCost(EXPENSES_CONSTRUCTION, len * base_cost);
922}
923
924
932{
934 if (ret.Failed()) return ret;
935
936 TileIndex endtile = GetOtherBridgeEnd(tile);
937
938 ret = TunnelBridgeIsFree(tile, endtile);
939 if (ret.Failed()) return ret;
940
941 DiagDirection direction = GetTunnelBridgeDirection(tile);
942 TileIndexDiff delta = TileOffsByDiagDir(direction);
943
944 Town *t = nullptr;
945 if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) {
946 t = ClosestTownFromTile(tile, UINT_MAX); // town penalty rating
947
948 /* Check if you are allowed to remove the bridge owned by a town
949 * Removal depends on difficulty settings */
951 if (ret.Failed()) return ret;
952 }
953
954 /* checks if the owner is town then decrease town rating by RATING_TUNNEL_BRIDGE_DOWN_STEP until
955 * you have a "Poor" (0) town rating */
956 if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) {
958 }
959
960 Money base_cost = TunnelBridgeClearCost(tile, PR_CLEAR_BRIDGE);
961 uint len = GetTunnelBridgeLength(tile, endtile) + 2; // Don't forget the end tiles.
962
963 if (flags.Test(DoCommandFlag::Execute)) {
964 /* read this value before actual removal of bridge */
965 bool rail = GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL;
966 Owner owner = GetTileOwner(tile);
967 int height = GetBridgeHeight(tile);
968 Train *v = nullptr;
969
970 if (rail && HasTunnelBridgeReservation(tile)) {
971 v = GetTrainForReservation(tile, DiagDirToDiagTrack(direction));
972 if (v != nullptr) FreeTrainTrackReservation(v);
973 }
974
975 /* Update company infrastructure counts. */
976 if (rail) {
977 if (Company::IsValidID(owner)) Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= len * TUNNELBRIDGE_TRACKBIT_FACTOR;
978 } else if (GetTunnelBridgeTransportType(tile) == TRANSPORT_ROAD) {
979 /* A full diagonal road tile has two road bits. */
980 UpdateCompanyRoadInfrastructure(GetRoadTypeRoad(tile), GetRoadOwner(tile, RTT_ROAD), -(int)(len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR));
981 UpdateCompanyRoadInfrastructure(GetRoadTypeTram(tile), GetRoadOwner(tile, RTT_TRAM), -(int)(len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR));
982 } else { // Aqueduct
983 if (Company::IsValidID(owner)) Company::Get(owner)->infrastructure.water -= len * TUNNELBRIDGE_TRACKBIT_FACTOR;
984 }
986
987 DoClearSquare(tile);
988 DoClearSquare(endtile);
989
990 for (TileIndex c = tile + delta; c != endtile; c += delta) {
991 /* do not let trees appear from 'nowhere' after removing bridge */
993 int minz = GetTileMaxZ(c) + 3;
994 if (height < minz) SetRoadside(c, ROADSIDE_PAVED);
995 }
997 MarkTileDirtyByTile(c, height - TileHeight(c));
998 }
999
1000 if (rail) {
1001 /* cannot use INVALID_DIAGDIR for signal update because the bridge doesn't exist anymore */
1002 AddSideToSignalBuffer(tile, ReverseDiagDir(direction), owner);
1003 AddSideToSignalBuffer(endtile, direction, owner);
1004
1005 Track track = DiagDirToDiagTrack(direction);
1006 YapfNotifyTrackLayoutChange(tile, track);
1007 YapfNotifyTrackLayoutChange(endtile, track);
1008
1009 if (v != nullptr) TryPathReserve(v, true);
1010 }
1011 }
1012
1013 return CommandCost(EXPENSES_CONSTRUCTION, len * base_cost);
1014}
1015
1023{
1024 if (IsTunnel(tile)) {
1025 if (flags.Test(DoCommandFlag::Auto)) return CommandCost(STR_ERROR_MUST_DEMOLISH_TUNNEL_FIRST);
1026 return DoClearTunnel(tile, flags);
1027 } else { // IsBridge(tile)
1028 if (flags.Test(DoCommandFlag::Auto)) return CommandCost(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
1029 return DoClearBridge(tile, flags);
1030 }
1031}
1032
1043static inline void DrawPillar(const PalSpriteID &psid, int x, int y, int z, uint8_t w, uint8_t h, const SubSprite *subsprite)
1044{
1045 static const int PILLAR_Z_OFFSET = TILE_HEIGHT - BRIDGE_Z_START;
1046 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);
1047}
1048
1060static int DrawPillarColumn(int z_bottom, int z_top, const PalSpriteID &psid, int x, int y, int w, int h)
1061{
1062 int cur_z;
1063 for (cur_z = z_top; cur_z >= z_bottom; cur_z -= TILE_HEIGHT) {
1064 DrawPillar(psid, x, y, cur_z, w, h, nullptr);
1065 }
1066 return cur_z;
1067}
1068
1080static void DrawBridgePillars(const PalSpriteID &psid, const TileInfo *ti, Axis axis, bool drawfarpillar, int x, int y, int z_bridge)
1081{
1082 static const int bounding_box_size[2] = {16, 2};
1083 static const int back_pillar_offset[2] = { 0, 9};
1084
1085 static const int INF = 1000;
1086 static const SubSprite half_pillar_sub_sprite[2][2] = {
1087 { { -14, -INF, INF, INF }, { -INF, -INF, -15, INF } }, // X axis, north and south
1088 { { -INF, -INF, 15, INF }, { 16, -INF, INF, INF } }, // Y axis, north and south
1089 };
1090
1091 if (psid.sprite == 0) return;
1092
1093 /* Determine ground height under pillars */
1094 DiagDirection south_dir = AxisToDiagDir(axis);
1095 int z_front_north = ti->z;
1096 int z_back_north = ti->z;
1097 int z_front_south = ti->z;
1098 int z_back_south = ti->z;
1099 GetSlopePixelZOnEdge(ti->tileh, south_dir, z_front_south, z_back_south);
1100 GetSlopePixelZOnEdge(ti->tileh, ReverseDiagDir(south_dir), z_front_north, z_back_north);
1101
1102 /* Shared height of pillars */
1103 int z_front = std::max(z_front_north, z_front_south);
1104 int z_back = std::max(z_back_north, z_back_south);
1105
1106 /* x and y size of bounding-box of pillars */
1107 int w = bounding_box_size[axis];
1108 int h = bounding_box_size[OtherAxis(axis)];
1109 /* sprite position of back facing pillar */
1110 int x_back = x - back_pillar_offset[axis];
1111 int y_back = y - back_pillar_offset[OtherAxis(axis)];
1112
1113 /* Draw front pillars */
1114 int bottom_z = DrawPillarColumn(z_front, z_bridge, psid, x, y, w, h);
1115 if (z_front_north < z_front) DrawPillar(psid, x, y, bottom_z, w, h, &half_pillar_sub_sprite[axis][0]);
1116 if (z_front_south < z_front) DrawPillar(psid, x, y, bottom_z, w, h, &half_pillar_sub_sprite[axis][1]);
1117
1118 /* Draw back pillars, skip top two parts, which are hidden by the bridge */
1119 int z_bridge_back = z_bridge - 2 * (int)TILE_HEIGHT;
1120 if (drawfarpillar && (z_back_north <= z_bridge_back || z_back_south <= z_bridge_back)) {
1121 bottom_z = DrawPillarColumn(z_back, z_bridge_back, psid, x_back, y_back, w, h);
1122 if (z_back_north < z_back) DrawPillar(psid, x_back, y_back, bottom_z, w, h, &half_pillar_sub_sprite[axis][0]);
1123 if (z_back_south < z_back) DrawPillar(psid, x_back, y_back, bottom_z, w, h, &half_pillar_sub_sprite[axis][1]);
1124 }
1125}
1126
1136static void GetBridgeRoadCatenary(const RoadTypeInfo *rti, TileIndex head_tile, int offset, bool head, SpriteID &spr_back, SpriteID &spr_front)
1137{
1138 static const SpriteID back_offsets[6] = { 95, 96, 99, 102, 100, 101 };
1139 static const SpriteID front_offsets[6] = { 97, 98, 103, 106, 104, 105 };
1140
1141 /* Simplified from DrawRoadTypeCatenary() to remove all the special cases required for regular ground road */
1142 spr_back = GetCustomRoadSprite(rti, head_tile, ROTSG_CATENARY_BACK, head ? TCX_NORMAL : TCX_ON_BRIDGE);
1143 spr_front = GetCustomRoadSprite(rti, head_tile, ROTSG_CATENARY_FRONT, head ? TCX_NORMAL : TCX_ON_BRIDGE);
1144 if (spr_back == 0 && spr_front == 0) {
1145 spr_back = SPR_TRAMWAY_BASE + back_offsets[offset];
1146 spr_front = SPR_TRAMWAY_BASE + front_offsets[offset];
1147 } else {
1148 if (spr_back != 0) spr_back += 23 + offset;
1149 if (spr_front != 0) spr_front += 23 + offset;
1150 }
1151}
1152
1162static void DrawBridgeRoadBits(TileIndex head_tile, int x, int y, int z, int offset, bool head)
1163{
1164 RoadType road_rt = GetRoadTypeRoad(head_tile);
1165 RoadType tram_rt = GetRoadTypeTram(head_tile);
1166 const RoadTypeInfo *road_rti = road_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(road_rt);
1167 const RoadTypeInfo *tram_rti = tram_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(tram_rt);
1168
1169 SpriteID seq_back[4] = { 0 };
1170 bool trans_back[4] = { false };
1171 SpriteID seq_front[4] = { 0 };
1172 bool trans_front[4] = { false };
1173
1174 static const SpriteID overlay_offsets[6] = { 0, 1, 11, 12, 13, 14 };
1175 if (head || !IsInvisibilitySet(TO_BRIDGES)) {
1176 /* Road underlay takes precedence over tram */
1177 trans_back[0] = !head && IsTransparencySet(TO_BRIDGES);
1178 if (road_rti != nullptr) {
1179 if (road_rti->UsesOverlay()) {
1180 seq_back[0] = GetCustomRoadSprite(road_rti, head_tile, ROTSG_BRIDGE, head ? TCX_NORMAL : TCX_ON_BRIDGE) + offset;
1181 }
1182 } else if (tram_rti != nullptr) {
1183 if (tram_rti->UsesOverlay()) {
1184 seq_back[0] = GetCustomRoadSprite(tram_rti, head_tile, ROTSG_BRIDGE, head ? TCX_NORMAL : TCX_ON_BRIDGE) + offset;
1185 } else {
1186 seq_back[0] = SPR_TRAMWAY_BRIDGE + offset;
1187 }
1188 }
1189
1190 /* Draw road overlay */
1191 trans_back[1] = !head && IsTransparencySet(TO_BRIDGES);
1192 if (road_rti != nullptr) {
1193 if (road_rti->UsesOverlay()) {
1194 seq_back[1] = GetCustomRoadSprite(road_rti, head_tile, ROTSG_OVERLAY, head ? TCX_NORMAL : TCX_ON_BRIDGE);
1195 if (seq_back[1] != 0) seq_back[1] += overlay_offsets[offset];
1196 }
1197 }
1198
1199 /* Draw tram overlay */
1200 trans_back[2] = !head && IsTransparencySet(TO_BRIDGES);
1201 if (tram_rti != nullptr) {
1202 if (tram_rti->UsesOverlay()) {
1203 seq_back[2] = GetCustomRoadSprite(tram_rti, head_tile, ROTSG_OVERLAY, head ? TCX_NORMAL : TCX_ON_BRIDGE);
1204 if (seq_back[2] != 0) seq_back[2] += overlay_offsets[offset];
1205 } else if (road_rti != nullptr) {
1206 seq_back[2] = SPR_TRAMWAY_OVERLAY + overlay_offsets[offset];
1207 }
1208 }
1209
1210 /* Road catenary takes precedence over tram */
1211 trans_back[3] = IsTransparencySet(TO_CATENARY);
1212 trans_front[0] = IsTransparencySet(TO_CATENARY);
1213 if (road_rti != nullptr && HasRoadCatenaryDrawn(road_rt)) {
1214 GetBridgeRoadCatenary(road_rti, head_tile, offset, head, seq_back[3], seq_front[0]);
1215 } else if (tram_rti != nullptr && HasRoadCatenaryDrawn(tram_rt)) {
1216 GetBridgeRoadCatenary(tram_rti, head_tile, offset, head, seq_back[3], seq_front[0]);
1217 }
1218 }
1219
1220 static constexpr SpriteBounds back_bounds[6] = {
1221 {{}, {0, TILE_SIZE, 40}, {}},
1222 {{}, {TILE_SIZE, 0, 40}, {}},
1223 {{}, {TILE_SIZE, 0, 40}, {}},
1224 {{}, {0, TILE_SIZE, 40}, {}},
1225 {{}, {TILE_SIZE, 0, 40}, {}},
1226 {{}, {0, TILE_SIZE, 40}, {}},
1227 };
1228
1229 /* The sprites under the vehicles are drawn as SpriteCombine. StartSpriteCombine() has already been called
1230 * The bounding boxes here are the same as for bridge front/roof */
1231 for (uint i = 0; i < lengthof(seq_back); ++i) {
1232 if (seq_back[i] != 0) {
1233 AddSortableSpriteToDraw(seq_back[i], PAL_NONE, x, y, z, back_bounds[offset], trans_back[i]);
1234 }
1235 }
1236
1237 /* Start a new SpriteCombine for the front part */
1240
1241 static constexpr SpriteBounds front_bounds[6] = {
1242 {{15, 0, 0}, {0, TILE_SIZE, 40}, {-15, 0, 0}},
1243 {{0, 15, 0}, {TILE_SIZE, 0, 40}, {0, -15, 0}},
1244 {{0, 15, 0}, {TILE_SIZE, 0, 40}, {0, -15, 0}},
1245 {{15, 0, 0}, {0, TILE_SIZE, 40}, {-15, 0, 0}},
1246 {{0, 15, 0}, {TILE_SIZE, 0, 40}, {0, -15, 0}},
1247 {{15, 0, 0}, {0, TILE_SIZE, 40}, {-15, 0, 0}},
1248 };
1249
1250 for (uint i = 0; i < lengthof(seq_front); ++i) {
1251 if (seq_front[i] != 0) {
1252 AddSortableSpriteToDraw(seq_front[i], PAL_NONE, x, y, z, front_bounds[offset], trans_front[i]);
1253 }
1254 }
1255}
1256
1271{
1272 TransportType transport_type = GetTunnelBridgeTransportType(ti->tile);
1273 DiagDirection tunnelbridge_direction = GetTunnelBridgeDirection(ti->tile);
1274
1275 if (IsTunnel(ti->tile)) {
1276 /* Front view of tunnel bounding boxes:
1277 *
1278 * 122223 <- BB_Z_SEPARATOR
1279 * 1 3
1280 * 1 3 1,3 = empty helper BB
1281 * 1 3 2 = SpriteCombine of tunnel-roof and catenary (tram & elrail)
1282 *
1283 */
1284
1285 /* Tunnel sprites are positioned at 15,15, but the bounding box covers most of the tile. */
1286 static constexpr SpriteBounds roof_bounds[DIAGDIR_END] = {
1287 {{0, 1, BB_Z_SEPARATOR}, {TILE_SIZE, TILE_SIZE - 1, 1}, {TILE_SIZE - 1, TILE_SIZE - 2, -BB_Z_SEPARATOR}}, // NE
1288 {{1, 0, BB_Z_SEPARATOR}, {TILE_SIZE - 1, TILE_SIZE, 1}, {TILE_SIZE - 2, TILE_SIZE - 1, -BB_Z_SEPARATOR}}, // SE
1289 {{0, 1, BB_Z_SEPARATOR}, {TILE_SIZE, TILE_SIZE - 1, 1}, {TILE_SIZE - 1, TILE_SIZE - 2, -BB_Z_SEPARATOR}}, // SW
1290 {{1, 0, BB_Z_SEPARATOR}, {TILE_SIZE - 1, TILE_SIZE, 1}, {TILE_SIZE - 2, TILE_SIZE - 1, -BB_Z_SEPARATOR}}, // NW
1291 };
1292
1293 /* Catenary sprites are positioned at 0,0, with the same bounding box as above. */
1294 static constexpr SpriteBounds catenary_bounds[DIAGDIR_END] = {
1295 {{0, 1, BB_Z_SEPARATOR}, {TILE_SIZE, TILE_SIZE - 1, 1}, {0, -1, -BB_Z_SEPARATOR}}, // NE
1296 {{1, 0, BB_Z_SEPARATOR}, {TILE_SIZE - 1, TILE_SIZE, 1}, {-1, 0, -BB_Z_SEPARATOR}}, // SE
1297 {{0, 1, BB_Z_SEPARATOR}, {TILE_SIZE, TILE_SIZE - 1, 1}, {0, -1, -BB_Z_SEPARATOR}}, // SW
1298 {{1, 0, BB_Z_SEPARATOR}, {TILE_SIZE - 1, TILE_SIZE, 1}, {-1, 0, -BB_Z_SEPARATOR}}, // NW
1299 };
1300
1301 static constexpr SpriteBounds rear_sep[DIAGDIR_END] = {
1302 {{}, {TILE_SIZE, 1, TILE_HEIGHT}, {}}, // NE
1303 {{}, {1, TILE_SIZE, TILE_HEIGHT}, {}}, // SE
1304 {{}, {TILE_SIZE, 1, TILE_HEIGHT}, {}}, // SW
1305 {{}, {1, TILE_SIZE, TILE_HEIGHT}, {}}, // NW
1306 };
1307
1308 static constexpr SpriteBounds front_sep[DIAGDIR_END] = {
1309 {{0, TILE_SIZE - 1, 0}, {TILE_SIZE, 1, TILE_HEIGHT}, {}}, // NE
1310 {{TILE_SIZE - 1, 0, 0}, {1, TILE_SIZE, TILE_HEIGHT}, {}}, // SE
1311 {{0, TILE_SIZE - 1, 0}, {TILE_SIZE, 1, TILE_HEIGHT}, {}}, // SW
1312 {{TILE_SIZE - 1, 0, 0}, {1, TILE_SIZE, TILE_HEIGHT}, {}}, // NW
1313 };
1314
1315 bool catenary = false;
1316
1317 SpriteID image;
1318 SpriteID railtype_overlay = 0;
1319 if (transport_type == TRANSPORT_RAIL) {
1320 const RailTypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
1321 image = rti->base_sprites.tunnel;
1322 if (rti->UsesOverlay()) {
1323 /* Check if the railtype has custom tunnel portals. */
1324 railtype_overlay = GetCustomRailSprite(rti, ti->tile, RTSG_TUNNEL_PORTAL);
1325 if (railtype_overlay != 0) image = SPR_RAILTYPE_TUNNEL_BASE; // Draw blank grass tunnel base.
1326 }
1327 } else {
1328 image = SPR_TUNNEL_ENTRY_REAR_ROAD;
1329 }
1330
1331 if (HasTunnelBridgeSnowOrDesert(ti->tile)) image += railtype_overlay != 0 ? 8 : 32;
1332
1333 image += tunnelbridge_direction * 2;
1334 DrawGroundSprite(image, PAL_NONE);
1335
1336 if (transport_type == TRANSPORT_ROAD) {
1337 RoadType road_rt = GetRoadTypeRoad(ti->tile);
1338 RoadType tram_rt = GetRoadTypeTram(ti->tile);
1339 const RoadTypeInfo *road_rti = road_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(road_rt);
1340 const RoadTypeInfo *tram_rti = tram_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(tram_rt);
1341 uint sprite_offset = DiagDirToAxis(tunnelbridge_direction) == AXIS_X ? 1 : 0;
1342 bool draw_underlay = true;
1343
1344 /* Road underlay takes precedence over tram */
1345 if (road_rti != nullptr) {
1346 if (road_rti->UsesOverlay()) {
1347 SpriteID ground = GetCustomRoadSprite(road_rti, ti->tile, ROTSG_TUNNEL);
1348 if (ground != 0) {
1349 DrawGroundSprite(ground + tunnelbridge_direction, PAL_NONE);
1350 draw_underlay = false;
1351 }
1352 }
1353 } else {
1354 if (tram_rti->UsesOverlay()) {
1355 SpriteID ground = GetCustomRoadSprite(tram_rti, ti->tile, ROTSG_TUNNEL);
1356 if (ground != 0) {
1357 DrawGroundSprite(ground + tunnelbridge_direction, PAL_NONE);
1358 draw_underlay = false;
1359 }
1360 }
1361 }
1362
1363 DrawRoadOverlays(ti, PAL_NONE, road_rti, tram_rti, sprite_offset, sprite_offset, draw_underlay);
1364
1365 /* Road catenary takes precedence over tram */
1366 SpriteID catenary_sprite_base = 0;
1367 if (road_rti != nullptr && HasRoadCatenaryDrawn(road_rt)) {
1368 catenary_sprite_base = GetCustomRoadSprite(road_rti, ti->tile, ROTSG_CATENARY_FRONT);
1369 if (catenary_sprite_base == 0) {
1370 catenary_sprite_base = SPR_TRAMWAY_TUNNEL_WIRES;
1371 } else {
1372 catenary_sprite_base += 19;
1373 }
1374 } else if (tram_rti != nullptr && HasRoadCatenaryDrawn(tram_rt)) {
1375 catenary_sprite_base = GetCustomRoadSprite(tram_rti, ti->tile, ROTSG_CATENARY_FRONT);
1376 if (catenary_sprite_base == 0) {
1377 catenary_sprite_base = SPR_TRAMWAY_TUNNEL_WIRES;
1378 } else {
1379 catenary_sprite_base += 19;
1380 }
1381 }
1382
1383 if (catenary_sprite_base != 0) {
1384 catenary = true;
1386 AddSortableSpriteToDraw(catenary_sprite_base + tunnelbridge_direction, PAL_NONE, *ti, catenary_bounds[tunnelbridge_direction], IsTransparencySet(TO_CATENARY));
1387 }
1388 } else {
1389 const RailTypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
1390 if (rti->UsesOverlay()) {
1391 SpriteID surface = GetCustomRailSprite(rti, ti->tile, RTSG_TUNNEL);
1392 if (surface != 0) DrawGroundSprite(surface + tunnelbridge_direction, PAL_NONE);
1393 }
1394
1395 /* PBS debugging, draw reserved tracks darker */
1396 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasTunnelBridgeReservation(ti->tile)) {
1397 if (rti->UsesOverlay()) {
1398 SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
1399 DrawGroundSprite(overlay + RTO_X + DiagDirToAxis(tunnelbridge_direction), PALETTE_CRASH);
1400 } else {
1402 }
1403 }
1404
1406 /* Maybe draw pylons on the entry side */
1407 DrawRailCatenary(ti);
1408
1409 catenary = true;
1411 /* Draw wire above the ramp */
1413 }
1414 }
1415
1416 if (railtype_overlay != 0 && !catenary) StartSpriteCombine();
1417
1418 AddSortableSpriteToDraw(image + 1, PAL_NONE, *ti, roof_bounds[tunnelbridge_direction], false);
1419 /* Draw railtype tunnel portal overlay if defined. */
1420 if (railtype_overlay != 0) AddSortableSpriteToDraw(railtype_overlay + tunnelbridge_direction, PAL_NONE, *ti, roof_bounds[tunnelbridge_direction], false);
1421
1422 if (catenary || railtype_overlay != 0) EndSpriteCombine();
1423
1424 /* Add helper BB for sprite sorting that separates the tunnel from things beside of it. */
1425 AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, *ti, rear_sep[tunnelbridge_direction]);
1426 AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, *ti, front_sep[tunnelbridge_direction]);
1427
1428 DrawBridgeMiddle(ti, BridgePillarFlag::EdgeNE + tunnelbridge_direction);
1429 } else { // IsBridge(ti->tile)
1430 DrawFoundation(ti, GetBridgeFoundation(ti->tileh, DiagDirToAxis(tunnelbridge_direction)));
1431
1432 uint base_offset = GetBridgeRampDirectionBaseOffset(tunnelbridge_direction);
1433 std::span<const PalSpriteID> psid;
1434 if (transport_type != TRANSPORT_WATER) {
1435 if (ti->tileh == SLOPE_FLAT) base_offset += 4; // sloped bridge head
1436 base_offset += GetBridgeSpriteTableBaseOffset(transport_type, ti->tile);
1437 psid = GetBridgeSpriteTable(GetBridgeType(ti->tile), BRIDGE_PIECE_HEAD);
1438 } else {
1439 psid = _aqueduct_sprite_table_heads;
1440 }
1441 psid = psid.subspan(base_offset, 1);
1442
1444 TileIndex next = ti->tile + TileOffsByDiagDir(tunnelbridge_direction);
1445 if (ti->tileh != SLOPE_FLAT && ti->z == 0 && HasTileWaterClass(next) && GetWaterClass(next) == WATER_CLASS_SEA) {
1446 DrawShoreTile(ti->tileh);
1447 } else {
1448 DrawClearLandTile(ti, 3);
1449 }
1450 } else {
1451 DrawGroundSprite(SPR_FLAT_SNOW_DESERT_TILE + SlopeToSpriteOffset(ti->tileh), PAL_NONE);
1452 }
1453
1454 /* draw ramp */
1455
1456 /* Draw Trambits and PBS Reservation as SpriteCombine */
1457 if (transport_type == TRANSPORT_ROAD || transport_type == TRANSPORT_RAIL) StartSpriteCombine();
1458
1459 /* HACK set the height of the BB of a sloped ramp to 1 so a vehicle on
1460 * it doesn't disappear behind it
1461 */
1462 /* Bridge heads are drawn solid no matter how invisibility/transparency is set */
1463 AddSortableSpriteToDraw(psid[0].sprite, psid[0].pal, *ti, {{}, {TILE_SIZE, TILE_SIZE, static_cast<uint8_t>(ti->tileh == SLOPE_FLAT ? 0 : TILE_HEIGHT)}, {}});
1464
1465 if (transport_type == TRANSPORT_ROAD) {
1466 uint offset = tunnelbridge_direction;
1467 int z = ti->z;
1468 if (ti->tileh != SLOPE_FLAT) {
1469 offset = (offset + 1) & 1;
1470 z += TILE_HEIGHT;
1471 } else {
1472 offset += 2;
1473 }
1474
1475 /* DrawBridgeRoadBits() calls EndSpriteCombine() and StartSpriteCombine() */
1476 DrawBridgeRoadBits(ti->tile, ti->x, ti->y, z, offset, true);
1477
1479 } else if (transport_type == TRANSPORT_RAIL) {
1480 const RailTypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
1481 if (rti->UsesOverlay()) {
1482 SpriteID surface = GetCustomRailSprite(rti, ti->tile, RTSG_BRIDGE);
1483 if (surface != 0) {
1484 if (HasBridgeFlatRamp(ti->tileh, DiagDirToAxis(tunnelbridge_direction))) {
1485 AddSortableSpriteToDraw(surface + ((DiagDirToAxis(tunnelbridge_direction) == AXIS_X) ? RTBO_X : RTBO_Y), PAL_NONE, *ti, {{0, 0, TILE_HEIGHT}, {TILE_SIZE, TILE_SIZE, 0}, {}});
1486 } else {
1487 AddSortableSpriteToDraw(surface + RTBO_SLOPE + tunnelbridge_direction, PAL_NONE, *ti, {{}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT}, {}});
1488 }
1489 }
1490 /* Don't fallback to non-overlay sprite -- the spec states that
1491 * if an overlay is present then the bridge surface must be
1492 * present. */
1493 }
1494
1495 /* PBS debugging, draw reserved tracks darker */
1496 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasTunnelBridgeReservation(ti->tile)) {
1497 if (rti->UsesOverlay()) {
1498 SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
1499 if (HasBridgeFlatRamp(ti->tileh, DiagDirToAxis(tunnelbridge_direction))) {
1500 AddSortableSpriteToDraw(overlay + RTO_X + DiagDirToAxis(tunnelbridge_direction), PALETTE_CRASH, *ti, {{0, 0, TILE_HEIGHT}, {TILE_SIZE, TILE_SIZE, 0}, {}});
1501 } else {
1502 AddSortableSpriteToDraw(overlay + RTO_SLOPE_NE + tunnelbridge_direction, PALETTE_CRASH, *ti, {{}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT}, {}});
1503 }
1504 } else {
1505 if (HasBridgeFlatRamp(ti->tileh, DiagDirToAxis(tunnelbridge_direction))) {
1506 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}, {}});
1507 } else {
1508 AddSortableSpriteToDraw(rti->base_sprites.single_sloped + tunnelbridge_direction, PALETTE_CRASH, *ti, {{}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT}, {}});
1509 }
1510 }
1511 }
1512
1515 DrawRailCatenary(ti);
1516 }
1517 }
1518
1519 BridgePillarFlags blocked_pillars;
1520 if (DiagDirToAxis(tunnelbridge_direction) == AXIS_X) {
1521 blocked_pillars = {BridgePillarFlag::EdgeSW, BridgePillarFlag::EdgeNE};
1522 } else {
1523 blocked_pillars = {BridgePillarFlag::EdgeNW, BridgePillarFlag::EdgeSE};
1524 }
1525 DrawBridgeMiddle(ti, blocked_pillars);
1526 }
1527}
1528
1529
1548static BridgePieces CalcBridgePiece(uint north, uint south)
1549{
1550 if (north == 1) {
1551 return BRIDGE_PIECE_NORTH;
1552 } else if (south == 1) {
1553 return BRIDGE_PIECE_SOUTH;
1554 } else if (north < south) {
1555 return north & 1 ? BRIDGE_PIECE_INNER_SOUTH : BRIDGE_PIECE_INNER_NORTH;
1556 } else if (north > south) {
1557 return south & 1 ? BRIDGE_PIECE_INNER_NORTH : BRIDGE_PIECE_INNER_SOUTH;
1558 } else {
1559 return north & 1 ? BRIDGE_PIECE_MIDDLE_EVEN : BRIDGE_PIECE_MIDDLE_ODD;
1560 }
1561}
1562
1573{
1574 if (transport_type == TRANSPORT_WATER) return BRIDGEPILLARFLAGS_ALL_CORNERS;
1575
1576 const BridgeSpec *spec = GetBridgeSpec(type);
1578 BridgePieces piece = CalcBridgePiece(GetTunnelBridgeLength(tile, rampnorth) + 1, GetTunnelBridgeLength(tile, rampsouth) + 1);
1579 Axis axis = TileX(rampnorth) == TileX(rampsouth) ? AXIS_Y : AXIS_X;
1580
1581 return spec->pillar_flags[piece][axis == AXIS_Y ? 1 : 0];
1582 }
1583
1584 return BRIDGEPILLARFLAGS_ALL_CORNERS;
1585}
1586
1592void DrawBridgeMiddle(const TileInfo *ti, BridgePillarFlags blocked_pillars)
1593{
1594 /* Sectional view of bridge bounding boxes:
1595 *
1596 * 1 2 1,2 = SpriteCombine of Bridge front/(back&floor) and RoadCatenary
1597 * 1 2 3 = empty helper BB
1598 * 1 7 2 4,5 = pillars under higher bridges
1599 * 1 6 88888 6 2 6 = elrail-pylons
1600 * 1 6 88888 6 2 7 = elrail-wire
1601 * 1 6 88888 6 2 <- TILE_HEIGHT 8 = rail-vehicle on bridge
1602 * 3333333333333 <- BB_Z_SEPARATOR
1603 * <- unused
1604 * 4 5 <- BB_HEIGHT_UNDER_BRIDGE
1605 * 4 5
1606 * 4 5
1607 *
1608 */
1609
1610 if (!IsBridgeAbove(ti->tile)) return;
1611
1612 TileIndex rampnorth = GetNorthernBridgeEnd(ti->tile);
1613 TileIndex rampsouth = GetSouthernBridgeEnd(ti->tile);
1614 TransportType transport_type = GetTunnelBridgeTransportType(rampsouth);
1615 Axis axis = GetBridgeAxis(ti->tile);
1616 BridgePillarFlags pillars;
1617
1618 uint base_offset = GetBridgeMiddleAxisBaseOffset(axis);
1619 std::span<const PalSpriteID> psid;
1620 bool drawfarpillar;
1621 if (transport_type != TRANSPORT_WATER) {
1622 BridgeType bridge_type = GetBridgeType(rampsouth);
1623 drawfarpillar = !HasBit(GetBridgeSpec(bridge_type)->flags, 0);
1624 base_offset += GetBridgeSpriteTableBaseOffset(transport_type, rampsouth);
1625 psid = GetBridgeSpriteTable(bridge_type, CalcBridgePiece(GetTunnelBridgeLength(ti->tile, rampnorth) + 1, GetTunnelBridgeLength(ti->tile, rampsouth) + 1));
1626 pillars = GetBridgeTilePillarFlags(ti->tile, rampnorth, rampsouth, bridge_type, transport_type);
1627 } else {
1628 drawfarpillar = true;
1629 psid = _aqueduct_sprite_table_middle;
1630 pillars = BRIDGEPILLARFLAGS_ALL_CORNERS;
1631 }
1632 psid = psid.subspan(base_offset, 3);
1633
1634 int x = ti->x;
1635 int y = ti->y;
1636 uint bridge_z = GetBridgePixelHeight(rampsouth);
1637 int z = bridge_z - BRIDGE_Z_START;
1638
1639 /* Add a bounding box that separates the bridge from things below it. */
1640 AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, x, y, bridge_z - TILE_HEIGHT + BB_Z_SEPARATOR, {{}, {TILE_SIZE, TILE_SIZE, 1}, {}});
1641
1642 /* Draw Trambits as SpriteCombine */
1643 if (transport_type == TRANSPORT_ROAD || transport_type == TRANSPORT_RAIL) StartSpriteCombine();
1644
1645 /* Draw floor and far part of bridge*/
1647 if (axis == AXIS_X) {
1648 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));
1649 } else {
1650 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));
1651 }
1652 }
1653
1654 if (transport_type == TRANSPORT_ROAD) {
1655 /* DrawBridgeRoadBits() calls EndSpriteCombine() and StartSpriteCombine() */
1656 DrawBridgeRoadBits(rampsouth, x, y, bridge_z, axis ^ 1, false);
1657 } else if (transport_type == TRANSPORT_RAIL) {
1658 const RailTypeInfo *rti = GetRailTypeInfo(GetRailType(rampsouth));
1659 if (rti->UsesOverlay() && !IsInvisibilitySet(TO_BRIDGES)) {
1660 SpriteID surface = GetCustomRailSprite(rti, rampsouth, RTSG_BRIDGE, TCX_ON_BRIDGE);
1661 if (surface != 0) {
1662 AddSortableSpriteToDraw(surface + axis, PAL_NONE, x, y, bridge_z, {{}, {TILE_SIZE, TILE_SIZE, 0}, {}}, IsTransparencySet(TO_BRIDGES));
1663 }
1664 }
1665
1667 if (rti->UsesOverlay()) {
1668 SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
1669 AddSortableSpriteToDraw(overlay + RTO_X + axis, PALETTE_CRASH, ti->x, ti->y, bridge_z, {{}, {TILE_SIZE, TILE_SIZE, 0}, {}}, IsTransparencySet(TO_BRIDGES));
1670 } else {
1672 }
1673 }
1674
1676
1677 if (HasRailCatenaryDrawn(GetRailType(rampsouth))) {
1679 }
1680 }
1681
1682 /* draw roof, the component of the bridge which is logically between the vehicle and the camera */
1684 if (axis == AXIS_X) {
1685 y += 12;
1686 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));
1687 } else {
1688 x += 12;
1689 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));
1690 }
1691 }
1692
1693 /* Draw TramFront as SpriteCombine */
1694 if (transport_type == TRANSPORT_ROAD) EndSpriteCombine();
1695
1696 /* Do not draw anything more if bridges are invisible */
1697 if (IsInvisibilitySet(TO_BRIDGES)) return;
1698
1699 if (blocked_pillars.Any(pillars)) return;
1700 DrawBridgePillars(psid[2], ti, axis, drawfarpillar, x, y, z);
1701}
1702
1703
1704static int GetSlopePixelZ_TunnelBridge(TileIndex tile, uint x, uint y, bool ground_vehicle)
1705{
1706 auto [tileh, z] = GetTilePixelSlope(tile);
1707
1708 x &= 0xF;
1709 y &= 0xF;
1710
1711 if (IsTunnel(tile)) {
1712 /* In the tunnel entrance? */
1713 if (ground_vehicle) return z;
1714 } else { // IsBridge(tile)
1717
1718 /* On the bridge ramp? */
1719 if (ground_vehicle) {
1720 if (tileh != SLOPE_FLAT) return z + TILE_HEIGHT;
1721
1722 switch (dir) {
1723 default: NOT_REACHED();
1724 case DIAGDIR_NE: tileh = SLOPE_NE; break;
1725 case DIAGDIR_SE: tileh = SLOPE_SE; break;
1726 case DIAGDIR_SW: tileh = SLOPE_SW; break;
1727 case DIAGDIR_NW: tileh = SLOPE_NW; break;
1728 }
1729 }
1730 }
1731
1732 return z + GetPartialPixelZ(x, y, tileh);
1733}
1734
1735static Foundation GetFoundation_TunnelBridge(TileIndex tile, Slope tileh)
1736{
1738}
1739
1740static void GetTileDesc_TunnelBridge(TileIndex tile, TileDesc &td)
1741{
1743
1744 if (IsTunnel(tile)) {
1745 td.str = (tt == TRANSPORT_RAIL) ? STR_LAI_TUNNEL_DESCRIPTION_RAILROAD : STR_LAI_TUNNEL_DESCRIPTION_ROAD;
1746 } else { // IsBridge(tile)
1747 td.str = (tt == TRANSPORT_WATER) ? STR_LAI_BRIDGE_DESCRIPTION_AQUEDUCT : GetBridgeSpec(GetBridgeType(tile))->transport_name[tt];
1748 }
1749 td.owner[0] = GetTileOwner(tile);
1750
1751 Owner road_owner = INVALID_OWNER;
1752 Owner tram_owner = INVALID_OWNER;
1753 RoadType road_rt = (tt == TRANSPORT_ROAD) ? GetRoadTypeRoad(tile) : INVALID_ROADTYPE;
1754 RoadType tram_rt = (tt == TRANSPORT_ROAD) ? GetRoadTypeTram(tile) : INVALID_ROADTYPE;
1755 if (road_rt != INVALID_ROADTYPE) {
1756 const RoadTypeInfo *rti = GetRoadTypeInfo(road_rt);
1757 td.roadtype = rti->strings.name;
1758 td.road_speed = rti->max_speed / 2;
1759 road_owner = GetRoadOwner(tile, RTT_ROAD);
1760 }
1761 if (tram_rt != INVALID_ROADTYPE) {
1762 const RoadTypeInfo *rti = GetRoadTypeInfo(tram_rt);
1763 td.tramtype = rti->strings.name;
1764 td.tram_speed = rti->max_speed / 2;
1765 tram_owner = GetRoadOwner(tile, RTT_TRAM);
1766 }
1767
1768 /* Is there a mix of owners? */
1769 if ((tram_owner != INVALID_OWNER && tram_owner != td.owner[0]) ||
1770 (road_owner != INVALID_OWNER && road_owner != td.owner[0])) {
1771 uint i = 1;
1772 if (road_owner != INVALID_OWNER) {
1773 td.owner_type[i] = STR_LAND_AREA_INFORMATION_ROAD_OWNER;
1774 td.owner[i] = road_owner;
1775 i++;
1776 }
1777 if (tram_owner != INVALID_OWNER) {
1778 td.owner_type[i] = STR_LAND_AREA_INFORMATION_TRAM_OWNER;
1779 td.owner[i] = tram_owner;
1780 }
1781 }
1782
1783 if (tt == TRANSPORT_RAIL) {
1784 const RailTypeInfo *rti = GetRailTypeInfo(GetRailType(tile));
1785 td.rail_speed = rti->max_speed;
1786 td.railtype = rti->strings.name;
1787
1788 if (!IsTunnel(tile)) {
1789 uint16_t spd = GetBridgeSpec(GetBridgeType(tile))->speed;
1790 /* rail speed special-cases 0 as unlimited, hides display of limit etc. */
1791 if (spd == UINT16_MAX) spd = 0;
1792 if (td.rail_speed == 0 || spd < td.rail_speed) {
1793 td.rail_speed = spd;
1794 }
1795 }
1796 } else if (tt == TRANSPORT_ROAD && !IsTunnel(tile)) {
1797 uint16_t spd = GetBridgeSpec(GetBridgeType(tile))->speed;
1798 /* road speed special-cases 0 as unlimited, hides display of limit etc. */
1799 if (spd == UINT16_MAX) spd = 0;
1800 if (road_rt != INVALID_ROADTYPE && (td.road_speed == 0 || spd < td.road_speed)) td.road_speed = spd;
1801 if (tram_rt != INVALID_ROADTYPE && (td.tram_speed == 0 || spd < td.tram_speed)) td.tram_speed = spd;
1802 }
1803}
1804
1805
1806static void TileLoop_TunnelBridge(TileIndex tile)
1807{
1808 bool snow_or_desert = HasTunnelBridgeSnowOrDesert(tile);
1810 case LandscapeType::Arctic: {
1811 /* As long as we do not have a snow density, we want to use the density
1812 * from the entry edge. For tunnels this is the lowest point for bridges the highest point.
1813 * (Independent of foundations) */
1814 int z = IsBridge(tile) ? GetTileMaxZ(tile) : GetTileZ(tile);
1815 if (snow_or_desert != (z > GetSnowLine())) {
1816 SetTunnelBridgeSnowOrDesert(tile, !snow_or_desert);
1817 MarkTileDirtyByTile(tile);
1818 }
1819 break;
1820 }
1821
1822 case LandscapeType::Tropic:
1823 if (GetTropicZone(tile) == TROPICZONE_DESERT && !snow_or_desert) {
1824 SetTunnelBridgeSnowOrDesert(tile, true);
1825 MarkTileDirtyByTile(tile);
1826 }
1827 break;
1828
1829 default:
1830 break;
1831 }
1832}
1833
1834static TrackStatus GetTileTrackStatus_TunnelBridge(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
1835{
1836 TransportType transport_type = GetTunnelBridgeTransportType(tile);
1837 if (transport_type != mode || (transport_type == TRANSPORT_ROAD && !HasTileRoadType(tile, (RoadTramType)sub_mode))) return 0;
1838
1840 if (side != INVALID_DIAGDIR && side != ReverseDiagDir(dir)) return 0;
1842}
1843
1844static void ChangeTileOwner_TunnelBridge(TileIndex tile, Owner old_owner, Owner new_owner)
1845{
1846 TileIndex other_end = GetOtherTunnelBridgeEnd(tile);
1847 /* Set number of pieces to zero if it's the southern tile as we
1848 * don't want to update the infrastructure counts twice. */
1849 uint num_pieces = tile < other_end ? (GetTunnelBridgeLength(tile, other_end) + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR : 0;
1850
1852
1853 if (tt == TRANSPORT_ROAD) {
1854 for (RoadTramType rtt : _roadtramtypes) {
1855 /* Update all roadtypes, no matter if they are present */
1856 if (GetRoadOwner(tile, rtt) == old_owner) {
1857 RoadType rt = GetRoadType(tile, rtt);
1858 if (rt != INVALID_ROADTYPE) {
1859 /* Update company infrastructure counts. A full diagonal road tile has two road bits.
1860 * No need to dirty windows here, we'll redraw the whole screen anyway. */
1861 Company::Get(old_owner)->infrastructure.road[rt] -= num_pieces * 2;
1862 if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.road[rt] += num_pieces * 2;
1863 }
1864
1865 SetRoadOwner(tile, rtt, new_owner == INVALID_OWNER ? OWNER_NONE : new_owner);
1866 }
1867 }
1868 }
1869
1870 if (!IsTileOwner(tile, old_owner)) return;
1871
1872 /* Update company infrastructure counts for rail and water as well.
1873 * No need to dirty windows here, we'll redraw the whole screen anyway. */
1874 Company *old = Company::Get(old_owner);
1875 if (tt == TRANSPORT_RAIL) {
1876 old->infrastructure.rail[GetRailType(tile)] -= num_pieces;
1877 if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.rail[GetRailType(tile)] += num_pieces;
1878 } else if (tt == TRANSPORT_WATER) {
1879 old->infrastructure.water -= num_pieces;
1880 if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.water += num_pieces;
1881 }
1882
1883 if (new_owner != INVALID_OWNER) {
1884 SetTileOwner(tile, new_owner);
1885 } else {
1886 if (tt == TRANSPORT_RAIL) {
1887 /* Since all of our vehicles have been removed, it is safe to remove the rail
1888 * bridge / tunnel. */
1890 assert(ret.Succeeded());
1891 } else {
1892 /* In any other case, we can safely reassign the ownership to OWNER_NONE. */
1893 SetTileOwner(tile, OWNER_NONE);
1894 }
1895 }
1896}
1897
1910template <typename T>
1911static void PrepareToEnterBridge(T *gv)
1912{
1913 if (HasBit(gv->gv_flags, GVF_GOINGUP_BIT)) {
1914 gv->z_pos++;
1915 ClrBit(gv->gv_flags, GVF_GOINGUP_BIT);
1916 } else {
1917 ClrBit(gv->gv_flags, GVF_GOINGDOWN_BIT);
1918 }
1919}
1920
1926static const uint8_t TUNNEL_SOUND_FRAME = 1;
1927
1936extern const uint8_t _tunnel_visibility_frame[DIAGDIR_END] = {12, 8, 8, 12};
1937
1938static VehicleEnterTileStates VehicleEnter_TunnelBridge(Vehicle *v, TileIndex tile, int x, int y)
1939{
1940 int z = GetSlopePixelZ(x, y, true) - v->z_pos;
1941
1942 if (abs(z) > 2) return VehicleEnterTileState::CannotEnter;
1943 /* Direction into the wormhole */
1944 const DiagDirection dir = GetTunnelBridgeDirection(tile);
1945 /* Direction of the vehicle */
1946 const DiagDirection vdir = DirToDiagDir(v->direction);
1947 /* New position of the vehicle on the tile */
1948 uint8_t pos = (DiagDirToAxis(vdir) == AXIS_X ? x : y) & TILE_UNIT_MASK;
1949 /* Number of units moved by the vehicle since entering the tile */
1950 uint8_t frame = (vdir == DIAGDIR_NE || vdir == DIAGDIR_NW) ? TILE_SIZE - 1 - pos : pos;
1951
1952 if (IsTunnel(tile)) {
1953 if (v->type == VEH_TRAIN) {
1954 Train *t = Train::From(v);
1955
1956 if (t->track != TRACK_BIT_WORMHOLE && dir == vdir) {
1957 if (t->IsFrontEngine() && frame == TUNNEL_SOUND_FRAME) {
1958 if (!PlayVehicleSound(t, VSE_TUNNEL) && RailVehInfo(t->engine_type)->engclass == 0) {
1959 SndPlayVehicleFx(SND_05_TRAIN_THROUGH_TUNNEL, v);
1960 }
1961 return {};
1962 }
1963 if (frame == _tunnel_visibility_frame[dir]) {
1964 t->tile = tile;
1965 t->track = TRACK_BIT_WORMHOLE;
1968 }
1969 }
1970
1971 if (dir == ReverseDiagDir(vdir) && frame == TILE_SIZE - _tunnel_visibility_frame[dir] && z == 0) {
1972 /* We're at the tunnel exit ?? */
1973 t->tile = tile;
1974 t->track = DiagDirToDiagTrackBits(vdir);
1975 assert(t->track);
1978 }
1979 } else if (v->type == VEH_ROAD) {
1981
1982 /* Enter tunnel? */
1983 if (rv->state != RVSB_WORMHOLE && dir == vdir) {
1984 if (frame == _tunnel_visibility_frame[dir]) {
1985 /* Frame should be equal to the next frame number in the RV's movement */
1986 assert(frame == rv->frame + 1);
1987 rv->tile = tile;
1988 rv->state = RVSB_WORMHOLE;
1991 } else {
1992 return {};
1993 }
1994 }
1995
1996 /* We're at the tunnel exit ?? */
1997 if (dir == ReverseDiagDir(vdir) && frame == TILE_SIZE - _tunnel_visibility_frame[dir] && z == 0) {
1998 rv->tile = tile;
1999 rv->state = DiagDirToDiagTrackdir(vdir);
2000 rv->frame = frame;
2003 }
2004 }
2005 } else { // IsBridge(tile)
2006 if (v->type != VEH_SHIP) {
2007 /* modify speed of vehicle */
2008 uint16_t spd = GetBridgeSpec(GetBridgeType(tile))->speed;
2009
2010 if (v->type == VEH_ROAD) spd *= 2;
2011 Vehicle *first = v->First();
2012 first->cur_speed = std::min(first->cur_speed, spd);
2013 }
2014
2015 if (vdir == dir) {
2016 /* Vehicle enters bridge at the last frame inside this tile. */
2017 if (frame != TILE_SIZE - 1) return {};
2018 switch (v->type) {
2019 case VEH_TRAIN: {
2020 Train *t = Train::From(v);
2021 t->track = TRACK_BIT_WORMHOLE;
2023 break;
2024 }
2025
2026 case VEH_ROAD: {
2028 rv->state = RVSB_WORMHOLE;
2030 break;
2031 }
2032
2033 case VEH_SHIP:
2035 break;
2036
2037 default: NOT_REACHED();
2038 }
2040 } else if (vdir == ReverseDiagDir(dir)) {
2041 v->tile = tile;
2042 switch (v->type) {
2043 case VEH_TRAIN: {
2044 Train *t = Train::From(v);
2045 if (t->track == TRACK_BIT_WORMHOLE) {
2046 t->track = DiagDirToDiagTrackBits(vdir);
2048 }
2049 break;
2050 }
2051
2052 case VEH_ROAD: {
2054 if (rv->state == RVSB_WORMHOLE) {
2055 rv->state = DiagDirToDiagTrackdir(vdir);
2056 rv->frame = 0;
2058 }
2059 break;
2060 }
2061
2062 case VEH_SHIP: {
2063 Ship *ship = Ship::From(v);
2064 if (ship->state == TRACK_BIT_WORMHOLE) {
2065 ship->state = DiagDirToDiagTrackBits(vdir);
2067 }
2068 break;
2069 }
2070
2071 default: NOT_REACHED();
2072 }
2073 }
2074 }
2075 return {};
2076}
2077
2078static CommandCost TerraformTile_TunnelBridge(TileIndex tile, DoCommandFlags flags, int z_new, Slope tileh_new)
2079{
2081 DiagDirection direction = GetTunnelBridgeDirection(tile);
2082 Axis axis = DiagDirToAxis(direction);
2083 CommandCost res;
2084 auto [tileh_old, z_old] = GetTileSlopeZ(tile);
2085
2086 /* Check if new slope is valid for bridges in general (so we can safely call GetBridgeFoundation()) */
2087 if ((direction == DIAGDIR_NW) || (direction == DIAGDIR_NE)) {
2088 CheckBridgeSlope(BRIDGE_PIECE_SOUTH, axis, tileh_old, z_old);
2089 res = CheckBridgeSlope(BRIDGE_PIECE_SOUTH, axis, tileh_new, z_new);
2090 } else {
2091 CheckBridgeSlope(BRIDGE_PIECE_NORTH, axis, tileh_old, z_old);
2092 res = CheckBridgeSlope(BRIDGE_PIECE_NORTH, axis, tileh_new, z_new);
2093 }
2094
2095 /* Surface slope is valid and remains unchanged? */
2096 if (res.Succeeded() && (z_old == z_new) && (tileh_old == tileh_new)) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
2097 }
2098
2099 return Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile);
2100}
2101
2102static CommandCost CheckBuildAbove_TunnelBridge(TileIndex tile, DoCommandFlags flags, Axis axis, int height)
2103{
2104 if (IsTunnel(tile)) return CommandCost();
2105
2106 if (axis != DiagDirToAxis(GetTunnelBridgeDirection(tile)) && height > GetBridgeHeight(tile)) {
2107 return CommandCost();
2108 }
2109
2110 return Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile);
2111}
2112
2113extern const TileTypeProcs _tile_type_tunnelbridge_procs = {
2114 DrawTile_TunnelBridge, // draw_tile_proc
2115 GetSlopePixelZ_TunnelBridge, // get_slope_z_proc
2116 ClearTile_TunnelBridge, // clear_tile_proc
2117 nullptr, // add_accepted_cargo_proc
2118 GetTileDesc_TunnelBridge, // get_tile_desc_proc
2119 GetTileTrackStatus_TunnelBridge, // get_tile_track_status_proc
2120 nullptr, // click_tile_proc
2121 nullptr, // animate_tile_proc
2122 TileLoop_TunnelBridge, // tile_loop_proc
2123 ChangeTileOwner_TunnelBridge, // change_tile_owner_proc
2124 nullptr, // add_produced_cargo_proc
2125 VehicleEnter_TunnelBridge, // vehicle_enter_tile_proc
2126 GetFoundation_TunnelBridge, // get_foundation_proc
2127 TerraformTile_TunnelBridge, // terraform_tile_proc
2128 CheckBuildAbove_TunnelBridge, // check_build_above_proc
2129};
Functions related to autoslope.
bool AutoslopeEnabled()
Tests if autoslope is enabled for _current_company.
Definition autoslope.h:65
debug_inline 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
This file contains all the sprites for bridges It consists of a number of arrays.
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:181
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:169
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:153
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
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.
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?
Enum-as-bit-set wrapper.
This struct contains all the info that is needed to draw and construct tracks.
Definition rail.h:118
SpriteID single_x
single piece of rail in X direction, without ground
Definition rail.h:128
uint16_t max_speed
Maximum speed for vehicles travelling on this rail type.
Definition rail.h:222
struct RailTypeInfo::@20 base_sprites
Struct containing the main sprites.
SpriteID single_y
single piece of rail in Y direction, without ground
Definition rail.h:129
StringID name
Name of this rail type.
Definition rail.h:167
uint8_t bridge_offset
Bridge offset.
Definition rail.h:187
struct RailTypeInfo::@23 strings
Strings associated with the rail type.
SpriteID tunnel
tunnel sprites base
Definition rail.h:136
SpriteID single_sloped
single piece of rail for slopes
Definition rail.h:134
uint16_t max_speed
Maximum speed for vehicles travelling on this road type.
Definition road.h:133
StringID name
Name of this rail type.
Definition road.h:94
struct RoadTypeInfo::@26 strings
Strings associated with the rail type.
static Year year
Current year, starting at 0.
Functions related to clear (MP_CLEAR) land.
CommandCost CommandCostWithParam(StringID str, uint64_t value)
Return an error status, with string and parameter.
Definition command.cpp:417
Functions related to commands.
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
@ Execute
execute the given command
@ QueryCost
query cost only, don't build.
@ Bankrupt
company bankrupts, skip money check, skip vehicle on tile check in some cases
@ Auto
don't allow building on structures
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.
@ 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.
void DrawRailCatenaryOnBridge(const TileInfo *ti)
Draws wires on a tunnel tile.
Definition elrail.cpp:490
void DrawRailCatenaryOnTunnel(const TileInfo *ti)
Draws wires on a tunnel tile.
Definition elrail.cpp:249
void DrawRailCatenary(const TileInfo *ti)
Draws overhead wires and pylons for electric railways.
Definition elrail.cpp:550
header file for electrified rail specific functions
bool HasRailCatenaryDrawn(RailType rt)
Test if we should draw rail catenary.
Definition elrail_func.h:30
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23)
Definition enum_type.hpp:17
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.
uint GetPartialPixelZ(int x, int y, Slope corners)
Determines height at given coordinate of a slope.
void DrawFoundation(TileInfo *ti, Foundation f)
Draw foundation f at tile ti.
void GetSlopePixelZOnEdge(Slope tileh, DiagDirection edge, int &z1, int &z2)
Determine the Z height of the corners of a specific tile edge.
const TileTypeProcs *const _tile_type_procs[16]
Tile callback functions for each type of tile.
Definition landscape.cpp:66
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:126
Command definitions related to landscape (slopes etc.).
uint DistanceSquare(TileIndex t0, TileIndex t1)
Gets the 'Square' distance between the two given tiles.
Definition map.cpp:159
TileIndexDiff TileDiffXY(int x, int y)
Calculates an offset for the given coordinate(-offset).
Definition map_func.h:388
TileIndexDiff TileOffsByAxis(Axis axis)
Convert an Axis to a TileIndexDiff.
Definition map_func.h:554
static debug_inline uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition map_func.h:424
static debug_inline uint TileX(TileIndex tile)
Get the X component of a tile.
Definition map_func.h:414
TileIndexDiff TileOffsByDiagDir(DiagDirection dir)
Convert a DiagDirection to a TileIndexDiff.
Definition map_func.h:569
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, RailTypeSpriteGroup 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, RoadTypeSpriteGroup 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:331
PBS support routines.
bool ValParamRailType(const RailType rail)
Validate functions for rail building.
Definition rail.cpp:208
@ 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
Money RailClearCost(RailType railtype)
Returns the 'cost' of clearing the specified railtype.
Definition rail.h:392
Money RailBuildCost(RailType railtype)
Returns the cost of building the specified railtype.
Definition rail.h:381
const RailTypeInfo * GetRailTypeInfo(RailType railtype)
Returns a pointer to the Railtype information for a given railtype.
Definition rail.h:300
@ RTSG_TUNNEL
Main group of ground images for snow or desert.
Definition rail.h:44
@ RTSG_OVERLAY
Images for overlaying track.
Definition rail.h:42
@ RTSG_BRIDGE
Bridge surface images.
Definition rail.h:47
@ RTSG_TUNNEL_PORTAL
Tunnel portal overlay.
Definition rail.h:51
@ 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
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
@ INVALID_RAILTYPE
Flag for invalid railtype.
Definition rail_type.h:32
bool ValParamRoadType(RoadType roadtype)
Validate functions for rail building.
Definition road.cpp:152
Money RoadClearCost(RoadType roadtype)
Returns the cost of clearing the specified roadtype.
Definition road.h:279
const RoadTypeInfo * GetRoadTypeInfo(RoadType roadtype)
Returns a pointer to the Roadtype information for a given roadtype.
Definition road.h:230
@ ROTSG_OVERLAY
Optional: Images for overlaying track.
Definition road.h:52
@ ROTSG_CATENARY_BACK
Optional: Catenary back.
Definition road.h:56
@ ROTSG_BRIDGE
Required: Bridge surface images.
Definition road.h:57
@ ROTSG_CATENARY_FRONT
Optional: Catenary front.
Definition road.h:55
@ ROTSG_TUNNEL
Optional: Ground images for tunnels.
Definition road.h:54
Money RoadBuildCost(RoadType roadtype)
Returns the cost of building the specified roadtype.
Definition road.h:268
void UpdateCompanyRoadInfrastructure(RoadType rt, Owner o, int count)
Update road infrastructure counts for a company.
Definition road_cmd.cpp:186
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:145
void SetRoadOwner(Tile t, RoadTramType rtt, Owner o)
Set the owner of a specific road type.
Definition road_map.h:235
static debug_inline bool IsNormalRoadTile(Tile t)
Return whether a tile is a normal road tile.
Definition road_map.h:58
bool HasTileRoadType(Tile t, RoadTramType rtt)
Check if a tile has a road or a tram road type.
Definition road_map.h:195
Roadside GetRoadside(Tile tile)
Get the decorations of a road.
Definition road_map.h:473
Owner GetRoadOwner(Tile t, RoadTramType rtt)
Get the owner of a specific road type.
Definition road_map.h:218
void SetRoadside(Tile tile, Roadside s)
Set the decorations of a road.
Definition road_map.h:483
@ ROADSIDE_PAVED
Road with paved sidewalks.
Definition road_map.h:460
@ ROADSIDE_TREES
Road with trees on paved sidewalks.
Definition road_map.h:463
RoadType
The different roadtypes we support.
Definition road_type.h:23
@ INVALID_ROADTYPE
flag for invalid roadtype
Definition road_type.h:28
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:619
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:48
@ SLOPE_SW
south and west corner are raised
Definition slope_type.h:56
@ SLOPE_FLAT
a flat tile
Definition slope_type.h:49
@ SLOPE_NE
north and east corner are raised
Definition slope_type.h:58
@ SLOPE_SE
south and east corner are raised
Definition slope_type.h:57
@ SLOPE_NW
north and west corner are raised
Definition slope_type.h:55
Foundation
Enumeration for Foundations.
Definition slope_type.h:93
@ FOUNDATION_NONE
The tile has no foundation, the slope remains unchanged.
Definition slope_type.h:94
Functions related to sound.
@ SND_05_TRAIN_THROUGH_TUNNEL
3 == 0x03 Train enters tunnel: steam engine
Definition sound_type.h:50
static constexpr uint32_t SPRITE_MASK
The mask to for the main sprite.
Definition sprites.h:1562
static const PaletteID PALETTE_CRASH
Recolour sprite greying of crashed vehicles.
Definition sprites.h:1611
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.
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
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
bool value
tells if the bool cheat is active or not
Definition cheat_type.h:18
Cheat crossing_tunnels
allow tunnels that cross each other
Definition cheat_type.h:30
Cheat magic_bulldozer
dynamite industries, objects
Definition cheat_type.h:27
Keeps track of removed objects during execution/testruns of commands.
Definition object_base.h:86
TileIndex first_tile
The first tile being cleared, which then causes the whole object to be cleared.
Definition object_base.h:87
GUISettings gui
settings related to the GUI
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.
uint8_t max_bridge_height
maximum height of bridges
bool build_on_slopes
allow building on slopes
bool extra_dynamite
extra dynamite
uint16_t max_bridge_length
maximum length of bridges
uint16_t max_tunnel_length
maximum length of tunnels
T x
X coordinate.
T y
Y coordinate.
T z
Z coordinate.
bool show_track_reservation
highlight reserved tracks.
LandscapeType landscape
the landscape we're currently in
ConstructionSettings construction
construction of things in-game
GameCreationSettings game_creation
settings used during the creation of a game (map)
static debug_inline uint MaxX()
Gets the maximum X coordinate within the map, including MP_VOID.
Definition map_func.h:296
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 Titem * Get(auto index)
Returns Titem with given index.
Tindex index
Index of this pool item.
static bool IsValidID(auto index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
static Titem * GetIfValid(auto index)
Returns Titem with given index.
EngineClass engclass
Class of engine for this vehicle.
Definition engine_type.h:59
Buses, trucks and trams belong to this class.
Definition roadveh.h:98
uint8_t state
Definition roadveh.h:100
All ships have this type.
Definition ship.h:32
TrackBits state
The "track" the ship is following.
Definition ship.h:34
static T * From(Vehicle *v)
Converts a Vehicle to SpecializedVehicle with type checking.
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:36
uint16_t rail_speed
Speed limit of rail (bridges and track)
Definition tile_cmd.h:49
StringID str
Description of the tile.
Definition tile_cmd.h:37
std::array< Owner, 4 > owner
Name of the owner(s)
Definition tile_cmd.h:39
uint16_t tram_speed
Speed limit of tram (bridges and track)
Definition tile_cmd.h:53
StringID roadtype
Type of road on the tile.
Definition tile_cmd.h:50
StringID tramtype
Type of tram on the tile.
Definition tile_cmd.h:52
StringID railtype
Type of rail on the tile.
Definition tile_cmd.h:48
uint16_t road_speed
Speed limit of road (bridges and track)
Definition tile_cmd.h:51
std::array< StringID, 4 > owner_type
Type of each owner.
Definition tile_cmd.h:40
Tile information, used while rendering the tile.
Definition tile_cmd.h:30
Slope tileh
Slope of the tile.
Definition tile_cmd.h:31
TileIndex tile
Tile index.
Definition tile_cmd.h:32
Set of callback functions for performing tile operations of a given tile type.
Definition tile_cmd.h:152
std::array< uint32_t, NUM_HOUSE_ZONES > squared_town_zone_radius
UpdateTownRadius updates this given the house count.
Definition town.h:46
Town data structure.
Definition town.h:53
TileIndex xy
town center tile
Definition town.h:54
TownCache cache
Container for all cacheable data.
Definition town.h:56
'Train' is either a loco or a wagon.
Definition train.h:91
Vehicle data structure.
EngineID engine_type
The type of engine used for this vehicle.
int32_t z_pos
z coordinate.
Direction direction
facing
VehStates vehstatus
Status.
debug_inline bool IsFrontEngine() const
Check if the vehicle is a front engine.
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.
@ EnteredWormhole
The vehicle either entered a bridge, tunnel or depot tile (this includes the last tile of the bridge/...
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:136
int GetTileZ(TileIndex tile)
Get bottom height of the tile.
Definition tile_map.cpp:116
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
static debug_inline TileType GetTileType(Tile tile)
Get the tiletype of a given tile.
Definition tile_map.h:96
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 debug_inline uint TileHeight(Tile tile)
Returns the height of a tile.
Definition tile_map.h:29
static constexpr uint TILE_UNIT_MASK
For masking in/out the inner-tile world coordinate units.
Definition tile_type.h:16
@ TROPICZONE_DESERT
Tile is desert.
Definition tile_type.h:78
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:95
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.
Town * ClosestTownFromTile(TileIndex tile, uint threshold)
Return the town closest (in distance or ownership) to a given tile, within a given threshold.
@ TUNNELBRIDGE_REMOVE
Removal of a tunnel or bridge owned by the town.
Definition town.h:216
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:388
TrackBits DiagDirToDiagTrackBits(DiagDirection diagdir)
Maps a (4-way) direction to the diagonal track bits incidating with that diagdir.
Definition track_func.h:524
Trackdir DiagDirToDiagTrackdir(DiagDirection diagdir)
Maps a (4-way) direction to the diagonal trackdir that runs in that direction.
Definition track_func.h:537
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:512
@ 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:73
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:50
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)
CommandCost CmdBuildBridge(DoCommandFlags flags, TileIndex tile_end, TileIndex tile_start, TransportType transport_type, BridgeType bridge_type, uint8_t road_rail_type)
Build a Bridge.
static CommandCost ClearTile_TunnelBridge(TileIndex tile, DoCommandFlags flags)
Remove a tunnel or a bridge from the game.
CommandCost CmdBuildTunnel(DoCommandFlags flags, TileIndex start_tile, TransportType transport_type, uint8_t road_rail_type)
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 CommandCost CheckAllowRemoveTunnelBridge(TileIndex tile)
Are we allowed to remove the tunnel or bridge at tile?
static Money TunnelBridgeClearCost(TileIndex tile, Price base_price)
Calculate the base cost of clearing a tunnel/bridge per tile.
Foundation GetBridgeFoundation(Slope tileh, Axis axis)
Get the foundation for a bridge.
static void DrawBridgeRoadBits(TileIndex head_tile, int x, int y, int z, int offset, bool head)
Draws the road and trambits over an already drawn (lower end) of 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 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 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.
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)
Draws a tunnel of bridge tile.
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 uint8_t GetBridgeMiddleAxisBaseOffset(Axis axis)
Get bridge sprite table base offset for the middle part of bridge.
TileIndex _build_tunnel_endtile
The end of a tunnel; as hidden return from the tunnel build command for GUI purposes.
BridgeSpec _bridge[MAX_BRIDGES]
The specification of all bridges.
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 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 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? Bridge: Does the bridge ramp lie in a snow...
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:551
@ 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:764
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:663
void EndSpriteCombine()
Terminates a block of sprites started by StartSpriteCombine.
Definition viewport.cpp:774
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:350
@ WATER_CLASS_SEA
Sea.
Definition water_map.h:40
bool HasTileWaterClass(Tile t)
Checks whether the tile has an waterclass associated.
Definition water_map.h:101
WaterClass GetWaterClass(Tile t)
Get the water class at a tile.
Definition water_map.h:112
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.