diff --git a/core/src/com/unciv/logic/automation/UnitAutomation.kt b/core/src/com/unciv/logic/automation/UnitAutomation.kt index 6e055d0282..68f32d91dc 100644 --- a/core/src/com/unciv/logic/automation/UnitAutomation.kt +++ b/core/src/com/unciv/logic/automation/UnitAutomation.kt @@ -387,16 +387,16 @@ object UnitAutomation { private fun tryHeadTowardsEnemyCity(unit: MapUnit): Boolean { if (unit.civInfo.cities.isEmpty()) return false - var enemyCities = unit.civInfo.gameInfo.civilizations + var enemyCities = unit.civInfo.gameInfo.civilizations.asSequence() .filter { unit.civInfo.isAtWarWith(it) } - .flatMap { it.cities }.asSequence() + .flatMap { it.cities } .filter { it.location in unit.civInfo.exploredTiles } if (unit.baseUnit.isRanged()) // ranged units don't harm capturable cities, waste of a turn enemyCities = enemyCities.filterNot { it.health == 1 } val closestReachableEnemyCity = enemyCities - .asSequence().map { it.getCenterTile() } + .map { it.getCenterTile() } .sortedBy { cityCenterTile -> // sort enemy cities by closeness to our cities, and only then choose the first reachable - checking canReach is comparatively very time-intensive! unit.civInfo.cities.asSequence() diff --git a/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt b/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt index 6630d359dd..a743778b88 100644 --- a/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt +++ b/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt @@ -82,6 +82,16 @@ class UnitMovementAlgorithms(val unit:MapUnit) { return terrainCost + extraCost // no road or other movement cost reduction } + fun getTilesExertingZoneOfControl(tileInfo: TileInfo, civInfo: CivilizationInfo): Sequence { + return tileInfo.neighbors.filter { + it.isCityCenter() && civInfo.isAtWarWith(it.getOwner()!!) + || + it.militaryUnit != null && + civInfo.isAtWarWith(it.militaryUnit!!.civInfo) && + (it.militaryUnit!!.type.isWaterUnit() || (!it.militaryUnit!!.isEmbarked() && unit.type.isLandUnit())) + } + } + /** Returns whether the movement between the adjacent tiles [from] and [to] is affected by Zone of Control */ private fun isMovementAffectedByZoneOfControl(from: TileInfo, to: TileInfo, civInfo: CivilizationInfo): Boolean { // Sources: @@ -100,22 +110,8 @@ class UnitMovementAlgorithms(val unit:MapUnit) { // these two tiles can perhaps be optimized. Using a hex-math-based "commonAdjacentTiles" // function is surprisingly less efficient than the current neighbor-intersection approach. // See #4085 for more details. - if (from.neighbors.none{ - ( - ( - it.isCityCenter() && - civInfo.isAtWarWith(it.getOwner()!!) - ) - || - ( - it.militaryUnit != null && - civInfo.isAtWarWith(it.militaryUnit!!.civInfo) && - (it.militaryUnit!!.type.isWaterUnit() || (!it.militaryUnit!!.isEmbarked() && unit.type.isLandUnit())) - ) - ) - && - to.neighbors.contains(it) - }) + val tilesExertingZoneOfControl = getTilesExertingZoneOfControl(from, civInfo) + if (tilesExertingZoneOfControl.none { to.neighbors.contains(it)}) return false // Even though this is a very fast check, we perform it last. This is because very few units @@ -203,13 +199,16 @@ class UnitMovementAlgorithms(val unit:MapUnit) { var distance = 1 val newTilesToCheck = ArrayList() val distanceToDestination = HashMap() + var considerZoneOfControl = true // only for first distance! while (true) { - if (distance == 2) // only set this once after distance > 1 + if (distance == 2) { // only set this once after distance > 1 movementThisTurn = unit.getMaxMovement().toFloat() + considerZoneOfControl = false // by then units would have moved around, we don't need to consider untenable futures when it harms performance! + } newTilesToCheck.clear() distanceToDestination.clear() for (tileToCheck in tilesToCheck) { - val distanceToTilesThisTurn = getDistanceToTilesWithinTurn(tileToCheck.position, movementThisTurn) + val distanceToTilesThisTurn = getDistanceToTilesWithinTurn(tileToCheck.position, movementThisTurn, considerZoneOfControl) for (reachableTile in distanceToTilesThisTurn.keys) { // Avoid damaging terrain on first pass if (avoidDamagingTerrain && unit.getDamageFromTerrain(reachableTile) > 0)