From 4e5ec53d64df18aadb999777196e25f4fdfd063b Mon Sep 17 00:00:00 2001 From: Yair Morgenstern Date: Wed, 19 Jun 2024 17:28:53 +0300 Subject: [PATCH] Resolves #11772 - Allow hidden conditionals (#11778) * Allow hidden conditionals * SomeTrog fixes * We sure display uniques to users A LOT --- .../src/com/unciv/logic/map/tile/TileStatFunctions.kt | 4 ++-- core/src/com/unciv/models/ruleset/unique/Unique.kt | 3 +++ core/src/com/unciv/models/ruleset/unit/BaseUnit.kt | 6 +++--- .../ui/objectdescriptions/BaseUnitDescriptions.kt | 9 ++++----- .../ui/objectdescriptions/BuildingDescriptions.kt | 2 +- .../unciv/ui/objectdescriptions/DescriptionHelpers.kt | 11 +++++++---- .../ui/objectdescriptions/ImprovementDescriptions.kt | 4 ++-- .../ui/screens/civilopediascreen/FormattedLine.kt | 2 +- .../diplomacyscreen/CityStateDiplomacyTable.kt | 2 +- .../pickerscreens/ReligionPickerScreenCommon.kt | 2 +- .../ui/screens/pickerscreens/TechPickerScreen.kt | 2 +- 11 files changed, 26 insertions(+), 21 deletions(-) diff --git a/core/src/com/unciv/logic/map/tile/TileStatFunctions.kt b/core/src/com/unciv/logic/map/tile/TileStatFunctions.kt index 55db991633..6dd5e3b67f 100644 --- a/core/src/com/unciv/logic/map/tile/TileStatFunctions.kt +++ b/core/src/com/unciv/logic/map/tile/TileStatFunctions.kt @@ -77,7 +77,7 @@ class TileStatFunctions(val tile: Tile) { for (unique in statsFromTilesUniques + statsFromObjectsUniques + statsFromTilesWithoutUniques) { val tileType = unique.params[1] if (tile.matchesFilter(tileType, observingCiv, true)) - listOfStats.add("{${unique.sourceObjectName}} ({${unique.text}})" to unique.stats) + listOfStats.add("{${unique.sourceObjectName}} ({${unique.getDisplayText()}})" to unique.stats) else if (improvement != null && improvement.matchesFilter(tileType)) improvementStats.add(unique.stats) else if (road != null && road.matchesFilter(tileType)) @@ -147,7 +147,7 @@ class TileStatFunctions(val tile: Tile) { val list = arrayListOf(terrain.name to (terrain as Stats)) for (unique in terrain.getMatchingUniques(UniqueType.Stats, stateForConditionals)) { - list.add(terrain.name+": "+unique.text to unique.stats) + list.add(terrain.name+": "+unique.getDisplayText() to unique.stats) } return list } diff --git a/core/src/com/unciv/models/ruleset/unique/Unique.kt b/core/src/com/unciv/models/ruleset/unique/Unique.kt index 95936ac05b..41d267f651 100644 --- a/core/src/com/unciv/models/ruleset/unique/Unique.kt +++ b/core/src/com/unciv/models/ruleset/unique/Unique.kt @@ -11,6 +11,7 @@ import com.unciv.models.stats.Stats import com.unciv.models.translations.getConditionals import com.unciv.models.translations.getPlaceholderParameters import com.unciv.models.translations.getPlaceholderText +import com.unciv.models.translations.removeConditionals class Unique(val text: String, val sourceObjectType: UniqueTarget? = null, val sourceObjectName: String? = null) { @@ -177,6 +178,8 @@ class Unique(val text: String, val sourceObjectType: UniqueTarget? = null, val s override fun toString() = if (type == null) "\"$text\"" else "$type (\"$text\")" + fun getDisplayText(): String = if (conditionals.none { it.isHiddenToUsers() }) text + else text.removeConditionals() + " " + conditionals.filter { !it.isHiddenToUsers() }.joinToString(" ") { "<${it.text}>" } } /** Used to cache results of getMatchingUniques diff --git a/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt b/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt index 6275aae3b4..a3e3bfcffb 100644 --- a/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt +++ b/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt @@ -188,7 +188,7 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction { for (unique in getMatchingUniques(UniqueType.RequiresPopulation)) if (unique.params[0].toInt() > cityConstructions.city.population.population) - yield(RejectionReasonType.PopulationRequirement.toInstance(unique.text)) + yield(RejectionReasonType.PopulationRequirement.toInstance(unique.getDisplayText())) yieldAll(getRejectionReasons(civInfo, cityConstructions.city)) @@ -252,7 +252,7 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction { it.type == UniqueType.ConditionalBelowHappiness || it.type == UniqueType.ConditionalBetweenHappiness } if (hasHappinessCondition) - yield(RejectionReasonType.CannotBeBuiltUnhappiness.toInstance(unique.text)) + yield(RejectionReasonType.CannotBeBuiltUnhappiness.toInstance(unique.getDisplayText())) else yield(RejectionReasonType.CannotBeBuilt.toInstance()) } } @@ -295,7 +295,7 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction { } else -> { if (built) - yield(RejectionReasonType.CanOnlyBeBuiltInSpecificCities.toInstance(unique.text)) + yield(RejectionReasonType.CanOnlyBeBuiltInSpecificCities.toInstance(unique.getDisplayText())) else yield(RejectionReasonType.ShouldNotBeDisplayed.toInstance()) } diff --git a/core/src/com/unciv/ui/objectdescriptions/BaseUnitDescriptions.kt b/core/src/com/unciv/ui/objectdescriptions/BaseUnitDescriptions.kt index 125dcb52fa..d280071fe1 100644 --- a/core/src/com/unciv/ui/objectdescriptions/BaseUnitDescriptions.kt +++ b/core/src/com/unciv/ui/objectdescriptions/BaseUnitDescriptions.kt @@ -293,11 +293,10 @@ object BaseUnitDescriptions { // Need double translation of the "ability" here - unique texts may contain nuts - pardon, square brackets yield("Lost ability (vs [${originalUnit.name}]): [${unique.text.tr()}]" to null) } - for (promotion in betterUnit.promotions.filter { it !in originalUnit.promotions }) { - // Needs tr for **individual** translations (no bracket nesting), default separator would have extra blank - val effects = ruleset.unitPromotions[promotion]!!.uniques - .joinToString() { it.tr() } - yield("{$promotion} ($effects)" to "Promotion/$promotion") + for (promotionName in betterUnit.promotions.filter { it !in originalUnit.promotions }) { + val promotion = ruleset.unitPromotions[promotionName]!! + val effects = promotion.uniquesToDescription().joinToString() + yield("{$promotionName} ($effects)" to promotion.makeLink()) } } diff --git a/core/src/com/unciv/ui/objectdescriptions/BuildingDescriptions.kt b/core/src/com/unciv/ui/objectdescriptions/BuildingDescriptions.kt index 0d7dff97ba..60e63cb7e3 100644 --- a/core/src/com/unciv/ui/objectdescriptions/BuildingDescriptions.kt +++ b/core/src/com/unciv/ui/objectdescriptions/BuildingDescriptions.kt @@ -143,7 +143,7 @@ object BuildingDescriptions { } else { val newAbilityPredicate: (Unique)->Boolean = { it.text in originalBuilding.uniques || it.isHiddenToUsers() } for (unique in replacementBuilding.uniqueObjects.filterNot(newAbilityPredicate)) - yield(FormattedLine(unique.text, indent=1)) // FormattedLine(unique) would look worse - no indent and autolinking could distract + yield(FormattedLine(unique.getDisplayText(), indent=1)) // FormattedLine(unique) would look worse - no indent and autolinking could distract } val lostAbilityPredicate: (Unique)->Boolean = { it.text in replacementBuilding.uniques || it.isHiddenToUsers() } diff --git a/core/src/com/unciv/ui/objectdescriptions/DescriptionHelpers.kt b/core/src/com/unciv/ui/objectdescriptions/DescriptionHelpers.kt index 5ff3f27315..53faf1cfc1 100644 --- a/core/src/com/unciv/ui/objectdescriptions/DescriptionHelpers.kt +++ b/core/src/com/unciv/ui/objectdescriptions/DescriptionHelpers.kt @@ -10,17 +10,20 @@ import com.unciv.ui.screens.civilopediascreen.FormattedLine * Appends user-visible Uniques as translated text to a [line collection][lineList]. * * Follows json order. + * @param lineList Target collection, will be mutated. Defaults to an empty List for easier use with consumer-only client code. * @param exclude Predicate that can exclude Uniques by returning `true` (defaults to return `false`). + * @return the [lineList] with added, translated info on [this.uniques] - for chaining */ fun IHasUniques.uniquesToDescription( - lineList: MutableCollection, + lineList: MutableCollection = mutableListOf(), exclude: Unique.() -> Boolean = {false} -): Unit { +): MutableCollection { for (unique in uniqueObjects) { if (unique.isHiddenToUsers()) continue if (unique.exclude()) continue - lineList += unique.text.tr() + lineList += unique.getDisplayText().tr() } + return lineList } /** @@ -48,7 +51,7 @@ fun IHasUniques.uniquesToCivilopediaTextLines( // (the other constructor guesses the first object by name in the Unique parameters). yield( if (colorConsumesResources && unique.type == UniqueType.ConsumesResources) - FormattedLine(unique.text, link = "Resources/${unique.params[1]}", color = "#F42") + FormattedLine(unique.getDisplayText(), link = "Resources/${unique.params[1]}", color = "#F42") else FormattedLine(unique) ) } diff --git a/core/src/com/unciv/ui/objectdescriptions/ImprovementDescriptions.kt b/core/src/com/unciv/ui/objectdescriptions/ImprovementDescriptions.kt index 6a5ef0b958..06233ae3d2 100644 --- a/core/src/com/unciv/ui/objectdescriptions/ImprovementDescriptions.kt +++ b/core/src/com/unciv/ui/objectdescriptions/ImprovementDescriptions.kt @@ -37,12 +37,12 @@ object ImprovementDescriptions { val newAbilityPredicate: (Unique)->Boolean = { it.text in originalImprovement.uniques || it.isHiddenToUsers() } for (unique in replacementImprovement.uniqueObjects.filterNot(newAbilityPredicate)) - yield(FormattedLine(unique.text, indent=1)) // FormattedLine(unique) would look worse - no indent and auto-linking could distract + yield(FormattedLine(unique.getDisplayText(), indent=1)) // FormattedLine(unique) would look worse - no indent and auto-linking could distract val lostAbilityPredicate: (Unique)->Boolean = { it.text in replacementImprovement.uniques || it.isHiddenToUsers() } for (unique in originalImprovement.uniqueObjects.filterNot(lostAbilityPredicate)) { // Need double translation of the "ability" here - unique texts may contain square brackets - yield(FormattedLine("Lost ability (vs [${originalImprovement.name}]): [${unique.text.tr()}]", indent=1)) + yield(FormattedLine("Lost ability (vs [${originalImprovement.name}]): [${unique.getDisplayText().tr()}]", indent=1)) } } diff --git a/core/src/com/unciv/ui/screens/civilopediascreen/FormattedLine.kt b/core/src/com/unciv/ui/screens/civilopediascreen/FormattedLine.kt index 9852d503b6..6984a7a6c1 100644 --- a/core/src/com/unciv/ui/screens/civilopediascreen/FormattedLine.kt +++ b/core/src/com/unciv/ui/screens/civilopediascreen/FormattedLine.kt @@ -84,7 +84,7 @@ class FormattedLine ( // have no backing field, be `by lazy` or use @Transient, Thank you. /** Looks for linkable ruleset objects in [Unique] parameters and returns a linked [FormattedLine] if successful, a plain one otherwise */ - constructor(unique: Unique, indent: Int = 0) : this(unique.text, getUniqueLink(unique), indent = indent) + constructor(unique: Unique, indent: Int = 0) : this(unique.getDisplayText(), getUniqueLink(unique), indent = indent) /** Link types that can be used for [FormattedLine.link] */ enum class LinkType { diff --git a/core/src/com/unciv/ui/screens/diplomacyscreen/CityStateDiplomacyTable.kt b/core/src/com/unciv/ui/screens/diplomacyscreen/CityStateDiplomacyTable.kt index f171afa29e..6c5823226f 100644 --- a/core/src/com/unciv/ui/screens/diplomacyscreen/CityStateDiplomacyTable.kt +++ b/core/src/com/unciv/ui/screens/diplomacyscreen/CityStateDiplomacyTable.kt @@ -179,7 +179,7 @@ class CityStateDiplomacyTable(private val diplomacyScreen: DiplomacyScreen) { .getCityStateBonuses(otherCiv.cityStateType, level) .filterNot { it.isHiddenToUsers() } if (bonuses.none()) return "" - return (sequenceOf(header) + bonuses.map { it.text }).joinToString(separator = "\n") { it.tr() } + return (sequenceOf(header) + bonuses.map { it.getDisplayText() }).joinToString(separator = "\n") { it.tr() } } fun addBonusLabel(header: String, bonusLevel: RelationshipLevel, relationLevel: RelationshipLevel) { val bonusLabelColor = if (relationLevel == bonusLevel) Color.GREEN else Color.GRAY diff --git a/core/src/com/unciv/ui/screens/pickerscreens/ReligionPickerScreenCommon.kt b/core/src/com/unciv/ui/screens/pickerscreens/ReligionPickerScreenCommon.kt index 362b129b03..276eb33730 100644 --- a/core/src/com/unciv/ui/screens/pickerscreens/ReligionPickerScreenCommon.kt +++ b/core/src/com/unciv/ui/screens/pickerscreens/ReligionPickerScreenCommon.kt @@ -84,7 +84,7 @@ abstract class ReligionPickerScreenCommon( add(belief.type.name.toLabel(fontColor = Color.valueOf(belief.type.color))).row() val nameLabel = WrappableLabel(belief.name, labelWidth, fontSize = Constants.headingFontSize) add(nameLabel.apply { wrap = true }).row() - val effectLabel = WrappableLabel(belief.uniqueObjects.filter { !it.isHiddenToUsers() }.map { it.text } + val effectLabel = WrappableLabel(belief.uniqueObjects.filter { !it.isHiddenToUsers() }.map { it.getDisplayText() } .joinToString("\n") { it.tr() }, labelWidth) add(effectLabel.apply { wrap = true }) } diff --git a/core/src/com/unciv/ui/screens/pickerscreens/TechPickerScreen.kt b/core/src/com/unciv/ui/screens/pickerscreens/TechPickerScreen.kt index c1dd78ca86..7e2478abf7 100644 --- a/core/src/com/unciv/ui/screens/pickerscreens/TechPickerScreen.kt +++ b/core/src/com/unciv/ui/screens/pickerscreens/TechPickerScreen.kt @@ -410,7 +410,7 @@ class TechPickerScreen( for (requiredTech in pathToTech) { for (unique in requiredTech.uniqueObjects .filter { it.type == UniqueType.OnlyAvailable && !it.conditionalsApply(civInfo) }) { - rightSideButton.setText(unique.text.tr()) + rightSideButton.setText(unique.getDisplayText().tr()) rightSideButton.disable() return }