Air Units take damage in Combat (#6533)

* Changes required
Add isAirUnit to iCombatant

* Updating XP Rewards to match Civ5
Add isAirUnit() Boolean for ICombatant

* Air Units can only Intercept if they haven't moved this turn

* Change Intercept to only have the highest chance unit take the chance

* Exempt the defending unit from being able to Intercept
Add back in tryInterceptAirAttack() for all units of a civ to attempt intercept

* Combine back to 1 function.
Add filtering for defender

* Fix logic bug

* Change base damage to be centered on 25f (instead of 30f) if City is attacking. addRandomDamage is a guess

* Revert dmanageModifier code

* XP fix

Co-authored-by: itanasi <spellman23@gmail.com>
This commit is contained in:
itanasi 2022-04-16 13:06:30 -07:00 committed by GitHub
parent 8457c7ab1d
commit 7a89c84790
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 28 additions and 18 deletions

View File

@ -70,7 +70,7 @@ object Battle {
} }
if (attacker is MapUnitCombatant && attacker.unit.baseUnit.isAirUnit()) { if (attacker is MapUnitCombatant && attacker.unit.baseUnit.isAirUnit()) {
tryInterceptAirAttack(attacker, attackedTile, defender.getCivInfo()) tryInterceptAirAttack(attacker, attackedTile, defender.getCivInfo(), defender)
if (attacker.isDefeated()) return if (attacker.isDefeated()) return
} }
@ -221,7 +221,7 @@ object Battle {
if (defender is MapUnitCombatant && defender.unit.isCivilian() && attacker.isMelee()) { if (defender is MapUnitCombatant && defender.unit.isCivilian() && attacker.isMelee()) {
captureCivilianUnit(attacker, defender) 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 defender.takeDamage(potentialDamageToDefender) // straight up
} else { } else {
//melee attack is complicated, because either side may defeat the other midway //melee attack is complicated, because either side may defeat the other midway
@ -662,7 +662,7 @@ object Battle {
.filter{it != attackingCiv}) { .filter{it != attackingCiv}) {
tryDeclareWar(civWhoseUnitWasAttacked) tryDeclareWar(civWhoseUnitWasAttacked)
if (attacker.unit.baseUnit.isAirUnit() && !attacker.isDefeated()) { if (attacker.unit.baseUnit.isAirUnit() && !attacker.isDefeated()) {
tryInterceptAirAttack(attacker, targetTile, civWhoseUnitWasAttacked) tryInterceptAirAttack(attacker, targetTile, civWhoseUnitWasAttacked, null)
} }
} }
if (attacker.isDefeated()) return if (attacker.isDefeated()) return
@ -791,11 +791,16 @@ object Battle {
if (targetedCity.population.population < 1) targetedCity.population.setPopulation(1) 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 if (attacker.unit.hasUnique("Cannot be intercepted")) return
// Pick highest chance interceptor
for (interceptor in interceptingCiv.getCivUnits() for (interceptor in interceptingCiv.getCivUnits()
.filter { it.canIntercept(attackedTile) }) { .filter { it.canIntercept(attackedTile) }
if (Random().nextFloat() > interceptor.interceptChance() / 100f) continue .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( var damage = BattleDamage.calculateDamageToDefender(
MapUnitCombatant(interceptor), MapUnitCombatant(interceptor),
@ -813,6 +818,9 @@ object Battle {
if (damage > 0) if (damage > 0)
addXp(MapUnitCombatant(interceptor), 2, attacker) addXp(MapUnitCombatant(interceptor), 2, attacker)
if (damage > 0)
addXp(MapUnitCombatant(interceptor), 2, attacker)
val attackerName = attacker.getName() val attackerName = attacker.getName()
val interceptorName = interceptor.name val interceptorName = interceptor.name
val locations = LocationAction(interceptor.currentTile.position, attacker.unit.currentTile.position) val locations = LocationAction(interceptor.currentTile.position, attacker.unit.currentTile.position)

View File

@ -264,7 +264,7 @@ object BattleDamage {
defender: ICombatant, defender: ICombatant,
ignoreRandomness: Boolean = false, ignoreRandomness: Boolean = false,
): Int { ): Int {
if (attacker.isRanged()) return 0 if (attacker.isRanged() && !attacker.isAirUnit()) return 0
if (defender.isCivilian()) return 0 if (defender.isCivilian()) return 0
val ratio = val ratio =
getAttackingStrength(attacker, defender) / getDefendingStrength( getAttackingStrength(attacker, defender) / getDefendingStrength(

View File

@ -979,6 +979,8 @@ class MapUnit {
fun canIntercept(): Boolean { fun canIntercept(): Boolean {
if (interceptChance() == 0) return false 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 + val maxAttacksPerTurn = 1 +
getMatchingUniques("[] extra interceptions may be made per turn").sumOf { it.params[0].toInt() } getMatchingUniques("[] extra interceptions may be made per turn").sumOf { it.params[0].toInt() }
if (attacksThisTurn >= maxAttacksPerTurn) return false if (attacksThisTurn >= maxAttacksPerTurn) return false