From 2e32eccbce2716570ffb031d07b312dbb1e6e218 Mon Sep 17 00:00:00 2001 From: SeventhM <127357473+SeventhM@users.noreply.github.com> Date: Sat, 4 Jan 2025 10:02:28 -0800 Subject: [PATCH] Allow for city level stockpiles to actually function (#12710) * Allow for city level stockpiles to actually function * Disallow civs to gain citywide stockpiles from gainStockpiledResource * Give the correct resource amount from city.getAvailableResourceAmount * Make getReserve for cities explicit for tileResources * Remove city function for adding stockpiles via a string * Remove civ function for adding stockpiles via a string --- core/src/com/unciv/logic/city/City.kt | 21 ++++++++++++------- .../com/unciv/logic/city/CityConstructions.kt | 6 ++++-- .../src/com/unciv/logic/city/CityResources.kt | 6 +++--- .../unciv/logic/civilization/Civilization.kt | 9 ++++---- .../civilization/managers/TurnManager.kt | 2 +- .../transients/CivInfoTransientCache.kt | 2 +- .../unciv/models/ruleset/tile/TileResource.kt | 2 +- .../ruleset/unique/UniqueTriggerActivation.kt | 6 ++++-- .../unit/actions/UnitActionModifiers.kt | 5 +++-- 9 files changed, 36 insertions(+), 23 deletions(-) diff --git a/core/src/com/unciv/logic/city/City.kt b/core/src/com/unciv/logic/city/City.kt index af3b2dd56b5be..ea2d3655eacf5 100644 --- a/core/src/com/unciv/logic/city/City.kt +++ b/core/src/com/unciv/logic/city/City.kt @@ -16,6 +16,7 @@ import com.unciv.logic.map.TileMap import com.unciv.logic.map.mapunit.MapUnit import com.unciv.logic.map.tile.RoadStatus import com.unciv.logic.map.tile.Tile +import com.unciv.models.Counter import com.unciv.models.ruleset.Building import com.unciv.models.ruleset.tile.TileResource import com.unciv.models.ruleset.unique.StateForConditionals @@ -73,6 +74,8 @@ class City : IsPartOfGameInfoSerialization, INamed { @Transient // CityStats has no serializable fields var cityStats = CityStats(this) + + var resourceStockpiles = Counter() /** All tiles that this city controls */ var tiles = HashSet() @@ -136,6 +139,7 @@ class City : IsPartOfGameInfoSerialization, INamed { toReturn.tiles = tiles toReturn.workedTiles = workedTiles toReturn.lockedTiles = lockedTiles + toReturn.resourceStockpiles = resourceStockpiles.clone() toReturn.isBeingRazed = isBeingRazed toReturn.attackedThisTurn = attackedThisTurn toReturn.foundingCiv = foundingCiv @@ -207,6 +211,11 @@ class City : IsPartOfGameInfoSerialization, INamed { fun getGreatPersonPercentageBonus() = GreatPersonPointsBreakdown.getGreatPersonPercentageBonus(this) fun getGreatPersonPoints() = GreatPersonPointsBreakdown(this).sum() + fun gainStockpiledResource(resource: TileResource, amount: Int) { + if (resource.isCityWide) resourceStockpiles.add(resource.name, amount) + else civ.resourceStockpiles.add(resource.name, amount) + } + fun addStat(stat: Stat, amount: Int) { when (stat) { Stat.Production -> cityConstructions.addProductionPoints(amount) @@ -218,8 +227,7 @@ class City : IsPartOfGameInfoSerialization, INamed { fun addGameResource(stat: GameResource, amount: Int) { if (stat is TileResource) { if (!stat.isStockpiled) return - if (!stat.isCityWide) civ.gainStockpiledResource(stat.name, amount) - else { /*TODO*/ } + gainStockpiledResource(stat, amount) return } when (stat) { @@ -238,11 +246,10 @@ class City : IsPartOfGameInfoSerialization, INamed { } fun getReserve(stat: GameResource): Int { - if (stat is TileResource && stat.isCityWide) { - return if (stat.isStockpiled) { - // TODO - 0 - } else 0 + if (stat is TileResource) { + if (!stat.isStockpiled) return 0 + if (stat.isCityWide) return resourceStockpiles[stat.name] + return civ.resourceStockpiles[stat.name] } return when (stat) { Stat.Production -> cityConstructions.getWorkDone(cityConstructions.getCurrentConstruction().name) diff --git a/core/src/com/unciv/logic/city/CityConstructions.kt b/core/src/com/unciv/logic/city/CityConstructions.kt index dce5c5d994d5d..40088ef8c7e51 100644 --- a/core/src/com/unciv/logic/city/CityConstructions.kt +++ b/core/src/com/unciv/logic/city/CityConstructions.kt @@ -435,7 +435,8 @@ class CityConstructions : IsPartOfGameInfoSerialization { for (unique in costUniques) { val amount = unique.params[0].toInt() val resourceName = unique.params[1] - city.civ.gainStockpiledResource(resourceName, -amount) + val resource = city.civ.gameInfo.ruleset.tileResources[resourceName] ?: continue + city.gainStockpiledResource(resource, -amount) } if (construction !is Building) return @@ -705,7 +706,8 @@ class CityConstructions : IsPartOfGameInfoSerialization { for (unique in costUniques) { val amount = unique.params[0].toInt() val resourceName = unique.params[1] - city.civ.gainStockpiledResource(resourceName, -amount) + val resource = city.civ.gameInfo.ruleset.tileResources[resourceName] ?: continue + city.gainStockpiledResource(resource, -amount) } } } diff --git a/core/src/com/unciv/logic/city/CityResources.kt b/core/src/com/unciv/logic/city/CityResources.kt index dfe0a2eb64cc2..f1080c998fd0c 100644 --- a/core/src/com/unciv/logic/city/CityResources.kt +++ b/core/src/com/unciv/logic/city/CityResources.kt @@ -69,9 +69,9 @@ object CityResources { fun getAvailableResourceAmount(city: City, resourceName: String): Int { val resource = city.getRuleset().tileResources[resourceName] ?: return 0 - if (resource.isCityWide) - return getCityResourcesAvailableToCity(city).asSequence().filter { it.resource == resource }.sumOf { it.amount } - return city.civ.getResourceAmount(resourceName) + if (!resource.isCityWide) return city.civ.getResourceAmount(resourceName) + if (resource.isStockpiled) return city.resourceStockpiles[resourceName] + return getCityResourcesAvailableToCity(city).asSequence().filter { it.resource == resource }.sumOf { it.amount } } private fun addResourcesFromTiles(city: City, resourceModifer: HashMap, cityResources: ResourceSupplyList) { diff --git a/core/src/com/unciv/logic/civilization/Civilization.kt b/core/src/com/unciv/logic/civilization/Civilization.kt index bb3811e680ae5..9c44919f02c42 100644 --- a/core/src/com/unciv/logic/civilization/Civilization.kt +++ b/core/src/com/unciv/logic/civilization/Civilization.kt @@ -866,7 +866,7 @@ class Civilization : IsPartOfGameInfoSerialization { } fun addGameResource(stat: GameResource, amount: Int) { - if (stat is TileResource && !stat.isCityWide && stat.isStockpiled) gainStockpiledResource(stat.name, amount) + if (stat is TileResource && stat.isStockpiled) gainStockpiledResource(stat, amount) when (stat) { Stat.Culture -> { policies.addCulture(amount) if (amount > 0) totalCultureForContests += amount } @@ -880,9 +880,10 @@ class Civilization : IsPartOfGameInfoSerialization { // Happiness cannot be added as it is recalculated again, use a unique instead } } - - fun gainStockpiledResource(resourceName: String, amount: Int) { - resourceStockpiles.add(resourceName, amount) + + fun gainStockpiledResource(resource: TileResource, amount: Int) { + if (resource.isCityWide) return + resourceStockpiles.add(resource.name, amount) } fun getStatReserve(stat: Stat): Int { diff --git a/core/src/com/unciv/logic/civilization/managers/TurnManager.kt b/core/src/com/unciv/logic/civilization/managers/TurnManager.kt index 8fbd7f74bbfae..cc3cd052b8bfa 100644 --- a/core/src/com/unciv/logic/civilization/managers/TurnManager.kt +++ b/core/src/com/unciv/logic/civilization/managers/TurnManager.kt @@ -41,7 +41,7 @@ class TurnManager(val civInfo: Civilization) { civInfo.cache.updateCivResources() // If you offered a trade last turn, this turn it will have been accepted/declined for (stockpiledResource in civInfo.getCivResourceSupply().filter { it.resource.isStockpiled }) - civInfo.gainStockpiledResource(stockpiledResource.resource.name, stockpiledResource.amount) + civInfo.gainStockpiledResource(stockpiledResource.resource, stockpiledResource.amount) civInfo.civConstructions.startTurn() civInfo.attacksSinceTurnStart.clear() diff --git a/core/src/com/unciv/logic/civilization/transients/CivInfoTransientCache.kt b/core/src/com/unciv/logic/civilization/transients/CivInfoTransientCache.kt index a535e81c1ac38..40ac88d188cc6 100644 --- a/core/src/com/unciv/logic/civilization/transients/CivInfoTransientCache.kt +++ b/core/src/com/unciv/logic/civilization/transients/CivInfoTransientCache.kt @@ -355,7 +355,7 @@ class CivInfoTransientCache(val civInfo: Civilization) { newDetailedCivResources.subtractResourceRequirements( unit.getResourceRequirementsPerTurn(), civInfo.gameInfo.ruleset, "Units") - newDetailedCivResources.removeAll { it.resource.hasUnique(UniqueType.CityResource) } + newDetailedCivResources.removeAll { it.resource.isCityWide } // Check if anything has actually changed so we don't update stats for no reason - this uses List equality which means it checks the elements if (civInfo.detailedCivResources == newDetailedCivResources) return diff --git a/core/src/com/unciv/models/ruleset/tile/TileResource.kt b/core/src/com/unciv/models/ruleset/tile/TileResource.kt index cc5757a265214..ef25911bd2f4c 100644 --- a/core/src/com/unciv/models/ruleset/tile/TileResource.kt +++ b/core/src/com/unciv/models/ruleset/tile/TileResource.kt @@ -36,7 +36,7 @@ class TileResource : RulesetStatsObject(), GameResource { var majorDepositAmount: DepositAmount = DepositAmount() var minorDepositAmount: DepositAmount = DepositAmount() - + val isCityWide by lazy { hasUnique(UniqueType.CityResource, StateForConditionals.IgnoreConditionals) } val isStockpiled by lazy { hasUnique(UniqueType.Stockpiled, StateForConditionals.IgnoreConditionals) } diff --git a/core/src/com/unciv/models/ruleset/unique/UniqueTriggerActivation.kt b/core/src/com/unciv/models/ruleset/unique/UniqueTriggerActivation.kt index 22f86e8fe1498..f17740b6d347c 100644 --- a/core/src/com/unciv/models/ruleset/unique/UniqueTriggerActivation.kt +++ b/core/src/com/unciv/models/ruleset/unique/UniqueTriggerActivation.kt @@ -526,7 +526,8 @@ object UniqueTriggerActivation { return { val amount = unique.params[0].toInt() - civInfo.gainStockpiledResource(resourceName, amount) + if (city != null) city.gainStockpiledResource(resource, amount) + else civInfo.gainStockpiledResource(resource, amount) val notificationText = getNotificationText( notification, triggerNotificationText, @@ -545,7 +546,8 @@ object UniqueTriggerActivation { return { val amount = unique.params[0].toInt() - civInfo.gainStockpiledResource(resourceName, -amount) + if (city != null) city.gainStockpiledResource(resource, -amount) + else civInfo.gainStockpiledResource(resource, -amount) val notificationText = getNotificationText( notification, triggerNotificationText, diff --git a/core/src/com/unciv/ui/screens/worldscreen/unit/actions/UnitActionModifiers.kt b/core/src/com/unciv/ui/screens/worldscreen/unit/actions/UnitActionModifiers.kt index a867d98652989..ed12a36860285 100644 --- a/core/src/com/unciv/ui/screens/worldscreen/unit/actions/UnitActionModifiers.kt +++ b/core/src/com/unciv/ui/screens/worldscreen/unit/actions/UnitActionModifiers.kt @@ -115,8 +115,9 @@ object UnitActionModifiers { UniqueType.UnitActionStockpileCost -> { val amount = conditional.params[0].toInt() val resourceName = conditional.params[1] - if(unit.civ.getCivResourcesByName()[resourceName] != null) - unit.civ.gainStockpiledResource(resourceName, -amount) + val resource = unit.civ.gameInfo.ruleset.tileResources[resourceName] + if (resource != null && resource.isStockpiled) + unit.civ.gainStockpiledResource(resource, -amount) } UniqueType.UnitActionRemovingPromotion -> { val promotionName = conditional.params[0]