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