Likely fixed a bug where AI nukes could hit nations they had a peace treaty with (#5449)

* Likely fixed a bug where AI nukes could hit players they had a peace treaty with

* Typefied blast radius unique
This commit is contained in:
Xander Lenstra 2021-10-10 21:26:54 +02:00 committed by GitHub
parent 9fab1f6ee7
commit a73b7b008f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 43 additions and 32 deletions

View File

@ -14,12 +14,12 @@ object BattleHelper {
fun tryAttackNearbyEnemy(unit: MapUnit, stayOnTile: Boolean = false): Boolean {
if (unit.hasUnique("Cannot attack")) return false
val attackableEnemies = getAttackableEnemies(unit, unit.movement.getDistanceToTiles(), stayOnTile=stayOnTile)
// Only take enemies we can fight without dying
.filter {
BattleDamage.calculateDamageToAttacker(MapUnitCombatant(unit),
it.tileToAttackFrom,
Battle.getMapCombatantOfTile(it.tileToAttack)!!) < unit.health
}
// Only take enemies we can fight without dying
.filter {
BattleDamage.calculateDamageToAttacker(MapUnitCombatant(unit),
it.tileToAttackFrom,
Battle.getMapCombatantOfTile(it.tileToAttack)!!) < unit.health
}
val enemyTileToAttack = chooseAttackTarget(unit, attackableEnemies)

View File

@ -331,7 +331,7 @@ object SpecificUnitAutomation {
val tilesInRange = unit.currentTile.getTilesInDistance(unit.getRange())
for (tile in tilesInRange) {
// For now AI will only use nukes against cities because in all honesty that's the best use for them.
if (tile.isCityCenter() && tile.getOwner()!!.isAtWarWith(unit.civInfo)) {
if (tile.isCityCenter() && tile.getOwner()!!.isAtWarWith(unit.civInfo) && Battle.mayUseNuke(MapUnitCombatant(unit), tile)) {
Battle.NUKE(MapUnitCombatant(unit), tile)
return
}

View File

@ -11,6 +11,7 @@ import com.unciv.logic.map.TileInfo
import com.unciv.models.AttackableTile
import com.unciv.models.UnitActionType
import com.unciv.models.ruleset.unique.Unique
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.stats.Stat
import com.unciv.models.stats.Stats
import com.unciv.ui.utils.toPercent
@ -538,6 +539,28 @@ object Battle {
attacker.popupAlerts.add(PopupAlert(AlertType.Defeated, attackedCiv.civName))
}
}
fun mayUseNuke(nuke: MapUnitCombatant, targetTile: TileInfo): Boolean {
val blastRadius =
if (!nuke.unit.hasUnique(UniqueType.BlastRadius)) 2
else nuke.unit.getMatchingUniques(UniqueType.BlastRadius).first().params[0].toInt()
var canNuke = true
val attackerCiv = nuke.getCivInfo()
for (tile in targetTile.getTilesInDistance(blastRadius)) {
val defendingTileCiv = tile.getCity()?.civInfo
if (defendingTileCiv != null && attackerCiv.knows(defendingTileCiv)) {
canNuke = canNuke && attackerCiv.getDiplomacyManager(defendingTileCiv).canAttack()
}
val defender = getMapCombatantOfTile(tile) ?: continue
val defendingUnitCiv = defender.getCivInfo()
if (attackerCiv.knows(defendingUnitCiv)) {
canNuke = canNuke && attackerCiv.getDiplomacyManager(defendingUnitCiv).canAttack()
}
}
return canNuke
}
@Suppress("FunctionName") // Yes we want this name to stand out
fun NUKE(attacker: MapUnitCombatant, targetTile: TileInfo) {
@ -553,8 +576,8 @@ object Battle {
}
val blastRadius =
if (!attacker.unit.hasUnique("Blast radius []")) 2
else attacker.unit.getMatchingUniques("Blast radius []").first().params[0].toInt()
if (!attacker.unit.hasUnique(UniqueType.BlastRadius)) 2
else attacker.unit.getMatchingUniques(UniqueType.BlastRadius).first().params[0].toInt()
val strength = when {
(attacker.unit.hasUnique("Nuclear weapon of Strength []")) ->

View File

@ -187,6 +187,7 @@ enum class UniqueType(val text:String, vararg targets: UniqueTarget) {
@Deprecated("As of 3.17.5", ReplaceWith("[amount]% Spread Religion Strength <for [mapUnitFilter] units>"), DeprecationLevel.WARNING)
SpreadReligionStrengthUnits("[amount]% Spread Religion Strength for [mapUnitFilter] units", UniqueTarget.Global),
BlastRadius("Blast radius [amount]", UniqueTarget.Unit),
CarryAirUnits("Can carry [amount] [mapUnitFilter] units", UniqueTarget.Unit),
CarryExtraAirUnits("Can carry [amount] extra [mapUnitFilter] units", UniqueTarget.Unit),

View File

@ -13,6 +13,7 @@ import com.unciv.logic.automation.UnitAutomation
import com.unciv.logic.battle.*
import com.unciv.logic.map.TileInfo
import com.unciv.models.AttackableTile
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.translations.tr
import com.unciv.ui.utils.*
import com.unciv.ui.worldscreen.WorldScreen
@ -228,31 +229,17 @@ class BattleTable(val worldScreen: WorldScreen): Table() {
attackerNameWrapper.add(UnitGroup(attacker.unit,25f)).padRight(5f)
attackerNameWrapper.add(attackerLabel)
add(attackerNameWrapper)
var canNuke = true
val defenderNameWrapper = Table()
val canNuke = Battle.mayUseNuke(attacker, targetTile)
val blastRadius =
if (!attacker.unit.hasUnique("Blast radius []")) 2
else attacker.unit.getMatchingUniques("Blast radius []").first().params[0].toInt()
if (!attacker.unit.hasUnique(UniqueType.BlastRadius)) 2
else attacker.unit.getMatchingUniques(UniqueType.BlastRadius).first().params[0].toInt()
val defenderNameWrapper = Table()
for (tile in targetTile.getTilesInDistance(blastRadius)) {
//To make sure we dont nuke civilisations we cant declare war with
val attackerCiv = attacker.getCivInfo()
val defenderTileCiv = tile.getCity()?.civInfo
if(defenderTileCiv != null && defenderTileCiv.knows(attackerCiv)) {
val canAttackDefenderCiv = attackerCiv.getDiplomacyManager(defenderTileCiv).canAttack()
canNuke = canNuke && canAttackDefenderCiv
}
val defender = tryGetDefenderAtTile(tile, true) ?: continue
val defenderUnitCiv = defender.getCivInfo()
if( defenderUnitCiv.knows(attackerCiv))
{
val canAttackDefenderUnitCiv = attackerCiv.getDiplomacyManager(defenderUnitCiv).canAttack()
canNuke = canNuke && canAttackDefenderUnitCiv
}
val defenderLabel = Label(defender.getName().tr(), skin)
when (defender) {
is MapUnitCombatant ->
@ -271,7 +258,7 @@ class BattleTable(val worldScreen: WorldScreen): Table() {
addSeparator().pad(0f)
row().pad(5f)
val attackButton = "NUKE".toTextButton().apply { color= Color.RED }
val attackButton = "NUKE".toTextButton().apply { color = Color.RED }
val canReach = attacker.unit.currentTile.getTilesInDistance(attacker.unit.getRange()).contains(targetTile)