diff --git a/core/src/com/unciv/logic/automation/unit/UnitAutomation.kt b/core/src/com/unciv/logic/automation/unit/UnitAutomation.kt index c48aeacc1f..7eaa131d2f 100644 --- a/core/src/com/unciv/logic/automation/unit/UnitAutomation.kt +++ b/core/src/com/unciv/logic/automation/unit/UnitAutomation.kt @@ -31,6 +31,113 @@ object UnitAutomation { private const val CLOSE_ENEMY_TILES_AWAY_LIMIT = 5 private const val CLOSE_ENEMY_TURNS_AWAY_LIMIT = 3f + fun automateUnitMoves(unit: MapUnit) { + check(!unit.civ.isBarbarian) { "Barbarians is not allowed here." } + + // Might die next turn - move! + if (unit.getDamageFromTerrain() > 0 && tryHealUnit(unit)) return + + + if (unit.isCivilian()) { + CivilianUnitAutomation.automateCivilianUnit(unit, getDangerousTiles(unit)) + return + } + + while (unit.promotions.canBePromoted() && + // Restrict Human automated units from promotions via setting + (UncivGame.Current.settings.automatedUnitsChoosePromotions || unit.civ.isAI())) { + val promotions = unit.promotions.getAvailablePromotions() + val availablePromotions = if (unit.health <= 60 + && promotions.any {it.hasUnique(UniqueType.OneTimeUnitHeal)} + && !(unit.baseUnit.isAirUnit() || unit.hasUnique(UniqueType.CanMoveAfterAttacking))) { + promotions.filter { it.hasUnique(UniqueType.OneTimeUnitHeal) } + } else promotions.filterNot { it.hasUnique(UniqueType.SkipPromotion) } + + if (availablePromotions.none()) break + val freePromotions = availablePromotions.filter { it.hasUnique(UniqueType.FreePromotion) }.toList() + val stateForConditionals = unit.cache.state + + val chosenPromotion = if (freePromotions.isNotEmpty()) freePromotions.randomWeighted { it.getWeightForAiDecision(stateForConditionals) } + else availablePromotions.toList().randomWeighted { it.getWeightForAiDecision(stateForConditionals) } + + unit.promotions.addPromotion(chosenPromotion.name) + } + + // AI upgrades units via UseGoldAutomation in NextTurnAutomation + if (unit.civ.isHuman() && tryUpgradeUnit(unit)) return + + //This allows for military units with certain civilian abilities to behave as civilians in peace and soldiers in war + if ((unit.hasUnique(UniqueType.BuildImprovements) || unit.hasUnique(UniqueType.FoundCity) || + unit.hasUnique(UniqueType.ReligiousUnit) || unit.hasUnique(UniqueType.CreateWaterImprovements)) + && !unit.civ.isAtWar()){ + CivilianUnitAutomation.automateCivilianUnit(unit, getDangerousTiles(unit)) + return + } + + // Note that not all nukes have to be air units + if (unit.isNuclearWeapon()) { + return AirUnitAutomation.automateNukes(unit) + } + + if (unit.baseUnit.isAirUnit()) { + if (unit.canIntercept()) + return AirUnitAutomation.automateFighter(unit) + + if (unit.hasUnique(UniqueType.SelfDestructs)) + return AirUnitAutomation.automateMissile(unit) + + return AirUnitAutomation.automateBomber(unit) + } + + // Accompany settlers + if (tryAccompanySettlerOrGreatPerson(unit)) return + + if (tryGoToRuinAndEncampment(unit) && !unit.hasMovement()) return + + if (unit.health < 50 && (tryRetreat(unit) || tryHealUnit(unit))) return // do nothing but heal + + // If there are no enemies nearby and we can heal here, wait until we are at full health + if (unit.health < 100 && canUnitHealInTurnsOnCurrentTile(unit,2, 3)) return + + if (tryHeadTowardsOurSiegedCity(unit)) return + + // if a embarked melee unit can land and attack next turn, do not attack from water. + if (BattleHelper.tryDisembarkUnitToAttackPosition(unit)) return + + // if there is an attackable unit in the vicinity, attack! + if (tryAttacking(unit)) return + + if (tryTakeBackCapturedCity(unit)) return + + // Focus all units without a specific target on the enemy city closest to one of our cities + if (HeadTowardsEnemyCityAutomation.tryHeadTowardsEnemyCity(unit)) return + + if (tryGarrisoningRangedLandUnit(unit)) return + + if (tryStationingMeleeNavalUnit(unit)) return + + if (unit.health < 80 && tryHealUnit(unit)) return + + // move towards the closest reasonably attackable enemy unit within 3 turns of movement (and 5 tiles range) + if (tryAdvanceTowardsCloseEnemy(unit)) return + + if (tryHeadTowardsEncampment(unit)) return + + if (unit.health < 100 && tryHealUnit(unit)) return + + if (tryPrepare(unit)) return + + // else, try to go to unreached tiles + if (tryExplore(unit)) return + + if (tryFogBust(unit)) return + + // Idle CS units should wander so they don't obstruct players so much + if (unit.civ.isCityState) + wander(unit, stayInTerritory = true) + } + + @Readonly private fun isGoodTileToExplore(unit: MapUnit, tile: Tile): Boolean { return (tile.getOwner() == null || !tile.getOwner()!!.isCityState) @@ -174,112 +281,6 @@ object UnitAutomation { .filter { !isInvalidUpgradeDestination(it) && unit.upgrade.canUpgrade(it) } } - fun automateUnitMoves(unit: MapUnit) { - check(!unit.civ.isBarbarian) { "Barbarians is not allowed here." } - - // Might die next turn - move! - if (unit.getDamageFromTerrain() > 0 && tryHealUnit(unit)) return - - - if (unit.isCivilian()) { - CivilianUnitAutomation.automateCivilianUnit(unit, getDangerousTiles(unit)) - return - } - - while (unit.promotions.canBePromoted() && - // Restrict Human automated units from promotions via setting - (UncivGame.Current.settings.automatedUnitsChoosePromotions || unit.civ.isAI())) { - val promotions = unit.promotions.getAvailablePromotions() - val availablePromotions = if (unit.health <= 60 - && promotions.any {it.hasUnique(UniqueType.OneTimeUnitHeal)} - && !(unit.baseUnit.isAirUnit() || unit.hasUnique(UniqueType.CanMoveAfterAttacking))) { - promotions.filter { it.hasUnique(UniqueType.OneTimeUnitHeal) } - } else promotions.filterNot { it.hasUnique(UniqueType.SkipPromotion) } - - if (availablePromotions.none()) break - val freePromotions = availablePromotions.filter { it.hasUnique(UniqueType.FreePromotion) }.toList() - val stateForConditionals = unit.cache.state - - val chosenPromotion = if (freePromotions.isNotEmpty()) freePromotions.randomWeighted { it.getWeightForAiDecision(stateForConditionals) } - else availablePromotions.toList().randomWeighted { it.getWeightForAiDecision(stateForConditionals) } - - unit.promotions.addPromotion(chosenPromotion.name) - } - - // AI upgrades units via UseGoldAutomation in NextTurnAutomation - if (unit.civ.isHuman() && tryUpgradeUnit(unit)) return - - //This allows for military units with certain civilian abilities to behave as civilians in peace and soldiers in war - if ((unit.hasUnique(UniqueType.BuildImprovements) || unit.hasUnique(UniqueType.FoundCity) || - unit.hasUnique(UniqueType.ReligiousUnit) || unit.hasUnique(UniqueType.CreateWaterImprovements)) - && !unit.civ.isAtWar()){ - CivilianUnitAutomation.automateCivilianUnit(unit, getDangerousTiles(unit)) - return - } - - // Note that not all nukes have to be air units - if (unit.isNuclearWeapon()) { - return AirUnitAutomation.automateNukes(unit) - } - - if (unit.baseUnit.isAirUnit()) { - if (unit.canIntercept()) - return AirUnitAutomation.automateFighter(unit) - - if (unit.hasUnique(UniqueType.SelfDestructs)) - return AirUnitAutomation.automateMissile(unit) - - return AirUnitAutomation.automateBomber(unit) - } - - // Accompany settlers - if (tryAccompanySettlerOrGreatPerson(unit)) return - - if (tryGoToRuinAndEncampment(unit) && !unit.hasMovement()) return - - if (unit.health < 50 && (tryRetreat(unit) || tryHealUnit(unit))) return // do nothing but heal - - // If there are no enemies nearby and we can heal here, wait until we are at full health - if (unit.health < 100 && canUnitHealInTurnsOnCurrentTile(unit,2, 3)) return - - if (tryHeadTowardsOurSiegedCity(unit)) return - - // if a embarked melee unit can land and attack next turn, do not attack from water. - if (BattleHelper.tryDisembarkUnitToAttackPosition(unit)) return - - // if there is an attackable unit in the vicinity, attack! - if (tryAttacking(unit)) return - - if (tryTakeBackCapturedCity(unit)) return - - // Focus all units without a specific target on the enemy city closest to one of our cities - if (HeadTowardsEnemyCityAutomation.tryHeadTowardsEnemyCity(unit)) return - - if (tryGarrisoningRangedLandUnit(unit)) return - - if (tryStationingMeleeNavalUnit(unit)) return - - if (unit.health < 80 && tryHealUnit(unit)) return - - // move towards the closest reasonably attackable enemy unit within 3 turns of movement (and 5 tiles range) - if (tryAdvanceTowardsCloseEnemy(unit)) return - - if (tryHeadTowardsEncampment(unit)) return - - if (unit.health < 100 && tryHealUnit(unit)) return - - if (tryPrepare(unit)) return - - // else, try to go to unreached tiles - if (tryExplore(unit)) return - - if (tryFogBust(unit)) return - - // Idle CS units should wander so they don't obstruct players so much - if (unit.civ.isCityState) - wander(unit, stayInTerritory = true) - } - /** @return true only if the unit has 0 movement left */ private fun tryAttacking(unit: MapUnit): Boolean { diff --git a/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt b/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt index 62f0199d2d..1e5c5db4ca 100644 --- a/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt +++ b/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt @@ -578,8 +578,8 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction { -> power *= (unique.params[0].toInt() * 20f).toPercent() else -> {} } - power *= highestConditionalPowerBonus } + power *= highestConditionalPowerBonus return power.toInt() }