Refactor: Move checking targets from automation to logic (#9945)

* Move checking targets from automation to logic

* Ending newline, move attackable tile

* move getBombardableTiles for similar reasons

* fix package name

* remove import
This commit is contained in:
SeventhM 2023-08-19 23:18:47 -07:00 committed by GitHub
parent 7cb39dcecf
commit 08a04d3575
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 158 additions and 152 deletions

View File

@ -1,21 +1,18 @@
package com.unciv.logic.automation.unit package com.unciv.logic.automation.unit
import com.unciv.Constants import com.unciv.logic.battle.AttackableTile
import com.unciv.logic.battle.Battle import com.unciv.logic.battle.Battle
import com.unciv.logic.battle.BattleDamage import com.unciv.logic.battle.BattleDamage
import com.unciv.logic.battle.CityCombatant
import com.unciv.logic.battle.ICombatant
import com.unciv.logic.battle.MapUnitCombatant import com.unciv.logic.battle.MapUnitCombatant
import com.unciv.logic.battle.TargetHelper
import com.unciv.logic.map.mapunit.MapUnit import com.unciv.logic.map.mapunit.MapUnit
import com.unciv.logic.map.mapunit.PathsToTilesWithinTurn
import com.unciv.logic.map.tile.Tile
import com.unciv.models.ruleset.unique.UniqueType import com.unciv.models.ruleset.unique.UniqueType
object BattleHelper { object BattleHelper {
fun tryAttackNearbyEnemy(unit: MapUnit, stayOnTile: Boolean = false): Boolean { fun tryAttackNearbyEnemy(unit: MapUnit, stayOnTile: Boolean = false): Boolean {
if (unit.hasUnique(UniqueType.CannotAttack)) return false if (unit.hasUnique(UniqueType.CannotAttack)) return false
val attackableEnemies = getAttackableEnemies(unit, unit.movement.getDistanceToTiles(), stayOnTile=stayOnTile) val attackableEnemies = TargetHelper.getAttackableEnemies(unit, unit.movement.getDistanceToTiles(), stayOnTile=stayOnTile)
// Only take enemies we can fight without dying // Only take enemies we can fight without dying
.filter { .filter {
BattleDamage.calculateDamageToAttacker( BattleDamage.calculateDamageToAttacker(
@ -32,131 +29,11 @@ object BattleHelper {
return unit.currentMovement == 0f return unit.currentMovement == 0f
} }
fun getAttackableEnemies(
unit: MapUnit,
unitDistanceToTiles: PathsToTilesWithinTurn,
tilesToCheck: List<Tile>? = null,
stayOnTile: Boolean = false
): ArrayList<AttackableTile> {
val rangeOfAttack = unit.getRange()
val attackableTiles = ArrayList<AttackableTile>()
val unitMustBeSetUp = unit.hasUnique(UniqueType.MustSetUp)
val tilesToAttackFrom = if (stayOnTile || unit.baseUnit.movesLikeAirUnits())
sequenceOf(Pair(unit.currentTile, unit.currentMovement))
else
unitDistanceToTiles.asSequence()
.map { (tile, distance) ->
val movementPointsToExpendAfterMovement = if (unitMustBeSetUp) 1 else 0
val movementPointsToExpendHere =
if (unitMustBeSetUp && !unit.isSetUpForSiege()) 1 else 0
val movementPointsToExpendBeforeAttack =
if (tile == unit.currentTile) movementPointsToExpendHere else movementPointsToExpendAfterMovement
val movementLeft =
unit.currentMovement - distance.totalDistance - movementPointsToExpendBeforeAttack
Pair(tile, movementLeft)
}
// still got leftover movement points after all that, to attack
.filter { it.second > Constants.minimumMovementEpsilon }
.filter {
it.first == unit.getTile() || unit.movement.canMoveTo(it.first)
}
val tilesWithEnemies: HashSet<Tile> = HashSet()
val tilesWithoutEnemies: HashSet<Tile> = HashSet()
for ((reachableTile, movementLeft) in tilesToAttackFrom) { // tiles we'll still have energy after we reach there
val tilesInAttackRange =
if (unit.hasUnique(UniqueType.IndirectFire) || unit.baseUnit.movesLikeAirUnits())
reachableTile.getTilesInDistance(rangeOfAttack)
else reachableTile.tileMap.getViewableTiles(reachableTile.position, rangeOfAttack, true).asSequence()
for (tile in tilesInAttackRange) {
// Since military units can technically enter tiles with enemy civilians,
// some try to move to to the tile and then attack the unit it contains, which is silly
if (tile == reachableTile) continue
if (tile in tilesWithEnemies) attackableTiles += AttackableTile(
reachableTile,
tile,
movementLeft,
Battle.getMapCombatantOfTile(tile)
)
else if (tile in tilesWithoutEnemies) continue // avoid checking the same empty tile multiple times
else if (tileContainsAttackableEnemy(unit, tile, tilesToCheck)) {
tilesWithEnemies += tile
attackableTiles += AttackableTile(
reachableTile, tile, movementLeft,
Battle.getMapCombatantOfTile(tile)
)
} else if (unit.isPreparingAirSweep()) {
tilesWithEnemies += tile
attackableTiles += AttackableTile(
reachableTile, tile, movementLeft,
Battle.getMapCombatantOfTile(tile)
)
} else tilesWithoutEnemies += tile
}
}
return attackableTiles
}
private fun tileContainsAttackableEnemy(unit: MapUnit, tile: Tile, tilesToCheck: List<Tile>?): Boolean {
if (!containsAttackableEnemy(tile, MapUnitCombatant(unit))) return false
if (tile !in (tilesToCheck ?: unit.civ.viewableTiles)) return false
val mapCombatant = Battle.getMapCombatantOfTile(tile)
return (!unit.baseUnit.isMelee() || mapCombatant !is MapUnitCombatant || !mapCombatant.unit.isCivilian() || unit.movement.canPassThrough(tile))
}
fun containsAttackableEnemy(tile: Tile, combatant: ICombatant): Boolean {
if (combatant is MapUnitCombatant && combatant.unit.isEmbarked() && !combatant.hasUnique(UniqueType.AttackOnSea)) {
// Can't attack water units while embarked, only land
if (tile.isWater || combatant.isRanged())
return false
}
val tileCombatant = Battle.getMapCombatantOfTile(tile) ?: return false
if (tileCombatant.getCivInfo() == combatant.getCivInfo()) return false
// If the user automates units, one may capture the city before the user had a chance to decide what to do with it,
// and then the next unit should not attack that city
if (tileCombatant is CityCombatant && tileCombatant.city.hasJustBeenConquered) return false
if (!combatant.getCivInfo().isAtWarWith(tileCombatant.getCivInfo())) return false
if (combatant is MapUnitCombatant && combatant.isLandUnit() && combatant.isMelee() && tile.isWater &&
!combatant.getCivInfo().tech.unitsCanEmbark && !combatant.unit.cache.canMoveOnWater
)
return false
if (combatant is MapUnitCombatant && combatant.hasUnique(UniqueType.CannotAttack))
return false
if (combatant is MapUnitCombatant &&
combatant.unit.getMatchingUniques(UniqueType.CanOnlyAttackUnits).run {
any() && none { tileCombatant.matchesCategory(it.params[0]) }
}
)
return false
if (combatant is MapUnitCombatant &&
combatant.unit.getMatchingUniques(UniqueType.CanOnlyAttackTiles).run {
any() && none { tile.matchesFilter(it.params[0]) }
}
)
return false
// Only units with the right unique can view submarines (or other invisible units) from more then one tile away.
// Garrisoned invisible units can be attacked by anyone, as else the city will be in invincible.
if (tileCombatant.isInvisible(combatant.getCivInfo()) && !tile.isCityCenter()) {
return combatant is MapUnitCombatant
&& combatant.getCivInfo().viewableInvisibleUnitsTiles.map { it.position }.contains(tile.position)
}
return true
}
fun tryDisembarkUnitToAttackPosition(unit: MapUnit): Boolean { fun tryDisembarkUnitToAttackPosition(unit: MapUnit): Boolean {
if (!unit.baseUnit.isMelee() || !unit.baseUnit.isLandUnit() || !unit.isEmbarked()) return false if (!unit.baseUnit.isMelee() || !unit.baseUnit.isLandUnit() || !unit.isEmbarked()) return false
val unitDistanceToTiles = unit.movement.getDistanceToTiles() val unitDistanceToTiles = unit.movement.getDistanceToTiles()
val attackableEnemiesNextTurn = getAttackableEnemies(unit, unitDistanceToTiles) val attackableEnemiesNextTurn = TargetHelper.getAttackableEnemies(unit, unitDistanceToTiles)
// Only take enemies we can fight without dying // Only take enemies we can fight without dying
.filter { .filter {
BattleDamage.calculateDamageToAttacker( BattleDamage.calculateDamageToAttacker(

View File

@ -5,6 +5,7 @@ import com.unciv.logic.automation.Automation
import com.unciv.logic.battle.Battle import com.unciv.logic.battle.Battle
import com.unciv.logic.battle.GreatGeneralImplementation import com.unciv.logic.battle.GreatGeneralImplementation
import com.unciv.logic.battle.MapUnitCombatant import com.unciv.logic.battle.MapUnitCombatant
import com.unciv.logic.battle.TargetHelper
import com.unciv.logic.city.City import com.unciv.logic.city.City
import com.unciv.logic.civilization.diplomacy.DiplomaticModifiers import com.unciv.logic.civilization.diplomacy.DiplomaticModifiers
import com.unciv.logic.map.mapunit.MapUnit import com.unciv.logic.map.mapunit.MapUnit
@ -480,7 +481,7 @@ object SpecificUnitAutomation {
.filter { destinationCity -> .filter { destinationCity ->
destinationCity != airUnit.currentTile destinationCity != airUnit.currentTile
&& destinationCity.getTilesInDistance(airUnit.getRange()) && destinationCity.getTilesInDistance(airUnit.getRange())
.any { BattleHelper.containsAttackableEnemy(it, MapUnitCombatant(airUnit)) } .any { TargetHelper.containsAttackableEnemy(it, MapUnitCombatant(airUnit)) }
} }
if (citiesThatCanAttackFrom.isEmpty()) return if (citiesThatCanAttackFrom.isEmpty()) return
@ -547,7 +548,7 @@ object SpecificUnitAutomation {
if (city.getTilesInDistance(unit.getRange()) if (city.getTilesInDistance(unit.getRange())
.any { .any {
it.isVisible(unit.civ) && it.isVisible(unit.civ) &&
BattleHelper.containsAttackableEnemy( TargetHelper.containsAttackableEnemy(
it, it,
MapUnitCombatant(unit) MapUnitCombatant(unit)
) )

View File

@ -8,6 +8,7 @@ import com.unciv.logic.battle.BattleDamage
import com.unciv.logic.battle.CityCombatant import com.unciv.logic.battle.CityCombatant
import com.unciv.logic.battle.ICombatant import com.unciv.logic.battle.ICombatant
import com.unciv.logic.battle.MapUnitCombatant import com.unciv.logic.battle.MapUnitCombatant
import com.unciv.logic.battle.TargetHelper
import com.unciv.logic.city.City import com.unciv.logic.city.City
import com.unciv.logic.civilization.Civilization import com.unciv.logic.civilization.Civilization
import com.unciv.logic.civilization.NotificationCategory import com.unciv.logic.civilization.NotificationCategory
@ -467,11 +468,6 @@ object UnitAutomation {
return unit.currentMovement == 0f return unit.currentMovement == 0f
} }
/** Get a list of visible tiles which have something attackable */
fun getBombardableTiles(city: City): Sequence<Tile> =
city.getCenterTile().getTilesInDistance(city.range)
.filter { it.isVisible(city.civ) && BattleHelper.containsAttackableEnemy(it, CityCombatant(city)) }
/** Move towards the closest attackable enemy of the [unit]. /** Move towards the closest attackable enemy of the [unit].
* *
* Limited by [CLOSE_ENEMY_TURNS_AWAY_LIMIT] and [CLOSE_ENEMY_TILES_AWAY_LIMIT]. * Limited by [CLOSE_ENEMY_TURNS_AWAY_LIMIT] and [CLOSE_ENEMY_TILES_AWAY_LIMIT].
@ -482,7 +478,7 @@ object UnitAutomation {
unit.getTile().position, unit.getTile().position,
unit.getMaxMovement() * CLOSE_ENEMY_TURNS_AWAY_LIMIT unit.getMaxMovement() * CLOSE_ENEMY_TURNS_AWAY_LIMIT
) )
var closeEnemies = BattleHelper.getAttackableEnemies( var closeEnemies = TargetHelper.getAttackableEnemies(
unit, unit,
unitDistanceToTiles, unitDistanceToTiles,
tilesToCheck = unit.getTile().getTilesInDistance(CLOSE_ENEMY_TILES_AWAY_LIMIT).toList() tilesToCheck = unit.getTile().getTilesInDistance(CLOSE_ENEMY_TILES_AWAY_LIMIT).toList()
@ -674,7 +670,7 @@ object UnitAutomation {
} }
private fun chooseBombardTarget(city: City): ICombatant? { private fun chooseBombardTarget(city: City): ICombatant? {
var targets = getBombardableTiles(city).map { Battle.getMapCombatantOfTile(it)!! } var targets = TargetHelper.getBombardableTiles(city).map { Battle.getMapCombatantOfTile(it)!! }
if (targets.none()) return null if (targets.none()) return null
val siegeUnits = targets val siegeUnits = targets

View File

@ -1,4 +1,4 @@
package com.unciv.logic.automation.unit package com.unciv.logic.battle
import com.unciv.logic.battle.ICombatant import com.unciv.logic.battle.ICombatant
import com.unciv.logic.map.tile.Tile import com.unciv.logic.map.tile.Tile

View File

@ -4,7 +4,6 @@ import com.badlogic.gdx.math.Vector2
import com.unciv.Constants import com.unciv.Constants
import com.unciv.UncivGame import com.unciv.UncivGame
import com.unciv.logic.automation.civilization.NextTurnAutomation import com.unciv.logic.automation.civilization.NextTurnAutomation
import com.unciv.logic.automation.unit.AttackableTile
import com.unciv.logic.automation.unit.SpecificUnitAutomation import com.unciv.logic.automation.unit.SpecificUnitAutomation
import com.unciv.logic.city.City import com.unciv.logic.city.City
import com.unciv.logic.civilization.AlertType import com.unciv.logic.civilization.AlertType

View File

@ -1,6 +1,5 @@
package com.unciv.logic.battle package com.unciv.logic.battle
import com.unciv.logic.automation.unit.BattleHelper
import com.unciv.logic.automation.unit.SpecificUnitAutomation import com.unciv.logic.automation.unit.SpecificUnitAutomation
import com.unciv.logic.map.mapunit.MapUnit import com.unciv.logic.map.mapunit.MapUnit
import com.unciv.logic.map.tile.Tile import com.unciv.logic.map.tile.Tile
@ -95,7 +94,7 @@ object GreatGeneralImplementation {
unitTile.getTilesInDistance(unitBonusRadius).sumOf { auraTile -> unitTile.getTilesInDistance(unitBonusRadius).sumOf { auraTile ->
val militaryUnit = auraTile.militaryUnit val militaryUnit = auraTile.militaryUnit
if (militaryUnit == null || militaryUnit.civ != general.civ || militaryUnit.isEmbarked()) 0 if (militaryUnit == null || militaryUnit.civ != general.civ || militaryUnit.isEmbarked()) 0
else if (BattleHelper.getAttackableEnemies(militaryUnit, militaryUnit.movement.getDistanceToTiles()).isEmpty()) 0 else if (TargetHelper.getAttackableEnemies(militaryUnit, militaryUnit.movement.getDistanceToTiles()).isEmpty()) 0
else generalBonusData.firstOrNull { else generalBonusData.firstOrNull {
// "Military" as commented above only a small optimization // "Military" as commented above only a small optimization
auraTile.aerialDistanceTo(unitTile) <= it.radius auraTile.aerialDistanceTo(unitTile) <= it.radius

View File

@ -0,0 +1,136 @@
package com.unciv.logic.battle
import com.unciv.Constants
import com.unciv.logic.city.City
import com.unciv.logic.map.mapunit.MapUnit
import com.unciv.logic.map.mapunit.PathsToTilesWithinTurn
import com.unciv.logic.map.tile.Tile
import com.unciv.models.ruleset.unique.UniqueType
object TargetHelper {
fun getAttackableEnemies(
unit: MapUnit,
unitDistanceToTiles: PathsToTilesWithinTurn,
tilesToCheck: List<Tile>? = null,
stayOnTile: Boolean = false
): ArrayList<AttackableTile> {
val rangeOfAttack = unit.getRange()
val attackableTiles = ArrayList<AttackableTile>()
val unitMustBeSetUp = unit.hasUnique(UniqueType.MustSetUp)
val tilesToAttackFrom = if (stayOnTile || unit.baseUnit.movesLikeAirUnits())
sequenceOf(Pair(unit.currentTile, unit.currentMovement))
else
unitDistanceToTiles.asSequence()
.map { (tile, distance) ->
val movementPointsToExpendAfterMovement = if (unitMustBeSetUp) 1 else 0
val movementPointsToExpendHere =
if (unitMustBeSetUp && !unit.isSetUpForSiege()) 1 else 0
val movementPointsToExpendBeforeAttack =
if (tile == unit.currentTile) movementPointsToExpendHere else movementPointsToExpendAfterMovement
val movementLeft =
unit.currentMovement - distance.totalDistance - movementPointsToExpendBeforeAttack
Pair(tile, movementLeft)
}
// still got leftover movement points after all that, to attack
.filter { it.second > Constants.minimumMovementEpsilon }
.filter {
it.first == unit.getTile() || unit.movement.canMoveTo(it.first)
}
val tilesWithEnemies: HashSet<Tile> = HashSet()
val tilesWithoutEnemies: HashSet<Tile> = HashSet()
for ((reachableTile, movementLeft) in tilesToAttackFrom) { // tiles we'll still have energy after we reach there
val tilesInAttackRange =
if (unit.hasUnique(UniqueType.IndirectFire) || unit.baseUnit.movesLikeAirUnits())
reachableTile.getTilesInDistance(rangeOfAttack)
else reachableTile.tileMap.getViewableTiles(reachableTile.position, rangeOfAttack, true).asSequence()
for (tile in tilesInAttackRange) {
// Since military units can technically enter tiles with enemy civilians,
// some try to move to to the tile and then attack the unit it contains, which is silly
if (tile == reachableTile) continue
if (tile in tilesWithEnemies) attackableTiles += AttackableTile(
reachableTile,
tile,
movementLeft,
Battle.getMapCombatantOfTile(tile)
)
else if (tile in tilesWithoutEnemies) continue // avoid checking the same empty tile multiple times
else if (tileContainsAttackableEnemy(unit, tile, tilesToCheck)) {
tilesWithEnemies += tile
attackableTiles += AttackableTile(
reachableTile, tile, movementLeft,
Battle.getMapCombatantOfTile(tile)
)
} else if (unit.isPreparingAirSweep()) {
tilesWithEnemies += tile
attackableTiles += AttackableTile(
reachableTile, tile, movementLeft,
Battle.getMapCombatantOfTile(tile)
)
} else tilesWithoutEnemies += tile
}
}
return attackableTiles
}
private fun tileContainsAttackableEnemy(unit: MapUnit, tile: Tile, tilesToCheck: List<Tile>?): Boolean {
if (!containsAttackableEnemy(tile, MapUnitCombatant(unit))) return false
if (tile !in (tilesToCheck ?: unit.civ.viewableTiles)) return false
val mapCombatant = Battle.getMapCombatantOfTile(tile)
return (!unit.baseUnit.isMelee() || mapCombatant !is MapUnitCombatant || !mapCombatant.unit.isCivilian() || unit.movement.canPassThrough(tile))
}
fun containsAttackableEnemy(tile: Tile, combatant: ICombatant): Boolean {
if (combatant is MapUnitCombatant && combatant.unit.isEmbarked() && !combatant.hasUnique(UniqueType.AttackOnSea)) {
// Can't attack water units while embarked, only land
if (tile.isWater || combatant.isRanged())
return false
}
val tileCombatant = Battle.getMapCombatantOfTile(tile) ?: return false
if (tileCombatant.getCivInfo() == combatant.getCivInfo()) return false
// If the user automates units, one may capture the city before the user had a chance to decide what to do with it,
// and then the next unit should not attack that city
if (tileCombatant is CityCombatant && tileCombatant.city.hasJustBeenConquered) return false
if (!combatant.getCivInfo().isAtWarWith(tileCombatant.getCivInfo())) return false
if (combatant is MapUnitCombatant && combatant.isLandUnit() && combatant.isMelee() && tile.isWater &&
!combatant.getCivInfo().tech.unitsCanEmbark && !combatant.unit.cache.canMoveOnWater
)
return false
if (combatant is MapUnitCombatant && combatant.hasUnique(UniqueType.CannotAttack))
return false
if (combatant is MapUnitCombatant &&
combatant.unit.getMatchingUniques(UniqueType.CanOnlyAttackUnits).run {
any() && none { tileCombatant.matchesCategory(it.params[0]) }
}
)
return false
if (combatant is MapUnitCombatant &&
combatant.unit.getMatchingUniques(UniqueType.CanOnlyAttackTiles).run {
any() && none { tile.matchesFilter(it.params[0]) }
}
)
return false
// Only units with the right unique can view submarines (or other invisible units) from more then one tile away.
// Garrisoned invisible units can be attacked by anyone, as else the city will be in invincible.
if (tileCombatant.isInvisible(combatant.getCivInfo()) && !tile.isCityCenter()) {
return combatant is MapUnitCombatant
&& combatant.getCivInfo().viewableInvisibleUnitsTiles.map { it.position }.contains(tile.position)
}
return true
}
/** Get a list of visible tiles which have something attackable */
fun getBombardableTiles(city: City): Sequence<Tile> =
city.getCenterTile().getTilesInDistance(city.range)
.filter { it.isVisible(city.civ) && containsAttackableEnemy(it, CityCombatant(city)) }
}

View File

@ -15,12 +15,11 @@ import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.utils.Align import com.badlogic.gdx.utils.Align
import com.unciv.Constants import com.unciv.Constants
import com.unciv.UncivGame import com.unciv.UncivGame
import com.unciv.logic.automation.unit.AttackableTile
import com.unciv.logic.automation.unit.BattleHelper
import com.unciv.logic.automation.unit.CityLocationTileRanker import com.unciv.logic.automation.unit.CityLocationTileRanker
import com.unciv.logic.automation.unit.UnitAutomation import com.unciv.logic.battle.AttackableTile
import com.unciv.logic.battle.Battle import com.unciv.logic.battle.Battle
import com.unciv.logic.battle.MapUnitCombatant import com.unciv.logic.battle.MapUnitCombatant
import com.unciv.logic.battle.TargetHelper
import com.unciv.logic.city.City import com.unciv.logic.city.City
import com.unciv.logic.civilization.Civilization import com.unciv.logic.civilization.Civilization
import com.unciv.logic.map.TileMap import com.unciv.logic.map.TileMap
@ -224,7 +223,7 @@ class WorldMapHolder(
/** If we are in unit-swapping mode and didn't find a swap partner, we don't want to move or attack */ /** If we are in unit-swapping mode and didn't find a swap partner, we don't want to move or attack */
} else { } else {
// This seems inefficient as the tileToAttack is already known - but the method also calculates tileToAttackFrom // This seems inefficient as the tileToAttack is already known - but the method also calculates tileToAttackFrom
val attackableTile = BattleHelper val attackableTile = TargetHelper
.getAttackableEnemies(unit, unit.movement.getDistanceToTiles()) .getAttackableEnemies(unit, unit.movement.getDistanceToTiles())
.firstOrNull { it.tileToAttack == tile } .firstOrNull { it.tileToAttack == tile }
if (unit.canAttack() && attackableTile != null) { if (unit.canAttack() && attackableTile != null) {
@ -700,7 +699,7 @@ class WorldMapHolder(
|| (targetTile.isCityCenter() && unit.civ.hasExplored(targetTile)) } || (targetTile.isCityCenter() && unit.civ.hasExplored(targetTile)) }
.map { AttackableTile(unit.getTile(), it, 1f, null) } .map { AttackableTile(unit.getTile(), it, 1f, null) }
.toList() .toList()
else BattleHelper.getAttackableEnemies(unit, unit.movement.getDistanceToTiles()) else TargetHelper.getAttackableEnemies(unit, unit.movement.getDistanceToTiles())
.filter { it.tileToAttack.isVisible(unit.civ) } .filter { it.tileToAttack.isVisible(unit.civ) }
.distinctBy { it.tileToAttack } .distinctBy { it.tileToAttack }
@ -730,7 +729,7 @@ class WorldMapHolder(
private fun updateBombardableTilesForSelectedCity(city: City) { private fun updateBombardableTilesForSelectedCity(city: City) {
if (!city.canBombard()) return if (!city.canBombard()) return
for (attackableTile in UnitAutomation.getBombardableTiles(city)) { for (attackableTile in TargetHelper.getBombardableTiles(city)) {
val group = tileGroups[attackableTile]!! val group = tileGroups[attackableTile]!!
group.layerOverlay.showHighlight(colorFromRGB(237, 41, 57)) group.layerOverlay.showHighlight(colorFromRGB(237, 41, 57))
group.layerOverlay.showCrosshair() group.layerOverlay.showCrosshair()

View File

@ -4,14 +4,13 @@ import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.Touchable import com.badlogic.gdx.scenes.scene2d.Touchable
import com.badlogic.gdx.scenes.scene2d.ui.Label import com.badlogic.gdx.scenes.scene2d.ui.Label
import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.unciv.logic.automation.unit.AttackableTile import com.unciv.logic.battle.AttackableTile
import com.unciv.logic.automation.unit.BattleHelper
import com.unciv.logic.automation.unit.UnitAutomation
import com.unciv.logic.battle.Battle import com.unciv.logic.battle.Battle
import com.unciv.logic.battle.BattleDamage import com.unciv.logic.battle.BattleDamage
import com.unciv.logic.battle.CityCombatant import com.unciv.logic.battle.CityCombatant
import com.unciv.logic.battle.ICombatant import com.unciv.logic.battle.ICombatant
import com.unciv.logic.battle.MapUnitCombatant import com.unciv.logic.battle.MapUnitCombatant
import com.unciv.logic.battle.TargetHelper
import com.unciv.logic.map.tile.Tile import com.unciv.logic.map.tile.Tile
import com.unciv.models.UncivSound import com.unciv.models.UncivSound
import com.unciv.models.ruleset.unique.UniqueType import com.unciv.models.ruleset.unique.UniqueType
@ -73,7 +72,7 @@ class BattleTable(val worldScreen: WorldScreen): Table() {
val defender = tryGetDefender() ?: return hide() val defender = tryGetDefender() ?: return hide()
if (attacker is CityCombatant && defender is CityCombatant) return hide() if (attacker is CityCombatant && defender is CityCombatant) return hide()
val tileToAttackFrom = if (attacker is MapUnitCombatant) val tileToAttackFrom = if (attacker is MapUnitCombatant)
BattleHelper.getAttackableEnemies( TargetHelper.getAttackableEnemies(
attacker.unit, attacker.unit,
attacker.unit.movement.getDistanceToTiles() attacker.unit.movement.getDistanceToTiles()
) )
@ -247,11 +246,11 @@ class BattleTable(val worldScreen: WorldScreen): Table() {
if (attacker.canAttack()) { if (attacker.canAttack()) {
if (attacker is MapUnitCombatant) { if (attacker is MapUnitCombatant) {
attackableTile = BattleHelper attackableTile = TargetHelper
.getAttackableEnemies(attacker.unit, attacker.unit.movement.getDistanceToTiles()) .getAttackableEnemies(attacker.unit, attacker.unit.movement.getDistanceToTiles())
.firstOrNull{ it.tileToAttack == defender.getTile()} .firstOrNull{ it.tileToAttack == defender.getTile()}
} else if (attacker is CityCombatant) { } else if (attacker is CityCombatant) {
val canBombard = UnitAutomation.getBombardableTiles(attacker.city).contains(defender.getTile()) val canBombard = TargetHelper.getBombardableTiles(attacker.city).contains(defender.getTile())
if (canBombard) { if (canBombard) {
attackableTile = AttackableTile(attacker.getTile(), defender.getTile(), 0f, defender) attackableTile = AttackableTile(attacker.getTile(), defender.getTile(), 0f, defender)
} }