From 9625a12ba2387290f342d1ed63cd12fcc0d4a0ea Mon Sep 17 00:00:00 2001 From: Yair Morgenstern Date: Wed, 9 May 2018 18:24:30 +0300 Subject: [PATCH] Damage calculations are now according to extrapolated Civ V rules --- android/build.gradle | 2 +- core/src/com/unciv/logic/battle/Battle.kt | 52 ++++++++++++------- .../com/unciv/ui/worldscreen/CivStatsTable.kt | 6 ++- 3 files changed, 37 insertions(+), 23 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index e09be85c79..e374366660 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -21,7 +21,7 @@ android { applicationId "com.unciv.game" minSdkVersion 14 targetSdkVersion 26 - versionCode 48 + versionCode 49 versionName "2.1.0" } buildTypes { diff --git a/core/src/com/unciv/logic/battle/Battle.kt b/core/src/com/unciv/logic/battle/Battle.kt index 021c2c75af..55c9599380 100644 --- a/core/src/com/unciv/logic/battle/Battle.kt +++ b/core/src/com/unciv/logic/battle/Battle.kt @@ -7,24 +7,28 @@ import com.unciv.logic.map.UnitType import java.util.* import kotlin.collections.HashMap +/** + * Damage calculations according to civ v wiki and https://steamcommunity.com/sharedfiles/filedetails/?id=170194443 + */ class Battle(val gameInfo:GameInfo) { - fun getGeneralModifiers(combatant:ICombatant,enemy:ICombatant): HashMap { - val modifiers = HashMap() - if(combatant is MapUnitCombatant){ + + fun getGeneralModifiers(combatant: ICombatant, enemy: ICombatant): HashMap { + val modifiers = HashMap() + if (combatant is MapUnitCombatant) { val uniques = combatant.unit.getBaseUnit().uniques - if(uniques!=null) { + if (uniques != null) { // This beut allows us to have generic unit uniques: "Bonus vs City 75%", "Penatly vs Mounted 25%" etc. - for (unique in uniques){ + for (unique in uniques) { val regexResult = Regex("""(Bonus|Penalty) vs (\S*) (\d*)%""").matchEntire(unique) - if(regexResult==null) continue + if (regexResult == null) continue val vsType = UnitType.valueOf(regexResult.groups[2]!!.value) - val modificationAmount = regexResult.groups[3]!!.value.toFloat()/100 // if it says 15%, that's 0.15f in modification - if(enemy.getUnitType() == vsType){ - if(regexResult.groups[1]!!.value=="Bonus") - modifiers.put("Bonus vs $vsType",modificationAmount) - else modifiers.put("Penalty vs $vsType",-modificationAmount) + val modificationAmount = regexResult.groups[3]!!.value.toFloat() / 100 // if it says 15%, that's 0.15f in modification + if (enemy.getUnitType() == vsType) { + if (regexResult.groups[1]!!.value == "Bonus") + modifiers.put("Bonus vs $vsType", modificationAmount) + else modifiers.put("Penalty vs $vsType", -modificationAmount) } } } @@ -33,35 +37,41 @@ class Battle(val gameInfo:GameInfo) { } fun getAttackModifiers(attacker: ICombatant, defender: ICombatant): HashMap { - val modifiers = getGeneralModifiers(attacker,defender) - if(attacker.isMelee()) { + val modifiers = getGeneralModifiers(attacker, defender) + if (attacker.isMelee()) { val numberOfAttackersSurroundingDefender = defender.getTile().neighbors.count { it.unit != null && it.unit!!.owner == attacker.getCivilization().civName && MapUnitCombatant(it.unit!!).isMelee() } - if(numberOfAttackersSurroundingDefender >1) modifiers["Flanking"] = 0.15f + if (numberOfAttackersSurroundingDefender > 1) modifiers["Flanking"] = 0.15f } return modifiers } fun getDefenceModifiers(attacker: ICombatant, defender: ICombatant): HashMap { - val modifiers = getGeneralModifiers(defender,attacker) - if(!(defender is MapUnitCombatant && defender.unit.getBaseUnit().hasUnique("No defensive terrain bonus"))){ + val modifiers = getGeneralModifiers(defender, attacker) + if (!(defender is MapUnitCombatant && defender.unit.getBaseUnit().hasUnique("No defensive terrain bonus"))) { val tileDefenceBonus = defender.getTile().getDefensiveBonus() if (tileDefenceBonus > 0) modifiers["Terrain"] = tileDefenceBonus } return modifiers } - fun modifiersToMultiplicationBonus(modifiers:HashMap ):Float{ + fun modifiersToMultiplicationBonus(modifiers: HashMap): Float { // modifiers are like 0.1 for a 10% bonus, -0.1 for a 10% loss var modifier = 1f - for(m in modifiers.values) modifier *= (1+m) + for (m in modifiers.values) modifier *= (1 + m) return modifier } + fun getHealthDependantDamageRatio(combatant: ICombatant): Float { + if (combatant.getUnitType() == UnitType.City) return 1f; + return 1 / 2f + combatant.getHealth() / 200f // Each point of health reduces damage dealt by 0.5% + } + + /** * Includes attack modifiers */ @@ -81,11 +91,13 @@ class Battle(val gameInfo:GameInfo) { fun calculateDamageToAttacker(attacker: ICombatant, defender: ICombatant): Int { if(attacker.isRanged()) return 0 - return (getDefendingStrength(attacker,defender) * 50 / getAttackingStrength(attacker,defender)).toInt() + val ratio = getDefendingStrength(attacker,defender) / getAttackingStrength(attacker,defender) + return (ratio * 30 * getHealthDependantDamageRatio(defender)).toInt() } fun calculateDamageToDefender(attacker: ICombatant, defender: ICombatant): Int { - return (getAttackingStrength(attacker, defender)*50/ getDefendingStrength(attacker,defender)).toInt() + val ratio = getAttackingStrength(attacker,defender) / getDefendingStrength(attacker,defender) + return (ratio * 30 * getHealthDependantDamageRatio(attacker)).toInt() } fun attack(attacker: ICombatant, defender: ICombatant) { diff --git a/core/src/com/unciv/ui/worldscreen/CivStatsTable.kt b/core/src/com/unciv/ui/worldscreen/CivStatsTable.kt index 768e537e9e..497b08677c 100644 --- a/core/src/com/unciv/ui/worldscreen/CivStatsTable.kt +++ b/core/src/com/unciv/ui/worldscreen/CivStatsTable.kt @@ -39,6 +39,7 @@ class CivStatsTable(val screen: WorldScreen) : Table() { resourceLabels.put(resource.name, resourceLabel) resourceTable.add(resourceLabel) } + resourceTable.pack() add(resourceTable).row() @@ -50,11 +51,12 @@ class CivStatsTable(val screen: WorldScreen) : Table() { statsTable.add(scienceLabel.apply { setAlignment(Align.center) }) statsTable.add(happinessLabel.apply { setAlignment(Align.center) }) statsTable.add(cultureLabel.apply { setAlignment(Align.center) }) - add(statsTable) + statsTable.pack() + statsTable.width = screen.stage.width - 20 + add(statsTable) pack() width = screen.stage.width - 20 - statsTable.width = width } internal fun getMenuButton(): TextButton {