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