Fix unit force rankings

This commit is contained in:
yairm210 2025-08-25 23:15:08 +03:00
parent c1320357be
commit c738bc8878
2 changed files with 108 additions and 107 deletions

View File

@ -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 {

View File

@ -578,8 +578,8 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction {
-> power *= (unique.params[0].toInt() * 20f).toPercent()
else -> {}
}
power *= highestConditionalPowerBonus
}
power *= highestConditionalPowerBonus
return power.toInt()
}