Slight optimization of getAttackableEnemies (#7353)

This commit is contained in:
OptimizedForDensity
2022-07-04 09:35:49 -04:00
committed by GitHub
parent 716d5d3214
commit 1649b236bb

View File

@ -33,27 +33,12 @@ object BattleHelper {
}
fun getAttackableEnemies(
unit: MapUnit,
unitDistanceToTiles: PathsToTilesWithinTurn,
tilesToCheck: List<TileInfo>? = null,
stayOnTile: Boolean = false
unit: MapUnit,
unitDistanceToTiles: PathsToTilesWithinTurn,
tilesToCheck: List<TileInfo>? = null,
stayOnTile: Boolean = false
): ArrayList<AttackableTile> {
val tilesWithEnemies = (tilesToCheck ?: unit.civInfo.viewableTiles)
.filter { containsAttackableEnemy(it, MapUnitCombatant(unit)) }
// Filter out invalid Civilian Captures
.filterNot {
val mapCombatant = Battle.getMapCombatantOfTile(it)
// IF all of these are true, THEN the action we'll be taking is in fact CAPTURING the civilian.
unit.baseUnit.isMelee() && mapCombatant is MapUnitCombatant && mapCombatant.unit.isCivilian()
// If we can't pass though that tile, we can't capture the civilian "remotely"
// Can use "unit.movement.canPassThrough(it)" now that we can move through
// unguarded Civilian tiles. And this catches Naval trying to capture Land
// Civilians or Land attacking Water Civilians it can't Embark on
&& !unit.movement.canPassThrough(it)
}
val rangeOfAttack = unit.getRange()
val attackableTiles = ArrayList<AttackableTile>()
val unitMustBeSetUp = unit.hasUnique(UniqueType.MustSetUp)
@ -77,6 +62,8 @@ object BattleHelper {
it.first == unit.getTile() || unit.movement.canMoveTo(it.first)
}
val tilesWithEnemies: HashSet<TileInfo> = HashSet()
val tilesWithoutEnemies: HashSet<TileInfo> = 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())
@ -84,12 +71,27 @@ object BattleHelper {
else reachableTile.getViewableTilesList(rangeOfAttack)
.asSequence()
attackableTiles += tilesInAttackRange.filter { it in tilesWithEnemies }
.map { AttackableTile(reachableTile, it, movementLeft) }
for (tile in tilesInAttackRange) {
if (tile in tilesWithEnemies) attackableTiles += AttackableTile(reachableTile, tile, movementLeft)
else if (tile in tilesWithoutEnemies) continue // avoid checking the same empty tile multiple times
else if (checkTile(unit, tile, tilesToCheck)) {
tilesWithEnemies += tile
attackableTiles += AttackableTile(reachableTile, tile, movementLeft)
} else {
tilesWithoutEnemies += tile
}
}
}
return attackableTiles
}
private fun checkTile(unit: MapUnit, tile: TileInfo, tilesToCheck: List<TileInfo>?): Boolean {
if (!containsAttackableEnemy(tile, MapUnitCombatant(unit))) return false
if (tile !in (tilesToCheck ?: unit.civInfo.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: TileInfo, combatant: ICombatant): Boolean {
if (combatant is MapUnitCombatant && combatant.unit.isEmbarked() && !combatant.hasUnique(UniqueType.AttackOnSea)) {
// Can't attack water units while embarked, only land