From b6ce8b2aac63cf0cdca05f3156e6560eb6962fdf Mon Sep 17 00:00:00 2001 From: Xander Lenstra <71121390+xlenstra@users.noreply.github.com> Date: Sun, 5 Dec 2021 11:55:46 +0100 Subject: [PATCH] Fixed a bug where 'requires a [buildingName] in this city' would not work (#5754) --- .../src/com/unciv/logic/city/IConstruction.kt | 2 ++ core/src/com/unciv/models/ruleset/Building.kt | 26 ++++++++++--------- .../ruleset/unique/UniqueParameterType.kt | 10 +++++++ .../unciv/models/ruleset/unique/UniqueType.kt | 5 +++- .../ui/overviewscreen/WonderOverviewTable.kt | 5 ++-- 5 files changed, 32 insertions(+), 16 deletions(-) diff --git a/core/src/com/unciv/logic/city/IConstruction.kt b/core/src/com/unciv/logic/city/IConstruction.kt index 700f673967..b15f7e9bab 100644 --- a/core/src/com/unciv/logic/city/IConstruction.kt +++ b/core/src/com/unciv/logic/city/IConstruction.kt @@ -127,6 +127,8 @@ class RejectionReasons: HashSet() { } +// TODO: Put a wrapper class around this containing the errorMessage, so that we don't +// change the value of a enum constant sometimes. enum class RejectionReason(val shouldShow: Boolean, var errorMessage: String) { AlreadyBuilt(false, "Building already built in this city"), Unbuildable(false, "Unbuildable"), diff --git a/core/src/com/unciv/models/ruleset/Building.kt b/core/src/com/unciv/models/ruleset/Building.kt index 080e582c4a..8781a5a10b 100644 --- a/core/src/com/unciv/models/ruleset/Building.kt +++ b/core/src/com/unciv/models/ruleset/Building.kt @@ -122,13 +122,13 @@ class Building : RulesetStatsObject(), INonPerpetualConstruction { else (name in cityInfo.civInfo.civConstructions.getFreeBuildings(cityInfo.id)) if (uniqueTo != null) lines += if (replaces == null) "Unique to [$uniqueTo]" else "Unique to [$uniqueTo], replaces [$replaces]" - val missingunique = uniqueObjects.firstOrNull{ it.placeholderText == "Requires a [] in all cities" } + val missingUnique = getMatchingUniques(UniqueType.RequiresBuildingInAllCities).firstOrNull() // Inefficient in theory. In practice, buildings seem to have only a small handful of uniques. - val missingcities = if (cityInfo != null && missingunique != null) + val missingCities = if (cityInfo != null && missingUnique != null) // TODO: Unify with rejection reasons? cityInfo.civInfo.cities.filterNot { it.isPuppet - || it.cityConstructions.containsBuildingOrEquivalent(missingunique.params[0]) + || it.cityConstructions.containsBuildingOrEquivalent(missingUnique.params[0]) } else listOf() if (isWonder) lines += "Wonder" @@ -142,8 +142,8 @@ class Building : RulesetStatsObject(), INonPerpetualConstruction { if (uniques.isNotEmpty()) { if (replacementTextForUniques != "") lines += replacementTextForUniques else lines += getUniquesStringsWithoutDisablers( - filterUniques=if (missingcities.isEmpty()) null - else { unique -> unique.placeholderText != "Requires a [] in all cities" } + filterUniques=if (missingCities.isEmpty()) null + else { unique -> !unique.isOfType(UniqueType.RequiresBuildingInAllCities) } // Filter out the "Requires a [] in all cities" unique if any cities are still missing the required building, since in that case the list of cities will be appended at the end. ) } @@ -165,9 +165,11 @@ class Building : RulesetStatsObject(), INonPerpetualConstruction { if (cityStrength != 0) lines += "{City strength} +$cityStrength" if (cityHealth != 0) lines += "{City health} +$cityHealth" if (maintenance != 0 && !isFree) lines += "{Maintenance cost}: $maintenance {Gold}" - if (!missingcities.isEmpty()) { + if (missingCities.isNotEmpty()) { // Could be red. But IMO that should be done by enabling GDX's ColorMarkupLanguage globally instead of adding a separate label. - lines += "\n" + "[${cityInfo?.civInfo?.getEquivalentBuilding(missingunique!!.params[0])}] required:".tr() + " " + missingcities.map{ "{${it.name}}" }.joinToString(", ") + lines += "\n" + + "[${cityInfo?.civInfo?.getEquivalentBuilding(missingUnique!!.params[0])}] required:".tr() + + " " + missingCities.joinToString(", ") { "{${it.name}}" } // Can't nest square bracket placeholders inside curlies, and don't see any way to define wildcard placeholders. So run translation explicitly on base text. } return lines.joinToString("\n") { it.tr() }.trim() @@ -637,8 +639,8 @@ class Building : RulesetStatsObject(), INonPerpetualConstruction { rejectionReasons.add(RejectionReason.ReachedBuildCap) } - for (unique in uniqueObjects) when (unique.placeholderText) { - UniqueType.RequiresAnotherBuilding.text -> { + for (unique in uniqueObjects) when (unique.type) { + UniqueType.RequiresAnotherBuilding -> { val filter = unique.params[0] if (civInfo.gameInfo.ruleSet.buildings.containsKey(filter) && !cityConstructions.containsBuildingOrEquivalent(filter)) rejectionReasons.add( @@ -647,7 +649,7 @@ class Building : RulesetStatsObject(), INonPerpetualConstruction { ) } - "Requires a [] in all cities" -> { + UniqueType.RequiresBuildingInAllCities -> { val filter = unique.params[0] if (civInfo.gameInfo.ruleSet.buildings.containsKey(filter) && civInfo.cities.any { @@ -663,11 +665,11 @@ class Building : RulesetStatsObject(), INonPerpetualConstruction { } } - "Hidden until [] social policy branches have been completed" -> { + UniqueType.HiddenBeforeAmountPolicies -> { if (cityConstructions.cityInfo.civInfo.getCompletedPolicyBranchesCount() < unique.params[0].toInt()) rejectionReasons.add(RejectionReason.MorePolicyBranches.apply { errorMessage = unique.text }) } - "Hidden when [] Victory is disabled" -> { + UniqueType.HiddenWithoutVictoryType -> { if (!civInfo.gameInfo.gameParameters.victoryTypes.contains(VictoryType.valueOf(unique.params[0]))) rejectionReasons.add(RejectionReason.HiddenWithoutVictory.apply { errorMessage = unique.text }) } diff --git a/core/src/com/unciv/models/ruleset/unique/UniqueParameterType.kt b/core/src/com/unciv/models/ruleset/unique/UniqueParameterType.kt index 58834a7b3b..e8f1cc323b 100644 --- a/core/src/com/unciv/models/ruleset/unique/UniqueParameterType.kt +++ b/core/src/com/unciv/models/ruleset/unique/UniqueParameterType.kt @@ -2,6 +2,7 @@ package com.unciv.models.ruleset.unique import com.unciv.models.ruleset.BeliefType import com.unciv.models.ruleset.Ruleset +import com.unciv.models.ruleset.VictoryType import com.unciv.models.ruleset.tile.ResourceType import com.unciv.models.ruleset.tile.TerrainType import com.unciv.models.stats.Stat @@ -254,6 +255,15 @@ enum class UniqueParameterType(val parameterName:String) { } } }, + VictoryT("victoryType") { + override fun getErrorSeverity( + parameterText: String, + ruleset: Ruleset + ): UniqueType.UniqueComplianceErrorSeverity? { + return if (parameterText in VictoryType.values().map { it.name }) null + else UniqueType.UniqueComplianceErrorSeverity.RulesetInvariant + } + }, /** Behaves like [Unknown], but states explicitly the parameter is OK and its contents are ignored */ Comment("comment") { override fun getErrorSeverity(parameterText: String, ruleset: Ruleset): diff --git a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt index 9087cdfccb..6bdf3802c8 100644 --- a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt +++ b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt @@ -186,7 +186,8 @@ enum class UniqueType(val text:String, vararg targets: UniqueTarget, val flags: CanBePurchasedWithStat("Can be purchased with [stat] [cityFilter]", UniqueTarget.Building, UniqueTarget.Unit), CanBePurchasedForAmountStat("Can be purchased for [amount] [stat] [cityFilter]", UniqueTarget.Building, UniqueTarget.Unit), MaxNumberBuildable("Limited to [amount] per Civilization", UniqueTarget.Building, UniqueTarget.Unit), - + HiddenBeforeAmountPolicies("Hidden until [amount] social policy branches have been completed", UniqueTarget.Building, UniqueTarget.Unit), + //endregion @@ -196,6 +197,7 @@ enum class UniqueType(val text:String, vararg targets: UniqueTarget, val flags: CostIncreasesPerCity("Cost increases by [amount] per owned city", UniqueTarget.Building), CannotBeBuiltWith("Cannot be built with [buildingName]", UniqueTarget.Building), RequiresAnotherBuilding("Requires a [buildingName] in this city", UniqueTarget.Building), + RequiresBuildingInAllCities("Requires a [buildingName] in all cities", UniqueTarget.Building), NotDisplayedWithout("Not displayed as an available construction without [buildingName/tech/resource/policy]", UniqueTarget.Building, UniqueTarget.Unit), //UniqueType added in 3.18.4 @@ -444,6 +446,7 @@ enum class UniqueType(val text:String, vararg targets: UniqueTarget, val flags: HiddenAfterPantheon("Hidden after founding a Pantheon", UniqueTarget.Ruins), HiddenAfterGreatProphet("Hidden after generating a Great Prophet", UniqueTarget.Ruins), AvailableAfterCertainTurns("Only available after [amount] turns", UniqueTarget.Ruins), + HiddenWithoutVictoryType("Hidden when [victoryType] Victory is disabled", UniqueTarget.Building, UniqueTarget.Unit), // region DEPRECATED AND REMOVED diff --git a/core/src/com/unciv/ui/overviewscreen/WonderOverviewTable.kt b/core/src/com/unciv/ui/overviewscreen/WonderOverviewTable.kt index e67f03c35c..e61acf836c 100644 --- a/core/src/com/unciv/ui/overviewscreen/WonderOverviewTable.kt +++ b/core/src/com/unciv/ui/overviewscreen/WonderOverviewTable.kt @@ -88,9 +88,8 @@ class WonderOverviewTable( Constants.hideFromCivilopediaUnique in wonder.uniques -> false wonder.hasUnique(UniqueType.HiddenWithoutReligion) && hideReligionItems -> false wonder.name in startingObsolete -> false - wonder.uniqueObjects.filter { unique -> - unique.placeholderText == "Hidden when [] Victory is disabled" - }.any { unique -> + wonder.getMatchingUniques(UniqueType.HiddenWithoutVictoryType) + .any { unique -> !gameInfo.gameParameters.victoryTypes.contains(VictoryType.valueOf(unique.params[0])) } -> false else -> wonderEra <= viewerEra