diff --git a/android/assets/jsons/Civ V - Vanilla/UnitPromotions.json b/android/assets/jsons/Civ V - Vanilla/UnitPromotions.json index 201498ddd9..333eb70e32 100644 --- a/android/assets/jsons/Civ V - Vanilla/UnitPromotions.json +++ b/android/assets/jsons/Civ V - Vanilla/UnitPromotions.json @@ -9,130 +9,130 @@ // Ranged+Siege { "name": "Accuracy I", - "effect": "+[15]% Strength in [Open terrain]", + "uniques": ["+[15]% Strength in [Open terrain]"], "unitTypes": ["Siege","Ranged"] }, { "name": "Accuracy II", "prerequisites": ["Accuracy I"], - "effect": "+[15]% Strength in [Open terrain]", + "uniques": ["+[15]% Strength in [Open terrain]"], "unitTypes": ["Siege","Ranged"] }, { "name": "Accuracy III", "prerequisites": ["Accuracy II"], - "effect": "+[15]% Strength in [Open terrain]", + "uniques": ["+[15]% Strength in [Open terrain]"], "unitTypes": ["Siege","Ranged"] }, { "name": "Barrage I", - "effect": "+[15]% Strength in [Rough terrain]", + "uniques": ["+[15]% Strength in [Rough terrain]"], "unitTypes": ["Siege","Ranged"] }, { "name": "Barrage II", "prerequisites": ["Barrage I"], - "effect": "+[15]% Strength in [Rough terrain]", + "uniques": ["+[15]% Strength in [Rough terrain]"], "unitTypes": ["Siege","Ranged"] }, { "name": "Barrage III", "prerequisites": ["Barrage II"], - "effect": "+[15]% Strength in [Rough terrain]", + "uniques": ["+[15]% Strength in [Rough terrain]"], "unitTypes": ["Siege","Ranged"] }, { "name": "Volley", "prerequisites": ["Accuracy I","Barrage I"], - "effect": "+[50]% Strength vs [City]", + "uniques": ["+[50]% Strength vs [City]"], "unitTypes": ["Ranged","Siege"] }, { "name": "Extended Range", "prerequisites": ["Accuracy III","Barrage III","Targeting II","Bombardment II", "Wolfpack II"], - "effect": "[+1] Range", + "uniques": ["[+1] Range"], "unitTypes": ["Ranged","Siege","WaterRanged","WaterSubmarine"] }, { "name": "Indirect Fire", "prerequisites": ["Accuracy III", "Barrage III", "Bombardment II", "Targeting II"], - "effect": "Ranged attacks may be performed over obstacles", + "uniques": ["Ranged attacks may be performed over obstacles"], "unitTypes": ["Ranged","Siege","WaterRanged"] }, // Melee, Mounted+Armor { "name": "Shock I", - "effect": "+[15]% Strength in [Open terrain]", + "uniques": ["+[15]% Strength in [Open terrain]"], "unitTypes": ["Melee","Mounted","Armor"] }, { "name": "Shock II", "prerequisites": ["Shock I"], - "effect": "+[15]% Strength in [Open terrain]", + "uniques": ["+[15]% Strength in [Open terrain]"], "unitTypes": ["Melee","Mounted","Armor"] }, { "name": "Shock III", "prerequisites": ["Shock II"], - "effect": "+[15]% Strength in [Open terrain]", + "uniques": ["+[15]% Strength in [Open terrain]"], "unitTypes": ["Melee","Mounted","Armor"] }, { "name": "Drill I", - "effect": "+[15]% Strength in [Rough terrain]", + "uniques": ["+[15]% Strength in [Rough terrain]"], "unitTypes": ["Melee","Mounted","Armor"] }, { "name": "Drill II", "prerequisites": ["Drill I"], - "effect": "+[15]% Strength in [Rough terrain]", + "uniques": ["+[15]% Strength in [Rough terrain]"], "unitTypes": ["Melee","Mounted","Armor"] }, { "name": "Drill III", "prerequisites": ["Drill II"], - "effect": "+[15]% Strength in [Rough terrain]", + "uniques": ["+[15]% Strength in [Rough terrain]"], "unitTypes": ["Melee","Mounted","Armor"] }, { "name": "Charge", "prerequisites": ["Shock II","Drill II"], - "effect": "+[33]% Strength vs [wounded units]", + "uniques": ["+[33]% Strength vs [wounded units]"], "unitTypes": ["Mounted","Armor"] }, { "name": "Besiege", // Not called "Siege" in order to not conflict with siege type units for translations "prerequisites": ["Shock II","Drill II"], - "effect": "+[50]% Strength vs [City]", + "uniques": ["+[50]% Strength vs [City]"], "unitTypes": ["Melee"] }, { "name": "Formation I", "prerequisites": ["Shock II","Drill II"], // G&K also has Accuracy II & Barrage II as possible prerequisites for this, but I couldn't find a source for the unittypes - "effect": "+[33]% Strength vs [Mounted]", + "uniques": ["+[33]% Strength vs [Mounted]"], "unitTypes": ["Melee","Mounted"] }, { "name": "Formation II", "prerequisites": ["Formation I"], - "effect": "+[33]% Strength vs [Mounted]", + "uniques": ["+[33]% Strength vs [Mounted]"], "unitTypes": ["Melee","Mounted"] }, { "name": "Blitz", "prerequisites": ["Shock III","Drill III"], - "effect": "[1] additional attacks per turn", + "uniques": ["[1] additional attacks per turn"], "unitTypes": ["Melee","Mounted","Armor"] }, { "name": "Woodsman", "prerequisites": ["Shock III","Drill III"], - "effect": "Double movement rate through Forest and Jungle", + "uniques": ["Double movement rate through Forest and Jungle"], // This could be generalized: ["-[50]% movement costs through [Forest] tiles", "-[50]% movement costs through [Jungle] tiles"], // but with how getMovementCostBetweenAdjacentTiles() is optimized, that's difficult to implement. "unitTypes": ["Melee"] @@ -159,19 +159,19 @@ // Scout { "name": "Scouting I", - "effect": "[+1] Visibility Range", + "uniques": ["[+1] Visibility Range"], "unitTypes": ["Scout"] }, { "name": "Scouting II", "prerequisites": ["Scouting I"], - "effect": "[+1] Visibility Range", + "uniques": ["[+1] Visibility Range"], "unitTypes": ["Scout"] }, { "name": "Scouting III", "prerequisites": ["Scouting II"], - "effect": "[+1] Movement", + "uniques": ["[+1] Movement"], "unitTypes": ["Scout"] }, { @@ -196,19 +196,19 @@ // Water melee { "name": "Boarding Party I", - "effect": "+[15]% Strength vs [water units]", + "uniques": ["+[15]% Strength vs [water units]"], "unitTypes": ["WaterMelee"] }, { "name": "Boarding Party II", "prerequisites": ["Boarding Party I"], - "effect": "+[15]% Strength vs [water units]", + "uniques": ["+[15]% Strength vs [water units]"], "unitTypes": ["WaterMelee"] }, { "name": "Boarding Party III", "prerequisites": ["Boarding Party II"], - "effect": "+[15]% Strength vs [water units]", + "uniques": ["+[15]% Strength vs [water units]"], "unitTypes": ["WaterMelee"] }, @@ -233,74 +233,74 @@ // Water Ranged { "name": "Targeting I", - "effect": "+[15]% Strength vs [water units]", + "uniques": ["+[15]% Strength vs [water units]"], "unitTypes": ["WaterRanged"] }, { "name": "Targeting II", "prerequisites": ["Targeting I"], - "effect": "+[15]% Strength vs [water units]", + "uniques": ["+[15]% Strength vs [water units]"], "unitTypes": ["WaterRanged"] }, { "name": "Targeting III", "prerequisites": ["Targeting II"], - "effect": "+[15]% Strength vs [water units]", + "uniques": ["+[15]% Strength vs [water units]"], "unitTypes": ["WaterRanged"] }, // Submarine { "name": "Wolfpack I", - "effect": "+[25]% Strength when attacking", + "uniques": ["+[25]% Strength when attacking"], "unitTypes": ["WaterSubmarine"] }, { "name": "Wolfpack II", "prerequisites": ["Wolfpack I"], - "effect": "+[25]% Strength when attacking", + "uniques": ["+[25]% Strength when attacking"], "unitTypes": ["WaterSubmarine"] }, { "name": "Wolfpack III", "prerequisites": ["Wolfpack II"], - "effect": "+[25]% Strength when attacking", + "uniques": ["+[25]% Strength when attacking"], "unitTypes": ["WaterSubmarine"] }, // Aircraft Carrier { "name": "Armor Plating I", - "effect": "+[25]% Strength when defending", + "uniques": ["+[25]% Strength when defending"], "unitTypes": ["WaterAircraftCarrier"] }, { "name": "Armor Plating II", "prerequisites": ["Armor Plating I"], - "effect": "+[25]% Strength when defending", + "uniques": ["+[25]% Strength when defending"], "unitTypes": ["WaterAircraftCarrier"] }, { "name": "Armor Plating III", "prerequisites": ["Armor Plating II"], - "effect": "+[25]% Strength when defending", + "uniques": ["+[25]% Strength when defending"], "unitTypes": ["WaterAircraftCarrier"] }, { "name": "Flight Deck I", - "effect": "Can carry [1] extra [Air] units", + "uniques": ["Can carry [1] extra [Air] units"], "unitTypes": ["WaterAircraftCarrier"] }, { "name": "Flight Deck II", "prerequisites": ["Flight Deck I"], - "effect": "Can carry [1] extra [Air] units", + "uniques": ["Can carry [1] extra [Air] units"], "unitTypes": ["WaterAircraftCarrier"] }, { "name": "Flight Deck III", "prerequisites": ["Flight Deck II"], - "effect": "Can carry [1] extra [Air] units", + "uniques": ["Can carry [1] extra [Air] units"], "unitTypes": ["WaterAircraftCarrier"] }, @@ -315,62 +315,62 @@ // Bomber { "name": "Siege I", - "effect": "+[33]% Strength vs [City]", + "uniques": ["+[33]% Strength vs [City]"], "unitTypes": ["Bomber"] }, { "name": "Siege II", "prerequisites": ["Siege I"], - "effect": "+[33]% Strength vs [City]", + "uniques": ["+[33]% Strength vs [City]"], "unitTypes": ["Bomber"] }, { "name": "Siege III", "prerequisites": ["Siege II"], - "effect": "+[34]% Strength vs [City]", + "uniques": ["+[34]% Strength vs [City]"], "unitTypes": ["Bomber"] }, { "name": "Evasion", "prerequisites": ["Siege II", "Bombardment II"], - "effect": "Damage taken from interception reduced by [50]%", + "uniques": ["Damage taken from interception reduced by [50]%"], "unitTypes": ["Bomber"] }, // Fighter { "name": "Interception I", - "effect": "[+33]% Damage when intercepting", + "uniques": ["[+33]% Damage when intercepting"], "unitTypes": ["Fighter"] }, { "name": "Interception II", "prerequisites": ["Interception I"], - "effect": "[+33]% Damage when intercepting", + "uniques": ["[+33]% Damage when intercepting"], "unitTypes": ["Fighter"] }, { "name": "Interception III", "prerequisites": ["Interception II"], - "effect": "[+34]% Damage when intercepting", + "uniques": ["[+34]% Damage when intercepting"], "unitTypes": ["Fighter"] }, /* { "name": "Dogfighting I", - "effect": "Bonus when performing air sweep [33]%", // todo + "uniques": ["Bonus when performing air sweep [33]%"], // todo "unitTypes": ["Fighter"] }, { "name": "Dogfighting II", "prerequisites": ["Dogfighting I"], - "effect": "Bonus when performing air sweep [33]%", + "uniques": ["Bonus when performing air sweep [33]%"], "unitTypes": ["Fighter"] }, { "name": "Dogfighting III", "prerequisites": ["Dogfighting II"], - "effect": "Bonus when performing air sweep [34]%", + "uniques": ["Bonus when performing air sweep [34]%"], "unitTypes": ["Fighter"] } */ @@ -378,33 +378,33 @@ { "name": "Air Targeting I", "prerequisites": ["Interception I","Dogfighting I", "Siege I","Bombardment I"], - "effect": "+[33]% Strength vs [water units]", + "uniques": ["+[33]% Strength vs [water units]"], "unitTypes": ["Fighter","Bomber"] }, { "name": "Air Targeting II", "prerequisites": ["Air Targeting I"], - "effect": "+[33]% Strength vs [water units]", + "uniques": ["+[33]% Strength vs [water units]"], "unitTypes": ["Fighter","Bomber"] }, { "name": "Sortie", "prerequisites": ["Interception II", "Dogfighting II"], - "effect": "[1] extra interceptions may be made per turn", + "uniques": ["[1] extra interceptions may be made per turn"], "unitTypes": ["Fighter"] }, { "name": "Operational Range", "prerequisites": ["Interception I", /*"Dogfighting I",*/ "Siege I", "Bombardment I"], - "effect": "[+2] Range", + "uniques": ["[+2] Range"], "unitTypes": ["Fighter","Bomber"] }, { "name": "Air Repair", "prerequisites": ["Interception II", /*"Dogfighting II",*/ "Siege II", "Bombardment II"], - "effect": "Unit will heal every turn, even if it performs an action", + "uniques": ["Unit will heal every turn, even if it performs an action"], "unitTypes": ["Fighter","Bomber"] }, @@ -424,39 +424,39 @@ { "name": "March", "prerequisites": ["Accuracy II","Barrage II","Shock III","Drill III"], - "effect": "Unit will heal every turn, even if it performs an action", + "uniques": ["Unit will heal every turn, even if it performs an action"], "unitTypes": ["Melee","Ranged","Siege","Mounted"] }, { "name": "Mobility", "prerequisites": ["Shock II","Drill II","Targeting I", "Bombardment I","Boarding Party I", "Coastal Raider I", "Wolfpack I"], - "effect": "[+1] Movement", + "uniques": ["[+1] Movement"], "unitTypes": ["Mounted","WaterMelee","WaterRanged","Armor","WaterSubmarine"] }, { "name": "Sentry", "prerequisites": ["Accuracy I","Barrage I","Shock II","Drill II","Bombardment I","Targeting I","Boarding Party I","Coastal Raider I"], - "effect": "[+1] Visibility Range", + "uniques": ["[+1] Visibility Range"], "unitTypes": ["Melee","Mounted","WaterRanged","Armor","WaterMelee"] }, { "name": "Logistics", "prerequisites": ["Accuracy III","Barrage III","Targeting III", "Wolfpack III", "Bombardment III", "Coastal Raider III","Boarding Party III","Siege III"], - "effect": "[1] additional attacks per turn", + "uniques": ["[1] additional attacks per turn"], "unitTypes": ["Ranged","Siege","WaterMelee","WaterRanged","WaterSubmarine","Fighter","Bomber"] }, { "name": "Ambush I", - "effect": "+[33]% Strength vs [Armor]", + "uniques": ["+[33]% Strength vs [Armor]"], "unitTypes": ["Melee","Fighter","Bomber"] }, { "name": "Ambush II", "prerequisites": ["Ambush I"], - "effect": "+[33]% Strength vs [Armor]", + "uniques": ["+[33]% Strength vs [Armor]"], "unitTypes": ["Melee","Fighter","Bomber"] }, @@ -464,49 +464,49 @@ // Water ranged and air units { "name": "Bombardment I", - "effect": "+[33]% Strength vs [land units]", + "uniques": ["+[33]% Strength vs [land units]"], "unitTypes": ["WaterRanged","Fighter","Bomber"] }, { "name": "Bombardment II", "prerequisites": ["Bombardment I"], - "effect": "+[33]% Strength vs [land units]", + "uniques": ["+[33]% Strength vs [land units]"], "unitTypes": ["WaterRanged","Fighter","Bomber"] }, { "name": "Bombardment III", "prerequisites": ["Bombardment II"], - "effect": "+[34]% Strength vs [land units]", + "uniques": ["+[34]% Strength vs [land units]"], "unitTypes": ["WaterRanged","Fighter","Bomber"] }, // Uniques { "name": "Morale", // Heroic Epic - "effect": "+[15]% Combat Strength" + "uniques": ["+[15]% Combat Strength"] }, { "name": "Great Generals I", // only for Companion Cavalry, Keshik and their subsequent upgrades - "effect": "[Great General] is earned [50]% faster" + "uniques": ["[Great General] is earned [50]% faster"] }, { "name": "Great Generals II", // only for Samurai and subsequent upgrades - "effect": "[Great General] is earned [100]% faster" + "uniques": ["[Great General] is earned [100]% faster"] }, { "name": "Quick Study", // only for Keshik and subsequent upgrades - "effect": "[50]% Bonus XP gain" + "uniques": ["[50]% Bonus XP gain"] }, { "name": "Haka War Dance", // only for Maori Warrior and subsequent upgrades - "effect": "[-10]% Strength for enemy [Military] units in adjacent [All] tiles" + "uniques": ["[-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 - "effect": "All healing effects doubled" + "uniques": ["All healing effects doubled"] }, { "name": "Slinger Withdraw", // only for Slinger and subsequent upgrades - "effect": "May withdraw before melee ([80]%)" + "uniques": ["May withdraw before melee ([80]%)"] } ] diff --git a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt index f316c33774..75459ac70f 100644 --- a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt +++ b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt @@ -253,8 +253,8 @@ class CivilizationInfo { city -> city.getMatchingUniquesWithNonLocalEffects(uniqueTemplate) } + policies.policyUniques.getUniques(uniqueTemplate) + - tech.getTechUniques().filter { it.placeholderText == uniqueTemplate } + - temporaryUniques.asSequence().filter { it.first.placeholderText == uniqueTemplate }.map { it.first } + tech.techUniques.getUniques(uniqueTemplate) + + temporaryUniques.filter { it.first.placeholderText == uniqueTemplate }.map { it.first } } //region Units diff --git a/core/src/com/unciv/logic/civilization/PolicyManager.kt b/core/src/com/unciv/logic/civilization/PolicyManager.kt index e6db939ee3..2776acd0c8 100644 --- a/core/src/com/unciv/logic/civilization/PolicyManager.kt +++ b/core/src/com/unciv/logic/civilization/PolicyManager.kt @@ -1,5 +1,6 @@ package com.unciv.logic.civilization +import com.unciv.logic.map.MapSize import com.unciv.models.ruleset.Policy import com.unciv.models.ruleset.UniqueMap import com.unciv.models.ruleset.UniqueTriggerActivation @@ -89,7 +90,15 @@ class PolicyManager { // round down to nearest 5 fun getCultureNeededForNextPolicy(): Int { var policyCultureCost = 25 + (numberOfAdoptedPolicies * 6).toDouble().pow(1.7) - var cityModifier = 0.3f * (civInfo.cities.count { !it.isPuppet } - 1) + // https://civilization.fandom.com/wiki/Map_(Civ5) + val worldSizeModifier = with (civInfo.gameInfo.tileMap.mapParameters.mapSize) { + when { + radius >= MapSize.Huge.radius -> 0.05f + radius >= MapSize.Large.radius -> 0.075f + else -> 0.1f + } + } + var cityModifier = worldSizeModifier * (civInfo.cities.count { !it.isPuppet } - 1) for (unique in civInfo.getMatchingUniques("Each city founded increases culture cost of policies []% less than normal")) cityModifier *= 1 - unique.params[0].toFloat() / 100 @@ -128,9 +137,8 @@ class PolicyManager { if (freePolicies == 0 && storedCulture < getCultureNeededForNextPolicy()) return false - val hasAdoptablePolicies = civInfo.gameInfo.ruleSet.policies.values - .any { civInfo.policies.isAdoptable(it) } - return hasAdoptablePolicies + //Return true if there is a policy to adopt, else return false + return civInfo.gameInfo.ruleSet.policies.values.any { civInfo.policies.isAdoptable(it) } } fun adopt(policy: Policy, branchCompletion: Boolean = false) { @@ -157,11 +165,8 @@ class PolicyManager { } for (unique in policy.uniques) { - if (unique == "Triggers a global alert") { - triggerGlobalAlerts(policy) - } else if (unique.equalsPlaceholderText("Triggers the following global alert: []")) { + if (unique.equalsPlaceholderText("Triggers the following global alert: []")) triggerGlobalAlerts(policy, unique.getPlaceholderParameters()[0]) - } } for (unique in policy.uniqueObjects) @@ -196,7 +201,7 @@ class PolicyManager { } for (city in candidateCities) { val builtBuilding = city.cityConstructions.addCultureBuilding() - if (builtBuilding != null) cultureBuildingsAdded[city.id] = builtBuilding!! + if (builtBuilding != null) cultureBuildingsAdded[city.id] = builtBuilding } } diff --git a/core/src/com/unciv/logic/civilization/TechManager.kt b/core/src/com/unciv/logic/civilization/TechManager.kt index 415e70c15c..666ca30763 100644 --- a/core/src/com/unciv/logic/civilization/TechManager.kt +++ b/core/src/com/unciv/logic/civilization/TechManager.kt @@ -4,7 +4,7 @@ import com.unciv.logic.city.CityInfo import com.unciv.logic.map.MapSize import com.unciv.logic.map.RoadStatus import com.unciv.logic.map.TileInfo -import com.unciv.models.ruleset.Unique +import com.unciv.models.ruleset.UniqueMap import com.unciv.models.ruleset.UniqueTriggerActivation import com.unciv.models.ruleset.tech.Technology import com.unciv.models.ruleset.unit.BaseUnit @@ -23,7 +23,7 @@ class TechManager { @Transient var researchedTechnologies = ArrayList() @Transient - private var researchedTechUniques = ArrayList() + internal var techUniques = UniqueMap() // MapUnit.canPassThrough is the most called function in the game, and having these extremely specific booleans is or way of improving the time cost @Transient @@ -84,11 +84,11 @@ class TechManager { .count { it.isMajorCiv() && !it.isDefeated() } // https://forums.civfanatics.com/threads/the-mechanics-of-overflow-inflation.517970/ techCost /= 1 + techsResearchedKnownCivs / undefeatedCivs.toFloat() * 0.3f - // http://www.civclub.net/bbs/forum.php?mod=viewthread&tid=123976 + // https://civilization.fandom.com/wiki/Map_(Civ5) val worldSizeModifier = with (civInfo.gameInfo.tileMap.mapParameters.mapSize) { when { - radius >= MapSize.Huge.radius -> floatArrayOf(1.3f, 0.02f) - radius >= MapSize.Large.radius -> floatArrayOf(1.2f, 0.03f) + radius >= MapSize.Huge.radius -> floatArrayOf(1.3f, 0.025f) + radius >= MapSize.Large.radius -> floatArrayOf(1.2f, 0.0375f) radius >= MapSize.Medium.radius -> floatArrayOf(1.1f, 0.05f) else -> floatArrayOf(1f, 0.05f) } @@ -128,8 +128,6 @@ class TechManager { return tech.prerequisites.all { isResearched(it) } } - fun getTechUniques() = researchedTechUniques.asSequence() - //endregion fun getRequiredTechsToDestination(destinationTech: Technology): List { @@ -238,8 +236,8 @@ class TechManager { if (!newTech.isContinuallyResearchable()) techsToResearch.remove(techName) researchedTechnologies = researchedTechnologies.withItem(newTech) + addTechToTransients(newTech) for (unique in newTech.uniqueObjects) { - researchedTechUniques = researchedTechUniques.withItem(unique) UniqueTriggerActivation.triggerCivwideUnique(unique, civInfo) } updateTransientBooleans() @@ -312,6 +310,11 @@ class TechManager { } } + fun addTechToTransients(tech: Technology) { + for (unique in tech.uniqueObjects) + techUniques.addUnique(unique) + } + private fun notifyRevealedResources(techName: String) { data class CityTileAndDistance(val city: CityInfo, val tile: TileInfo, val distance: Int) @@ -354,7 +357,7 @@ class TechManager { fun setTransients() { researchedTechnologies.addAll(techsResearched.map { getRuleset().technologies[it]!! }) - researchedTechUniques.addAll(researchedTechnologies.asSequence().flatMap { it.uniqueObjects.asSequence() }) + researchedTechnologies.forEach { addTechToTransients(it) } updateTransientBooleans() } diff --git a/core/src/com/unciv/models/ruleset/Nation.kt b/core/src/com/unciv/models/ruleset/Nation.kt index 17096b4227..42bca3810f 100644 --- a/core/src/com/unciv/models/ruleset/Nation.kt +++ b/core/src/com/unciv/models/ruleset/Nation.kt @@ -172,7 +172,7 @@ class Nation : INamed, ICivilopediaText { for (unique in originalUnit.uniques.filterNot { it in unit.uniques }) textList += " " + "Lost ability".tr() + "(" + "vs [${originalUnit.name}]".tr() + "): " + unique.tr() for (promotion in unit.promotions.filter { it !in originalUnit.promotions }) - textList += " " + promotion.tr() + " (" + ruleset.unitPromotions[promotion]!!.effect.tr() + ")" + textList += " " + promotion.tr() + " (" + ruleset.unitPromotions[promotion]!!.uniquesWithEffect().joinToString(",") { it.tr() } + ")" } else if (unit.replaces != null) { textList += unit.name.tr() + " - " + "Replaces [${unit.replaces}], which is not found in the ruleset!".tr() } else { @@ -305,11 +305,10 @@ class Nation : INamed, ICivilopediaText { textList += FormattedLine("Lost ability".tr() + " (" + "vs [${originalUnit.name}]".tr() + "): " + unique.tr(), indent=1) for (promotion in unit.promotions.filter { it !in originalUnit.promotions }) { - val effect = ruleset.unitPromotions[promotion]!!.effect + val effect = ruleset.unitPromotions[promotion]!!.uniquesWithEffect() // "{$promotion} ({$effect})" won't work as effect may contain [] and tr() does not support that kind of nesting textList += FormattedLine( - if (effect.isEmpty()) promotion - else "${promotion.tr()} (${effect.tr()})", + "${promotion.tr()} (${effect.joinToString(",") { it.tr() }})", link = "Promotion/$promotion", indent = 1 ) } } else if (unit.replaces != null) { diff --git a/core/src/com/unciv/models/ruleset/unit/Promotion.kt b/core/src/com/unciv/models/ruleset/unit/Promotion.kt index f5bf181a6f..22e8530caf 100644 --- a/core/src/com/unciv/models/ruleset/unit/Promotion.kt +++ b/core/src/com/unciv/models/ruleset/unit/Promotion.kt @@ -15,7 +15,7 @@ class Promotion : INamed, ICivilopediaText { var unitTypes = listOf() // The json parser wouldn't agree to deserialize this as a list of UnitTypes. =( var uniques = ArrayList() - private fun uniquesWithEffect() = sequence { + fun uniquesWithEffect() = sequence { if (effect.isNotEmpty()) yield(effect) yieldAll(uniques) }