Battle calculation takes into account the tile that the unit will attack from

This commit is contained in:
Yair Morgenstern 2020-06-01 01:51:11 +03:00
parent 9496c4523e
commit 4b649825cd
4 changed files with 18 additions and 17 deletions

View File

@ -17,6 +17,7 @@ object BattleHelper {
// 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,
Battle.getMapCombatantOfTile(it.tileToAttack)!!) < unit.health Battle.getMapCombatantOfTile(it.tileToAttack)!!) < unit.health
} }
@ -112,6 +113,7 @@ object BattleHelper {
// 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,
Battle.getMapCombatantOfTile(it.tileToAttack)!!) < unit.health Battle.getMapCombatantOfTile(it.tileToAttack)!!) < unit.health
} }
.filter { it.tileToAttackFrom.isLand } .filter { it.tileToAttackFrom.isLand }

View File

@ -53,8 +53,8 @@ object Battle {
} }
} }
var damageToDefender = BattleDamage.calculateDamageToDefender(attacker,defender) var damageToDefender = BattleDamage.calculateDamageToDefender(attacker, attacker.getTile(), defender)
var damageToAttacker = BattleDamage.calculateDamageToAttacker(attacker,defender) var damageToAttacker = BattleDamage.calculateDamageToAttacker(attacker, attacker.getTile(), defender)
if(defender.getUnitType().isCivilian() && attacker.isMelee()){ if(defender.getUnitType().isCivilian() && attacker.isMelee()){
captureCivilianUnit(attacker,defender) captureCivilianUnit(attacker,defender)
@ -387,7 +387,7 @@ object Battle {
for (interceptor in defender.getCivInfo().getCivUnits().filter { it.canIntercept(attackedTile) }) { for (interceptor in defender.getCivInfo().getCivUnits().filter { it.canIntercept(attackedTile) }) {
if (Random().nextFloat() > 100f / interceptor.interceptChance()) continue if (Random().nextFloat() > 100f / interceptor.interceptChance()) continue
var damage = BattleDamage.calculateDamageToDefender(MapUnitCombatant(interceptor), attacker) var damage = BattleDamage.calculateDamageToDefender(MapUnitCombatant(interceptor), interceptor.getTile(), attacker)
damage += damage * interceptor.interceptDamagePercentBonus() / 100 damage += damage * interceptor.interceptDamagePercentBonus() / 100
if (attacker.unit.hasUnique("Reduces damage taken from interception by 50%")) damage /= 2 if (attacker.unit.hasUnique("Reduces damage taken from interception by 50%")) damage /= 2

View File

@ -110,12 +110,12 @@ object BattleDamage {
return modifiers return modifiers
} }
fun getAttackModifiers(attacker: ICombatant, defender: ICombatant): HashMap<String, Float> { fun getAttackModifiers(attacker: ICombatant, tileToAttackFrom:TileInfo?, defender: ICombatant): HashMap<String, Float> {
val modifiers = getGeneralModifiers(attacker, defender) val modifiers = getGeneralModifiers(attacker, defender)
val policies = attacker.getCivInfo().policies val policies = attacker.getCivInfo().policies
if(attacker is MapUnitCombatant) { if(attacker is MapUnitCombatant) {
modifiers.putAll(getTileSpecificModifiers(attacker,defender.getTile())) modifiers.putAll(getTileSpecificModifiers(attacker, defender.getTile()))
for (ability in attacker.unit.getUniques()) { for (ability in attacker.unit.getUniques()) {
val regexResult = Regex(BONUS_AS_ATTACKER).matchEntire(ability) //to do: extend to defender, and penalyy val regexResult = Regex(BONUS_AS_ATTACKER).matchEntire(ability) //to do: extend to defender, and penalyy
@ -138,8 +138,8 @@ object BattleDamage {
if (numberOfAttackersSurroundingDefender > 1) if (numberOfAttackersSurroundingDefender > 1)
modifiers["Flanking"] = 0.1f * (numberOfAttackersSurroundingDefender-1) //https://www.carlsguides.com/strategy/civilization5/war/combatbonuses.php modifiers["Flanking"] = 0.1f * (numberOfAttackersSurroundingDefender-1) //https://www.carlsguides.com/strategy/civilization5/war/combatbonuses.php
if (attacker.getTile().isConnectedByRiver(defender.getTile())){ if (tileToAttackFrom!=null && tileToAttackFrom.isConnectedByRiver(defender.getTile())){
if (!attacker.getTile().hasConnection(attacker.getCivInfo()) // meaning, the tiles are not road-connected for this civ if (!tileToAttackFrom.hasConnection(attacker.getCivInfo()) // meaning, the tiles are not road-connected for this civ
|| !defender.getTile().hasConnection(attacker.getCivInfo()) || !defender.getTile().hasConnection(attacker.getCivInfo())
|| !attacker.getCivInfo().tech.roadsConnectAcrossRivers){ || !attacker.getCivInfo().tech.roadsConnectAcrossRivers){
modifiers["Across river"] = -0.2f modifiers["Across river"] = -0.2f
@ -272,8 +272,8 @@ object BattleDamage {
/** /**
* Includes attack modifiers * Includes attack modifiers
*/ */
private fun getAttackingStrength(attacker: ICombatant, defender: ICombatant): Float { private fun getAttackingStrength(attacker: ICombatant, tileToAttackFrom: TileInfo?, defender: ICombatant): Float {
val attackModifier = modifiersToMultiplicationBonus(getAttackModifiers(attacker,defender)) val attackModifier = modifiersToMultiplicationBonus(getAttackModifiers(attacker,tileToAttackFrom, defender))
return attacker.getAttackingStrength() * attackModifier return attacker.getAttackingStrength() * attackModifier
} }
@ -287,15 +287,15 @@ object BattleDamage {
return defender.getDefendingStrength() * defenceModifier return defender.getDefendingStrength() * defenceModifier
} }
fun calculateDamageToAttacker(attacker: ICombatant, defender: ICombatant): Int { fun calculateDamageToAttacker(attacker: ICombatant, tileToAttackFrom: TileInfo?, defender: ICombatant): Int {
if(attacker.isRanged()) return 0 if(attacker.isRanged()) return 0
if(defender.getUnitType().isCivilian()) return 0 if(defender.getUnitType().isCivilian()) return 0
val ratio = getAttackingStrength(attacker,defender) / getDefendingStrength(attacker,defender) val ratio = getAttackingStrength(attacker, tileToAttackFrom, defender) / getDefendingStrength(attacker,defender)
return (damageModifier(ratio, true) * getHealthDependantDamageRatio(defender)).roundToInt() return (damageModifier(ratio, true) * getHealthDependantDamageRatio(defender)).roundToInt()
} }
fun calculateDamageToDefender(attacker: ICombatant, defender: ICombatant): Int { fun calculateDamageToDefender(attacker: ICombatant, tileToAttackFrom: TileInfo?, defender: ICombatant): Int {
val ratio = getAttackingStrength(attacker,defender) / getDefendingStrength(attacker,defender) val ratio = getAttackingStrength(attacker,tileToAttackFrom, defender) / getDefendingStrength(attacker,defender)
return (damageModifier(ratio,false) * getHealthDependantDamageRatio(attacker)).roundToInt() return (damageModifier(ratio,false) * getHealthDependantDamageRatio(attacker)).roundToInt()
} }

View File

@ -7,7 +7,6 @@ import com.badlogic.gdx.scenes.scene2d.actions.RepeatAction
import com.badlogic.gdx.scenes.scene2d.ui.Image import com.badlogic.gdx.scenes.scene2d.ui.Image
import com.badlogic.gdx.scenes.scene2d.ui.Label import com.badlogic.gdx.scenes.scene2d.ui.Label
import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
import com.unciv.UncivGame import com.unciv.UncivGame
import com.unciv.logic.automation.BattleHelper import com.unciv.logic.automation.BattleHelper
import com.unciv.logic.automation.UnitAutomation import com.unciv.logic.automation.UnitAutomation
@ -122,7 +121,7 @@ class BattleTable(val worldScreen: WorldScreen): Table() {
add("{Strength}: ".tr()+defender.getDefendingStrength()).row() add("{Strength}: ".tr()+defender.getDefendingStrength()).row()
val attackerModifiers = val attackerModifiers =
BattleDamage.getAttackModifiers(attacker,defender).map { BattleDamage.getAttackModifiers(attacker,null,defender).map {
val description = if(it.key.startsWith("vs ")) ("vs ["+it.key.replace("vs ","")+"]").tr() else it.key.tr() val description = if(it.key.startsWith("vs ")) ("vs ["+it.key.replace("vs ","")+"]").tr() else it.key.tr()
val percentage = (if(it.value>0)"+" else "")+(it.value*100).toInt()+"%" val percentage = (if(it.value>0)"+" else "")+(it.value*100).toInt()+"%"
"$description: $percentage" "$description: $percentage"
@ -142,8 +141,8 @@ class BattleTable(val worldScreen: WorldScreen): Table() {
row().pad(2f) row().pad(2f)
} }
var damageToDefender = BattleDamage.calculateDamageToDefender(attacker,defender) var damageToDefender = BattleDamage.calculateDamageToDefender(attacker,null,defender)
var damageToAttacker = BattleDamage.calculateDamageToAttacker(attacker,defender) var damageToAttacker = BattleDamage.calculateDamageToAttacker(attacker,null,defender)
if (damageToAttacker>attacker.getHealth() && damageToDefender>defender.getHealth()) // when damage exceeds health, we don't want to show negative health numbers if (damageToAttacker>attacker.getHealth() && damageToDefender>defender.getHealth()) // when damage exceeds health, we don't want to show negative health numbers