diff --git a/src/road.cpp b/src/road.cpp index da656a34d8..779b02e1c9 100644 --- a/src/road.cpp +++ b/src/road.cpp @@ -816,28 +816,54 @@ static void PublicRoad_FoundEndNode(AyStar *aystar, OpenListNode *current) } } -static const int32 BASE_COST_PER_TILE = 1; // Cost for existing road or tunnel/bridge. -static const int32 COST_FOR_NEW_ROAD = 100; // Cost for building a new road. -static const int32 COST_FOR_SLOPE = 50; // Additional cost if the road heads up or down a slope. +static const int32 BASE_COST_PER_TILE = 1; // Cost for existing road or tunnel/bridge. +static const int32 COST_FOR_NEW_ROAD = 100; // Cost for building a new road. +static const int32 COST_FOR_NEW_BRIDGE = 500; // Cost for building a new bridge (per tile). +static const int32 COST_FOR_NEW_TUNNEL = 500; // Cost for building a new tunnel (per tile, with non-linear increase with length as in CmdBuildTunnel costs). +static const int32 COST_FOR_SLOPE = 50; // Additional cost if the road heads up or down a slope. /** AyStar callback for getting the cost of the current node. */ static int32 PublicRoad_CalculateG(AyStar *, AyStarNode *current, OpenListNode *parent) { int32 cost = 0; + int32 distance = DistanceManhattan(parent->path.node.tile, current->tile); + if (IsTileType(current->tile, MP_ROAD) || IsTileType(current->tile, MP_TUNNELBRIDGE)) { - cost += (DistanceManhattan(parent->path.node.tile, current->tile)) * BASE_COST_PER_TILE; + cost += distance * BASE_COST_PER_TILE; } else { - cost += (DistanceManhattan(parent->path.node.tile, current->tile)) * COST_FOR_NEW_ROAD; + if (distance > 1) { + /* We are planning to build a bridge or tunnel. Make that much more expensive. */ + const DiagDirection road_direction = DiagdirBetweenTiles(parent->path.node.tile, current->tile); + if (IsUpwardsSlope(parent->path.node.tile, road_direction)) { + /* Tunnel */ + /* Prevent excessively long tunnels */ + if (distance > 30) return AYSTAR_INVALID_NODE; + + cost += 2 * COST_FOR_NEW_TUNNEL; + int32 middle_cost = 0; + int tiles_coef = 3; + int tiles_bump = 25; + for (int i = 1; i <= distance; i++) { + if (i == tiles_bump) { + tiles_coef++; + tiles_bump *= 2; + } + middle_cost += COST_FOR_NEW_TUNNEL; + middle_cost += middle_cost >> tiles_coef; + } + cost += middle_cost; + } else { + /* Bridge */ + cost += distance * COST_FOR_NEW_BRIDGE; + } + } else { + cost += distance * COST_FOR_NEW_ROAD; + } if (GetTileZ(parent->path.node.tile) != GetTileZ(current->tile)) { cost += COST_FOR_SLOPE; } - - if (DistanceManhattan(parent->path.node.tile, current->tile) > 1) { - // We are planning to build a bridge or tunnel. Make that a bit more expensive. - cost += 6 * COST_FOR_SLOPE; - } } if (_settings_game.game_creation.build_public_roads == PRC_AVOID_CURVES &&