mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-22 10:54:19 -04:00
Merge 899735cf5fc40f7b9b3a77a4b02291019c0e44b7 into d51ef24c205b6b05330b3c4d7ce79c402db44447
This commit is contained in:
commit
adb98489a4
@ -107,10 +107,6 @@ class RoadBetweenCitiesAutomation(val civInfo: Civilization, private val cachedF
|
||||
if (roadsToBuildByCitiesCache.containsKey(city))
|
||||
return roadsToBuildByCitiesCache[city]!!
|
||||
|
||||
// TODO: some better worker representative needs to be used here
|
||||
val workerUnit = civInfo.gameInfo.ruleset.units.map { it.value }.firstOrNull { it.hasUnique(UniqueType.BuildImprovements) }
|
||||
// This is a temporary unit only for AI purposes so it doesn't get a unique ID
|
||||
?.newMapUnit(civInfo, Constants.NO_ID) ?: return listOf()
|
||||
val roadToCapitalStatus = city.cityStats.getRoadTypeOfConnectionToCapital()
|
||||
|
||||
/** @return Rank 0, 1 or 2 of how important it is to build best available road to capital */
|
||||
@ -144,8 +140,8 @@ class RoadBetweenCitiesAutomation(val civInfo: Civilization, private val cachedF
|
||||
|
||||
// Try to build a plan for the road to the city
|
||||
// TODO: May return inconsistent paths across turns due to worker position, this makes it impossible to plan an exact road resulting in excessive roads built
|
||||
val roadPath = if (civInfo.cities.indexOf(city) < civInfo.cities.indexOf(closeCity)) MapPathing.getRoadPath(workerUnit, city.getCenterTile(), closeCity.getCenterTile()) ?: continue
|
||||
else MapPathing.getRoadPath(workerUnit, closeCity.getCenterTile(), city.getCenterTile()) ?: continue
|
||||
val roadPath = if (civInfo.cities.indexOf(city) < civInfo.cities.indexOf(closeCity)) MapPathing.getRoadPath(civInfo, city.getCenterTile(), closeCity.getCenterTile()) ?: continue
|
||||
else MapPathing.getRoadPath(civInfo, closeCity.getCenterTile(), city.getCenterTile()) ?: continue
|
||||
val worstRoadStatus = getWorstRoadTypeInPath(roadPath)
|
||||
if (worstRoadStatus == bestRoadAvailable) continue
|
||||
|
||||
@ -171,7 +167,7 @@ class RoadBetweenCitiesAutomation(val civInfo: Civilization, private val cachedF
|
||||
// If and only if we have no roads to build to close-by cities then we check for a road to build to the capital
|
||||
// The condition !city.isConnectedToCapital() is to avoid BFS for cities connected to capital with roads when railroads are unlocked
|
||||
else if (roadPlans.isEmpty() && (roadToCapitalStatus < bestRoadAvailable) && !city.isConnectedToCapital()) {
|
||||
val roadToCapital = getRoadToConnectCityToCapital(workerUnit, city)
|
||||
val roadToCapital = getRoadToConnectCityToCapital(city)
|
||||
|
||||
if (roadToCapital != null) {
|
||||
val worstRoadStatus = getWorstRoadTypeInPath(roadToCapital.second)
|
||||
@ -243,10 +239,10 @@ class RoadBetweenCitiesAutomation(val civInfo: Civilization, private val cachedF
|
||||
* @return a pair containing a list of tiles that resemble the road to build and the city that the road will connect to
|
||||
*/
|
||||
@Readonly
|
||||
private fun getRoadToConnectCityToCapital(unit: MapUnit, city: City): Pair<City, List<Tile>>? {
|
||||
private fun getRoadToConnectCityToCapital(city: City): Pair<City, List<Tile>>? {
|
||||
if (tilesOfConnectedCities.isEmpty()) return null // In mods with no capital city indicator, there are no connected cities
|
||||
|
||||
val isCandidateTilePredicate: (Tile) -> Boolean = { it.isLand && unit.movement.canPassThrough(it) }
|
||||
val isCandidateTilePredicate: (Tile) -> Boolean = { it.isLand && MapPathing.isValidRoadPathTile(city.civ, it) }
|
||||
val toConnectTile = city.getCenterTile()
|
||||
@LocalState val bfs: BFS = bfsCache[toConnectTile.position] ?: run {
|
||||
val bfs = BFS(toConnectTile, isCandidateTilePredicate)
|
||||
|
@ -52,7 +52,7 @@ class RoadToAutomation(val civInfo: Civilization) {
|
||||
|
||||
// The path does not exist, create it
|
||||
if (pathToDest == null) {
|
||||
val foundPath: List<Tile>? = MapPathing.getRoadPath(unit, currentTile, destinationTile)
|
||||
val foundPath: List<Tile>? = MapPathing.getRoadPath(unit.civ, unit.getTile(), destinationTile)
|
||||
if (foundPath == null) {
|
||||
Log.debug("WorkerAutomation: $unit -> connect road failed")
|
||||
stopAndCleanAutomation(unit)
|
||||
|
@ -16,29 +16,29 @@ object MapPathing {
|
||||
*/
|
||||
@Suppress("UNUSED_PARAMETER") // While `from` is unused, this function should stay close to the signatures expected by the AStar and getPath `heuristic` parameter.
|
||||
@Readonly
|
||||
private fun roadPreferredMovementCost(unit: MapUnit, from: Tile, to: Tile): Float{
|
||||
private fun roadPreferredMovementCost(civ: Civilization, from: Tile, to: Tile): Float{
|
||||
// hasRoadConnection accounts for civs that treat jungle/forest as roads
|
||||
// Ignore road over river penalties.
|
||||
if ((to.hasRoadConnection(unit.civ, false) || to.hasRailroadConnection(false)))
|
||||
if ((to.hasRoadConnection(civ, false) || to.hasRailroadConnection(false)))
|
||||
return .5f
|
||||
|
||||
return 1f
|
||||
}
|
||||
|
||||
@Readonly
|
||||
fun isValidRoadPathTile(unit: MapUnit, tile: Tile): Boolean {
|
||||
fun isValidRoadPathTile(civ: Civilization, tile: Tile): Boolean {
|
||||
val roadImprovement = tile.ruleset.roadImprovement
|
||||
val railRoadImprovement = tile.ruleset.railroadImprovement
|
||||
|
||||
if (tile.isWater) return false
|
||||
if (tile.isImpassible()) return false
|
||||
if (!unit.civ.hasExplored(tile)) return false
|
||||
if (!tile.canCivPassThrough(unit.civ)) return false
|
||||
if (!civ.hasExplored(tile)) return false
|
||||
if (!tile.canCivPassThrough(civ)) return false
|
||||
|
||||
return tile.hasRoadConnection(unit.civ, false)
|
||||
return tile.hasRoadConnection(civ, false)
|
||||
|| tile.hasRailroadConnection(false)
|
||||
|| roadImprovement != null && tile.improvementFunctions.canBuildImprovement(roadImprovement, unit.cache.state)
|
||||
|| railRoadImprovement != null && tile.improvementFunctions.canBuildImprovement(railRoadImprovement, unit.cache.state)
|
||||
|| roadImprovement != null && tile.improvementFunctions.canBuildImprovement(roadImprovement, civ.state)
|
||||
|| railRoadImprovement != null && tile.improvementFunctions.canBuildImprovement(railRoadImprovement,civ.state)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -46,14 +46,14 @@ object MapPathing {
|
||||
*
|
||||
* This function uses the A* search algorithm to find an optimal path for road construction between two specified tiles.
|
||||
*
|
||||
* @param unit The unit that will construct the road.
|
||||
* @param civ The civlization that will construct the road.
|
||||
* @param startTile The starting tile of the path.
|
||||
* @param endTile The destination tile of the path.
|
||||
* @return A sequence of tiles representing the path from startTile to endTile, or null if no valid path is found.
|
||||
*/
|
||||
@Readonly
|
||||
fun getRoadPath(unit: MapUnit, startTile: Tile, endTile: Tile): List<Tile>?{
|
||||
return getPath(unit,
|
||||
fun getRoadPath(civ: Civilization, startTile: Tile, endTile: Tile): List<Tile>? {
|
||||
return getConnection(civ,
|
||||
startTile,
|
||||
endTile,
|
||||
::isValidRoadPathTile,
|
||||
@ -112,13 +112,15 @@ object MapPathing {
|
||||
fun getConnection(civ: Civilization,
|
||||
startTile: Tile,
|
||||
endTile: Tile,
|
||||
predicate: (Civilization, Tile) -> Boolean
|
||||
predicate: (Civilization, Tile) -> Boolean,
|
||||
cost: (Civilization, Tile, Tile) -> Float = { _, _, _ -> 1f },
|
||||
heuristic: (Civilization, Tile, Tile) -> Float = { _, from, to -> from.aerialDistanceTo(to).toFloat() }
|
||||
): List<Tile>? {
|
||||
val astar = AStar(
|
||||
startTile,
|
||||
predicate = { tile -> predicate(civ, tile) },
|
||||
cost = { _, _ -> 1f },
|
||||
heuristic = { from, to -> from.aerialDistanceTo(to).toFloat() }
|
||||
cost = { from, to -> cost(civ, from, to) },
|
||||
heuristic = { from, to -> heuristic(civ, from, to) }
|
||||
)
|
||||
while (true) {
|
||||
if (astar.hasEnded()) {
|
||||
@ -136,4 +138,5 @@ object MapPathing {
|
||||
.reversed()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -468,7 +468,7 @@ class WorldMapHolder(
|
||||
selectedUnit.civ.hasExplored(tile)
|
||||
|
||||
if (validTile) {
|
||||
val roadPath: List<Tile>? = MapPathing.getRoadPath(selectedUnit, selectedUnit.currentTile, tile)
|
||||
val roadPath: List<Tile>? = MapPathing.getRoadPath(selectedUnit.civ, selectedUnit.getTile(), tile)
|
||||
launchOnGLThread {
|
||||
if (roadPath == null) { // give the regular tile overlays with no road connection
|
||||
addTileOverlays(tile)
|
||||
|
@ -104,7 +104,7 @@ object WorldMapTileUpdater {
|
||||
if (worldScreen.bottomUnitTable.selectedUnitIsConnectingRoad) {
|
||||
if (unit.currentTile.ruleset.roadImprovement == null) return
|
||||
val validTiles = unit.civ.gameInfo.tileMap.tileList.filter {
|
||||
MapPathing.isValidRoadPathTile(unit, it)
|
||||
MapPathing.isValidRoadPathTile(unit.civ, it)
|
||||
}
|
||||
val connectRoadTileOverlayColor = Color.RED
|
||||
for (tile in validTiles) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user