diff --git a/core/src/com/unciv/logic/battle/Battle.kt b/core/src/com/unciv/logic/battle/Battle.kt index 337e4242f0..1b55d3ef7d 100644 --- a/core/src/com/unciv/logic/battle/Battle.kt +++ b/core/src/com/unciv/logic/battle/Battle.kt @@ -70,7 +70,7 @@ object Battle { } if (attacker is MapUnitCombatant && attacker.unit.baseUnit.isAirUnit()) { - tryInterceptAirAttack(attacker, attackedTile, defender.getCivInfo()) + tryInterceptAirAttack(attacker, attackedTile, defender.getCivInfo(), defender) if (attacker.isDefeated()) return } @@ -221,7 +221,7 @@ object Battle { if (defender is MapUnitCombatant && defender.unit.isCivilian() && attacker.isMelee()) { captureCivilianUnit(attacker, defender) - } else if (attacker.isRanged()) { + } else if (attacker.isRanged() && !attacker.isAirUnit()) { // Air Units are Ranged, but take damage as well defender.takeDamage(potentialDamageToDefender) // straight up } else { //melee attack is complicated, because either side may defeat the other midway @@ -662,7 +662,7 @@ object Battle { .filter{it != attackingCiv}) { tryDeclareWar(civWhoseUnitWasAttacked) if (attacker.unit.baseUnit.isAirUnit() && !attacker.isDefeated()) { - tryInterceptAirAttack(attacker, targetTile, civWhoseUnitWasAttacked) + tryInterceptAirAttack(attacker, targetTile, civWhoseUnitWasAttacked, null) } } if (attacker.isDefeated()) return @@ -790,17 +790,22 @@ object Battle { targetedCity.population.addPopulation(-populationLoss.toInt()) if (targetedCity.population.population < 1) targetedCity.population.setPopulation(1) } - - private fun tryInterceptAirAttack(attacker: MapUnitCombatant, attackedTile:TileInfo, interceptingCiv:CivilizationInfo) { + + private fun tryInterceptAirAttack(attacker: MapUnitCombatant, attackedTile: TileInfo, interceptingCiv: CivilizationInfo, defender: ICombatant?) { if (attacker.unit.hasUnique("Cannot be intercepted")) return + // Pick highest chance interceptor for (interceptor in interceptingCiv.getCivUnits() - .filter { it.canIntercept(attackedTile) }) { - if (Random().nextFloat() > interceptor.interceptChance() / 100f) continue + .filter { it.canIntercept(attackedTile) } + .sortedByDescending { it.interceptChance() }) { + // defender can't also intercept + if (defender != null && defender is MapUnitCombatant && interceptor == defender.unit) continue + // Does Intercept happen? If not, exit + if (Random().nextFloat() > interceptor.interceptChance() / 100f) return var damage = BattleDamage.calculateDamageToDefender( - MapUnitCombatant(interceptor), - null, - attacker + MapUnitCombatant(interceptor), + null, + attacker ) var damageFactor = 1f + interceptor.interceptDamagePercentBonus().toFloat() / 100f @@ -813,19 +818,22 @@ object Battle { if (damage > 0) addXp(MapUnitCombatant(interceptor), 2, attacker) + if (damage > 0) + addXp(MapUnitCombatant(interceptor), 2, attacker) + val attackerName = attacker.getName() val interceptorName = interceptor.name val locations = LocationAction(interceptor.currentTile.position, attacker.unit.currentTile.position) val attackerText = if (attacker.isDefeated()) "Our [$attackerName] was destroyed by an intercepting [$interceptorName]" - else "Our [$attackerName] was attacked by an intercepting [$interceptorName]" + else "Our [$attackerName] was attacked by an intercepting [$interceptorName]" val interceptorText = if (attacker.isDefeated()) "Our [$interceptorName] intercepted and destroyed an enemy [$attackerName]" - else "Our [$interceptorName] intercepted and attacked an enemy [$attackerName]" + else "Our [$interceptorName] intercepted and attacked an enemy [$attackerName]" attacker.getCivInfo().addNotification(attackerText, interceptor.currentTile.position, - attackerName, NotificationIcon.War, interceptorName) + attackerName, NotificationIcon.War, interceptorName) interceptingCiv.addNotification(interceptorText, locations, - interceptorName, NotificationIcon.War, attackerName) + interceptorName, NotificationIcon.War, attackerName) return } } diff --git a/core/src/com/unciv/logic/battle/BattleDamage.kt b/core/src/com/unciv/logic/battle/BattleDamage.kt index 0aa2ac6b55..b7f38d0b11 100644 --- a/core/src/com/unciv/logic/battle/BattleDamage.kt +++ b/core/src/com/unciv/logic/battle/BattleDamage.kt @@ -264,7 +264,7 @@ object BattleDamage { defender: ICombatant, ignoreRandomness: Boolean = false, ): Int { - if (attacker.isRanged()) return 0 + if (attacker.isRanged() && !attacker.isAirUnit()) return 0 if (defender.isCivilian()) return 0 val ratio = getAttackingStrength(attacker, defender) / getDefendingStrength( @@ -302,9 +302,9 @@ object BattleDamage { if (damageToAttacker && attackerToDefenderRatio > 1 || !damageToAttacker && attackerToDefenderRatio < 1) // damage ratio from the weaker party is inverted ratioModifier = ratioModifier.pow(-1) val randomSeed = attacker.getCivInfo().gameInfo.turns * attacker.getTile().position.hashCode() // so people don't save-scum to get optimal results - val randomCenteredAround30 = 24 + - if (ignoreRandomness) 6f - else 12 * Random(randomSeed.toLong()).nextFloat() + val randomCenteredAround30 = 24 + + if (ignoreRandomness) 6f + else 12 * Random(randomSeed.toLong()).nextFloat() return randomCenteredAround30 * ratioModifier } } diff --git a/core/src/com/unciv/logic/map/MapUnit.kt b/core/src/com/unciv/logic/map/MapUnit.kt index 2584b47171..7eef0d6871 100644 --- a/core/src/com/unciv/logic/map/MapUnit.kt +++ b/core/src/com/unciv/logic/map/MapUnit.kt @@ -979,6 +979,8 @@ class MapUnit { fun canIntercept(): Boolean { if (interceptChance() == 0) return false + // Air Units can only Intercept if they didn't move this turn + if (baseUnit.isAirUnit() && currentMovement == 0f) return false val maxAttacksPerTurn = 1 + getMatchingUniques("[] extra interceptions may be made per turn").sumOf { it.params[0].toInt() } if (attacksThisTurn >= maxAttacksPerTurn) return false