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

View File

@ -331,7 +331,7 @@ object SpecificUnitAutomation {
val tilesInRange = unit.currentTile.getTilesInDistance(unit.getRange()) val tilesInRange = unit.currentTile.getTilesInDistance(unit.getRange())
for (tile in tilesInRange) { for (tile in tilesInRange) {
// For now AI will only use nukes against cities because in all honesty that's the best use for them. // 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) Battle.NUKE(MapUnitCombatant(unit), tile)
return return
} }

View File

@ -11,6 +11,7 @@ import com.unciv.logic.map.TileInfo
import com.unciv.models.AttackableTile import com.unciv.models.AttackableTile
import com.unciv.models.UnitActionType import com.unciv.models.UnitActionType
import com.unciv.models.ruleset.unique.Unique 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.Stat
import com.unciv.models.stats.Stats import com.unciv.models.stats.Stats
import com.unciv.ui.utils.toPercent import com.unciv.ui.utils.toPercent
@ -538,6 +539,28 @@ object Battle {
attacker.popupAlerts.add(PopupAlert(AlertType.Defeated, attackedCiv.civName)) 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 @Suppress("FunctionName") // Yes we want this name to stand out
fun NUKE(attacker: MapUnitCombatant, targetTile: TileInfo) { fun NUKE(attacker: MapUnitCombatant, targetTile: TileInfo) {
@ -553,8 +576,8 @@ object Battle {
} }
val blastRadius = val blastRadius =
if (!attacker.unit.hasUnique("Blast radius []")) 2 if (!attacker.unit.hasUnique(UniqueType.BlastRadius)) 2
else attacker.unit.getMatchingUniques("Blast radius []").first().params[0].toInt() else attacker.unit.getMatchingUniques(UniqueType.BlastRadius).first().params[0].toInt()
val strength = when { val strength = when {
(attacker.unit.hasUnique("Nuclear weapon of Strength []")) -> (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) @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), SpreadReligionStrengthUnits("[amount]% Spread Religion Strength for [mapUnitFilter] units", UniqueTarget.Global),
BlastRadius("Blast radius [amount]", UniqueTarget.Unit),
CarryAirUnits("Can carry [amount] [mapUnitFilter] units", UniqueTarget.Unit), CarryAirUnits("Can carry [amount] [mapUnitFilter] units", UniqueTarget.Unit),
CarryExtraAirUnits("Can carry [amount] extra [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.battle.*
import com.unciv.logic.map.TileInfo import com.unciv.logic.map.TileInfo
import com.unciv.models.AttackableTile import com.unciv.models.AttackableTile
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.translations.tr import com.unciv.models.translations.tr
import com.unciv.ui.utils.* import com.unciv.ui.utils.*
import com.unciv.ui.worldscreen.WorldScreen 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(UnitGroup(attacker.unit,25f)).padRight(5f)
attackerNameWrapper.add(attackerLabel) attackerNameWrapper.add(attackerLabel)
add(attackerNameWrapper) add(attackerNameWrapper)
var canNuke = true
val defenderNameWrapper = Table() val canNuke = Battle.mayUseNuke(attacker, targetTile)
val blastRadius = val blastRadius =
if (!attacker.unit.hasUnique("Blast radius []")) 2 if (!attacker.unit.hasUnique(UniqueType.BlastRadius)) 2
else attacker.unit.getMatchingUniques("Blast radius []").first().params[0].toInt() else attacker.unit.getMatchingUniques(UniqueType.BlastRadius).first().params[0].toInt()
val defenderNameWrapper = Table()
for (tile in targetTile.getTilesInDistance(blastRadius)) { 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 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) val defenderLabel = Label(defender.getName().tr(), skin)
when (defender) { when (defender) {
is MapUnitCombatant -> is MapUnitCombatant ->
@ -271,7 +258,7 @@ class BattleTable(val worldScreen: WorldScreen): Table() {
addSeparator().pad(0f) addSeparator().pad(0f)
row().pad(5f) 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) val canReach = attacker.unit.currentTile.getTilesInDistance(attacker.unit.getRange()).contains(targetTile)