Allow resources from follower beliefs (#11252)

* Allow resources from follower beliefs

* incorporate suggestions
This commit is contained in:
SeventhM
2024-03-13 14:19:18 -07:00
committed by GitHub
parent fc1e701c7f
commit b60dabc089
5 changed files with 37 additions and 14 deletions

View File

@ -456,24 +456,22 @@ class City : IsPartOfGameInfoSerialization {
// Finds matching uniques provided from both local and non-local sources. // Finds matching uniques provided from both local and non-local sources.
fun getMatchingUniques( fun getMatchingUniques(
uniqueType: UniqueType, uniqueType: UniqueType,
stateForConditionals: StateForConditionals = StateForConditionals(civ, this) stateForConditionals: StateForConditionals = StateForConditionals(this),
includeCivUniques: Boolean = true
): Sequence<Unique> { ): Sequence<Unique> {
return civ.getMatchingUniques(uniqueType, stateForConditionals) + return if (includeCivUniques)
civ.getMatchingUniques(uniqueType, stateForConditionals) +
getLocalMatchingUniques(uniqueType, stateForConditionals) getLocalMatchingUniques(uniqueType, stateForConditionals)
} else (
cityConstructions.builtBuildingUniqueMap.getUniques(uniqueType)
// Uniques special to this city
fun getLocalMatchingUniques(uniqueType: UniqueType, stateForConditionals: StateForConditionals = StateForConditionals(civ, this)): Sequence<Unique> {
return (
cityConstructions.builtBuildingUniqueMap.getUniques(uniqueType).filter { it.isLocalEffect }
+ religion.getUniques().filter { it.type == uniqueType } + religion.getUniques().filter { it.type == uniqueType }
).filter { ).filter {
!it.isTimedTriggerable && it.conditionalsApply(stateForConditionals) !it.isTimedTriggerable && it.conditionalsApply(stateForConditionals)
} }
} }
// Uniques coming from only this city // Uniques special to this city
fun getMatchingLocalOnlyUniques(uniqueType: UniqueType, stateForConditionals: StateForConditionals): Sequence<Unique> { fun getLocalMatchingUniques(uniqueType: UniqueType, stateForConditionals: StateForConditionals = StateForConditionals(this)): Sequence<Unique> {
val uniques = cityConstructions.builtBuildingUniqueMap.getUniques(uniqueType).filter { it.isLocalEffect } + val uniques = cityConstructions.builtBuildingUniqueMap.getUniques(uniqueType).filter { it.isLocalEffect } +
religion.getUniques().filter { it.type == uniqueType } religion.getUniques().filter { it.type == uniqueType }
return if (uniques.any()) uniques.filter { !it.isTimedTriggerable && it.conditionalsApply(stateForConditionals) } return if (uniques.any()) uniques.filter { !it.isTimedTriggerable && it.conditionalsApply(stateForConditionals) }

View File

@ -33,6 +33,8 @@ object CityResources {
// This way we get them once, but it is ugly, I welcome other ideas :/ // This way we get them once, but it is ugly, I welcome other ideas :/
getCityResourcesFromCiv(city, cityResources, resourceModifers) getCityResourcesFromCiv(city, cityResources, resourceModifers)
cityResources.removeAll { !it.resource.hasUnique(UniqueType.CityResource) }
return cityResources return cityResources
} }
@ -57,7 +59,7 @@ object CityResources {
} }
private fun addCityResourcesGeneratedFromUniqueBuildings(city: City, cityResources: ResourceSupplyList, resourceModifer: HashMap<String, Float>) { private fun addCityResourcesGeneratedFromUniqueBuildings(city: City, cityResources: ResourceSupplyList, resourceModifer: HashMap<String, Float>) {
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]] val resource = city.getRuleset().tileResources[unique.params[1]]
?: continue ?: continue
cityResources.add( cityResources.add(
@ -111,13 +113,13 @@ object CityResources {
for (building in city.cityConstructions.getBuiltBuildings()) { for (building in city.cityConstructions.getBuiltBuildings()) {
// Free buildings cost no resources // Free buildings cost no resources
if (building.name in freeBuildings) continue 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<String, Float>) { private fun getCityResourcesFromCiv(city: City, cityResources: ResourceSupplyList, resourceModifers: HashMap<String, Float>) {
// This includes the uniques from buildings, from this and all other cities // 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]] val resource = city.getRuleset().tileResources[unique.params[1]]
?: continue ?: continue
cityResources.add( cityResources.add(

View File

@ -181,6 +181,8 @@ class CityReligionManager : IsPartOfGameInfoSerialization {
if (oldMajorityReligion != newMajorityReligion && newMajorityReligion != null) { if (oldMajorityReligion != newMajorityReligion && newMajorityReligion != null) {
triggerReligionAdoption(newMajorityReligion) triggerReligionAdoption(newMajorityReligion)
} }
if (oldMajorityReligion != newMajorityReligion)
city.civ.cache.updateCivResources() // follower uniques can provide resources
if (followers != previousFollowers) if (followers != previousFollowers)
city.cityStats.update() city.cityStats.update()
} }

View File

@ -153,7 +153,7 @@ class CivConstructions : IsPartOfGameInfoSerialization {
// "Gain a free [buildingName] [cityFilter]" // "Gain a free [buildingName] [cityFilter]"
val freeBuildingsFromCiv = civInfo.getMatchingUniques(UniqueType.GainFreeBuildings, StateForConditionals.IgnoreConditionals) val freeBuildingsFromCiv = civInfo.getMatchingUniques(UniqueType.GainFreeBuildings, StateForConditionals.IgnoreConditionals)
for (city in civInfo.cities) { 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) val freeBuildingUniques = (freeBuildingsFromCiv + freeBuildingsFromCity)
.filter { city.matchesFilter(it.params[1]) && it.conditionalsApply(StateForConditionals(city.civ, city)) .filter { city.matchesFilter(it.params[1]) && it.conditionalsApply(StateForConditionals(city.civ, city))
&& !it.hasTriggerConditional() } && !it.hasTriggerConditional() }

View File

@ -2,6 +2,7 @@ package com.unciv.logic.city
import com.badlogic.gdx.math.Vector2 import com.badlogic.gdx.math.Vector2
import com.unciv.logic.civilization.Civilization import com.unciv.logic.civilization.Civilization
import com.unciv.models.ruleset.BeliefType
import com.unciv.models.ruleset.unique.UniqueType import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.testing.GdxTestRunner import com.unciv.testing.GdxTestRunner
import com.unciv.testing.TestGame import com.unciv.testing.TestGame
@ -97,6 +98,7 @@ class CityTest {
assertTrue(capitalCity.hasSoldBuildingThisTurn) assertTrue(capitalCity.hasSoldBuildingThisTurn)
} }
// Resource tests
@Test @Test
fun `should get resources from tiles`() { fun `should get resources from tiles`() {
// given // given
@ -190,4 +192,23 @@ class CityTest {
assertEquals(4, resourceAmountInCapital) 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)
}
} }