From 6d5fe2ff7a7311a97b26ef24e59b3214d02e27b4 Mon Sep 17 00:00:00 2001 From: Xander Lenstra <71121390+xlenstra@users.noreply.github.com> Date: Sat, 7 Aug 2021 22:44:53 +0200 Subject: [PATCH] Fixed bug where units could still be purchased if they used a depleted resource (#4798) --- core/src/com/unciv/logic/city/CityConstructions.kt | 11 +++++------ core/src/com/unciv/logic/city/IConstruction.kt | 10 +++++++++- core/src/com/unciv/models/ruleset/Building.kt | 2 +- core/src/com/unciv/models/ruleset/unit/BaseUnit.kt | 2 +- .../com/unciv/ui/cityscreen/CityConstructionsTable.kt | 11 ++++++----- 5 files changed, 22 insertions(+), 14 deletions(-) diff --git a/core/src/com/unciv/logic/city/CityConstructions.kt b/core/src/com/unciv/logic/city/CityConstructions.kt index e134c25d32..4bc61abc9e 100644 --- a/core/src/com/unciv/logic/city/CityConstructions.kt +++ b/core/src/com/unciv/logic/city/CityConstructions.kt @@ -365,12 +365,11 @@ class CityConstructions { val inProgressSnapshot = inProgressConstructions.keys.filter { it != currentConstructionFromQueue } for (constructionName in inProgressSnapshot) { val construction = getConstruction(constructionName) - val rejectionReason: String = - when (construction) { - is Building -> construction.getRejectionReason(this) - is BaseUnit -> construction.getRejectionReason(this) - else -> "" - } + // Perpetual constructions should always still be valid (I hope) + if (construction is PerpetualConstruction) continue + + val rejectionReason = + (construction as INonPerpetualConstruction).getRejectionReason(this) if (rejectionReason.endsWith("lready built") || rejectionReason.startsWith("Cannot be built with") diff --git a/core/src/com/unciv/logic/city/IConstruction.kt b/core/src/com/unciv/logic/city/IConstruction.kt index a58adfb427..bdb42bdb7f 100644 --- a/core/src/com/unciv/logic/city/IConstruction.kt +++ b/core/src/com/unciv/logic/city/IConstruction.kt @@ -22,6 +22,7 @@ interface INonPerpetualConstruction : IConstruction, INamed { fun getProductionCost(civInfo: CivilizationInfo): Int fun getStatBuyCost(cityInfo: CityInfo, stat: Stat): Int? + fun getRejectionReason(cityConstructions: CityConstructions): String private fun getMatchingUniques(uniqueTemplate: String): Sequence { return uniqueObjects.asSequence().filter { it.placeholderText == uniqueTemplate } @@ -41,6 +42,13 @@ interface INonPerpetualConstruction : IConstruction, INamed { ) return true return false } + + /** Checks if the construction should be purchasable, not whether it can be bought with a stat at all */ + fun isPurchasable(cityConstructions: CityConstructions): Boolean { + val rejectionReason = getRejectionReason(cityConstructions) + return rejectionReason == "" + || rejectionReason == "Can only be purchased" + } fun canBePurchasedWithAnyStat(cityInfo: CityInfo): Boolean { return Stat.values().any { canBePurchasedWithStat(cityInfo, it) } @@ -107,7 +115,7 @@ open class PerpetualConstruction(override var name: String, val description: Str override fun isBuildable(cityConstructions: CityConstructions): Boolean = throw Exception("Impossible!") - + override fun postBuildEvent(cityConstructions: CityConstructions, wasBought: Boolean) = throw Exception("Impossible!") diff --git a/core/src/com/unciv/models/ruleset/Building.kt b/core/src/com/unciv/models/ruleset/Building.kt index 33b84b0fd6..de83ee32c9 100644 --- a/core/src/com/unciv/models/ruleset/Building.kt +++ b/core/src/com/unciv/models/ruleset/Building.kt @@ -392,7 +392,7 @@ class Building : NamedStats(), INonPerpetualConstruction, ICivilopediaText { || rejectionReason == "Can only be purchased" } - fun getRejectionReason(construction: CityConstructions): String { + override fun getRejectionReason(construction: CityConstructions): String { if (construction.isBuilt(name)) return "Already built" // for buildings that are created as side effects of other things, and not directly built // unless they can be bought with faith diff --git a/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt b/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt index aa4af5af83..727e9f8b5a 100644 --- a/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt +++ b/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt @@ -240,7 +240,7 @@ class BaseUnit : INamed, INonPerpetualConstruction, CivilopediaText() { || rejectionReason == "Can only be purchased" } - fun getRejectionReason(cityConstructions: CityConstructions): String { + override fun getRejectionReason(cityConstructions: CityConstructions): String { if (isWaterUnit() && !cityConstructions.cityInfo.isCoastal()) return "Can only build water units in coastal cities" val civInfo = cityConstructions.cityInfo.civInfo diff --git a/core/src/com/unciv/ui/cityscreen/CityConstructionsTable.kt b/core/src/com/unciv/ui/cityscreen/CityConstructionsTable.kt index d7a962ebf5..30edbc1ae6 100644 --- a/core/src/com/unciv/ui/cityscreen/CityConstructionsTable.kt +++ b/core/src/com/unciv/ui/cityscreen/CityConstructionsTable.kt @@ -429,11 +429,12 @@ class CityConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBase } if (!cityScreen.canChangeState - || city.isPuppet - || city.isInResistance() - || !city.canPurchase(construction) - || (constructionBuyCost > city.getStatReserve(stat) && !city.civInfo.gameInfo.gameParameters.godMode)) - button.disable() + || !construction.isPurchasable(city.cityConstructions) + || city.isPuppet + || city.isInResistance() + || !city.canPurchase(construction) + || (constructionBuyCost > city.getStatReserve(stat) && !city.civInfo.gameInfo.gameParameters.godMode) + ) button.disable() } button.labelCell.pad(5f)