mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-23 03:23:17 -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))
|
if (roadsToBuildByCitiesCache.containsKey(city))
|
||||||
return roadsToBuildByCitiesCache[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()
|
val roadToCapitalStatus = city.cityStats.getRoadTypeOfConnectionToCapital()
|
||||||
|
|
||||||
/** @return Rank 0, 1 or 2 of how important it is to build best available road to capital */
|
/** @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
|
// 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
|
// 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
|
val roadPath = if (civInfo.cities.indexOf(city) < civInfo.cities.indexOf(closeCity)) MapPathing.getRoadPath(civInfo, city.getCenterTile(), closeCity.getCenterTile()) ?: continue
|
||||||
else MapPathing.getRoadPath(workerUnit, closeCity.getCenterTile(), city.getCenterTile()) ?: continue
|
else MapPathing.getRoadPath(civInfo, closeCity.getCenterTile(), city.getCenterTile()) ?: continue
|
||||||
val worstRoadStatus = getWorstRoadTypeInPath(roadPath)
|
val worstRoadStatus = getWorstRoadTypeInPath(roadPath)
|
||||||
if (worstRoadStatus == bestRoadAvailable) continue
|
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
|
// 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
|
// 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()) {
|
else if (roadPlans.isEmpty() && (roadToCapitalStatus < bestRoadAvailable) && !city.isConnectedToCapital()) {
|
||||||
val roadToCapital = getRoadToConnectCityToCapital(workerUnit, city)
|
val roadToCapital = getRoadToConnectCityToCapital(city)
|
||||||
|
|
||||||
if (roadToCapital != null) {
|
if (roadToCapital != null) {
|
||||||
val worstRoadStatus = getWorstRoadTypeInPath(roadToCapital.second)
|
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
|
* @return a pair containing a list of tiles that resemble the road to build and the city that the road will connect to
|
||||||
*/
|
*/
|
||||||
@Readonly
|
@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
|
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()
|
val toConnectTile = city.getCenterTile()
|
||||||
@LocalState val bfs: BFS = bfsCache[toConnectTile.position] ?: run {
|
@LocalState val bfs: BFS = bfsCache[toConnectTile.position] ?: run {
|
||||||
val bfs = BFS(toConnectTile, isCandidateTilePredicate)
|
val bfs = BFS(toConnectTile, isCandidateTilePredicate)
|
||||||
|
@ -52,7 +52,7 @@ class RoadToAutomation(val civInfo: Civilization) {
|
|||||||
|
|
||||||
// The path does not exist, create it
|
// The path does not exist, create it
|
||||||
if (pathToDest == null) {
|
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) {
|
if (foundPath == null) {
|
||||||
Log.debug("WorkerAutomation: $unit -> connect road failed")
|
Log.debug("WorkerAutomation: $unit -> connect road failed")
|
||||||
stopAndCleanAutomation(unit)
|
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.
|
@Suppress("UNUSED_PARAMETER") // While `from` is unused, this function should stay close to the signatures expected by the AStar and getPath `heuristic` parameter.
|
||||||
@Readonly
|
@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
|
// hasRoadConnection accounts for civs that treat jungle/forest as roads
|
||||||
// Ignore road over river penalties.
|
// 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 .5f
|
||||||
|
|
||||||
return 1f
|
return 1f
|
||||||
}
|
}
|
||||||
|
|
||||||
@Readonly
|
@Readonly
|
||||||
fun isValidRoadPathTile(unit: MapUnit, tile: Tile): Boolean {
|
fun isValidRoadPathTile(civ: Civilization, tile: Tile): Boolean {
|
||||||
val roadImprovement = tile.ruleset.roadImprovement
|
val roadImprovement = tile.ruleset.roadImprovement
|
||||||
val railRoadImprovement = tile.ruleset.railroadImprovement
|
val railRoadImprovement = tile.ruleset.railroadImprovement
|
||||||
|
|
||||||
if (tile.isWater) return false
|
if (tile.isWater) return false
|
||||||
if (tile.isImpassible()) return false
|
if (tile.isImpassible()) return false
|
||||||
if (!unit.civ.hasExplored(tile)) return false
|
if (!civ.hasExplored(tile)) return false
|
||||||
if (!tile.canCivPassThrough(unit.civ)) return false
|
if (!tile.canCivPassThrough(civ)) return false
|
||||||
|
|
||||||
return tile.hasRoadConnection(unit.civ, false)
|
return tile.hasRoadConnection(civ, false)
|
||||||
|| tile.hasRailroadConnection(false)
|
|| tile.hasRailroadConnection(false)
|
||||||
|| roadImprovement != null && tile.improvementFunctions.canBuildImprovement(roadImprovement, unit.cache.state)
|
|| roadImprovement != null && tile.improvementFunctions.canBuildImprovement(roadImprovement, civ.state)
|
||||||
|| railRoadImprovement != null && tile.improvementFunctions.canBuildImprovement(railRoadImprovement, unit.cache.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.
|
* 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 startTile The starting tile of the path.
|
||||||
* @param endTile The destination 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.
|
* @return A sequence of tiles representing the path from startTile to endTile, or null if no valid path is found.
|
||||||
*/
|
*/
|
||||||
@Readonly
|
@Readonly
|
||||||
fun getRoadPath(unit: MapUnit, startTile: Tile, endTile: Tile): List<Tile>?{
|
fun getRoadPath(civ: Civilization, startTile: Tile, endTile: Tile): List<Tile>? {
|
||||||
return getPath(unit,
|
return getConnection(civ,
|
||||||
startTile,
|
startTile,
|
||||||
endTile,
|
endTile,
|
||||||
::isValidRoadPathTile,
|
::isValidRoadPathTile,
|
||||||
@ -112,13 +112,15 @@ object MapPathing {
|
|||||||
fun getConnection(civ: Civilization,
|
fun getConnection(civ: Civilization,
|
||||||
startTile: Tile,
|
startTile: Tile,
|
||||||
endTile: 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>? {
|
): List<Tile>? {
|
||||||
val astar = AStar(
|
val astar = AStar(
|
||||||
startTile,
|
startTile,
|
||||||
predicate = { tile -> predicate(civ, tile) },
|
predicate = { tile -> predicate(civ, tile) },
|
||||||
cost = { _, _ -> 1f },
|
cost = { from, to -> cost(civ, from, to) },
|
||||||
heuristic = { from, to -> from.aerialDistanceTo(to).toFloat() }
|
heuristic = { from, to -> heuristic(civ, from, to) }
|
||||||
)
|
)
|
||||||
while (true) {
|
while (true) {
|
||||||
if (astar.hasEnded()) {
|
if (astar.hasEnded()) {
|
||||||
@ -136,4 +138,5 @@ object MapPathing {
|
|||||||
.reversed()
|
.reversed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -468,7 +468,7 @@ class WorldMapHolder(
|
|||||||
selectedUnit.civ.hasExplored(tile)
|
selectedUnit.civ.hasExplored(tile)
|
||||||
|
|
||||||
if (validTile) {
|
if (validTile) {
|
||||||
val roadPath: List<Tile>? = MapPathing.getRoadPath(selectedUnit, selectedUnit.currentTile, tile)
|
val roadPath: List<Tile>? = MapPathing.getRoadPath(selectedUnit.civ, selectedUnit.getTile(), tile)
|
||||||
launchOnGLThread {
|
launchOnGLThread {
|
||||||
if (roadPath == null) { // give the regular tile overlays with no road connection
|
if (roadPath == null) { // give the regular tile overlays with no road connection
|
||||||
addTileOverlays(tile)
|
addTileOverlays(tile)
|
||||||
|
@ -104,7 +104,7 @@ object WorldMapTileUpdater {
|
|||||||
if (worldScreen.bottomUnitTable.selectedUnitIsConnectingRoad) {
|
if (worldScreen.bottomUnitTable.selectedUnitIsConnectingRoad) {
|
||||||
if (unit.currentTile.ruleset.roadImprovement == null) return
|
if (unit.currentTile.ruleset.roadImprovement == null) return
|
||||||
val validTiles = unit.civ.gameInfo.tileMap.tileList.filter {
|
val validTiles = unit.civ.gameInfo.tileMap.tileList.filter {
|
||||||
MapPathing.isValidRoadPathTile(unit, it)
|
MapPathing.isValidRoadPathTile(unit.civ, it)
|
||||||
}
|
}
|
||||||
val connectRoadTileOverlayColor = Color.RED
|
val connectRoadTileOverlayColor = Color.RED
|
||||||
for (tile in validTiles) {
|
for (tile in validTiles) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user