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