mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-28 14:24:43 -04:00
Improvements to AI military unit usage (#7147)
* Add more opportunities for AI units to attack
This commit is contained in:
parent
9ac019caea
commit
ed922b182d
@ -21,16 +21,15 @@ object BattleHelper {
|
|||||||
BattleDamage.calculateDamageToAttacker(
|
BattleDamage.calculateDamageToAttacker(
|
||||||
MapUnitCombatant(unit),
|
MapUnitCombatant(unit),
|
||||||
Battle.getMapCombatantOfTile(it.tileToAttack)!!
|
Battle.getMapCombatantOfTile(it.tileToAttack)!!
|
||||||
) < unit.health
|
) + unit.getDamageFromTerrain(it.tileToAttackFrom) < unit.health
|
||||||
}
|
}
|
||||||
|
|
||||||
val enemyTileToAttack = chooseAttackTarget(unit, attackableEnemies)
|
val enemyTileToAttack = chooseAttackTarget(unit, attackableEnemies)
|
||||||
|
|
||||||
if (enemyTileToAttack != null) {
|
if (enemyTileToAttack != null) {
|
||||||
Battle.moveAndAttack(MapUnitCombatant(unit), enemyTileToAttack)
|
Battle.moveAndAttack(MapUnitCombatant(unit), enemyTileToAttack)
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
return false
|
return unit.currentMovement == 0f
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getAttackableEnemies(
|
fun getAttackableEnemies(
|
||||||
|
@ -119,7 +119,7 @@ object UnitAutomation {
|
|||||||
?: return false
|
?: return false
|
||||||
|
|
||||||
upgradeAction.action?.invoke()
|
upgradeAction.action?.invoke()
|
||||||
return true
|
return unit.isDestroyed // a successful upgrade action will destroy this unit
|
||||||
}
|
}
|
||||||
|
|
||||||
fun automateUnitMoves(unit: MapUnit) {
|
fun automateUnitMoves(unit: MapUnit) {
|
||||||
@ -215,7 +215,7 @@ object UnitAutomation {
|
|||||||
if (BattleHelper.tryDisembarkUnitToAttackPosition(unit)) return
|
if (BattleHelper.tryDisembarkUnitToAttackPosition(unit)) return
|
||||||
|
|
||||||
// if there is an attackable unit in the vicinity, attack!
|
// if there is an attackable unit in the vicinity, attack!
|
||||||
if (BattleHelper.tryAttackNearbyEnemy(unit)) return
|
if (tryAttacking(unit)) return
|
||||||
|
|
||||||
if (tryTakeBackCapturedCity(unit)) return
|
if (tryTakeBackCapturedCity(unit)) return
|
||||||
|
|
||||||
@ -243,6 +243,14 @@ object UnitAutomation {
|
|||||||
wander(unit, stayInTerritory = true)
|
wander(unit, stayInTerritory = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return true only if the unit has 0 movement left */
|
||||||
|
private fun tryAttacking(unit: MapUnit): Boolean {
|
||||||
|
for (attackNumber in unit.attacksThisTurn until unit.maxAttacksPerTurn()) {
|
||||||
|
if (BattleHelper.tryAttackNearbyEnemy(unit)) return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
private fun tryHeadTowardsEncampment(unit: MapUnit): Boolean {
|
private fun tryHeadTowardsEncampment(unit: MapUnit): Boolean {
|
||||||
if (unit.hasUnique(UniqueType.SelfDestructs)) return false // don't use single-use units against barbarians...
|
if (unit.hasUnique(UniqueType.SelfDestructs)) return false // don't use single-use units against barbarians...
|
||||||
val knownEncampments = unit.civInfo.gameInfo.tileMap.values.asSequence()
|
val knownEncampments = unit.civInfo.gameInfo.tileMap.values.asSequence()
|
||||||
@ -260,15 +268,12 @@ object UnitAutomation {
|
|||||||
if (unit.baseUnit.isRanged() && unit.hasUnique(UniqueType.HealsEvenAfterAction))
|
if (unit.baseUnit.isRanged() && unit.hasUnique(UniqueType.HealsEvenAfterAction))
|
||||||
return false // will heal anyway, and attacks don't hurt
|
return false // will heal anyway, and attacks don't hurt
|
||||||
|
|
||||||
|
if (tryPillageImprovement(unit)) return true
|
||||||
val unitDistanceToTiles = unit.movement.getDistanceToTiles()
|
val unitDistanceToTiles = unit.movement.getDistanceToTiles()
|
||||||
if (unitDistanceToTiles.isEmpty()) return true // can't move, so...
|
if (unitDistanceToTiles.isEmpty()) return true // can't move, so...
|
||||||
|
|
||||||
|
|
||||||
val currentUnitTile = unit.getTile()
|
val currentUnitTile = unit.getTile()
|
||||||
|
|
||||||
if (tryPillageImprovement(unit)) return true
|
|
||||||
|
|
||||||
|
|
||||||
val nearbyRangedEnemyUnits = unit.currentTile.getTilesInDistance(3)
|
val nearbyRangedEnemyUnits = unit.currentTile.getTilesInDistance(3)
|
||||||
.flatMap { tile -> tile.getUnits().filter { unit.civInfo.isAtWarWith(it.civInfo) } }
|
.flatMap { tile -> tile.getUnits().filter { unit.civInfo.isAtWarWith(it.civInfo) } }
|
||||||
|
|
||||||
@ -342,7 +347,7 @@ object UnitAutomation {
|
|||||||
unit.movement.moveToTile(tileToPillage)
|
unit.movement.moveToTile(tileToPillage)
|
||||||
|
|
||||||
UnitActions.getPillageAction(unit)?.action?.invoke()
|
UnitActions.getPillageAction(unit)?.action?.invoke()
|
||||||
return true
|
return unit.currentMovement == 0f
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getBombardTargets(city: CityInfo): Sequence<TileInfo> =
|
fun getBombardTargets(city: CityInfo): Sequence<TileInfo> =
|
||||||
@ -405,6 +410,9 @@ object UnitAutomation {
|
|||||||
it.health < it.getMaxHealth() * 0.75
|
it.health < it.getMaxHealth() * 0.75
|
||||||
} //Weird health issues and making sure that not all forces move to good defenses
|
} //Weird health issues and making sure that not all forces move to good defenses
|
||||||
|
|
||||||
|
if (siegedCities.any { it.getCenterTile().aerialDistanceTo(unit.getTile()) <= 2 })
|
||||||
|
return false
|
||||||
|
|
||||||
val reachableTileNearSiegedCity = siegedCities
|
val reachableTileNearSiegedCity = siegedCities
|
||||||
.flatMap { it.getCenterTile().getTilesAtDistance(2) }
|
.flatMap { it.getCenterTile().getTilesAtDistance(2) }
|
||||||
.sortedBy { it.aerialDistanceTo(unit.currentTile) }
|
.sortedBy { it.aerialDistanceTo(unit.currentTile) }
|
||||||
@ -413,9 +421,8 @@ object UnitAutomation {
|
|||||||
|
|
||||||
if (reachableTileNearSiegedCity != null) {
|
if (reachableTileNearSiegedCity != null) {
|
||||||
unit.movement.headTowards(reachableTileNearSiegedCity)
|
unit.movement.headTowards(reachableTileNearSiegedCity)
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
return false
|
return unit.currentMovement == 0f
|
||||||
}
|
}
|
||||||
|
|
||||||
fun tryHeadTowardsEnemyCity(unit: MapUnit): Boolean {
|
fun tryHeadTowardsEnemyCity(unit: MapUnit): Boolean {
|
||||||
@ -470,7 +477,7 @@ object UnitAutomation {
|
|||||||
unit.movement.headTowards(tileToMoveTo)
|
unit.movement.headTowards(tileToMoveTo)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false // didn't move
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
val numberOfUnitsAroundCity = closestReachableEnemyCity.getTilesInDistance(4)
|
val numberOfUnitsAroundCity = closestReachableEnemyCity.getTilesInDistance(4)
|
||||||
@ -482,12 +489,12 @@ object UnitAutomation {
|
|||||||
val tileToHeadTo = closestReachableEnemyCity.getTilesInDistanceRange(3..4)
|
val tileToHeadTo = closestReachableEnemyCity.getTilesInDistanceRange(3..4)
|
||||||
.filter { it.isLand && unit.getDamageFromTerrain(it) <= 0 } // Don't head for hurty terrain
|
.filter { it.isLand && unit.getDamageFromTerrain(it) <= 0 } // Don't head for hurty terrain
|
||||||
.sortedBy { it.aerialDistanceTo(unit.currentTile) }
|
.sortedBy { it.aerialDistanceTo(unit.currentTile) }
|
||||||
.firstOrNull { unit.movement.canReach(it) }
|
.firstOrNull { (unit.movement.canMoveTo(it) || it == unit.currentTile) && unit.movement.canReach(it) }
|
||||||
|
|
||||||
if (tileToHeadTo != null) { // no need to worry, keep going as the movement alg. says
|
if (tileToHeadTo != null) { // no need to worry, keep going as the movement alg. says
|
||||||
unit.movement.headTowards(tileToHeadTo)
|
unit.movement.headTowards(tileToHeadTo)
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
unit.movement.headTowards(closestReachableEnemyCity) // go for it!
|
unit.movement.headTowards(closestReachableEnemyCity) // go for it!
|
||||||
|
Loading…
x
Reference in New Issue
Block a user