From b60dabc089649efa6dd639235127318350a3e2a5 Mon Sep 17 00:00:00 2001 From: SeventhM <127357473+SeventhM@users.noreply.github.com> Date: Wed, 13 Mar 2024 14:19:18 -0700 Subject: [PATCH] Allow resources from follower beliefs (#11252) * Allow resources from follower beliefs * incorporate suggestions --- core/src/com/unciv/logic/city/City.kt | 18 +++++++--------- .../src/com/unciv/logic/city/CityResources.kt | 8 ++++--- .../city/managers/CityReligionManager.kt | 2 ++ .../logic/civilization/CivConstructions.kt | 2 +- tests/src/com/unciv/logic/city/CityTest.kt | 21 +++++++++++++++++++ 5 files changed, 37 insertions(+), 14 deletions(-) diff --git a/core/src/com/unciv/logic/city/City.kt b/core/src/com/unciv/logic/city/City.kt index bfe9cb7937..07dbb04677 100644 --- a/core/src/com/unciv/logic/city/City.kt +++ b/core/src/com/unciv/logic/city/City.kt @@ -456,24 +456,22 @@ class City : IsPartOfGameInfoSerialization { // Finds matching uniques provided from both local and non-local sources. fun getMatchingUniques( uniqueType: UniqueType, - stateForConditionals: StateForConditionals = StateForConditionals(civ, this) + stateForConditionals: StateForConditionals = StateForConditionals(this), + includeCivUniques: Boolean = true ): Sequence { - return civ.getMatchingUniques(uniqueType, stateForConditionals) + + return if (includeCivUniques) + civ.getMatchingUniques(uniqueType, stateForConditionals) + getLocalMatchingUniques(uniqueType, stateForConditionals) - } - - // Uniques special to this city - fun getLocalMatchingUniques(uniqueType: UniqueType, stateForConditionals: StateForConditionals = StateForConditionals(civ, this)): Sequence { - return ( - cityConstructions.builtBuildingUniqueMap.getUniques(uniqueType).filter { it.isLocalEffect } + else ( + cityConstructions.builtBuildingUniqueMap.getUniques(uniqueType) + religion.getUniques().filter { it.type == uniqueType } ).filter { !it.isTimedTriggerable && it.conditionalsApply(stateForConditionals) } } - // Uniques coming from only this city - fun getMatchingLocalOnlyUniques(uniqueType: UniqueType, stateForConditionals: StateForConditionals): Sequence { + // Uniques special to this city + fun getLocalMatchingUniques(uniqueType: UniqueType, stateForConditionals: StateForConditionals = StateForConditionals(this)): Sequence { val uniques = cityConstructions.builtBuildingUniqueMap.getUniques(uniqueType).filter { it.isLocalEffect } + religion.getUniques().filter { it.type == uniqueType } return if (uniques.any()) uniques.filter { !it.isTimedTriggerable && it.conditionalsApply(stateForConditionals) } diff --git a/core/src/com/unciv/logic/city/CityResources.kt b/core/src/com/unciv/logic/city/CityResources.kt index ee1ec2f9dd..538630231b 100644 --- a/core/src/com/unciv/logic/city/CityResources.kt +++ b/core/src/com/unciv/logic/city/CityResources.kt @@ -33,6 +33,8 @@ object CityResources { // This way we get them once, but it is ugly, I welcome other ideas :/ getCityResourcesFromCiv(city, cityResources, resourceModifers) + cityResources.removeAll { !it.resource.hasUnique(UniqueType.CityResource) } + return cityResources } @@ -57,7 +59,7 @@ object CityResources { } private fun addCityResourcesGeneratedFromUniqueBuildings(city: City, cityResources: ResourceSupplyList, resourceModifer: HashMap) { - for (unique in city.getMatchingUniquesWithNonLocalEffects(UniqueType.ProvidesResources, StateForConditionals(city.civ, city))) { // E.G "Provides [1] [Iron]" + for (unique in city.getMatchingUniques(UniqueType.ProvidesResources, StateForConditionals(city), false)) { // E.G "Provides [1] [Iron]" val resource = city.getRuleset().tileResources[unique.params[1]] ?: continue cityResources.add( @@ -111,13 +113,13 @@ object CityResources { for (building in city.cityConstructions.getBuiltBuildings()) { // Free buildings cost no resources if (building.name in freeBuildings) continue - cityResources.subtractResourceRequirements(building.getResourceRequirementsPerTurn(StateForConditionals(city.civ, city)), city.getRuleset(), "Buildings") + cityResources.subtractResourceRequirements(building.getResourceRequirementsPerTurn(StateForConditionals(city)), city.getRuleset(), "Buildings") } } private fun getCityResourcesFromCiv(city: City, cityResources: ResourceSupplyList, resourceModifers: HashMap) { // This includes the uniques from buildings, from this and all other cities - for (unique in city.getMatchingUniques(UniqueType.ProvidesResources, StateForConditionals(city.civ, city))) { // E.G "Provides [1] [Iron]" + for (unique in city.getMatchingUniques(UniqueType.ProvidesResources, StateForConditionals(city))) { // E.G "Provides [1] [Iron]" val resource = city.getRuleset().tileResources[unique.params[1]] ?: continue cityResources.add( diff --git a/core/src/com/unciv/logic/city/managers/CityReligionManager.kt b/core/src/com/unciv/logic/city/managers/CityReligionManager.kt index 9b73ea7507..5a7e2c0cdc 100644 --- a/core/src/com/unciv/logic/city/managers/CityReligionManager.kt +++ b/core/src/com/unciv/logic/city/managers/CityReligionManager.kt @@ -181,6 +181,8 @@ class CityReligionManager : IsPartOfGameInfoSerialization { if (oldMajorityReligion != newMajorityReligion && newMajorityReligion != null) { triggerReligionAdoption(newMajorityReligion) } + if (oldMajorityReligion != newMajorityReligion) + city.civ.cache.updateCivResources() // follower uniques can provide resources if (followers != previousFollowers) city.cityStats.update() } diff --git a/core/src/com/unciv/logic/civilization/CivConstructions.kt b/core/src/com/unciv/logic/civilization/CivConstructions.kt index 72d4126aec..355bb405ff 100644 --- a/core/src/com/unciv/logic/civilization/CivConstructions.kt +++ b/core/src/com/unciv/logic/civilization/CivConstructions.kt @@ -153,7 +153,7 @@ class CivConstructions : IsPartOfGameInfoSerialization { // "Gain a free [buildingName] [cityFilter]" val freeBuildingsFromCiv = civInfo.getMatchingUniques(UniqueType.GainFreeBuildings, StateForConditionals.IgnoreConditionals) for (city in civInfo.cities) { - val freeBuildingsFromCity = city.getMatchingLocalOnlyUniques(UniqueType.GainFreeBuildings, StateForConditionals.IgnoreConditionals) + val freeBuildingsFromCity = city.getLocalMatchingUniques(UniqueType.GainFreeBuildings, StateForConditionals.IgnoreConditionals) val freeBuildingUniques = (freeBuildingsFromCiv + freeBuildingsFromCity) .filter { city.matchesFilter(it.params[1]) && it.conditionalsApply(StateForConditionals(city.civ, city)) && !it.hasTriggerConditional() } diff --git a/tests/src/com/unciv/logic/city/CityTest.kt b/tests/src/com/unciv/logic/city/CityTest.kt index b3a2495b6c..437697eef7 100644 --- a/tests/src/com/unciv/logic/city/CityTest.kt +++ b/tests/src/com/unciv/logic/city/CityTest.kt @@ -2,6 +2,7 @@ package com.unciv.logic.city import com.badlogic.gdx.math.Vector2 import com.unciv.logic.civilization.Civilization +import com.unciv.models.ruleset.BeliefType import com.unciv.models.ruleset.unique.UniqueType import com.unciv.testing.GdxTestRunner import com.unciv.testing.TestGame @@ -97,6 +98,7 @@ class CityTest { assertTrue(capitalCity.hasSoldBuildingThisTurn) } + // Resource tests @Test fun `should get resources from tiles`() { // given @@ -190,4 +192,23 @@ class CityTest { assertEquals(4, resourceAmountInCapital) } + @Test + fun `Civ-wide resources can come from follower beliefs, and affect all cities`() { + // given + val religion = testGame.addReligion(testCiv) + val belief = testGame.createBelief(BeliefType.Follower, "Provides [1] [Iron]") + religion.followerBeliefs.add(belief.name) + capitalCity.population.setPopulation(1) + capitalCity.religion.addPressure(religion.name, 1000) + val otherCity = testCiv.addCity(Vector2(2f,2f)) // NOT religionized + + // when + val resourceAmountInCapital = capitalCity.getAvailableResourceAmount("Iron") + val resourceAmountInOtherCity = otherCity.getAvailableResourceAmount("Iron") + + // then + assertEquals(1, resourceAmountInCapital) + assertEquals(1, resourceAmountInOtherCity) + } + }