From d94a1d14320fee897fd4aae13642da5302355737 Mon Sep 17 00:00:00 2001 From: Xander Lenstra <71121390+xlenstra@users.noreply.github.com> Date: Fri, 2 Jul 2021 13:02:20 +0200 Subject: [PATCH] Updated and generalized more promotions (#4331) * Generalized "[1] extra interceptions may be made per turn" * Generalized and rephrased Cover promotion (requires #4311 to work) * Generalized Logistics * According to the civilopedia the defence value of cover has also risen, apparently * Updated Ambush strength values * Split up Targeting and Air Targeting (different strength bonus) * Generalized Haka War Dance * Added Supply promotion * Renamed a unique so it matches other uniques * Implemented May heal outside of friendly territory better * Implemented requested changes --- .../jsons/Civ V - Vanilla/UnitPromotions.json | 84 +++++++++++-------- .../com/unciv/logic/battle/BattleDamage.kt | 52 +++++++----- core/src/com/unciv/logic/map/MapUnit.kt | 20 +++-- 3 files changed, 93 insertions(+), 63 deletions(-) diff --git a/android/assets/jsons/Civ V - Vanilla/UnitPromotions.json b/android/assets/jsons/Civ V - Vanilla/UnitPromotions.json index 457fe9bfce..c7054e320d 100644 --- a/android/assets/jsons/Civ V - Vanilla/UnitPromotions.json +++ b/android/assets/jsons/Civ V - Vanilla/UnitPromotions.json @@ -229,6 +229,25 @@ "unitTypes": ["WaterMelee"] }, + // Water Ranged + { + "name": "Targeting I", + "effect": "+[15]% Strength vs [water units]", + "unitTypes": ["WaterRanged"] + }, + { + "name": "Targeting II", + "prerequisites": ["Targeting I"], + "effect": "+[15]% Strength vs [water units]", + "unitTypes": ["WaterRanged"] + }, + { + "name": "Targeting III", + "prerequisites": ["Targeting II"], + "effect": "+[15]% Strength vs [water units]", + "unitTypes": ["WaterRanged"] + }, + // Submarine { "name": "Wolfpack I", @@ -283,6 +302,13 @@ "effect": "Can carry [1] extra [Air] units", "unitTypes": ["WaterAircraftCarrier"] }, + + // Mixed Water + { + "name" : "Supply", + "prerequisites": ["Bombardment III", "Targeting III", "Boarding Party III", "Coastal Raider III"], + "uniques": ["May heal outside of friendly territory", "[+15] HP when healing in [Foreign Land] tiles"], + }, // Bomber { @@ -312,19 +338,19 @@ // Fighter { "name": "Interception I", - "effect": "Bonus when intercepting [33]%", + "effect": "[+33]% Damage when intercepting", "unitTypes": ["Fighter"] }, { "name": "Interception II", "prerequisites": ["Interception I"], - "effect": "Bonus when intercepting [33]%", + "effect": "[+33]% Damage when intercepting", "unitTypes": ["Fighter"] }, { "name": "Interception III", "prerequisites": ["Interception II"], - "effect": "Bonus when intercepting [34]%", + "effect": "[+34]% Damage when intercepting", "unitTypes": ["Fighter"] }, /* @@ -346,11 +372,24 @@ "unitTypes": ["Fighter"] } */ + + { + "name": "Air Targeting I", + "prerequisites": ["Interception I","Dogfighting I", "Siege I","Bombardment I"], + "effect": "+[33]% Strength vs [water units]", + "unitTypes": ["Fighter","Bomber"] + }, + { + "name": "Air Targeting II", + "prerequisites": ["Air Targeting I"], + "effect": "+[33]% Strength vs [water units]", + "unitTypes": ["Fighter","Bomber"] + }, { "name": "Sortie", "prerequisites": ["Interception II", "Dogfighting II"], - "effect": "1 extra Interception may be made per turn", + "effect": "[1] extra interceptions may be made per turn", "unitTypes": ["Fighter"] }, @@ -370,13 +409,13 @@ // Mixed { "name": "Cover I", - "effect": "+25% Defence against ranged attacks", + "effect": "[+33]% Strength when defending vs [Ranged]", "unitTypes": ["Melee","Ranged","Siege"] }, { "name": "Cover II", "prerequisites": ["Cover I"], - "effect": "+25% Defence against ranged attacks", + "effect": "[+33]% Strength when defending vs [Ranged]", "unitTypes": ["Melee","Ranged","Siege"] }, @@ -403,19 +442,19 @@ "name": "Logistics", "prerequisites": ["Accuracy III","Barrage III","Targeting III", "Wolfpack III", "Bombardment III", "Coastal Raider III","Boarding Party III","Siege III"], - "effect": "1 additional attack per turn", + "effect": "[1] additional attack per turn", "unitTypes": ["Ranged","Siege","WaterMelee","WaterRanged","WaterSubmarine","Fighter","Bomber"] }, { "name": "Ambush I", - "effect": "+[25]% Strength vs [Armor]", + "effect": "+[33]% Strength vs [Armor]", "unitTypes": ["Melee","Fighter","Bomber"] }, { "name": "Ambush II", "prerequisites": ["Ambush I"], - "effect": "+[25]% Strength vs [Armor]", + "effect": "+[33]% Strength vs [Armor]", "unitTypes": ["Melee","Fighter","Bomber"] }, @@ -439,31 +478,6 @@ "unitTypes": ["WaterRanged","Fighter","Bomber"] }, - // Targeting I has different requirements for air and waterranged units, this was the cleanest way to do so - { - "name": "Targeting I", - "effect": "+[15]% Strength vs [water units]", - "unitTypes": ["WaterRanged"] - }, - { - "name": "Targeting I (air)", - "prerequisites": ["Interception I","Dogfighting I", "Siege I","Bombardment I"], - "effect": "+[15]% Strength vs [water units]", - "unitTypes": ["Fighter","Bomber"] - }, - { - "name": "Targeting II", - "prerequisites": ["Targeting I","Targeting I (air)"], - "effect": "+[15]% Strength vs [water units]", - "unitTypes": ["WaterRanged","Fighter","Bomber"] - }, - { - "name": "Targeting III", - "prerequisites": ["Targeting II"], - "effect": "+[15]% Strength vs [water units]", - "unitTypes": ["WaterRanged"] - }, - // Uniques { "name": "Morale", // Heroic Epic @@ -483,7 +497,7 @@ }, { "name": "Haka War Dance", // only for Maori Warrior and subsequent upgrades - "effect": "-10% combat strength for adjacent enemy units" + "effect": "[-10]% Strength for enemy [Military] units in adjacent [All] tiles" }, { "name": "Rejuvenation", // only for Units that have been close to Natural Wonder Fountain of Youth diff --git a/core/src/com/unciv/logic/battle/BattleDamage.kt b/core/src/com/unciv/logic/battle/BattleDamage.kt index ebbeec4c6c..2f06384f82 100644 --- a/core/src/com/unciv/logic/battle/BattleDamage.kt +++ b/core/src/com/unciv/logic/battle/BattleDamage.kt @@ -51,17 +51,19 @@ object BattleDamage { } } - var adjacentUnitBonus = 0 + val adjacentUnits = combatant.getTile().neighbors.flatMap { it.getUnits() } + for (unique in civInfo.getMatchingUniques("+[]% Strength for [] units which have another [] unit in an adjacent tile")) { if (combatant.matchesCategory(unique.params[1]) - && combatant.getTile().neighbors.flatMap { it.getUnits() } - .any { it.civInfo == civInfo && it.matchesFilter(unique.params[2]) } + && adjacentUnits.any { it.civInfo == civInfo && it.matchesFilter(unique.params[2]) } ) { - adjacentUnitBonus += unique.params[0].toInt() + modifiers.add("Adjacent units", unique.params[0].toInt()) } } - if (adjacentUnitBonus != 0) - modifiers["Adjacent unit"] = adjacentUnitBonus + + for (unique in adjacentUnits.flatMap { it.getMatchingUniques("[]% Strength for enemy [] units in adjacent [] tiles") }) + if (combatant.matchesCategory(unique.params[1]) && combatant.getTile().matchesFilter(unique.params[2])) + modifiers.add("Adjacent enemy units", unique.params[0].toInt()) val civResources = civInfo.getCivResourcesByName() for (resource in combatant.unit.baseUnit.getResourceRequirements().keys) @@ -191,11 +193,18 @@ object BattleDamage { ) modifiers["Tile"] = (tileDefenceBonus * 100).toInt() - if (attacker.isRanged()) { - val defenceVsRanged = 25 * defender.unit.getUniques() - .count { it.text == "+25% Defence against ranged attacks" } - if (defenceVsRanged > 0) modifiers["defence vs ranged"] = defenceVsRanged + for (unique in defender.unit.getMatchingUniques("[]% Strength when defending vs []")) { + if (attacker.matchesCategory(unique.params[1])) + modifiers.add("defence vs [${unique.params[1]}] ", unique.params[0].toInt()) } + + // Deprecated since 3.15.7 + if (attacker.isRanged()) { + val defenceVsRanged = 25 * defender.unit.getUniques() + .count { it.text == "+25% Defence against ranged attacks" } + if (defenceVsRanged > 0) modifiers.add("defence vs ranged", defenceVsRanged) + } + // for (unique in defender.unit.getMatchingUniques("+[]% Strength when defending")) { modifiers.add("Defender Bonus", unique.params[0].toInt()) @@ -203,7 +212,7 @@ object BattleDamage { for (unique in defender.unit.getMatchingUniques("+[]% defence in [] tiles")) { if (tile.matchesFilter(unique.params[1])) - modifiers["[${unique.params[1]}] defence"] = unique.params[0].toInt() + modifiers.add("[${unique.params[1]}] defence", unique.params[0].toInt()) } if (defender.unit.isFortified()) @@ -244,17 +253,16 @@ object BattleDamage { ) modifiers[unique.params[2]] = unique.params[0].toInt() } - - if (tile.neighbors.flatMap { it.getUnits() } - .any { - it.hasUnique("-10% combat strength for adjacent enemy units") && it.civInfo.isAtWarWith( - unit.getCivInfo() - ) - }) - modifiers["Haka War Dance"] = -10 - - - + + // Deprecated since 3.15.7 + if (tile.neighbors.flatMap { it.getUnits() } + .any { + it.hasUnique("-10% combat strength for adjacent enemy units") && it.civInfo.isAtWarWith( + unit.getCivInfo() + ) + }) + modifiers["Haka War Dance"] = -10 + // return modifiers } diff --git a/core/src/com/unciv/logic/map/MapUnit.kt b/core/src/com/unciv/logic/map/MapUnit.kt index 3731a8c8b1..3b79ea5b26 100644 --- a/core/src/com/unciv/logic/map/MapUnit.kt +++ b/core/src/com/unciv/logic/map/MapUnit.kt @@ -518,7 +518,7 @@ class MapUnit { if (civInfo.hasUnique("Can only heal by pillaging")) return var amountToHealBy = rankTileForHealing(getTile()) - if (amountToHealBy == 0) return + if (amountToHealBy == 0 && !(hasUnique("May heal outside of friendly territory") && !getTile().isFriendlyTerritory(civInfo))) return // Deprecated since 3.15.6 if (hasUnique("+10 HP when healing")) amountToHealBy += 10 @@ -551,15 +551,18 @@ class MapUnit { isFriendlyTerritory -> 15 // Allied territory else -> 5 // Enemy territory } + + val mayHeal = healing > 0 || (tileInfo.isWater && hasUnique("May heal outside of friendly territory")) // Deprecated since 3.15.6 if (hasUnique("This unit and all others in adjacent tiles heal 5 additional HP. This unit heals 5 additional HP outside of friendly territory.") && !isFriendlyTerritory - && healing > 0 + && mayHeal )// Additional healing from medic is only applied when the unit is able to heal healing += 5 // - if (healing > 0) { + + if (mayHeal) { for (unique in getMatchingUniques("[] HP when healing in [] tiles")) { if (tileInfo.matchesFilter(unique.params[1])) { healing += unique.params[0].toInt() @@ -833,9 +836,13 @@ class MapUnit { } fun canIntercept(attackedTile: TileInfo): Boolean { - if (attacksThisTurn > 1) return false if (interceptChance() == 0) return false - if (attacksThisTurn > 0 && !hasUnique("1 extra Interception may be made per turn")) return false + val maxAttacksPerTurn = 1 + + getMatchingUniques("[] extra interceptions may be made per turn").sumBy { it.params[0].toInt() } + + // Deprecated since 3.15.7 + getMatchingUniques("1 extra interception may be made per turn").count() + // + if (attacksThisTurn >= maxAttacksPerTurn) return false if (currentTile.aerialDistanceTo(attackedTile) > baseUnit.interceptRange) return false return true } @@ -868,7 +875,8 @@ class MapUnit { } fun interceptDamagePercentBonus(): Int { - return getUniques().filter { it.placeholderText == "Bonus when intercepting []%" } + // "Bonus when intercepting []%" deprecated since 3.15.7 + return getUniques().filter { it.placeholderText == "Bonus when intercepting []%" || it.placeholderText == "[]% Damage when intercepting"} .sumBy { it.params[0].toInt() } }