* Grows the town with a tunnel. * First we check if a tunnel is reasonable. * If so we check if we are able to build it. * * @param t The current town * @param tile The current tile * @param tunnel_dir The valid direction in which to grow a tunnel * @return true if a tunnel has been built, else false */
| 1399 | * @return true if a tunnel has been built, else false |
| 1400 | */ |
| 1401 | static bool GrowTownWithTunnel(const Town *t, const TileIndex tile, const DiagDirection tunnel_dir) |
| 1402 | { |
| 1403 | assert(tunnel_dir < DIAGDIR_END); |
| 1404 | |
| 1405 | Slope slope = GetTileSlope(tile); |
| 1406 | |
| 1407 | /* Only consider building a tunnel if the starting tile is sloped properly. */ |
| 1408 | if (slope != InclinedSlope(tunnel_dir)) return false; |
| 1409 | |
| 1410 | /* Assure that the tunnel is connectable to the start side */ |
| 1411 | if (!(GetTownRoadBits(TileAddByDiagDir(tile, ReverseDiagDir(tunnel_dir))) & DiagDirToRoadBits(tunnel_dir))) return false; |
| 1412 | |
| 1413 | const TileIndexDiff delta = TileOffsByDiagDir(tunnel_dir); |
| 1414 | int max_tunnel_length = 0; |
| 1415 | |
| 1416 | /* There are two conditions for building tunnels: Under a mountain and under an obstruction. */ |
| 1417 | if (CanRoadContinueIntoNextTile(t, tile, tunnel_dir)) { |
| 1418 | /* Only tunnel under a mountain if the slope is continuous for at least 4 tiles. We want tunneling to be a last resort for large hills. */ |
| 1419 | TileIndex slope_tile = tile; |
| 1420 | for (uint8_t tiles = 0; tiles < 4; tiles++) { |
| 1421 | if (!IsValidTile(slope_tile)) return false; |
| 1422 | slope = GetTileSlope(slope_tile); |
| 1423 | if (slope != InclinedSlope(tunnel_dir) && !IsSteepSlope(slope) && !IsSlopeWithOneCornerRaised(slope)) return false; |
| 1424 | slope_tile += delta; |
| 1425 | } |
| 1426 | |
| 1427 | /* More population means longer tunnels, but make sure we can at least cover the smallest mountain which necessitates tunneling. */ |
| 1428 | max_tunnel_length = (t->cache.population / 1000) + 7; |
| 1429 | } else { |
| 1430 | /* When tunneling under an obstruction, the length limit is 5, enough to tunnel under a four-track railway. */ |
| 1431 | max_tunnel_length = 5; |
| 1432 | } |
| 1433 | |
| 1434 | uint8_t tunnel_length = 0; |
| 1435 | TileIndex tunnel_tile = tile; // Iterator to store the other end tile of the tunnel. |
| 1436 | |
| 1437 | /* Find the end tile of the tunnel for length and continuation checks. */ |
| 1438 | do { |
| 1439 | if (tunnel_length++ >= max_tunnel_length) return false; |
| 1440 | tunnel_tile += delta; |
| 1441 | /* The tunnel ends when start and end tiles are the same height. */ |
| 1442 | } while (IsValidTile(tunnel_tile) && GetTileZ(tile) != GetTileZ(tunnel_tile)); |
| 1443 | |
| 1444 | /* Don't allow a tunnel where the start and end tiles are adjacent. */ |
| 1445 | if (tunnel_length == 1) return false; |
| 1446 | |
| 1447 | /* Make sure the road can be continued past the tunnel. At this point, tunnel_tile holds the end tile of the tunnel. */ |
| 1448 | if (!CanRoadContinueIntoNextTile(t, tunnel_tile, tunnel_dir)) return false; |
| 1449 | |
| 1450 | /* Attempt to build the tunnel. Return false if it fails to let the town build a road instead. */ |
| 1451 | RoadType rt = GetTownRoadType(); |
| 1452 | if (Command<CMD_BUILD_TUNNEL>::Do(CommandFlagsToDCFlags(GetCommandFlags<CMD_BUILD_TUNNEL>()), tile, TRANSPORT_ROAD, rt).Succeeded()) { |
| 1453 | Command<CMD_BUILD_TUNNEL>::Do(CommandFlagsToDCFlags(GetCommandFlags<CMD_BUILD_TUNNEL>()).Set(DoCommandFlag::Execute), tile, TRANSPORT_ROAD, rt); |
| 1454 | return true; |
| 1455 | } |
| 1456 | |
| 1457 | return false; |
| 1458 | } |
no test coverage detected