OpenTTD Source 20241224-master-gf74b0cf984
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 /* First, free sprite table data */
89 for (BridgeType i = 0; i < MAX_BRIDGES; i++) {
90 if (_bridge[i].sprite_table != nullptr) {
91 for (BridgePieces j = BRIDGE_PIECE_NORTH; j < NUM_BRIDGE_PIECES; j++) free(_bridge[i].sprite_table[j]);
92 free(_bridge[i].sprite_table);
93 }
94 }
95
96 /* Then, wipe out current bridges */
97 memset(&_bridge, 0, sizeof(_bridge));
98 /* And finally, reinstall default data */
99 memcpy(&_bridge, &_orig_bridge, sizeof(_orig_bridge));
100}
101
109{
110 if (length < 2) return length;
111
112 length -= 2;
113 int sum = 2;
114 for (int delta = 1;; delta++) {
115 for (int count = 0; count < delta; count++) {
116 if (length == 0) return sum;
117 sum += delta;
118 length--;
119 }
120 }
121}
122
130{
131 if (tileh == SLOPE_FLAT ||
132 ((tileh == SLOPE_NE || tileh == SLOPE_SW) && axis == AXIS_X) ||
133 ((tileh == SLOPE_NW || tileh == SLOPE_SE) && axis == AXIS_Y)) return FOUNDATION_NONE;
134
135 return (HasSlopeHighestCorner(tileh) ? InclinedFoundation(axis) : FlatteningFoundation(tileh));
136}
137
145bool HasBridgeFlatRamp(Slope tileh, Axis axis)
146{
147 ApplyFoundationToSlope(GetBridgeFoundation(tileh, axis), tileh);
148 /* If the foundation slope is flat the bridge has a non-flat ramp and vice versa. */
149 return (tileh != SLOPE_FLAT);
150}
151
152static inline const PalSpriteID *GetBridgeSpriteTable(int index, BridgePieces table)
153{
154 const BridgeSpec *bridge = GetBridgeSpec(index);
155 assert(table < NUM_BRIDGE_PIECES);
156 if (bridge->sprite_table == nullptr || bridge->sprite_table[table] == nullptr) {
157 return _bridge_sprite_table[index][table];
158 } else {
159 return bridge->sprite_table[table];
160 }
161}
162
163
173static CommandCost CheckBridgeSlope(BridgePieces bridge_piece, Axis axis, Slope &tileh, int &z)
174{
175 assert(bridge_piece == BRIDGE_PIECE_NORTH || bridge_piece == BRIDGE_PIECE_SOUTH);
176
177 Foundation f = GetBridgeFoundation(tileh, axis);
178 z += ApplyFoundationToSlope(f, tileh);
179
180 Slope valid_inclined;
181 if (bridge_piece == BRIDGE_PIECE_NORTH) {
182 valid_inclined = (axis == AXIS_X ? SLOPE_NE : SLOPE_NW);
183 } else {
184 valid_inclined = (axis == AXIS_X ? SLOPE_SW : SLOPE_SE);
185 }
186 if ((tileh != SLOPE_FLAT) && (tileh != valid_inclined)) return CMD_ERROR;
187
188 if (f == FOUNDATION_NONE) return CommandCost();
189
190 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
191}
192
201{
202 if (flags & DC_QUERY_COST) {
203 if (bridge_len <= _settings_game.construction.max_bridge_length) return CommandCost();
204 return CommandCost(STR_ERROR_BRIDGE_TOO_LONG);
205 }
206
207 if (bridge_type >= MAX_BRIDGES) return CMD_ERROR;
208
209 const BridgeSpec *b = GetBridgeSpec(bridge_type);
211
213
214 if (b->min_length > bridge_len) return CMD_ERROR;
215 if (bridge_len <= max) return CommandCost();
216 return CommandCost(STR_ERROR_BRIDGE_TOO_LONG);
217}
218
225{
226 Money base_cost = _price[base_price];
227
228 /* Add the cost of the transport that is on the tunnel/bridge. */
229 switch (GetTunnelBridgeTransportType(tile)) {
230 case TRANSPORT_ROAD: {
231 RoadType road_rt = GetRoadTypeRoad(tile);
232 RoadType tram_rt = GetRoadTypeTram(tile);
233
234 if (road_rt != INVALID_ROADTYPE) {
235 base_cost += 2 * RoadClearCost(road_rt);
236 }
237 if (tram_rt != INVALID_ROADTYPE) {
238 base_cost += 2 * RoadClearCost(tram_rt);
239 }
240 } break;
241
242 case TRANSPORT_RAIL: base_cost += RailClearCost(GetRailType(tile)); break;
243 /* Aquaducts have their own clear price. */
244 case TRANSPORT_WATER: base_cost = _price[PR_CLEAR_AQUEDUCT]; break;
245 default: break;
246 }
247
248 return base_cost;
249}
250
261CommandCost CmdBuildBridge(DoCommandFlag flags, TileIndex tile_end, TileIndex tile_start, TransportType transport_type, BridgeType bridge_type, uint8_t road_rail_type)
262{
263 CompanyID company = _current_company;
264
265 RailType railtype = INVALID_RAILTYPE;
266 RoadType roadtype = INVALID_ROADTYPE;
267
268 if (!IsValidTile(tile_start)) return CommandCost(STR_ERROR_BRIDGE_THROUGH_MAP_BORDER);
269
270 /* type of bridge */
271 switch (transport_type) {
272 case TRANSPORT_ROAD:
273 roadtype = (RoadType)road_rail_type;
274 if (!ValParamRoadType(roadtype)) return CMD_ERROR;
275 break;
276
277 case TRANSPORT_RAIL:
278 railtype = (RailType)road_rail_type;
279 if (!ValParamRailType(railtype)) return CMD_ERROR;
280 break;
281
282 case TRANSPORT_WATER:
283 break;
284
285 default:
286 /* Airports don't have bridges. */
287 return CMD_ERROR;
288 }
289
290 if (company == OWNER_DEITY) {
291 if (transport_type != TRANSPORT_ROAD) return CMD_ERROR;
292 const Town *town = CalcClosestTownFromTile(tile_start);
293
294 company = OWNER_TOWN;
295
296 /* If we are not within a town, we are not owned by the town */
297 if (town == nullptr || DistanceSquare(tile_start, town->xy) > town->cache.squared_town_zone_radius[HZB_TOWN_EDGE]) {
298 company = OWNER_NONE;
299 }
300 }
301
302 if (tile_start == tile_end) {
303 return CommandCost(STR_ERROR_CAN_T_START_AND_END_ON);
304 }
305
306 Axis direction;
307 if (TileX(tile_start) == TileX(tile_end)) {
308 direction = AXIS_Y;
309 } else if (TileY(tile_start) == TileY(tile_end)) {
310 direction = AXIS_X;
311 } else {
312 return CommandCost(STR_ERROR_START_AND_END_MUST_BE_IN);
313 }
314
315 if (tile_end < tile_start) Swap(tile_start, tile_end);
316
317 uint bridge_len = GetTunnelBridgeLength(tile_start, tile_end);
318 if (transport_type != TRANSPORT_WATER) {
319 /* set and test bridge length, availability */
320 CommandCost ret = CheckBridgeAvailability(bridge_type, bridge_len, flags);
321 if (ret.Failed()) return ret;
322 } else {
323 if (bridge_len > _settings_game.construction.max_bridge_length) return CommandCost(STR_ERROR_BRIDGE_TOO_LONG);
324 }
325 bridge_len += 2; // begin and end tiles/ramps
326
327 auto [tileh_start, z_start] = GetTileSlopeZ(tile_start);
328 auto [tileh_end, z_end] = GetTileSlopeZ(tile_end);
329 bool pbs_reservation = false;
330
331 CommandCost terraform_cost_north = CheckBridgeSlope(BRIDGE_PIECE_NORTH, direction, tileh_start, z_start);
332 CommandCost terraform_cost_south = CheckBridgeSlope(BRIDGE_PIECE_SOUTH, direction, tileh_end, z_end);
333
334 /* Aqueducts can't be built of flat land. */
335 if (transport_type == TRANSPORT_WATER && (tileh_start == SLOPE_FLAT || tileh_end == SLOPE_FLAT)) return CommandCost(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
336 if (z_start != z_end) return CommandCost(STR_ERROR_BRIDGEHEADS_NOT_SAME_HEIGHT);
337
339 Owner owner;
340 bool is_new_owner;
341 RoadType road_rt = INVALID_ROADTYPE;
342 RoadType tram_rt = INVALID_ROADTYPE;
343 if (IsBridgeTile(tile_start) && IsBridgeTile(tile_end) &&
344 GetOtherBridgeEnd(tile_start) == tile_end &&
345 GetTunnelBridgeTransportType(tile_start) == transport_type) {
346 /* Replace a current bridge. */
347
348 switch (transport_type) {
349 case TRANSPORT_RAIL:
350 /* Keep the reservation, the path stays valid. */
351 pbs_reservation = HasTunnelBridgeReservation(tile_start);
352 break;
353
354 case TRANSPORT_ROAD:
355 /* Do not remove road types when upgrading a bridge */
356 road_rt = GetRoadTypeRoad(tile_start);
357 tram_rt = GetRoadTypeTram(tile_start);
358 break;
359
360 default: break;
361 }
362
363 /* If this is a railway bridge, make sure the railtypes match. */
364 if (transport_type == TRANSPORT_RAIL && GetRailType(tile_start) != railtype) {
365 return CommandCost(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
366 }
367
368 /* If this is a road bridge, make sure the roadtype matches. */
369 if (transport_type == TRANSPORT_ROAD) {
370 RoadType existing_rt = RoadTypeIsRoad(roadtype) ? road_rt : tram_rt;
371 if (existing_rt != roadtype && existing_rt != INVALID_ROADTYPE) {
372 return CommandCost(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
373 }
374 }
375
376 if (!(flags & DC_QUERY_COST)) {
377 /* Do not replace the bridge with the same bridge type. */
378 if ((bridge_type == GetBridgeType(tile_start)) && (transport_type != TRANSPORT_ROAD || road_rt == roadtype || tram_rt == roadtype)) {
379 return CommandCost(STR_ERROR_ALREADY_BUILT);
380 }
381
382 /* Do not replace town bridges with lower speed bridges, unless in scenario editor. */
383 if (IsTileOwner(tile_start, OWNER_TOWN) && _game_mode != GM_EDITOR) {
384 Town *t = ClosestTownFromTile(tile_start, UINT_MAX);
385 if (t == nullptr) return CMD_ERROR;
386
387 if (GetBridgeSpec(bridge_type)->speed < GetBridgeSpec(GetBridgeType(tile_start))->speed) {
388 SetDParam(0, t->index);
389 return CommandCost(STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS);
390 } else {
391 ChangeTownRating(t, RATING_TUNNEL_BRIDGE_UP_STEP, RATING_MAXIMUM, flags);
392 }
393 }
394 }
395
396 /* Do not allow replacing another company's bridges. */
397 if (!IsTileOwner(tile_start, company) && !IsTileOwner(tile_start, OWNER_TOWN) && !IsTileOwner(tile_start, OWNER_NONE)) {
398 return CommandCost(STR_ERROR_AREA_IS_OWNED_BY_ANOTHER);
399 }
400
401 /* The cost of clearing the current bridge. */
402 cost.AddCost(bridge_len * TunnelBridgeClearCost(tile_start, PR_CLEAR_BRIDGE));
403 owner = GetTileOwner(tile_start);
404
405 /* If bridge belonged to bankrupt company, it has a new owner now */
406 is_new_owner = (owner == OWNER_NONE);
407 if (is_new_owner) owner = company;
408 } else {
409 /* Build a new bridge. */
410
411 bool allow_on_slopes = (_settings_game.construction.build_on_slopes && transport_type != TRANSPORT_WATER);
412
413 /* Try and clear the start landscape */
414 CommandCost ret = Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile_start);
415 if (ret.Failed()) return ret;
416 cost = ret;
417
418 if (terraform_cost_north.Failed() || (terraform_cost_north.GetCost() != 0 && !allow_on_slopes)) return CommandCost(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
419 cost.AddCost(terraform_cost_north);
420
421 /* Try and clear the end landscape */
422 ret = Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile_end);
423 if (ret.Failed()) return ret;
424 cost.AddCost(ret);
425
426 /* false - end tile slope check */
427 if (terraform_cost_south.Failed() || (terraform_cost_south.GetCost() != 0 && !allow_on_slopes)) return CommandCost(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
428 cost.AddCost(terraform_cost_south);
429
430 const TileIndex heads[] = {tile_start, tile_end};
431 for (int i = 0; i < 2; i++) {
432 if (IsBridgeAbove(heads[i])) {
433 TileIndex north_head = GetNorthernBridgeEnd(heads[i]);
434
435 if (direction == GetBridgeAxis(heads[i])) return CommandCost(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
436
437 if (z_start + 1 == GetBridgeHeight(north_head)) {
438 return CommandCost(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
439 }
440 }
441 }
442
443 TileIndexDiff delta = TileOffsByAxis(direction);
444 for (TileIndex tile = tile_start + delta; tile != tile_end; tile += delta) {
445 if (GetTileMaxZ(tile) > z_start) return CommandCost(STR_ERROR_BRIDGE_TOO_LOW_FOR_TERRAIN);
446
447 if (z_start >= (GetTileZ(tile) + _settings_game.construction.max_bridge_height)) {
448 /*
449 * Disallow too high bridges.
450 * Properly rendering a map where very high bridges (might) exist is expensive.
451 * See http://www.tt-forums.net/viewtopic.php?f=33&t=40844&start=980#p1131762
452 * for a detailed discussion. z_start here is one heightlevel below the bridge level.
453 */
454 return CommandCost(STR_ERROR_BRIDGE_TOO_HIGH_FOR_TERRAIN);
455 }
456
457 if (IsBridgeAbove(tile)) {
458 /* Disallow crossing bridges for the time being */
459 return CommandCost(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
460 }
461
462 switch (GetTileType(tile)) {
463 case MP_WATER:
464 if (!IsWater(tile) && !IsCoast(tile)) goto not_valid_below;
465 break;
466
467 case MP_RAILWAY:
468 if (!IsPlainRail(tile)) goto not_valid_below;
469 break;
470
471 case MP_ROAD:
472 if (IsRoadDepot(tile)) goto not_valid_below;
473 break;
474
475 case MP_TUNNELBRIDGE:
476 if (IsTunnel(tile)) break;
477 if (direction == DiagDirToAxis(GetTunnelBridgeDirection(tile))) goto not_valid_below;
478 if (z_start < GetBridgeHeight(tile)) goto not_valid_below;
479 break;
480
481 case MP_OBJECT: {
482 const ObjectSpec *spec = ObjectSpec::GetByTile(tile);
483 if ((spec->flags & OBJECT_FLAG_ALLOW_UNDER_BRIDGE) == 0) goto not_valid_below;
484 if (GetTileMaxZ(tile) + spec->height > z_start) goto not_valid_below;
485 break;
486 }
487
488 case MP_CLEAR:
489 break;
490
491 default:
492 not_valid_below:;
493 /* try and clear the middle landscape */
494 ret = Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile);
495 if (ret.Failed()) return ret;
496 cost.AddCost(ret);
497 break;
498 }
499
500 if (flags & DC_EXEC) {
501 /* We do this here because when replacing a bridge with another
502 * type calling SetBridgeMiddle isn't needed. After all, the
503 * tile already has the has_bridge_above bits set. */
504 SetBridgeMiddle(tile, direction);
505 }
506 }
507
508 owner = company;
509 is_new_owner = true;
510 }
511
512 bool hasroad = road_rt != INVALID_ROADTYPE;
513 bool hastram = tram_rt != INVALID_ROADTYPE;
514 if (transport_type == TRANSPORT_ROAD) {
515 if (RoadTypeIsRoad(roadtype)) road_rt = roadtype;
516 if (RoadTypeIsTram(roadtype)) tram_rt = roadtype;
517 }
518
519 /* do the drill? */
520 if (flags & DC_EXEC) {
521 DiagDirection dir = AxisToDiagDir(direction);
522
523 Company *c = Company::GetIfValid(company);
524 switch (transport_type) {
525 case TRANSPORT_RAIL:
526 /* Add to company infrastructure count if required. */
527 if (is_new_owner && c != nullptr) c->infrastructure.rail[railtype] += bridge_len * TUNNELBRIDGE_TRACKBIT_FACTOR;
528 MakeRailBridgeRamp(tile_start, owner, bridge_type, dir, railtype);
529 MakeRailBridgeRamp(tile_end, owner, bridge_type, ReverseDiagDir(dir), railtype);
530 SetTunnelBridgeReservation(tile_start, pbs_reservation);
531 SetTunnelBridgeReservation(tile_end, pbs_reservation);
532 break;
533
534 case TRANSPORT_ROAD: {
535 if (is_new_owner) {
536 /* Also give unowned present roadtypes to new owner */
537 if (hasroad && GetRoadOwner(tile_start, RTT_ROAD) == OWNER_NONE) hasroad = false;
538 if (hastram && GetRoadOwner(tile_start, RTT_TRAM) == OWNER_NONE) hastram = false;
539 }
540 if (c != nullptr) {
541 /* Add all new road types to the company infrastructure counter. */
542 if (!hasroad && road_rt != INVALID_ROADTYPE) {
543 /* A full diagonal road tile has two road bits. */
544 c->infrastructure.road[road_rt] += bridge_len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR;
545 }
546 if (!hastram && tram_rt != INVALID_ROADTYPE) {
547 /* A full diagonal road tile has two road bits. */
548 c->infrastructure.road[tram_rt] += bridge_len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR;
549 }
550 }
551 Owner owner_road = hasroad ? GetRoadOwner(tile_start, RTT_ROAD) : company;
552 Owner owner_tram = hastram ? GetRoadOwner(tile_start, RTT_TRAM) : company;
553 MakeRoadBridgeRamp(tile_start, owner, owner_road, owner_tram, bridge_type, dir, road_rt, tram_rt);
554 MakeRoadBridgeRamp(tile_end, owner, owner_road, owner_tram, bridge_type, ReverseDiagDir(dir), road_rt, tram_rt);
555 break;
556 }
557
558 case TRANSPORT_WATER:
559 if (is_new_owner && c != nullptr) c->infrastructure.water += bridge_len * TUNNELBRIDGE_TRACKBIT_FACTOR;
560 MakeAqueductBridgeRamp(tile_start, owner, dir);
561 MakeAqueductBridgeRamp(tile_end, owner, ReverseDiagDir(dir));
562 CheckForDockingTile(tile_start);
563 CheckForDockingTile(tile_end);
564 break;
565
566 default:
567 NOT_REACHED();
568 }
569
570 /* Mark all tiles dirty */
571 MarkBridgeDirty(tile_start, tile_end, AxisToDiagDir(direction), z_start);
573 }
574
575 if ((flags & DC_EXEC) && transport_type == TRANSPORT_RAIL) {
576 Track track = AxisToTrack(direction);
577 AddSideToSignalBuffer(tile_start, INVALID_DIAGDIR, company);
578 YapfNotifyTrackLayoutChange(tile_start, track);
579 }
580
581 /* Human players that build bridges get a selection to choose from (DC_QUERY_COST)
582 * It's unnecessary to execute this command every time for every bridge.
583 * So it is done only for humans and cost is computed in bridge_gui.cpp.
584 * For (non-spectated) AI, Towns this has to be of course calculated. */
585 Company *c = Company::GetIfValid(company);
586 if (!(flags & DC_QUERY_COST) || (c != nullptr && c->is_ai && company != _local_company)) {
587 switch (transport_type) {
588 case TRANSPORT_ROAD:
589 if (road_rt != INVALID_ROADTYPE) {
590 cost.AddCost(bridge_len * 2 * RoadBuildCost(road_rt));
591 }
592 if (tram_rt != INVALID_ROADTYPE) {
593 cost.AddCost(bridge_len * 2 * RoadBuildCost(tram_rt));
594 }
595 break;
596
597 case TRANSPORT_RAIL: cost.AddCost(bridge_len * RailBuildCost(railtype)); break;
598 default: break;
599 }
600
601 if (c != nullptr) bridge_len = CalcBridgeLenCostFactor(bridge_len);
602
603 if (transport_type != TRANSPORT_WATER) {
604 cost.AddCost((int64_t)bridge_len * _price[PR_BUILD_BRIDGE] * GetBridgeSpec(bridge_type)->price >> 8);
605 } else {
606 /* Aqueducts use a separate base cost. */
607 cost.AddCost((int64_t)bridge_len * _price[PR_BUILD_AQUEDUCT]);
608 }
609
610 }
611
612 return cost;
613}
614
615
624CommandCost CmdBuildTunnel(DoCommandFlag flags, TileIndex start_tile, TransportType transport_type, uint8_t road_rail_type)
625{
626 CompanyID company = _current_company;
627
628 RailType railtype = INVALID_RAILTYPE;
629 RoadType roadtype = INVALID_ROADTYPE;
631 switch (transport_type) {
632 case TRANSPORT_RAIL:
633 railtype = (RailType)road_rail_type;
634 if (!ValParamRailType(railtype)) return CMD_ERROR;
635 break;
636
637 case TRANSPORT_ROAD:
638 roadtype = (RoadType)road_rail_type;
639 if (!ValParamRoadType(roadtype)) return CMD_ERROR;
640 break;
641
642 default: return CMD_ERROR;
643 }
644
645 if (company == OWNER_DEITY) {
646 if (transport_type != TRANSPORT_ROAD) return CMD_ERROR;
647 const Town *town = CalcClosestTownFromTile(start_tile);
648
649 company = OWNER_TOWN;
650
651 /* If we are not within a town, we are not owned by the town */
652 if (town == nullptr || DistanceSquare(start_tile, town->xy) > town->cache.squared_town_zone_radius[HZB_TOWN_EDGE]) {
653 company = OWNER_NONE;
654 }
655 }
656
657 auto [start_tileh, start_z] = GetTileSlopeZ(start_tile);
658 DiagDirection direction = GetInclinedSlopeDirection(start_tileh);
659 if (direction == INVALID_DIAGDIR) return CommandCost(STR_ERROR_SITE_UNSUITABLE_FOR_TUNNEL);
660
661 if (HasTileWaterGround(start_tile)) return CommandCost(STR_ERROR_CAN_T_BUILD_ON_WATER);
662
663 CommandCost ret = Command<CMD_LANDSCAPE_CLEAR>::Do(flags, start_tile);
664 if (ret.Failed()) return ret;
665
666 /* XXX - do NOT change 'ret' in the loop, as it is used as the price
667 * for the clearing of the entrance of the tunnel. Assigning it to
668 * cost before the loop will yield different costs depending on start-
669 * position, because of increased-cost-by-length: 'cost += cost >> 3' */
670
671 TileIndexDiff delta = TileOffsByDiagDir(direction);
672 DiagDirection tunnel_in_way_dir;
673 if (DiagDirToAxis(direction) == AXIS_Y) {
674 tunnel_in_way_dir = (TileX(start_tile) < (Map::MaxX() / 2)) ? DIAGDIR_SW : DIAGDIR_NE;
675 } else {
676 tunnel_in_way_dir = (TileY(start_tile) < (Map::MaxX() / 2)) ? DIAGDIR_SE : DIAGDIR_NW;
677 }
678
679 TileIndex end_tile = start_tile;
680
681 /* Tile shift coefficient. Will decrease for very long tunnels to avoid exponential growth of price*/
682 int tiles_coef = 3;
683 /* Number of tiles from start of tunnel */
684 int tiles = 0;
685 /* Number of tiles at which the cost increase coefficient per tile is halved */
686 int tiles_bump = 25;
687
689 Slope end_tileh;
690 int end_z;
691 for (;;) {
692 end_tile += delta;
693 if (!IsValidTile(end_tile)) return CommandCost(STR_ERROR_TUNNEL_THROUGH_MAP_BORDER);
694 std::tie(end_tileh, end_z) = GetTileSlopeZ(end_tile);
695
696 if (start_z == end_z) break;
697
698 if (!_cheats.crossing_tunnels.value && IsTunnelInWayDir(end_tile, start_z, tunnel_in_way_dir)) {
699 return CommandCost(STR_ERROR_ANOTHER_TUNNEL_IN_THE_WAY);
700 }
701
702 tiles++;
703 if (tiles == tiles_bump) {
704 tiles_coef++;
705 tiles_bump *= 2;
706 }
707
708 cost.AddCost(_price[PR_BUILD_TUNNEL]);
709 cost.AddCost(cost.GetCost() >> tiles_coef); // add a multiplier for longer tunnels
710 }
711
712 /* Add the cost of the entrance */
713 cost.AddCost(_price[PR_BUILD_TUNNEL]);
714 cost.AddCost(ret);
715
716 /* if the command fails from here on we want the end tile to be highlighted */
717 _build_tunnel_endtile = end_tile;
718
719 if (tiles > _settings_game.construction.max_tunnel_length) return CommandCost(STR_ERROR_TUNNEL_TOO_LONG);
720
721 if (HasTileWaterGround(end_tile)) return CommandCost(STR_ERROR_CAN_T_BUILD_ON_WATER);
722
723 /* Clear the tile in any case */
724 ret = Command<CMD_LANDSCAPE_CLEAR>::Do(flags, end_tile);
725 if (ret.Failed()) return CommandCost(STR_ERROR_UNABLE_TO_EXCAVATE_LAND);
726 cost.AddCost(ret);
727
728 /* slope of end tile must be complementary to the slope of the start tile */
729 if (end_tileh != ComplementSlope(start_tileh)) {
730 /* Mark the tile as already cleared for the terraform command.
731 * Do this for all tiles (like trees), not only objects. */
732 ClearedObjectArea *coa = FindClearedObject(end_tile);
733 if (coa == nullptr) {
734 coa = &_cleared_object_areas.emplace_back(ClearedObjectArea{ end_tile, TileArea(end_tile, 1, 1) });
735 }
736
737 /* Hide the tile from the terraforming command */
738 TileIndex old_first_tile = coa->first_tile;
740
741 /* CMD_TERRAFORM_LAND may append further items to _cleared_object_areas,
742 * however it will never erase or re-order existing items.
743 * _cleared_object_areas is a value-type self-resizing vector, therefore appending items
744 * may result in a backing-store re-allocation, which would invalidate the coa pointer.
745 * The index of the coa pointer into the _cleared_object_areas vector remains valid,
746 * and can be used safely after the CMD_TERRAFORM_LAND operation.
747 * Deliberately clear the coa pointer to avoid leaving dangling pointers which could
748 * inadvertently be dereferenced.
749 */
750 ClearedObjectArea *begin = _cleared_object_areas.data();
751 assert(coa >= begin && coa < begin + _cleared_object_areas.size());
752 size_t coa_index = coa - begin;
753 assert(coa_index < UINT_MAX); // more than 2**32 cleared areas would be a bug in itself
754 coa = nullptr;
755
756 ret = std::get<0>(Command<CMD_TERRAFORM_LAND>::Do(flags, end_tile, end_tileh & start_tileh, false));
757 _cleared_object_areas[(uint)coa_index].first_tile = old_first_tile;
758 if (ret.Failed()) return CommandCost(STR_ERROR_UNABLE_TO_EXCAVATE_LAND);
759 cost.AddCost(ret);
760 }
761 cost.AddCost(_price[PR_BUILD_TUNNEL]);
762
763 /* Pay for the rail/road in the tunnel including entrances */
764 switch (transport_type) {
765 case TRANSPORT_ROAD: cost.AddCost((tiles + 2) * RoadBuildCost(roadtype) * 2); break;
766 case TRANSPORT_RAIL: cost.AddCost((tiles + 2) * RailBuildCost(railtype)); break;
767 default: NOT_REACHED();
768 }
769
770 if (flags & DC_EXEC) {
771 Company *c = Company::GetIfValid(company);
772 uint num_pieces = (tiles + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR;
773 if (transport_type == TRANSPORT_RAIL) {
774 if (c != nullptr) c->infrastructure.rail[railtype] += num_pieces;
775 MakeRailTunnel(start_tile, company, direction, railtype);
776 MakeRailTunnel(end_tile, company, ReverseDiagDir(direction), railtype);
777 AddSideToSignalBuffer(start_tile, INVALID_DIAGDIR, company);
778 YapfNotifyTrackLayoutChange(start_tile, DiagDirToDiagTrack(direction));
779 } else {
780 if (c != nullptr) c->infrastructure.road[roadtype] += num_pieces * 2; // A full diagonal road has two road bits.
781 RoadType road_rt = RoadTypeIsRoad(roadtype) ? roadtype : INVALID_ROADTYPE;
782 RoadType tram_rt = RoadTypeIsTram(roadtype) ? roadtype : INVALID_ROADTYPE;
783 MakeRoadTunnel(start_tile, company, direction, road_rt, tram_rt);
784 MakeRoadTunnel(end_tile, company, ReverseDiagDir(direction), road_rt, tram_rt);
785 }
787 }
788
789 return cost;
790}
791
792
799{
800 /* Floods can remove anything as well as the scenario editor */
801 if (_current_company == OWNER_WATER || _game_mode == GM_EDITOR) return CommandCost();
802
803 switch (GetTunnelBridgeTransportType(tile)) {
804 case TRANSPORT_ROAD: {
805 RoadType road_rt = GetRoadTypeRoad(tile);
806 RoadType tram_rt = GetRoadTypeTram(tile);
807 Owner road_owner = _current_company;
808 Owner tram_owner = _current_company;
809
810 if (road_rt != INVALID_ROADTYPE) road_owner = GetRoadOwner(tile, RTT_ROAD);
811 if (tram_rt != INVALID_ROADTYPE) tram_owner = GetRoadOwner(tile, RTT_TRAM);
812
813 /* We can remove unowned road and if the town allows it */
815 /* Town does not allow */
816 return CheckTileOwnership(tile);
817 }
818 if (road_owner == OWNER_NONE || road_owner == OWNER_TOWN) road_owner = _current_company;
819 if (tram_owner == OWNER_NONE) tram_owner = _current_company;
820
821 CommandCost ret = CheckOwnership(road_owner, tile);
822 if (ret.Succeeded()) ret = CheckOwnership(tram_owner, tile);
823 return ret;
824 }
825
826 case TRANSPORT_RAIL:
827 return CheckOwnership(GetTileOwner(tile));
828
829 case TRANSPORT_WATER: {
830 /* Always allow to remove aqueducts without owner. */
831 Owner aqueduct_owner = GetTileOwner(tile);
832 if (aqueduct_owner == OWNER_NONE) aqueduct_owner = _current_company;
833 return CheckOwnership(aqueduct_owner);
834 }
835
836 default: NOT_REACHED();
837 }
838}
839
847{
849 if (ret.Failed()) return ret;
850
851 TileIndex endtile = GetOtherTunnelEnd(tile);
852
853 ret = TunnelBridgeIsFree(tile, endtile);
854 if (ret.Failed()) return ret;
855
856 _build_tunnel_endtile = endtile;
857
858 Town *t = nullptr;
859 if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) {
860 t = ClosestTownFromTile(tile, UINT_MAX); // town penalty rating
861
862 /* Check if you are allowed to remove the tunnel owned by a town
863 * Removal depends on difficulty settings */
865 if (ret.Failed()) return ret;
866 }
867
868 /* checks if the owner is town then decrease town rating by RATING_TUNNEL_BRIDGE_DOWN_STEP until
869 * you have a "Poor" (0) town rating */
870 if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) {
872 }
873
874 Money base_cost = TunnelBridgeClearCost(tile, PR_CLEAR_TUNNEL);
875 uint len = GetTunnelBridgeLength(tile, endtile) + 2; // Don't forget the end tiles.
876
877 if (flags & DC_EXEC) {
879 /* We first need to request values before calling DoClearSquare */
881 Track track = DiagDirToDiagTrack(dir);
882 Owner owner = GetTileOwner(tile);
883
884 Train *v = nullptr;
885 if (HasTunnelBridgeReservation(tile)) {
886 v = GetTrainForReservation(tile, track);
887 if (v != nullptr) FreeTrainTrackReservation(v);
888 }
889
890 if (Company::IsValidID(owner)) {
891 Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= len * TUNNELBRIDGE_TRACKBIT_FACTOR;
893 }
894
895 DoClearSquare(tile);
896 DoClearSquare(endtile);
897
898 /* cannot use INVALID_DIAGDIR for signal update because the tunnel doesn't exist anymore */
899 AddSideToSignalBuffer(tile, ReverseDiagDir(dir), owner);
900 AddSideToSignalBuffer(endtile, dir, owner);
901
902 YapfNotifyTrackLayoutChange(tile, track);
903 YapfNotifyTrackLayoutChange(endtile, track);
904
905 if (v != nullptr) TryPathReserve(v);
906 } else {
907 /* A full diagonal road tile has two road bits. */
908 UpdateCompanyRoadInfrastructure(GetRoadTypeRoad(tile), GetRoadOwner(tile, RTT_ROAD), -(int)(len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR));
909 UpdateCompanyRoadInfrastructure(GetRoadTypeTram(tile), GetRoadOwner(tile, RTT_TRAM), -(int)(len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR));
910
911 DoClearSquare(tile);
912 DoClearSquare(endtile);
913 }
914 }
915
916 return CommandCost(EXPENSES_CONSTRUCTION, len * base_cost);
917}
918
919
927{
929 if (ret.Failed()) return ret;
930
931 TileIndex endtile = GetOtherBridgeEnd(tile);
932
933 ret = TunnelBridgeIsFree(tile, endtile);
934 if (ret.Failed()) return ret;
935
936 DiagDirection direction = GetTunnelBridgeDirection(tile);
937 TileIndexDiff delta = TileOffsByDiagDir(direction);
938
939 Town *t = nullptr;
940 if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) {
941 t = ClosestTownFromTile(tile, UINT_MAX); // town penalty rating
942
943 /* Check if you are allowed to remove the bridge owned by a town
944 * Removal depends on difficulty settings */
946 if (ret.Failed()) return ret;
947 }
948
949 /* checks if the owner is town then decrease town rating by RATING_TUNNEL_BRIDGE_DOWN_STEP until
950 * you have a "Poor" (0) town rating */
951 if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) {
953 }
954
955 Money base_cost = TunnelBridgeClearCost(tile, PR_CLEAR_BRIDGE);
956 uint len = GetTunnelBridgeLength(tile, endtile) + 2; // Don't forget the end tiles.
957
958 if (flags & DC_EXEC) {
959 /* read this value before actual removal of bridge */
960 bool rail = GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL;
961 Owner owner = GetTileOwner(tile);
962 int height = GetBridgeHeight(tile);
963 Train *v = nullptr;
964
965 if (rail && HasTunnelBridgeReservation(tile)) {
966 v = GetTrainForReservation(tile, DiagDirToDiagTrack(direction));
967 if (v != nullptr) FreeTrainTrackReservation(v);
968 }
969
970 /* Update company infrastructure counts. */
971 if (rail) {
972 if (Company::IsValidID(owner)) Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= len * TUNNELBRIDGE_TRACKBIT_FACTOR;
973 } else if (GetTunnelBridgeTransportType(tile) == TRANSPORT_ROAD) {
974 /* A full diagonal road tile has two road bits. */
975 UpdateCompanyRoadInfrastructure(GetRoadTypeRoad(tile), GetRoadOwner(tile, RTT_ROAD), -(int)(len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR));
976 UpdateCompanyRoadInfrastructure(GetRoadTypeTram(tile), GetRoadOwner(tile, RTT_TRAM), -(int)(len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR));
977 } else { // Aqueduct
978 if (Company::IsValidID(owner)) Company::Get(owner)->infrastructure.water -= len * TUNNELBRIDGE_TRACKBIT_FACTOR;
979 }
981
982 DoClearSquare(tile);
983 DoClearSquare(endtile);
984
985 for (TileIndex c = tile + delta; c != endtile; c += delta) {
986 /* do not let trees appear from 'nowhere' after removing bridge */
988 int minz = GetTileMaxZ(c) + 3;
989 if (height < minz) SetRoadside(c, ROADSIDE_PAVED);
990 }
992 MarkTileDirtyByTile(c, height - TileHeight(c));
993 }
994
995 if (rail) {
996 /* cannot use INVALID_DIAGDIR for signal update because the bridge doesn't exist anymore */
997 AddSideToSignalBuffer(tile, ReverseDiagDir(direction), owner);
998 AddSideToSignalBuffer(endtile, direction, owner);
999
1000 Track track = DiagDirToDiagTrack(direction);
1001 YapfNotifyTrackLayoutChange(tile, track);
1002 YapfNotifyTrackLayoutChange(endtile, track);
1003
1004 if (v != nullptr) TryPathReserve(v, true);
1005 }
1006 }
1007
1008 return CommandCost(EXPENSES_CONSTRUCTION, len * base_cost);
1009}
1010
1018{
1019 if (IsTunnel(tile)) {
1020 if (flags & DC_AUTO) return CommandCost(STR_ERROR_MUST_DEMOLISH_TUNNEL_FIRST);
1021 return DoClearTunnel(tile, flags);
1022 } else { // IsBridge(tile)
1023 if (flags & DC_AUTO) return CommandCost(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
1024 return DoClearBridge(tile, flags);
1025 }
1026}
1027
1038static inline void DrawPillar(const PalSpriteID *psid, int x, int y, int z, int w, int h, const SubSprite *subsprite)
1039{
1040 static const int PILLAR_Z_OFFSET = TILE_HEIGHT - BRIDGE_Z_START;
1041 AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, w, h, BB_HEIGHT_UNDER_BRIDGE - PILLAR_Z_OFFSET, z, IsTransparencySet(TO_BRIDGES), 0, 0, -PILLAR_Z_OFFSET, subsprite);
1042}
1043
1055static int DrawPillarColumn(int z_bottom, int z_top, const PalSpriteID *psid, int x, int y, int w, int h)
1056{
1057 int cur_z;
1058 for (cur_z = z_top; cur_z >= z_bottom; cur_z -= TILE_HEIGHT) {
1059 DrawPillar(psid, x, y, cur_z, w, h, nullptr);
1060 }
1061 return cur_z;
1062}
1063
1075static void DrawBridgePillars(const PalSpriteID *psid, const TileInfo *ti, Axis axis, bool drawfarpillar, int x, int y, int z_bridge)
1076{
1077 static const int bounding_box_size[2] = {16, 2};
1078 static const int back_pillar_offset[2] = { 0, 9};
1079
1080 static const int INF = 1000;
1081 static const SubSprite half_pillar_sub_sprite[2][2] = {
1082 { { -14, -INF, INF, INF }, { -INF, -INF, -15, INF } }, // X axis, north and south
1083 { { -INF, -INF, 15, INF }, { 16, -INF, INF, INF } }, // Y axis, north and south
1084 };
1085
1086 if (psid->sprite == 0) return;
1087
1088 /* Determine ground height under pillars */
1089 DiagDirection south_dir = AxisToDiagDir(axis);
1090 int z_front_north = ti->z;
1091 int z_back_north = ti->z;
1092 int z_front_south = ti->z;
1093 int z_back_south = ti->z;
1094 GetSlopePixelZOnEdge(ti->tileh, south_dir, z_front_south, z_back_south);
1095 GetSlopePixelZOnEdge(ti->tileh, ReverseDiagDir(south_dir), z_front_north, z_back_north);
1096
1097 /* Shared height of pillars */
1098 int z_front = std::max(z_front_north, z_front_south);
1099 int z_back = std::max(z_back_north, z_back_south);
1100
1101 /* x and y size of bounding-box of pillars */
1102 int w = bounding_box_size[axis];
1103 int h = bounding_box_size[OtherAxis(axis)];
1104 /* sprite position of back facing pillar */
1105 int x_back = x - back_pillar_offset[axis];
1106 int y_back = y - back_pillar_offset[OtherAxis(axis)];
1107
1108 /* Draw front pillars */
1109 int bottom_z = DrawPillarColumn(z_front, z_bridge, psid, x, y, w, h);
1110 if (z_front_north < z_front) DrawPillar(psid, x, y, bottom_z, w, h, &half_pillar_sub_sprite[axis][0]);
1111 if (z_front_south < z_front) DrawPillar(psid, x, y, bottom_z, w, h, &half_pillar_sub_sprite[axis][1]);
1112
1113 /* Draw back pillars, skip top two parts, which are hidden by the bridge */
1114 int z_bridge_back = z_bridge - 2 * (int)TILE_HEIGHT;
1115 if (drawfarpillar && (z_back_north <= z_bridge_back || z_back_south <= z_bridge_back)) {
1116 bottom_z = DrawPillarColumn(z_back, z_bridge_back, psid, x_back, y_back, w, h);
1117 if (z_back_north < z_back) DrawPillar(psid, x_back, y_back, bottom_z, w, h, &half_pillar_sub_sprite[axis][0]);
1118 if (z_back_south < z_back) DrawPillar(psid, x_back, y_back, bottom_z, w, h, &half_pillar_sub_sprite[axis][1]);
1119 }
1120}
1121
1131static void GetBridgeRoadCatenary(const RoadTypeInfo *rti, TileIndex head_tile, int offset, bool head, SpriteID &spr_back, SpriteID &spr_front)
1132{
1133 static const SpriteID back_offsets[6] = { 95, 96, 99, 102, 100, 101 };
1134 static const SpriteID front_offsets[6] = { 97, 98, 103, 106, 104, 105 };
1135
1136 /* Simplified from DrawRoadTypeCatenary() to remove all the special cases required for regular ground road */
1137 spr_back = GetCustomRoadSprite(rti, head_tile, ROTSG_CATENARY_BACK, head ? TCX_NORMAL : TCX_ON_BRIDGE);
1138 spr_front = GetCustomRoadSprite(rti, head_tile, ROTSG_CATENARY_FRONT, head ? TCX_NORMAL : TCX_ON_BRIDGE);
1139 if (spr_back == 0 && spr_front == 0) {
1140 spr_back = SPR_TRAMWAY_BASE + back_offsets[offset];
1141 spr_front = SPR_TRAMWAY_BASE + front_offsets[offset];
1142 } else {
1143 if (spr_back != 0) spr_back += 23 + offset;
1144 if (spr_front != 0) spr_front += 23 + offset;
1145 }
1146}
1147
1157static void DrawBridgeRoadBits(TileIndex head_tile, int x, int y, int z, int offset, bool head)
1158{
1159 RoadType road_rt = GetRoadTypeRoad(head_tile);
1160 RoadType tram_rt = GetRoadTypeTram(head_tile);
1161 const RoadTypeInfo *road_rti = road_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(road_rt);
1162 const RoadTypeInfo *tram_rti = tram_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(tram_rt);
1163
1164 SpriteID seq_back[4] = { 0 };
1165 bool trans_back[4] = { false };
1166 SpriteID seq_front[4] = { 0 };
1167 bool trans_front[4] = { false };
1168
1169 static const SpriteID overlay_offsets[6] = { 0, 1, 11, 12, 13, 14 };
1170 if (head || !IsInvisibilitySet(TO_BRIDGES)) {
1171 /* Road underlay takes precedence over tram */
1172 trans_back[0] = !head && IsTransparencySet(TO_BRIDGES);
1173 if (road_rti != nullptr) {
1174 if (road_rti->UsesOverlay()) {
1175 seq_back[0] = GetCustomRoadSprite(road_rti, head_tile, ROTSG_BRIDGE, head ? TCX_NORMAL : TCX_ON_BRIDGE) + offset;
1176 }
1177 } else if (tram_rti != nullptr) {
1178 if (tram_rti->UsesOverlay()) {
1179 seq_back[0] = GetCustomRoadSprite(tram_rti, head_tile, ROTSG_BRIDGE, head ? TCX_NORMAL : TCX_ON_BRIDGE) + offset;
1180 } else {
1181 seq_back[0] = SPR_TRAMWAY_BRIDGE + offset;
1182 }
1183 }
1184
1185 /* Draw road overlay */
1186 trans_back[1] = !head && IsTransparencySet(TO_BRIDGES);
1187 if (road_rti != nullptr) {
1188 if (road_rti->UsesOverlay()) {
1189 seq_back[1] = GetCustomRoadSprite(road_rti, head_tile, ROTSG_OVERLAY, head ? TCX_NORMAL : TCX_ON_BRIDGE);
1190 if (seq_back[1] != 0) seq_back[1] += overlay_offsets[offset];
1191 }
1192 }
1193
1194 /* Draw tram overlay */
1195 trans_back[2] = !head && IsTransparencySet(TO_BRIDGES);
1196 if (tram_rti != nullptr) {
1197 if (tram_rti->UsesOverlay()) {
1198 seq_back[2] = GetCustomRoadSprite(tram_rti, head_tile, ROTSG_OVERLAY, head ? TCX_NORMAL : TCX_ON_BRIDGE);
1199 if (seq_back[2] != 0) seq_back[2] += overlay_offsets[offset];
1200 } else if (road_rti != nullptr) {
1201 seq_back[2] = SPR_TRAMWAY_OVERLAY + overlay_offsets[offset];
1202 }
1203 }
1204
1205 /* Road catenary takes precedence over tram */
1206 trans_back[3] = IsTransparencySet(TO_CATENARY);
1207 trans_front[0] = IsTransparencySet(TO_CATENARY);
1208 if (road_rti != nullptr && HasRoadCatenaryDrawn(road_rt)) {
1209 GetBridgeRoadCatenary(road_rti, head_tile, offset, head, seq_back[3], seq_front[0]);
1210 } else if (tram_rti != nullptr && HasRoadCatenaryDrawn(tram_rt)) {
1211 GetBridgeRoadCatenary(tram_rti, head_tile, offset, head, seq_back[3], seq_front[0]);
1212 }
1213 }
1214
1215 static const uint size_x[6] = { 1, 16, 16, 1, 16, 1 };
1216 static const uint size_y[6] = { 16, 1, 1, 16, 1, 16 };
1217 static const uint front_bb_offset_x[6] = { 15, 0, 0, 15, 0, 15 };
1218 static const uint front_bb_offset_y[6] = { 0, 15, 15, 0, 15, 0 };
1219
1220 /* The sprites under the vehicles are drawn as SpriteCombine. StartSpriteCombine() has already been called
1221 * The bounding boxes here are the same as for bridge front/roof */
1222 for (uint i = 0; i < lengthof(seq_back); ++i) {
1223 if (seq_back[i] != 0) {
1224 AddSortableSpriteToDraw(seq_back[i], PAL_NONE,
1225 x, y, size_x[offset], size_y[offset], 0x28, z,
1226 trans_back[i]);
1227 }
1228 }
1229
1230 /* Start a new SpriteCombine for the front part */
1233
1234 for (uint i = 0; i < lengthof(seq_front); ++i) {
1235 if (seq_front[i] != 0) {
1236 AddSortableSpriteToDraw(seq_front[i], PAL_NONE,
1237 x, y, size_x[offset] + front_bb_offset_x[offset], size_y[offset] + front_bb_offset_y[offset], 0x28, z,
1238 trans_front[i],
1239 front_bb_offset_x[offset], front_bb_offset_y[offset]);
1240 }
1241 }
1242}
1243
1258{
1259 TransportType transport_type = GetTunnelBridgeTransportType(ti->tile);
1260 DiagDirection tunnelbridge_direction = GetTunnelBridgeDirection(ti->tile);
1261
1262 if (IsTunnel(ti->tile)) {
1263 /* Front view of tunnel bounding boxes:
1264 *
1265 * 122223 <- BB_Z_SEPARATOR
1266 * 1 3
1267 * 1 3 1,3 = empty helper BB
1268 * 1 3 2 = SpriteCombine of tunnel-roof and catenary (tram & elrail)
1269 *
1270 */
1271
1272 static const int _tunnel_BB[4][12] = {
1273 /* tunnnel-roof | Z-separator | tram-catenary
1274 * w h bb_x bb_y| x y w h |bb_x bb_y w h */
1275 { 1, 0, -15, -14, 0, 15, 16, 1, 0, 1, 16, 15 }, // NE
1276 { 0, 1, -14, -15, 15, 0, 1, 16, 1, 0, 15, 16 }, // SE
1277 { 1, 0, -15, -14, 0, 15, 16, 1, 0, 1, 16, 15 }, // SW
1278 { 0, 1, -14, -15, 15, 0, 1, 16, 1, 0, 15, 16 }, // NW
1279 };
1280 const int *BB_data = _tunnel_BB[tunnelbridge_direction];
1281
1282 bool catenary = false;
1283
1284 SpriteID image;
1285 SpriteID railtype_overlay = 0;
1286 if (transport_type == TRANSPORT_RAIL) {
1287 const RailTypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
1288 image = rti->base_sprites.tunnel;
1289 if (rti->UsesOverlay()) {
1290 /* Check if the railtype has custom tunnel portals. */
1291 railtype_overlay = GetCustomRailSprite(rti, ti->tile, RTSG_TUNNEL_PORTAL);
1292 if (railtype_overlay != 0) image = SPR_RAILTYPE_TUNNEL_BASE; // Draw blank grass tunnel base.
1293 }
1294 } else {
1295 image = SPR_TUNNEL_ENTRY_REAR_ROAD;
1296 }
1297
1298 if (HasTunnelBridgeSnowOrDesert(ti->tile)) image += railtype_overlay != 0 ? 8 : 32;
1299
1300 image += tunnelbridge_direction * 2;
1301 DrawGroundSprite(image, PAL_NONE);
1302
1303 if (transport_type == TRANSPORT_ROAD) {
1304 RoadType road_rt = GetRoadTypeRoad(ti->tile);
1305 RoadType tram_rt = GetRoadTypeTram(ti->tile);
1306 const RoadTypeInfo *road_rti = road_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(road_rt);
1307 const RoadTypeInfo *tram_rti = tram_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(tram_rt);
1308 uint sprite_offset = DiagDirToAxis(tunnelbridge_direction) == AXIS_X ? 1 : 0;
1309 bool draw_underlay = true;
1310
1311 /* Road underlay takes precedence over tram */
1312 if (road_rti != nullptr) {
1313 if (road_rti->UsesOverlay()) {
1314 SpriteID ground = GetCustomRoadSprite(road_rti, ti->tile, ROTSG_TUNNEL);
1315 if (ground != 0) {
1316 DrawGroundSprite(ground + tunnelbridge_direction, PAL_NONE);
1317 draw_underlay = false;
1318 }
1319 }
1320 } else {
1321 if (tram_rti->UsesOverlay()) {
1322 SpriteID ground = GetCustomRoadSprite(tram_rti, ti->tile, ROTSG_TUNNEL);
1323 if (ground != 0) {
1324 DrawGroundSprite(ground + tunnelbridge_direction, PAL_NONE);
1325 draw_underlay = false;
1326 }
1327 }
1328 }
1329
1330 DrawRoadOverlays(ti, PAL_NONE, road_rti, tram_rti, sprite_offset, sprite_offset, draw_underlay);
1331
1332 /* Road catenary takes precedence over tram */
1333 SpriteID catenary_sprite_base = 0;
1334 if (road_rti != nullptr && HasRoadCatenaryDrawn(road_rt)) {
1335 catenary_sprite_base = GetCustomRoadSprite(road_rti, ti->tile, ROTSG_CATENARY_FRONT);
1336 if (catenary_sprite_base == 0) {
1337 catenary_sprite_base = SPR_TRAMWAY_TUNNEL_WIRES;
1338 } else {
1339 catenary_sprite_base += 19;
1340 }
1341 } else if (tram_rti != nullptr && HasRoadCatenaryDrawn(tram_rt)) {
1342 catenary_sprite_base = GetCustomRoadSprite(tram_rti, ti->tile, ROTSG_CATENARY_FRONT);
1343 if (catenary_sprite_base == 0) {
1344 catenary_sprite_base = SPR_TRAMWAY_TUNNEL_WIRES;
1345 } else {
1346 catenary_sprite_base += 19;
1347 }
1348 }
1349
1350 if (catenary_sprite_base != 0) {
1351 catenary = true;
1353 AddSortableSpriteToDraw(catenary_sprite_base + tunnelbridge_direction, PAL_NONE, ti->x, ti->y, BB_data[10], BB_data[11], TILE_HEIGHT, ti->z, IsTransparencySet(TO_CATENARY), BB_data[8], BB_data[9], BB_Z_SEPARATOR);
1354 }
1355 } else {
1356 const RailTypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
1357 if (rti->UsesOverlay()) {
1358 SpriteID surface = GetCustomRailSprite(rti, ti->tile, RTSG_TUNNEL);
1359 if (surface != 0) DrawGroundSprite(surface + tunnelbridge_direction, PAL_NONE);
1360 }
1361
1362 /* PBS debugging, draw reserved tracks darker */
1363 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasTunnelBridgeReservation(ti->tile)) {
1364 if (rti->UsesOverlay()) {
1365 SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
1366 DrawGroundSprite(overlay + RTO_X + DiagDirToAxis(tunnelbridge_direction), PALETTE_CRASH);
1367 } else {
1369 }
1370 }
1371
1373 /* Maybe draw pylons on the entry side */
1374 DrawRailCatenary(ti);
1375
1376 catenary = true;
1378 /* Draw wire above the ramp */
1380 }
1381 }
1382
1383 if (railtype_overlay != 0 && !catenary) StartSpriteCombine();
1384
1385 AddSortableSpriteToDraw(image + 1, PAL_NONE, ti->x + TILE_SIZE - 1, ti->y + TILE_SIZE - 1, BB_data[0], BB_data[1], TILE_HEIGHT, ti->z, false, BB_data[2], BB_data[3], BB_Z_SEPARATOR);
1386 /* Draw railtype tunnel portal overlay if defined. */
1387 if (railtype_overlay != 0) AddSortableSpriteToDraw(railtype_overlay + tunnelbridge_direction, PAL_NONE, ti->x + TILE_SIZE - 1, ti->y + TILE_SIZE - 1, BB_data[0], BB_data[1], TILE_HEIGHT, ti->z, false, BB_data[2], BB_data[3], BB_Z_SEPARATOR);
1388
1389 if (catenary || railtype_overlay != 0) EndSpriteCombine();
1390
1391 /* Add helper BB for sprite sorting that separates the tunnel from things beside of it. */
1392 AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, ti->x, ti->y, BB_data[6], BB_data[7], TILE_HEIGHT, ti->z);
1393 AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, ti->x + BB_data[4], ti->y + BB_data[5], BB_data[6], BB_data[7], TILE_HEIGHT, ti->z);
1394
1395 DrawBridgeMiddle(ti);
1396 } else { // IsBridge(ti->tile)
1397 const PalSpriteID *psid;
1398 int base_offset;
1399 bool ice = HasTunnelBridgeSnowOrDesert(ti->tile);
1400
1401 if (transport_type == TRANSPORT_RAIL) {
1402 base_offset = GetRailTypeInfo(GetRailType(ti->tile))->bridge_offset;
1403 assert(base_offset != 8); // This one is used for roads
1404 } else {
1405 base_offset = 8;
1406 }
1407
1408 /* as the lower 3 bits are used for other stuff, make sure they are clear */
1409 assert( (base_offset & 0x07) == 0x00);
1410
1411 DrawFoundation(ti, GetBridgeFoundation(ti->tileh, DiagDirToAxis(tunnelbridge_direction)));
1412
1413 /* HACK Wizardry to convert the bridge ramp direction into a sprite offset */
1414 base_offset += (6 - tunnelbridge_direction) % 4;
1415
1416 /* Table number BRIDGE_PIECE_HEAD always refers to the bridge heads for any bridge type */
1417 if (transport_type != TRANSPORT_WATER) {
1418 if (ti->tileh == SLOPE_FLAT) base_offset += 4; // sloped bridge head
1419 psid = &GetBridgeSpriteTable(GetBridgeType(ti->tile), BRIDGE_PIECE_HEAD)[base_offset];
1420 } else {
1421 psid = _aqueduct_sprites + base_offset;
1422 }
1423
1424 if (!ice) {
1425 TileIndex next = ti->tile + TileOffsByDiagDir(tunnelbridge_direction);
1426 if (ti->tileh != SLOPE_FLAT && ti->z == 0 && HasTileWaterClass(next) && GetWaterClass(next) == WATER_CLASS_SEA) {
1427 DrawShoreTile(ti->tileh);
1428 } else {
1429 DrawClearLandTile(ti, 3);
1430 }
1431 } else {
1432 DrawGroundSprite(SPR_FLAT_SNOW_DESERT_TILE + SlopeToSpriteOffset(ti->tileh), PAL_NONE);
1433 }
1434
1435 /* draw ramp */
1436
1437 /* Draw Trambits and PBS Reservation as SpriteCombine */
1438 if (transport_type == TRANSPORT_ROAD || transport_type == TRANSPORT_RAIL) StartSpriteCombine();
1439
1440 /* HACK set the height of the BB of a sloped ramp to 1 so a vehicle on
1441 * it doesn't disappear behind it
1442 */
1443 /* Bridge heads are drawn solid no matter how invisibility/transparency is set */
1444 AddSortableSpriteToDraw(psid->sprite, psid->pal, ti->x, ti->y, 16, 16, ti->tileh == SLOPE_FLAT ? 0 : 8, ti->z);
1445
1446 if (transport_type == TRANSPORT_ROAD) {
1447 uint offset = tunnelbridge_direction;
1448 int z = ti->z;
1449 if (ti->tileh != SLOPE_FLAT) {
1450 offset = (offset + 1) & 1;
1451 z += TILE_HEIGHT;
1452 } else {
1453 offset += 2;
1454 }
1455
1456 /* DrawBridgeRoadBits() calls EndSpriteCombine() and StartSpriteCombine() */
1457 DrawBridgeRoadBits(ti->tile, ti->x, ti->y, z, offset, true);
1458
1460 } else if (transport_type == TRANSPORT_RAIL) {
1461 const RailTypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
1462 if (rti->UsesOverlay()) {
1463 SpriteID surface = GetCustomRailSprite(rti, ti->tile, RTSG_BRIDGE);
1464 if (surface != 0) {
1465 if (HasBridgeFlatRamp(ti->tileh, DiagDirToAxis(tunnelbridge_direction))) {
1466 AddSortableSpriteToDraw(surface + ((DiagDirToAxis(tunnelbridge_direction) == AXIS_X) ? RTBO_X : RTBO_Y), PAL_NONE, ti->x, ti->y, 16, 16, 0, ti->z + 8);
1467 } else {
1468 AddSortableSpriteToDraw(surface + RTBO_SLOPE + tunnelbridge_direction, PAL_NONE, ti->x, ti->y, 16, 16, 8, ti->z);
1469 }
1470 }
1471 /* Don't fallback to non-overlay sprite -- the spec states that
1472 * if an overlay is present then the bridge surface must be
1473 * present. */
1474 }
1475
1476 /* PBS debugging, draw reserved tracks darker */
1477 if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasTunnelBridgeReservation(ti->tile)) {
1478 if (rti->UsesOverlay()) {
1479 SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
1480 if (HasBridgeFlatRamp(ti->tileh, DiagDirToAxis(tunnelbridge_direction))) {
1481 AddSortableSpriteToDraw(overlay + RTO_X + DiagDirToAxis(tunnelbridge_direction), PALETTE_CRASH, ti->x, ti->y, 16, 16, 0, ti->z + 8);
1482 } else {
1483 AddSortableSpriteToDraw(overlay + RTO_SLOPE_NE + tunnelbridge_direction, PALETTE_CRASH, ti->x, ti->y, 16, 16, 8, ti->z);
1484 }
1485 } else {
1486 if (HasBridgeFlatRamp(ti->tileh, DiagDirToAxis(tunnelbridge_direction))) {
1487 AddSortableSpriteToDraw(DiagDirToAxis(tunnelbridge_direction) == AXIS_X ? rti->base_sprites.single_x : rti->base_sprites.single_y, PALETTE_CRASH, ti->x, ti->y, 16, 16, 0, ti->z + 8);
1488 } else {
1489 AddSortableSpriteToDraw(rti->base_sprites.single_sloped + tunnelbridge_direction, PALETTE_CRASH, ti->x, ti->y, 16, 16, 8, ti->z);
1490 }
1491 }
1492 }
1493
1496 DrawRailCatenary(ti);
1497 }
1498 }
1499
1500 DrawBridgeMiddle(ti);
1501 }
1502}
1503
1504
1523static BridgePieces CalcBridgePiece(uint north, uint south)
1524{
1525 if (north == 1) {
1526 return BRIDGE_PIECE_NORTH;
1527 } else if (south == 1) {
1528 return BRIDGE_PIECE_SOUTH;
1529 } else if (north < south) {
1530 return north & 1 ? BRIDGE_PIECE_INNER_SOUTH : BRIDGE_PIECE_INNER_NORTH;
1531 } else if (north > south) {
1532 return south & 1 ? BRIDGE_PIECE_INNER_NORTH : BRIDGE_PIECE_INNER_SOUTH;
1533 } else {
1534 return north & 1 ? BRIDGE_PIECE_MIDDLE_EVEN : BRIDGE_PIECE_MIDDLE_ODD;
1535 }
1536}
1537
1543{
1544 /* Sectional view of bridge bounding boxes:
1545 *
1546 * 1 2 1,2 = SpriteCombine of Bridge front/(back&floor) and RoadCatenary
1547 * 1 2 3 = empty helper BB
1548 * 1 7 2 4,5 = pillars under higher bridges
1549 * 1 6 88888 6 2 6 = elrail-pylons
1550 * 1 6 88888 6 2 7 = elrail-wire
1551 * 1 6 88888 6 2 <- TILE_HEIGHT 8 = rail-vehicle on bridge
1552 * 3333333333333 <- BB_Z_SEPARATOR
1553 * <- unused
1554 * 4 5 <- BB_HEIGHT_UNDER_BRIDGE
1555 * 4 5
1556 * 4 5
1557 *
1558 */
1559
1560 if (!IsBridgeAbove(ti->tile)) return;
1561
1562 TileIndex rampnorth = GetNorthernBridgeEnd(ti->tile);
1563 TileIndex rampsouth = GetSouthernBridgeEnd(ti->tile);
1564 TransportType transport_type = GetTunnelBridgeTransportType(rampsouth);
1565
1566 Axis axis = GetBridgeAxis(ti->tile);
1568 GetTunnelBridgeLength(ti->tile, rampnorth) + 1,
1569 GetTunnelBridgeLength(ti->tile, rampsouth) + 1
1570 );
1571
1572 const PalSpriteID *psid;
1573 bool drawfarpillar;
1574 if (transport_type != TRANSPORT_WATER) {
1575 BridgeType type = GetBridgeType(rampsouth);
1576 drawfarpillar = !HasBit(GetBridgeSpec(type)->flags, 0);
1577
1578 uint base_offset;
1579 if (transport_type == TRANSPORT_RAIL) {
1580 base_offset = GetRailTypeInfo(GetRailType(rampsouth))->bridge_offset;
1581 } else {
1582 base_offset = 8;
1583 }
1584
1585 psid = base_offset + GetBridgeSpriteTable(type, piece);
1586 } else {
1587 drawfarpillar = true;
1588 psid = _aqueduct_sprites;
1589 }
1590
1591 if (axis != AXIS_X) psid += 4;
1592
1593 int x = ti->x;
1594 int y = ti->y;
1595 uint bridge_z = GetBridgePixelHeight(rampsouth);
1596 int z = bridge_z - BRIDGE_Z_START;
1597
1598 /* Add a bounding box that separates the bridge from things below it. */
1599 AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, x, y, 16, 16, 1, bridge_z - TILE_HEIGHT + BB_Z_SEPARATOR);
1600
1601 /* Draw Trambits as SpriteCombine */
1602 if (transport_type == TRANSPORT_ROAD || transport_type == TRANSPORT_RAIL) StartSpriteCombine();
1603
1604 /* Draw floor and far part of bridge*/
1606 if (axis == AXIS_X) {
1607 AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, 16, 1, 0x28, z, IsTransparencySet(TO_BRIDGES), 0, 0, BRIDGE_Z_START);
1608 } else {
1609 AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, 1, 16, 0x28, z, IsTransparencySet(TO_BRIDGES), 0, 0, BRIDGE_Z_START);
1610 }
1611 }
1612
1613 psid++;
1614
1615 if (transport_type == TRANSPORT_ROAD) {
1616 /* DrawBridgeRoadBits() calls EndSpriteCombine() and StartSpriteCombine() */
1617 DrawBridgeRoadBits(rampsouth, x, y, bridge_z, axis ^ 1, false);
1618 } else if (transport_type == TRANSPORT_RAIL) {
1619 const RailTypeInfo *rti = GetRailTypeInfo(GetRailType(rampsouth));
1620 if (rti->UsesOverlay() && !IsInvisibilitySet(TO_BRIDGES)) {
1621 SpriteID surface = GetCustomRailSprite(rti, rampsouth, RTSG_BRIDGE, TCX_ON_BRIDGE);
1622 if (surface != 0) {
1623 AddSortableSpriteToDraw(surface + axis, PAL_NONE, x, y, 16, 16, 0, bridge_z, IsTransparencySet(TO_BRIDGES));
1624 }
1625 }
1626
1628 if (rti->UsesOverlay()) {
1629 SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
1630 AddSortableSpriteToDraw(overlay + RTO_X + axis, PALETTE_CRASH, ti->x, ti->y, 16, 16, 0, bridge_z, IsTransparencySet(TO_BRIDGES));
1631 } else {
1632 AddSortableSpriteToDraw(axis == AXIS_X ? rti->base_sprites.single_x : rti->base_sprites.single_y, PALETTE_CRASH, ti->x, ti->y, 16, 16, 0, bridge_z, IsTransparencySet(TO_BRIDGES));
1633 }
1634 }
1635
1637
1638 if (HasRailCatenaryDrawn(GetRailType(rampsouth))) {
1640 }
1641 }
1642
1643 /* draw roof, the component of the bridge which is logically between the vehicle and the camera */
1645 if (axis == AXIS_X) {
1646 y += 12;
1647 if (psid->sprite & SPRITE_MASK) AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, 16, 4, 0x28, z, IsTransparencySet(TO_BRIDGES), 0, 3, BRIDGE_Z_START);
1648 } else {
1649 x += 12;
1650 if (psid->sprite & SPRITE_MASK) AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, 4, 16, 0x28, z, IsTransparencySet(TO_BRIDGES), 3, 0, BRIDGE_Z_START);
1651 }
1652 }
1653
1654 /* Draw TramFront as SpriteCombine */
1655 if (transport_type == TRANSPORT_ROAD) EndSpriteCombine();
1656
1657 /* Do not draw anything more if bridges are invisible */
1658 if (IsInvisibilitySet(TO_BRIDGES)) return;
1659
1660 psid++;
1661 DrawBridgePillars(psid, ti, axis, drawfarpillar, x, y, z);
1662}
1663
1664
1665static int GetSlopePixelZ_TunnelBridge(TileIndex tile, uint x, uint y, bool ground_vehicle)
1666{
1667 auto [tileh, z] = GetTilePixelSlope(tile);
1668
1669 x &= 0xF;
1670 y &= 0xF;
1671
1672 if (IsTunnel(tile)) {
1673 /* In the tunnel entrance? */
1674 if (ground_vehicle) return z;
1675 } else { // IsBridge(tile)
1678
1679 /* On the bridge ramp? */
1680 if (ground_vehicle) {
1681 if (tileh != SLOPE_FLAT) return z + TILE_HEIGHT;
1682
1683 switch (dir) {
1684 default: NOT_REACHED();
1685 case DIAGDIR_NE: tileh = SLOPE_NE; break;
1686 case DIAGDIR_SE: tileh = SLOPE_SE; break;
1687 case DIAGDIR_SW: tileh = SLOPE_SW; break;
1688 case DIAGDIR_NW: tileh = SLOPE_NW; break;
1689 }
1690 }
1691 }
1692
1693 return z + GetPartialPixelZ(x, y, tileh);
1694}
1695
1696static Foundation GetFoundation_TunnelBridge(TileIndex tile, Slope tileh)
1697{
1699}
1700
1701static void GetTileDesc_TunnelBridge(TileIndex tile, TileDesc *td)
1702{
1704
1705 if (IsTunnel(tile)) {
1706 td->str = (tt == TRANSPORT_RAIL) ? STR_LAI_TUNNEL_DESCRIPTION_RAILROAD : STR_LAI_TUNNEL_DESCRIPTION_ROAD;
1707 } else { // IsBridge(tile)
1708 td->str = (tt == TRANSPORT_WATER) ? STR_LAI_BRIDGE_DESCRIPTION_AQUEDUCT : GetBridgeSpec(GetBridgeType(tile))->transport_name[tt];
1709 }
1710 td->owner[0] = GetTileOwner(tile);
1711
1712 Owner road_owner = INVALID_OWNER;
1713 Owner tram_owner = INVALID_OWNER;
1714 RoadType road_rt = GetRoadTypeRoad(tile);
1715 RoadType tram_rt = GetRoadTypeTram(tile);
1716 if (road_rt != INVALID_ROADTYPE) {
1717 const RoadTypeInfo *rti = GetRoadTypeInfo(road_rt);
1718 td->roadtype = rti->strings.name;
1719 td->road_speed = rti->max_speed / 2;
1720 road_owner = GetRoadOwner(tile, RTT_ROAD);
1721 }
1722 if (tram_rt != INVALID_ROADTYPE) {
1723 const RoadTypeInfo *rti = GetRoadTypeInfo(tram_rt);
1724 td->tramtype = rti->strings.name;
1725 td->tram_speed = rti->max_speed / 2;
1726 tram_owner = GetRoadOwner(tile, RTT_TRAM);
1727 }
1728
1729 /* Is there a mix of owners? */
1730 if ((tram_owner != INVALID_OWNER && tram_owner != td->owner[0]) ||
1731 (road_owner != INVALID_OWNER && road_owner != td->owner[0])) {
1732 uint i = 1;
1733 if (road_owner != INVALID_OWNER) {
1734 td->owner_type[i] = STR_LAND_AREA_INFORMATION_ROAD_OWNER;
1735 td->owner[i] = road_owner;
1736 i++;
1737 }
1738 if (tram_owner != INVALID_OWNER) {
1739 td->owner_type[i] = STR_LAND_AREA_INFORMATION_TRAM_OWNER;
1740 td->owner[i] = tram_owner;
1741 }
1742 }
1743
1744 if (tt == TRANSPORT_RAIL) {
1745 const RailTypeInfo *rti = GetRailTypeInfo(GetRailType(tile));
1746 td->rail_speed = rti->max_speed;
1747 td->railtype = rti->strings.name;
1748
1749 if (!IsTunnel(tile)) {
1750 uint16_t spd = GetBridgeSpec(GetBridgeType(tile))->speed;
1751 /* rail speed special-cases 0 as unlimited, hides display of limit etc. */
1752 if (spd == UINT16_MAX) spd = 0;
1753 if (td->rail_speed == 0 || spd < td->rail_speed) {
1754 td->rail_speed = spd;
1755 }
1756 }
1757 } else if (tt == TRANSPORT_ROAD && !IsTunnel(tile)) {
1758 uint16_t spd = GetBridgeSpec(GetBridgeType(tile))->speed;
1759 /* road speed special-cases 0 as unlimited, hides display of limit etc. */
1760 if (spd == UINT16_MAX) spd = 0;
1761 if (road_rt != INVALID_ROADTYPE && (td->road_speed == 0 || spd < td->road_speed)) td->road_speed = spd;
1762 if (tram_rt != INVALID_ROADTYPE && (td->tram_speed == 0 || spd < td->tram_speed)) td->tram_speed = spd;
1763 }
1764}
1765
1766
1767static void TileLoop_TunnelBridge(TileIndex tile)
1768{
1769 bool snow_or_desert = HasTunnelBridgeSnowOrDesert(tile);
1771 case LT_ARCTIC: {
1772 /* As long as we do not have a snow density, we want to use the density
1773 * from the entry edge. For tunnels this is the lowest point for bridges the highest point.
1774 * (Independent of foundations) */
1775 int z = IsBridge(tile) ? GetTileMaxZ(tile) : GetTileZ(tile);
1776 if (snow_or_desert != (z > GetSnowLine())) {
1777 SetTunnelBridgeSnowOrDesert(tile, !snow_or_desert);
1778 MarkTileDirtyByTile(tile);
1779 }
1780 break;
1781 }
1782
1783 case LT_TROPIC:
1784 if (GetTropicZone(tile) == TROPICZONE_DESERT && !snow_or_desert) {
1785 SetTunnelBridgeSnowOrDesert(tile, true);
1786 MarkTileDirtyByTile(tile);
1787 }
1788 break;
1789
1790 default:
1791 break;
1792 }
1793}
1794
1795static TrackStatus GetTileTrackStatus_TunnelBridge(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
1796{
1797 TransportType transport_type = GetTunnelBridgeTransportType(tile);
1798 if (transport_type != mode || (transport_type == TRANSPORT_ROAD && !HasTileRoadType(tile, (RoadTramType)sub_mode))) return 0;
1799
1801 if (side != INVALID_DIAGDIR && side != ReverseDiagDir(dir)) return 0;
1803}
1804
1805static void ChangeTileOwner_TunnelBridge(TileIndex tile, Owner old_owner, Owner new_owner)
1806{
1807 TileIndex other_end = GetOtherTunnelBridgeEnd(tile);
1808 /* Set number of pieces to zero if it's the southern tile as we
1809 * don't want to update the infrastructure counts twice. */
1810 uint num_pieces = tile < other_end ? (GetTunnelBridgeLength(tile, other_end) + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR : 0;
1811
1812 for (RoadTramType rtt : _roadtramtypes) {
1813 /* Update all roadtypes, no matter if they are present */
1814 if (GetRoadOwner(tile, rtt) == old_owner) {
1815 RoadType rt = GetRoadType(tile, rtt);
1816 if (rt != INVALID_ROADTYPE) {
1817 /* Update company infrastructure counts. A full diagonal road tile has two road bits.
1818 * No need to dirty windows here, we'll redraw the whole screen anyway. */
1819 Company::Get(old_owner)->infrastructure.road[rt] -= num_pieces * 2;
1820 if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.road[rt] += num_pieces * 2;
1821 }
1822
1823 SetRoadOwner(tile, rtt, new_owner == INVALID_OWNER ? OWNER_NONE : new_owner);
1824 }
1825 }
1826
1827 if (!IsTileOwner(tile, old_owner)) return;
1828
1829 /* Update company infrastructure counts for rail and water as well.
1830 * No need to dirty windows here, we'll redraw the whole screen anyway. */
1832 Company *old = Company::Get(old_owner);
1833 if (tt == TRANSPORT_RAIL) {
1834 old->infrastructure.rail[GetRailType(tile)] -= num_pieces;
1835 if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.rail[GetRailType(tile)] += num_pieces;
1836 } else if (tt == TRANSPORT_WATER) {
1837 old->infrastructure.water -= num_pieces;
1838 if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.water += num_pieces;
1839 }
1840
1841 if (new_owner != INVALID_OWNER) {
1842 SetTileOwner(tile, new_owner);
1843 } else {
1844 if (tt == TRANSPORT_RAIL) {
1845 /* Since all of our vehicles have been removed, it is safe to remove the rail
1846 * bridge / tunnel. */
1847 [[maybe_unused]] CommandCost ret = Command<CMD_LANDSCAPE_CLEAR>::Do(DC_EXEC | DC_BANKRUPT, tile);
1848 assert(ret.Succeeded());
1849 } else {
1850 /* In any other case, we can safely reassign the ownership to OWNER_NONE. */
1851 SetTileOwner(tile, OWNER_NONE);
1852 }
1853 }
1854}
1855
1868template <typename T>
1869static void PrepareToEnterBridge(T *gv)
1870{
1871 if (HasBit(gv->gv_flags, GVF_GOINGUP_BIT)) {
1872 gv->z_pos++;
1873 ClrBit(gv->gv_flags, GVF_GOINGUP_BIT);
1874 } else {
1875 ClrBit(gv->gv_flags, GVF_GOINGDOWN_BIT);
1876 }
1877}
1878
1884static const uint8_t TUNNEL_SOUND_FRAME = 1;
1885
1894extern const uint8_t _tunnel_visibility_frame[DIAGDIR_END] = {12, 8, 8, 12};
1895
1896static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex tile, int x, int y)
1897{
1898 int z = GetSlopePixelZ(x, y, true) - v->z_pos;
1899
1900 if (abs(z) > 2) return VETSB_CANNOT_ENTER;
1901 /* Direction into the wormhole */
1902 const DiagDirection dir = GetTunnelBridgeDirection(tile);
1903 /* Direction of the vehicle */
1904 const DiagDirection vdir = DirToDiagDir(v->direction);
1905 /* New position of the vehicle on the tile */
1906 uint8_t pos = (DiagDirToAxis(vdir) == AXIS_X ? x : y) & TILE_UNIT_MASK;
1907 /* Number of units moved by the vehicle since entering the tile */
1908 uint8_t frame = (vdir == DIAGDIR_NE || vdir == DIAGDIR_NW) ? TILE_SIZE - 1 - pos : pos;
1909
1910 if (IsTunnel(tile)) {
1911 if (v->type == VEH_TRAIN) {
1912 Train *t = Train::From(v);
1913
1914 if (t->track != TRACK_BIT_WORMHOLE && dir == vdir) {
1915 if (t->IsFrontEngine() && frame == TUNNEL_SOUND_FRAME) {
1916 if (!PlayVehicleSound(t, VSE_TUNNEL) && RailVehInfo(t->engine_type)->engclass == 0) {
1917 SndPlayVehicleFx(SND_05_TRAIN_THROUGH_TUNNEL, v);
1918 }
1919 return VETSB_CONTINUE;
1920 }
1921 if (frame == _tunnel_visibility_frame[dir]) {
1922 t->tile = tile;
1923 t->track = TRACK_BIT_WORMHOLE;
1924 t->vehstatus |= VS_HIDDEN;
1926 }
1927 }
1928
1929 if (dir == ReverseDiagDir(vdir) && frame == TILE_SIZE - _tunnel_visibility_frame[dir] && z == 0) {
1930 /* We're at the tunnel exit ?? */
1931 t->tile = tile;
1932 t->track = DiagDirToDiagTrackBits(vdir);
1933 assert(t->track);
1934 t->vehstatus &= ~VS_HIDDEN;
1936 }
1937 } else if (v->type == VEH_ROAD) {
1939
1940 /* Enter tunnel? */
1941 if (rv->state != RVSB_WORMHOLE && dir == vdir) {
1942 if (frame == _tunnel_visibility_frame[dir]) {
1943 /* Frame should be equal to the next frame number in the RV's movement */
1944 assert(frame == rv->frame + 1);
1945 rv->tile = tile;
1946 rv->state = RVSB_WORMHOLE;
1947 rv->vehstatus |= VS_HIDDEN;
1949 } else {
1950 return VETSB_CONTINUE;
1951 }
1952 }
1953
1954 /* We're at the tunnel exit ?? */
1955 if (dir == ReverseDiagDir(vdir) && frame == TILE_SIZE - _tunnel_visibility_frame[dir] && z == 0) {
1956 rv->tile = tile;
1957 rv->state = DiagDirToDiagTrackdir(vdir);
1958 rv->frame = frame;
1959 rv->vehstatus &= ~VS_HIDDEN;
1961 }
1962 }
1963 } else { // IsBridge(tile)
1964 if (v->type != VEH_SHIP) {
1965 /* modify speed of vehicle */
1966 uint16_t spd = GetBridgeSpec(GetBridgeType(tile))->speed;
1967
1968 if (v->type == VEH_ROAD) spd *= 2;
1969 Vehicle *first = v->First();
1970 first->cur_speed = std::min(first->cur_speed, spd);
1971 }
1972
1973 if (vdir == dir) {
1974 /* Vehicle enters bridge at the last frame inside this tile. */
1975 if (frame != TILE_SIZE - 1) return VETSB_CONTINUE;
1976 switch (v->type) {
1977 case VEH_TRAIN: {
1978 Train *t = Train::From(v);
1979 t->track = TRACK_BIT_WORMHOLE;
1981 break;
1982 }
1983
1984 case VEH_ROAD: {
1986 rv->state = RVSB_WORMHOLE;
1988 break;
1989 }
1990
1991 case VEH_SHIP:
1993 break;
1994
1995 default: NOT_REACHED();
1996 }
1998 } else if (vdir == ReverseDiagDir(dir)) {
1999 v->tile = tile;
2000 switch (v->type) {
2001 case VEH_TRAIN: {
2002 Train *t = Train::From(v);
2003 if (t->track == TRACK_BIT_WORMHOLE) {
2004 t->track = DiagDirToDiagTrackBits(vdir);
2006 }
2007 break;
2008 }
2009
2010 case VEH_ROAD: {
2012 if (rv->state == RVSB_WORMHOLE) {
2013 rv->state = DiagDirToDiagTrackdir(vdir);
2014 rv->frame = 0;
2016 }
2017 break;
2018 }
2019
2020 case VEH_SHIP: {
2021 Ship *ship = Ship::From(v);
2022 if (ship->state == TRACK_BIT_WORMHOLE) {
2023 ship->state = DiagDirToDiagTrackBits(vdir);
2025 }
2026 break;
2027 }
2028
2029 default: NOT_REACHED();
2030 }
2031 }
2032 }
2033 return VETSB_CONTINUE;
2034}
2035
2036static CommandCost TerraformTile_TunnelBridge(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new)
2037{
2039 DiagDirection direction = GetTunnelBridgeDirection(tile);
2040 Axis axis = DiagDirToAxis(direction);
2041 CommandCost res;
2042 auto [tileh_old, z_old] = GetTileSlopeZ(tile);
2043
2044 /* Check if new slope is valid for bridges in general (so we can safely call GetBridgeFoundation()) */
2045 if ((direction == DIAGDIR_NW) || (direction == DIAGDIR_NE)) {
2046 CheckBridgeSlope(BRIDGE_PIECE_SOUTH, axis, tileh_old, z_old);
2047 res = CheckBridgeSlope(BRIDGE_PIECE_SOUTH, axis, tileh_new, z_new);
2048 } else {
2049 CheckBridgeSlope(BRIDGE_PIECE_NORTH, axis, tileh_old, z_old);
2050 res = CheckBridgeSlope(BRIDGE_PIECE_NORTH, axis, tileh_new, z_new);
2051 }
2052
2053 /* Surface slope is valid and remains unchanged? */
2054 if (res.Succeeded() && (z_old == z_new) && (tileh_old == tileh_new)) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
2055 }
2056
2057 return Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile);
2058}
2059
2060extern const TileTypeProcs _tile_type_tunnelbridge_procs = {
2061 DrawTile_TunnelBridge, // draw_tile_proc
2062 GetSlopePixelZ_TunnelBridge, // get_slope_z_proc
2063 ClearTile_TunnelBridge, // clear_tile_proc
2064 nullptr, // add_accepted_cargo_proc
2065 GetTileDesc_TunnelBridge, // get_tile_desc_proc
2066 GetTileTrackStatus_TunnelBridge, // get_tile_track_status_proc
2067 nullptr, // click_tile_proc
2068 nullptr, // animate_tile_proc
2069 TileLoop_TunnelBridge, // tile_loop_proc
2070 ChangeTileOwner_TunnelBridge, // change_tile_owner_proc
2071 nullptr, // add_produced_cargo_proc
2072 VehicleEnter_TunnelBridge, // vehicle_enter_tile_proc
2073 GetFoundation_TunnelBridge, // get_foundation_proc
2074 TerraformTile_TunnelBridge, // terraform_tile_proc
2075};
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:67
BridgePieces
This enum is related to the definition of bridge pieces, which is used to determine the proper sprite...
Definition bridge.h:22
uint BridgeType
Bridge spec number.
Definition bridge.h:38
static const uint MAX_BRIDGES
Maximal number of available bridge specs.
Definition bridge.h:35
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
Cheats _cheats
All the cheats.
Definition cheat.cpp:16
Types related to cheating.
Common return value for all commands.
bool Succeeded() const
Did this command succeed?
void AddCost(const Money &cost)
Adds the given cost to the cost of the command.
Money GetCost() const
The costs as made up to this moment.
bool Failed() const
Did this command fail?
This struct contains all the info that is needed to draw and construct tracks.
Definition rail.h:127
SpriteID single_x
single piece of rail in X direction, without ground
Definition rail.h:137
SpriteID bridge_offset
Bridge offset.
Definition rail.h:196
uint16_t max_speed
Maximum speed for vehicles travelling on this rail type.
Definition rail.h:231
struct RailTypeInfo::@23 base_sprites
Struct containing the main sprites.
struct RailTypeInfo::@26 strings
Strings associated with the rail type.
SpriteID single_y
single piece of rail in Y direction, without ground
Definition rail.h:138
StringID name
Name of this rail type.
Definition rail.h:176
SpriteID tunnel
tunnel sprites base
Definition rail.h:145
SpriteID single_sloped
single piece of rail for slopes
Definition rail.h:143
struct RoadTypeInfo::@29 strings
Strings associated with the rail type.
uint16_t max_speed
Maximum speed for vehicles travelling on this road type.
Definition road.h:142
StringID name
Name of this rail type.
Definition road.h:103
static Year year
Current year, starting at 0.
Functions related to clear (MP_CLEAR) land.
Functions related to commands.
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
DoCommandFlag
List of flags for a command.
@ DC_AUTO
don't allow building on structures
@ DC_BANKRUPT
company bankrupts, skip money check, skip vehicle on tile check in some cases
@ DC_QUERY_COST
query cost only, don't build.
@ DC_EXEC
execute the given command
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.
Owner
Enum for all companies/owners.
@ INVALID_OWNER
An invalid owner.
@ OWNER_DEITY
The object is owned by a superuser / goal script.
@ OWNER_NONE
The tile has no ownership.
@ OWNER_WATER
The tile/execution is done by "water".
@ OWNER_TOWN
A town owns the tile, or a town is expanding.
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:506
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:568
header file for electrified rail specific functions
bool HasRailCatenaryDrawn(RailType rt)
Test if we should draw rail catenary.
Definition elrail_func.h:30
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:18
@ 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:163
TileIndexDiff TileOffsByAxis(Axis axis)
Convert an Axis to a TileIndexDiff.
Definition map_func.h:552
static debug_inline uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition map_func.h:425
static debug_inline uint TileX(TileIndex tile)
Get the X component of a tile.
Definition map_func.h:415
TileIndexDiff TileOffsByDiagDir(DiagDirection dir)
Convert a DiagDirection to a TileIndexDiff.
Definition map_func.h:567
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
constexpr void Swap(T &a, T &b)
Type safe swap operation.
@ TCX_ON_BRIDGE
Querying information about stuff on the bridge (via some bridgehead).
@ TCX_NORMAL
Nothing special.
Functions related to NewGRF objects.
@ OBJECT_FLAG_ALLOW_UNDER_BRIDGE
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:330
PBS support routines.
bool ValParamRailType(const RailType rail)
Validate functions for rail building.
Definition rail.cpp:206
@ RTSG_TUNNEL
Main group of ground images for snow or desert.
Definition rail.h:53
@ RTSG_OVERLAY
Images for overlaying track.
Definition rail.h:51
@ RTSG_BRIDGE
Bridge surface images.
Definition rail.h:56
@ RTSG_TUNNEL_PORTAL
Tunnel portal overlay.
Definition rail.h:60
@ RTBO_Y
Piece of rail in Y direction.
Definition rail.h:94
@ RTBO_X
Piece of rail in X direction.
Definition rail.h:93
@ RTBO_SLOPE
Sloped rail pieces, in order NE, SE, SW, NW.
Definition rail.h:95
Money RailClearCost(RailType railtype)
Returns the 'cost' of clearing the specified railtype.
Definition rail.h:386
Money RailBuildCost(RailType railtype)
Returns the cost of building the specified railtype.
Definition rail.h:375
@ RTO_SLOPE_NE
Piece of rail on slope with north-east raised.
Definition rail.h:77
@ RTO_X
Piece of rail in X direction.
Definition rail.h:71
const RailTypeInfo * GetRailTypeInfo(RailType railtype)
Returns a pointer to the Railtype information for a given railtype.
Definition rail.h:307
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:27
@ INVALID_RAILTYPE
Flag for invalid railtype.
Definition rail_type.h:34
bool ValParamRoadType(RoadType roadtype)
Validate functions for rail building.
Definition road.cpp:153
Money RoadClearCost(RoadType roadtype)
Returns the cost of clearing the specified roadtype.
Definition road.h:263
const RoadTypeInfo * GetRoadTypeInfo(RoadType roadtype)
Returns a pointer to the Roadtype information for a given roadtype.
Definition road.h:227
@ ROTSG_OVERLAY
Optional: Images for overlaying track.
Definition road.h:61
@ ROTSG_CATENARY_BACK
Optional: Catenary back.
Definition road.h:65
@ ROTSG_BRIDGE
Required: Bridge surface images.
Definition road.h:66
@ ROTSG_CATENARY_FRONT
Optional: Catenary front.
Definition road.h:64
@ ROTSG_TUNNEL
Optional: Ground images for tunnels.
Definition road.h:63
Money RoadBuildCost(RoadType roadtype)
Returns the cost of building the specified roadtype.
Definition road.h:252
void UpdateCompanyRoadInfrastructure(RoadType rt, Owner o, int count)
Update road infrastructure counts for a company.
Definition road_cmd.cpp:190
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:251
static debug_inline bool IsNormalRoadTile(Tile t)
Return whether a tile is a normal road tile.
Definition road_map.h:74
static debug_inline bool IsRoadDepot(Tile t)
Return whether a tile is a road depot.
Definition road_map.h:106
bool HasTileRoadType(Tile t, RoadTramType rtt)
Check if a tile has a road or a tram road type.
Definition road_map.h:211
Roadside GetRoadside(Tile tile)
Get the decorations of a road.
Definition road_map.h:493
Owner GetRoadOwner(Tile t, RoadTramType rtt)
Get the owner of a specific road type.
Definition road_map.h:234
void SetRoadside(Tile tile, Roadside s)
Set the decorations of a road.
Definition road_map.h:503
@ ROADSIDE_PAVED
Road with paved sidewalks.
Definition road_map.h:480
@ ROADSIDE_TREES
Road with trees on paved sidewalks.
Definition road_map.h:483
RoadType
The different roadtypes we support.
Definition road_type.h:25
@ INVALID_ROADTYPE
flag for invalid roadtype
Definition road_type.h:30
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:57
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:56
Base for ships.
void AddSideToSignalBuffer(TileIndex tile, DiagDirection side, Owner owner)
Add side of tile to signal update buffer.
Definition signal.cpp:624
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:1556
static const PaletteID PALETTE_CRASH
Recolour sprite greying of crashed vehicles.
Definition sprites.h:1605
static const SpriteID SPR_RAILTYPE_TUNNEL_BASE
Tunnel sprites with grass only for custom railtype tunnel.
Definition sprites.h:299
static const SpriteID SPR_TRAMWAY_BASE
Tramway sprites.
Definition sprites.h:272
Functions related to stations.
Definition of base types and functions in a cross-platform compatible way.
void free(const void *ptr)
Version of the standard free that accepts const pointers.
Definition stdafx.h:334
#define lengthof(array)
Return the length of an fixed size array.
Definition stdafx.h:280
void SetDParam(size_t n, uint64_t v)
Set a string parameter v at index n in the global string parameter array.
Definition strings.cpp:104
Functions related to OTTD's strings.
VehicleType type
Type of vehicle.
Struct containing information about a single bridge type.
Definition bridge.h:43
uint8_t min_length
the minimum length (not counting start and end tile)
Definition bridge.h:45
TimerGameCalendar::Year avail_year
the year where it becomes available
Definition bridge.h:44
PalSpriteID ** sprite_table
table of sprites for drawing the bridge
Definition bridge.h:53
uint16_t speed
maximum travel speed (1 unit = 1/1.6 mph = 1 km-ish/h)
Definition bridge.h:48
uint16_t max_length
the maximum length (not counting start and end tile)
Definition bridge.h:46
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:84
TileIndex first_tile
The first tile being cleared, which then causes the whole object to be cleared.
Definition object_base.h:85
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
bool show_track_reservation
highlight reserved tracks.
uint8_t 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:297
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:23
SpriteID sprite
The 'real' sprite.
Definition gfx_type.h:24
PaletteID pal
The palette (use PAL_NONE) if not needed)
Definition gfx_type.h:25
Tindex index
Index of this pool item.
static bool IsValidID(size_t index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
static Titem * GetIfValid(size_t index)
Returns Titem with given index.
static Titem * Get(size_t index)
Returns Titem with given index.
EngineClass engclass
Class of engine for this vehicle.
Definition engine_type.h:54
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:231
Tile description for the 'land area information' tool.
Definition tile_cmd.h:52
uint16_t rail_speed
Speed limit of rail (bridges and track)
Definition tile_cmd.h:65
StringID str
Description of the tile.
Definition tile_cmd.h:53
uint16_t tram_speed
Speed limit of tram (bridges and track)
Definition tile_cmd.h:69
StringID roadtype
Type of road on the tile.
Definition tile_cmd.h:66
StringID tramtype
Type of tram on the tile.
Definition tile_cmd.h:68
StringID railtype
Type of rail on the tile.
Definition tile_cmd.h:64
uint16_t road_speed
Speed limit of road (bridges and track)
Definition tile_cmd.h:67
Owner owner[4]
Name of the owner(s)
Definition tile_cmd.h:55
StringID owner_type[4]
Type of each owner.
Definition tile_cmd.h:56
Tile information, used while rendering the tile.
Definition tile_cmd.h:43
int z
Height.
Definition tile_cmd.h:48
int x
X position of the tile in unit coordinates.
Definition tile_cmd.h:44
Slope tileh
Slope of the tile.
Definition tile_cmd.h:46
TileIndex tile
Tile index.
Definition tile_cmd.h:47
int y
Y position of the tile in unit coordinates.
Definition tile_cmd.h:45
Set of callback functions for performing tile operations of a given tile type.
Definition tile_cmd.h:158
std::array< uint32_t, HZB_END > squared_town_zone_radius
UpdateTownRadius updates this given the house count.
Definition town.h:47
Town data structure.
Definition town.h:54
TileIndex xy
town center tile
Definition town.h:55
TownCache cache
Container for all cacheable data.
Definition town.h:57
'Train' is either a loco or a wagon.
Definition train.h:89
Vehicle data structure.
EngineID engine_type
The type of engine used for this vehicle.
int32_t z_pos
z coordinate.
Direction direction
facing
debug_inline bool IsFrontEngine() const
Check if the vehicle is a front engine.
Vehicle * First() const
Get the first vehicle of this vehicle chain.
uint8_t vehstatus
Status.
uint16_t cur_speed
current speed
TileIndex tile
Current tile index.
Command definitions related to terraforming.
VehicleEnterTileStatus
The returned bits of VehicleEnterTile.
Definition tile_cmd.h:21
@ VETSB_ENTERED_WORMHOLE
The vehicle either entered a bridge, tunnel or depot tile (this includes the last tile of the bridge/...
Definition tile_cmd.h:37
@ VETSB_CANNOT_ENTER
The vehicle cannot enter the tile.
Definition tile_cmd.h:38
@ VETSB_CONTINUE
Bit sets of the above specified bits.
Definition tile_cmd.h:35
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
@ TROPICZONE_DESERT
Tile is desert.
Definition tile_type.h:78
static const uint TILE_HEIGHT
Height of a height level in world coordinate AND in pixels in ZOOM_BASE.
Definition tile_type.h:18
static const uint TILE_SIZE
Tile size in world coordinates.
Definition tile_type.h:15
static const uint TILE_UNIT_MASK
For masking in/out the inner-tile world coordinate units.
Definition tile_type.h:16
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:95
@ 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.
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:177
void ChangeTownRating(Town *t, int add, int max, DoCommandFlag flags)
Changes town rating of the current company.
Town * CalcClosestTownFromTile(TileIndex tile, uint threshold=UINT_MAX)
Return the town closest to the given tile within threshold.
CommandCost CheckforTownRating(DoCommandFlag 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:56
static constexpr int RATING_TUNNEL_BRIDGE_MINIMUM
minimum rating after removing tunnel or bridge
Definition town_type.h:58
static constexpr int RATING_TUNNEL_BRIDGE_DOWN_STEP
penalty for removing town owned tunnel or bridge
Definition town_type.h:57
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:99
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.
@ TO_BRIDGES
bridges
@ TO_CATENARY
catenary
bool IsTransparencySet(TransparencyOption to)
Check if the transparency option bit is set and if we aren't in the game menu (there's never transpar...
bool IsInvisibilitySet(TransparencyOption to)
Check if the invisibility option bit is set and if we aren't in the game menu (there's never transpar...
TransportType
Available types of transport.
@ 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 CmdBuildTunnel(DoCommandFlag flags, TileIndex start_tile, TransportType transport_type, uint8_t road_rail_type)
Build Tunnel.
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 CommandCost DoClearBridge(TileIndex tile, DoCommandFlag flags)
Remove a bridge from the game, update town rating, etc.
static Money TunnelBridgeClearCost(TileIndex tile, Price base_price)
Calculate the base cost of clearing a tunnel/bridge per tile.
void DrawBridgeMiddle(const TileInfo *ti)
Draw the middle bits of a bridge.
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 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).
void MarkBridgeDirty(TileIndex begin, TileIndex end, DiagDirection direction, uint bridge_height)
Mark bridge tiles dirty.
CommandCost CheckBridgeAvailability(BridgeType bridge_type, uint bridge_len, DoCommandFlag flags)
Is a bridge of the specified type and length available?
bool HasBridgeFlatRamp(Slope tileh, Axis axis)
Determines if the track on a bridge ramp is flat or goes up/down.
CommandCost CmdBuildBridge(DoCommandFlag flags, TileIndex tile_end, TileIndex tile_start, TransportType transport_type, BridgeType bridge_type, uint8_t road_rail_type)
Build a Bridge.
static void DrawTile_TunnelBridge(TileInfo *ti)
Draws a tunnel of bridge tile.
static CommandCost ClearTile_TunnelBridge(TileIndex tile, DoCommandFlag flags)
Remove a tunnel or a bridge from the game.
static const int BRIDGE_Z_START
Z position of the bridge sprites relative to bridge height (downwards)
static CommandCost DoClearTunnel(TileIndex tile, DoCommandFlag flags)
Remove a tunnel from the game, update town rating, etc.
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 void DrawPillar(const PalSpriteID *psid, int x, int y, int z, int w, int h, const SubSprite *subsprite)
Draw a single pillar sprite.
void ResetBridges()
Reset the data been eventually changed by the grf loaded.
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 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:575
@ VS_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:767
void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int w, int h, int dz, int z, bool transparent, int bb_offset_x, int bb_offset_y, int bb_offset_z, const SubSprite *sub)
Draw a (transparent) sprite at given coordinates with a given bounding box.
Definition viewport.cpp:671
void EndSpriteCombine()
Terminates a block of sprites started by StartSpriteCombine.
Definition viewport.cpp:777
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:587
Functions related to (drawing on) viewports.
static const uint BB_HEIGHT_UNDER_BRIDGE
Some values for constructing bounding boxes (BB).
static const uint 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.