From 1649b236bbb1d45a4f2f78dc2a1711cba7259bff Mon Sep 17 00:00:00 2001 From: OptimizedForDensity <105244635+OptimizedForDensity@users.noreply.github.com> Date: Mon, 4 Jul 2022 09:35:49 -0400 Subject: [PATCH] Slight optimization of getAttackableEnemies (#7353) --- .../unciv/logic/automation/BattleHelper.kt | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/core/src/com/unciv/logic/automation/BattleHelper.kt b/core/src/com/unciv/logic/automation/BattleHelper.kt index aac9596f62..0199f4bc4a 100644 --- a/core/src/com/unciv/logic/automation/BattleHelper.kt +++ b/core/src/com/unciv/logic/automation/BattleHelper.kt @@ -33,27 +33,12 @@ object BattleHelper { } fun getAttackableEnemies( - unit: MapUnit, - unitDistanceToTiles: PathsToTilesWithinTurn, - tilesToCheck: List? = null, - stayOnTile: Boolean = false + unit: MapUnit, + unitDistanceToTiles: PathsToTilesWithinTurn, + tilesToCheck: List? = null, + stayOnTile: Boolean = false ): ArrayList { - 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() val unitMustBeSetUp = unit.hasUnique(UniqueType.MustSetUp) @@ -77,6 +62,8 @@ object BattleHelper { it.first == unit.getTile() || unit.movement.canMoveTo(it.first) } + val tilesWithEnemies: HashSet = HashSet() + val tilesWithoutEnemies: HashSet = 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?): 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