From 376ae64e771b25169a85a502e372af2247c2d261 Mon Sep 17 00:00:00 2001 From: Yair Morgenstern Date: Wed, 8 Aug 2018 08:26:23 +0300 Subject: [PATCH] AI Ranged units no longer head towards defeated cities --- .../unciv/logic/automation/UnitAutomation.kt | 152 ++++++++++-------- .../com/unciv/logic/city/CityConstructions.kt | 2 +- 2 files changed, 88 insertions(+), 66 deletions(-) diff --git a/core/src/com/unciv/logic/automation/UnitAutomation.kt b/core/src/com/unciv/logic/automation/UnitAutomation.kt index a4871e429e..d4508ddccd 100644 --- a/core/src/com/unciv/logic/automation/UnitAutomation.kt +++ b/core/src/com/unciv/logic/automation/UnitAutomation.kt @@ -12,13 +12,64 @@ import com.unciv.logic.map.MapUnit import com.unciv.logic.map.TileInfo import com.unciv.models.gamebasics.GameBasics import com.unciv.ui.utils.getRandom +import com.unciv.ui.worldscreen.unit.UnitAction import com.unciv.ui.worldscreen.unit.UnitActions class UnitAutomation{ + fun automateUnitMoves(unit: MapUnit) { + + if (unit.name == "Settler") { + automateSettlerActions(unit) + return + } + + if (unit.name == "Worker") { + WorkerAutomation(unit).automateWorkerAction() + return + } + + if(unit.name.startsWith("Great")) return // I don't know what to do with you yet. + + val unitActions = UnitActions().getUnitActions(unit,UnCivGame.Current.worldScreen) + + if (tryUpgradeUnit(unit, unitActions)) return + + // Accompany settlers + if (tryAccompanySettler(unit)) return + + if (unit.health < 50) { + healUnit(unit) + return + } // do nothing but heal + + // if there is an attackable unit in the vicinity, attack! + if (tryAttackNearbyEnemy(unit)) return + + if (tryGarrisoningUnit(unit)) return + + if (unit.health < 80) { + healUnit(unit) + return + } // do nothing but heal until 80 health + + // find the closest enemy unit that we know of within 5 spaces and advance towards it + if (tryAdvanceTowardsCloseEnemy(unit)) return + + if (unit.health < 100) { + healUnit(unit) + return + } + + // Focus all units without a specific target on the enemy city closest to one of our cities + if (tryHeadTowardsEnemyCity(unit)) return + + // else, go to a random space + randomWalk(unit) + // if both failed, then... there aren't any reachable tiles. Which is possible. + } + fun healUnit(unit:MapUnit) { - // If we're low on health then heal - // todo: go to a more defensible place if there is one val tilesInDistance = unit.getDistanceToTiles().keys val unitTile = unit.getTile() @@ -70,78 +121,53 @@ class UnitAutomation{ return attackableTiles } - fun automateUnitMoves(unit: MapUnit) { + private fun tryAdvanceTowardsCloseEnemy(unit: MapUnit): Boolean { + var closeEnemies = unit.getTile().getTilesInDistance(5) + .filter{ containsAttackableEnemy(it, unit.civInfo) && unit.movementAlgs().canReach(it)} + if(unit.getBaseUnit().unitType.isRanged()) + closeEnemies = closeEnemies.filterNot { it.isCityCenter() && it.getCity()!!.health==1 } - if (unit.name == "Settler") { - automateSettlerActions(unit) - return + val closestEnemy = closeEnemies.minBy { it.arialDistanceTo(unit.getTile()) } + + if (closestEnemy != null) { + unit.movementAlgs().headTowards(closestEnemy) + return true } + return false + } - if (unit.name == "Worker") { - WorkerAutomation(unit).automateWorkerAction() - return + private fun tryAccompanySettler(unit: MapUnit): Boolean { + val closeTileWithSettler = unit.getDistanceToTiles().keys.firstOrNull { + it.civilianUnit != null && it.civilianUnit!!.name == "Settler" } + if (closeTileWithSettler != null && unit.canMoveTo(closeTileWithSettler)) { + unit.movementAlgs().headTowards(closeTileWithSettler) + return true + } + return false + } - if(unit.name.startsWith("Great")) return // I don't know what to do with you yet. - - val unitActions = UnitActions().getUnitActions(unit,UnCivGame.Current.worldScreen) - - if(unit.getBaseUnit().upgradesTo!=null) { + private fun tryUpgradeUnit(unit: MapUnit, unitActions: List): Boolean { + if (unit.getBaseUnit().upgradesTo != null) { val upgradedUnit = GameBasics.Units[unit.getBaseUnit().upgradesTo!!]!! if (upgradedUnit.isBuildable(unit.civInfo)) { val goldCostOfUpgrade = (upgradedUnit.cost - unit.getBaseUnit().cost) * 2 + 10 val upgradeAction = unitActions.firstOrNull { it.name.startsWith("Upgrade to") } if (upgradeAction != null && unit.civInfo.gold > goldCostOfUpgrade) { upgradeAction.action() - return + return true } } } + return false + } - // Accompany settlers - val closeTileWithSettler = unit.getDistanceToTiles().keys.firstOrNull{ - it.civilianUnit!=null && it.civilianUnit!!.name=="Settler"} - if(closeTileWithSettler != null && unit.canMoveTo(closeTileWithSettler)){ - unit.movementAlgs().headTowards(closeTileWithSettler) - return - } - - if (unit.health < 50) { - healUnit(unit) - return - } // do nothing but heal - - // if there is an attackable unit in the vicinity, attack! - if (tryAttackNearbyEnemy(unit)) return - - if (tryGarrisoningUnit(unit)) return - - - - if (unit.health < 80) { - healUnit(unit) - return - } // do nothing but heal until 80 health - - - // find the closest enemy unit that we know of within 5 spaces and advance towards it - val closestEnemy = unit.getTile().getTilesInDistance(5) - .firstOrNull { containsAttackableEnemy(it,unit.civInfo) && unit.movementAlgs().canReach(it) } - - if (closestEnemy != null) { - unit.movementAlgs().headTowards(closestEnemy) - return - } - - if (unit.health < 100) { - healUnit(unit) - return - } - - // Focus all units without a specific target on the enemy city closest to one of our cities - val enemyCities = unit.civInfo.exploredTiles.map { unit.civInfo.gameInfo.tileMap[it] } - .filter { it.isCityCenter() && it.getOwner()!=unit.civInfo } - if(enemyCities.isNotEmpty() && unit.civInfo.cities.isNotEmpty()) { + private fun tryHeadTowardsEnemyCity(unit: MapUnit): Boolean { + var enemyCities = unit.civInfo.exploredTiles.map { unit.civInfo.gameInfo.tileMap[it] } + .filter { it.isCityCenter() && it.getOwner() != unit.civInfo } + if(unit.getBaseUnit().unitType.isRanged()) + enemyCities = enemyCities.filterNot { it.getCity()!!.health==1 } + if (enemyCities.isNotEmpty() && unit.civInfo.cities.isNotEmpty()) { val closestReachableEnemyCity = enemyCities .filter { unit.movementAlgs().canReach(it) } .minBy { city -> @@ -149,13 +175,10 @@ class UnitAutomation{ } if (closestReachableEnemyCity != null) { unit.movementAlgs().headTowards(closestReachableEnemyCity) - return + return true } } - - // else, go to a random space - randomWalk(unit) - // if both failed, then... there aren't any reachable tiles. Which is possible. + return false } private fun tryAttackNearbyEnemy(unit: MapUnit): Boolean { @@ -177,7 +200,6 @@ class UnitAutomation{ if (unit.getBaseUnit().unitType.isMelee() && capturableCity!=null) enemyTileToAttack = capturableCity // enter it quickly, top priority! - else if (nonCityTilesToAttack.isNotEmpty()) // second priority, units enemyTileToAttack = nonCityTilesToAttack.minBy { Battle().getMapCombatantOfTile(it.tileToAttack)!!.getHealth() } else if (cityWithHealthLeft!=null) enemyTileToAttack = cityWithHealthLeft// third priority, city diff --git a/core/src/com/unciv/logic/city/CityConstructions.kt b/core/src/com/unciv/logic/city/CityConstructions.kt index 19f2d39333..c63c76384c 100644 --- a/core/src/com/unciv/logic/city/CityConstructions.kt +++ b/core/src/com/unciv/logic/city/CityConstructions.kt @@ -43,7 +43,7 @@ class CityConstructions { } fun getCityProductionTextForCityButton(): String { - var result = currentConstruction + var result = currentConstruction.tr() if (SpecialConstruction.getSpecialConstructions().none { it.name==result }) result += "\r\n" + turnsToConstruction(currentConstruction) + " {turns}".tr() return result