mirror of
https://github.com/yairm210/Unciv.git
synced 2025-07-31 15:19:29 +07:00
Refactored the way cities determine what uniques should apply when (#4393)
* I'm so sorry for the size of this PR * Uniques are better generalized * Code now compiles * Missed a line * Some more cleaning up
This commit is contained in:
@ -79,13 +79,40 @@ class CityConstructions {
|
||||
val stats = Stats()
|
||||
for (building in getBuiltBuildings())
|
||||
stats.add(building.getStats(cityInfo))
|
||||
|
||||
for (unique in builtBuildingUniqueMap.getAllUniques()) when (unique.placeholderText) {
|
||||
"[] per [] population []" -> if (cityInfo.matchesFilter(unique.params[2]))
|
||||
stats.add(unique.stats.times(cityInfo.population.population / unique.params[1].toFloat()))
|
||||
"[] once [] is discovered" -> if (cityInfo.civInfo.tech.isResearched(unique.params[1])) stats.add(unique.stats)
|
||||
|
||||
// Why only the local matching uniques you ask? Well, the non-local uniques are evaluated in
|
||||
// CityStats.getStatsFromUniques(uniques). This function gets a list of uniques and one of
|
||||
// the placeholderTexts it filters for is "[] per [] population []". Why doesn't that function
|
||||
// then not also handle the local (i.e. cityFilter == "in this city") versions?
|
||||
// This is because of what it is used for. The only time time a unique with this placeholderText
|
||||
// is actually contained in `uniques`, is when `getStatsFromUniques` is called for determining
|
||||
// the stats a city receives from wonders. It is then called with `unique` being the list
|
||||
// of all specifically non-local uniques of all cities.
|
||||
//
|
||||
// This averts the problem, albeit it barely, and it might change in the future without
|
||||
// anyone noticing, which might lead to further bugs. So why can't these two unique checks
|
||||
// just be merged then? Because of another problem.
|
||||
//
|
||||
// As noted earlier, `getStatsFromUniques` is called in that case to calculate the stats
|
||||
// this city received from wonders, both local and non-local. This function, `getStats`,
|
||||
// is only called to calculate the stats the city receives from local buildings.
|
||||
// In the current codebase with the current JSON objects it just so happens to be that
|
||||
// all non-local uniques with this placeholderText from other cities belong to wonders,
|
||||
// while the local uniques with this placeholderText are from buildings, but this is in no
|
||||
// way a given. In reality, there should be functions getBuildingStats and getWonderStats,
|
||||
// to solve this, with getStats merely adding these two together. Implementing this is on
|
||||
// my ToDoList, but this PR is already large enough as it is.
|
||||
for (unique in cityInfo.getLocalMatchingUniques("[] per [] population []")
|
||||
.filter { cityInfo.matchesFilter(it.params[2])}
|
||||
) {
|
||||
stats.add(unique.stats.times(cityInfo.population.population / unique.params[1].toFloat()))
|
||||
}
|
||||
|
||||
|
||||
for (unique in cityInfo.getLocalMatchingUniques("[] once [] is discovered")) {
|
||||
if (cityInfo.civInfo.tech.isResearched(unique.params[1]))
|
||||
stats.add(unique.stats)
|
||||
}
|
||||
|
||||
return stats
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ import com.unciv.logic.civilization.diplomacy.DiplomacyFlags
|
||||
import com.unciv.logic.map.RoadStatus
|
||||
import com.unciv.logic.map.TileInfo
|
||||
import com.unciv.logic.map.TileMap
|
||||
import com.unciv.models.ruleset.Unique
|
||||
import com.unciv.models.ruleset.tile.ResourceSupplyList
|
||||
import com.unciv.models.ruleset.tile.ResourceType
|
||||
import com.unciv.models.ruleset.unit.BaseUnit
|
||||
@ -253,7 +254,7 @@ class CityInfo {
|
||||
cityResources.add(resource, -amount, "Buildings")
|
||||
}
|
||||
}
|
||||
for (unique in cityConstructions.builtBuildingUniqueMap.getUniques("Provides [] []")) { // E.G "Provides [1] [Iron]"
|
||||
for (unique in getLocalMatchingUniques("Provides [] []")) { // E.G "Provides [1] [Iron]"
|
||||
val resource = getRuleset().tileResources[unique.params[1]]
|
||||
if (resource != null) {
|
||||
cityResources.add(resource, unique.params[0].toInt() * civInfo.getResourceModifier(resource), "Tiles")
|
||||
@ -337,10 +338,20 @@ class CityInfo {
|
||||
// this is not very efficient, and if it causes problems we can try and think of a way of improving it
|
||||
if (stat != null) entry.value.add(stat, entry.value.get(stat) * unique.params[1].toFloat() / 100)
|
||||
}
|
||||
|
||||
for (unique in civInfo.getMatchingUniques("+[]% great person generation in all cities")
|
||||
+ cityConstructions.builtBuildingUniqueMap.getUniques("+[]% great person generation in this city"))
|
||||
stats[entry.key] = stats[entry.key]!!.times(1 + (unique.params[0].toFloat() / 100))
|
||||
|
||||
for (unique in getMatchingUniques("[]% great person generation []")) {
|
||||
if (!matchesFilter(unique.params[1])) continue
|
||||
stats[entry.key]!!.timesInPlace(1 + unique.params[0].toFloat() / 100f)
|
||||
}
|
||||
|
||||
// Deprecated since 3.15.9
|
||||
for (unique in getMatchingUniques("+[]% great person generation in this city")
|
||||
+ getMatchingUniques("+[]% great person generation in all cities")
|
||||
) {
|
||||
stats[entry.key]!!.timesInPlace(1 + unique.params[0].toFloat() / 100f)
|
||||
}
|
||||
//
|
||||
|
||||
}
|
||||
|
||||
return stats
|
||||
@ -532,6 +543,54 @@ class CityInfo {
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
// So everywhere in the codebase there were continuous calls to either
|
||||
// `cityConstructions.builtBuildingUniqueMap.getUniques()` or `cityConstructions.builtBuildingMap.getAllUniques()`,
|
||||
// which was fine as long as those were the only uniques that cities could provide.
|
||||
// However, with the introduction of religion, cities might also get uniques from the religion the city follows.
|
||||
// Adding both calls to `builtBuildingsUniqueMap` and `Religion` every time is not really modular and also ugly, so something had to be done.
|
||||
// Looking at all the use cases, the following functions were written to handle all findMatchingUniques() problems.
|
||||
// Sadly, due to the large disparity between use cases, there needed to be lots of functions.
|
||||
|
||||
|
||||
// Finds matching uniques provided from both local and non-local sources.
|
||||
fun getMatchingUniques(
|
||||
placeholderText: String,
|
||||
// We might have this cached to avoid concurrency problems. If we don't, just get it directly
|
||||
localUniques: Sequence<Unique> = getLocalMatchingUniques(placeholderText),
|
||||
): Sequence<Unique> {
|
||||
// The localUniques might not be filtered when passed as a parameter, so we filter it anyway
|
||||
// The time loss shouldn't be that large I don't think
|
||||
return civInfo.getMatchingUniques(placeholderText, this) +
|
||||
localUniques.filter { it.placeholderText == placeholderText }
|
||||
}
|
||||
|
||||
// Matching uniques provided by sources in the city itself
|
||||
fun getLocalMatchingUniques(placeholderText: String): Sequence<Unique> {
|
||||
return (
|
||||
cityConstructions.builtBuildingUniqueMap.getUniques(placeholderText) +
|
||||
religion.getMatchingUniques(placeholderText)
|
||||
).asSequence()
|
||||
}
|
||||
|
||||
// Get all uniques that originate from this city
|
||||
fun getAllLocalUniques(): Sequence<Unique> {
|
||||
return cityConstructions.builtBuildingUniqueMap.getAllUniques() + religion.getUniques()
|
||||
}
|
||||
|
||||
// Get all matching uniques that don't apply to only this city
|
||||
fun getMatchingUniquesWithNonLocalEffects(placeholderText: String): Sequence<Unique> {
|
||||
return cityConstructions.builtBuildingUniqueMap.getUniques(placeholderText).asSequence()
|
||||
.filter { it.params.none { param -> param == "in this city" } }
|
||||
// Note that we don't query religion here, as those only have local effects (for now at least)
|
||||
}
|
||||
|
||||
// Get all uniques that don't apply to only this city
|
||||
fun getAllUniquesWithNonLocalEffects(): Sequence<Unique> {
|
||||
return cityConstructions.builtBuildingUniqueMap.getAllUniques()
|
||||
.filter { it.params.none { param -> param == "in this city" } }
|
||||
// Note that we don't query religion here, as those only have local effects (for now at least)
|
||||
}
|
||||
|
||||
//endregion
|
||||
}
|
||||
|
@ -8,14 +8,14 @@ class CityInfoReligionManager: Counter<String>() {
|
||||
@Transient
|
||||
lateinit var cityInfo: CityInfo
|
||||
|
||||
fun getUniques(): List<Unique> {
|
||||
fun getUniques(): Sequence<Unique> {
|
||||
val majorityReligion = getMajorityReligion()
|
||||
if (majorityReligion == null) return listOf()
|
||||
if (majorityReligion == null) return sequenceOf()
|
||||
// This should later be changed when religions can have multiple beliefs
|
||||
return cityInfo.civInfo.gameInfo.ruleSet.beliefs[majorityReligion]!!.uniqueObjects
|
||||
return cityInfo.civInfo.gameInfo.ruleSet.beliefs[majorityReligion]!!.uniqueObjects.asSequence()
|
||||
}
|
||||
|
||||
fun getMatchingUniques(unique: String): List<Unique> {
|
||||
fun getMatchingUniques(unique: String): Sequence<Unique> {
|
||||
return getUniques().filter { it.placeholderText == unique }
|
||||
}
|
||||
|
||||
|
@ -373,22 +373,24 @@ class CityStats {
|
||||
newBaseStatList["National ability"] = getStatsFromNationUnique()
|
||||
newBaseStatList["Wonders"] = getStatsFromUniques(civInfo.getCivWideBuildingUniques())
|
||||
newBaseStatList["City-States"] = getStatsFromCityStates()
|
||||
newBaseStatList["Religion"] = getStatsFromUniques(cityInfo.religion.getUniques())
|
||||
|
||||
baseStatList = newBaseStatList
|
||||
}
|
||||
|
||||
|
||||
private fun updateStatPercentBonusList(currentConstruction: IConstruction, citySpecificUniques: Sequence<Unique>) {
|
||||
private fun updateStatPercentBonusList(currentConstruction: IConstruction, localBuildingUniques: Sequence<Unique>) {
|
||||
val newStatPercentBonusList = LinkedHashMap<String, Stats>()
|
||||
newStatPercentBonusList["Golden Age"] = getStatPercentBonusesFromGoldenAge(cityInfo.civInfo.goldenAges.isGoldenAge())
|
||||
newStatPercentBonusList["Policies"] = getStatPercentBonusesFromUniques(currentConstruction, cityInfo.civInfo.policies.policyUniques.getAllUniques())
|
||||
newStatPercentBonusList["Buildings"] = getStatPercentBonusesFromUniques(currentConstruction, citySpecificUniques)
|
||||
newStatPercentBonusList["Buildings"] = getStatPercentBonusesFromUniques(currentConstruction, localBuildingUniques)
|
||||
.plus(cityInfo.cityConstructions.getStatPercentBonuses()) // This function is to be deprecated but it'll take a while.
|
||||
newStatPercentBonusList["Wonders"] = getStatPercentBonusesFromUniques(currentConstruction, cityInfo.civInfo.getCivWideBuildingUniques())
|
||||
newStatPercentBonusList["Railroad"] = getStatPercentBonusesFromRailroad()
|
||||
newStatPercentBonusList["Resources"] = getStatPercentBonusesFromResources(currentConstruction)
|
||||
newStatPercentBonusList["National ability"] = getStatPercentBonusesFromNationUnique(currentConstruction)
|
||||
newStatPercentBonusList["Puppet City"] = getStatPercentBonusesFromPuppetCity()
|
||||
newStatPercentBonusList["Religion"] = getStatPercentBonusesFromUniques(currentConstruction, cityInfo.religion.getUniques())
|
||||
|
||||
if (UncivGame.Current.superchargedForDebug) {
|
||||
val stats = Stats()
|
||||
@ -402,12 +404,13 @@ class CityStats {
|
||||
fun update(currentConstruction: IConstruction = cityInfo.cityConstructions.getCurrentConstruction()) {
|
||||
// We calculate this here for concurrency reasons
|
||||
// If something needs this, we pass this through as a parameter
|
||||
val citySpecificUniques = getCitySpecificUniques()
|
||||
val localBuildingUniques = cityInfo.cityConstructions.builtBuildingUniqueMap.getAllUniques()
|
||||
val citySpecificUniques = cityInfo.getAllLocalUniques()
|
||||
|
||||
// We need to compute Tile yields before happiness
|
||||
updateBaseStatList()
|
||||
updateCityHappiness()
|
||||
updateStatPercentBonusList(currentConstruction, citySpecificUniques)
|
||||
updateStatPercentBonusList(currentConstruction, localBuildingUniques)
|
||||
|
||||
updateFinalStatList(currentConstruction, citySpecificUniques) // again, we don't edit the existing currentCityStats directly, in order to avoid concurrency exceptions
|
||||
|
||||
@ -498,21 +501,6 @@ class CityStats {
|
||||
finalStatList = newFinalStatList
|
||||
}
|
||||
|
||||
private fun getCitySpecificUniques(): Sequence<Unique> {
|
||||
return cityInfo.cityConstructions.builtBuildingUniqueMap.getAllUniques()
|
||||
.filter { it.params.isNotEmpty() && it.params.last() == "in this city" }
|
||||
}
|
||||
|
||||
private fun getUniquesForThisCity(
|
||||
unique: String,
|
||||
// We might have to cached to avoid concurrency problems, so if we don't, just get it directly
|
||||
citySpecificUniques: Sequence<Unique> = getCitySpecificUniques()
|
||||
): Sequence<Unique> {
|
||||
return citySpecificUniques.filter { it.placeholderText == unique } +
|
||||
cityInfo.civInfo.getMatchingUniques(unique).filter { cityInfo.matchesFilter(it.params[1]) } +
|
||||
cityInfo.religion.getMatchingUniques(unique)
|
||||
}
|
||||
|
||||
private fun getBuildingMaintenanceCosts(citySpecificUniques: Sequence<Unique>): Float {
|
||||
// Same here - will have a different UI display.
|
||||
var buildingsMaintenance = cityInfo.cityConstructions.getMaintenanceCosts().toFloat() // this is AFTER the bonus calculation!
|
||||
@ -521,12 +509,12 @@ class CityStats {
|
||||
}
|
||||
|
||||
// e.g. "-[50]% maintenance costs for buildings [in this city]"
|
||||
for (unique in getUniquesForThisCity("-[]% maintenance cost for buildings []", citySpecificUniques)) {
|
||||
for (unique in cityInfo.getMatchingUniques("-[]% maintenance cost for buildings []", citySpecificUniques)) {
|
||||
buildingsMaintenance *= (1f - unique.params[0].toFloat() / 100)
|
||||
}
|
||||
|
||||
// Deprecated since 3.15
|
||||
for (unique in getUniquesForThisCity("-[]% building maintenance costs []", citySpecificUniques)) {
|
||||
for (unique in cityInfo.getMatchingUniques("-[]% building maintenance costs []", citySpecificUniques)) {
|
||||
buildingsMaintenance *= (1f - unique.params[0].toFloat() / 100)
|
||||
}
|
||||
//
|
||||
|
@ -59,9 +59,11 @@ class PopulationManager {
|
||||
}
|
||||
if (foodStored >= getFoodToNextPopulation()) { // growth!
|
||||
foodStored -= getFoodToNextPopulation()
|
||||
val percentOfFoodCarriedOver = cityInfo.cityConstructions.builtBuildingUniqueMap
|
||||
.getUniques("[]% of food is carried over after population increases")
|
||||
var percentOfFoodCarriedOver = cityInfo
|
||||
.getMatchingUniques("[]% of food is carried over after population increases")
|
||||
.sumBy { it.params[0].toInt() }
|
||||
// Try to avoid runaway food gain in mods, just in case mod makes don't notice it
|
||||
if (percentOfFoodCarriedOver > 95) percentOfFoodCarriedOver = 95
|
||||
foodStored += (getFoodToNextPopulation() * percentOfFoodCarriedOver / 100f).toInt()
|
||||
population++
|
||||
autoAssignPopulation()
|
||||
|
@ -242,18 +242,16 @@ class CivilizationInfo {
|
||||
fun hasResource(resourceName: String): Boolean = getCivResourcesByName()[resourceName]!! > 0
|
||||
|
||||
fun getCivWideBuildingUniques(): Sequence<Unique> = cities.asSequence().flatMap {
|
||||
city -> city.cityConstructions.builtBuildingUniqueMap.getAllUniques()
|
||||
.filter { it.params.isEmpty() || it.params.last() != "in this city" }
|
||||
city -> city.getAllUniquesWithNonLocalEffects()
|
||||
}
|
||||
|
||||
fun hasUnique(unique: String) = getMatchingUniques(unique).any()
|
||||
|
||||
// Does not return local uniques, only global ones.
|
||||
fun getMatchingUniques(uniqueTemplate: String): Sequence<Unique> {
|
||||
fun getMatchingUniques(uniqueTemplate: String, cityToIgnore: CityInfo? = null): Sequence<Unique> {
|
||||
return nation.uniqueObjects.asSequence().filter { it.placeholderText == uniqueTemplate } +
|
||||
cities.asSequence().flatMap {
|
||||
city -> city.cityConstructions.builtBuildingUniqueMap.getUniques(uniqueTemplate).asSequence()
|
||||
.filter { it.params.isEmpty() || it.params.last() != "in this city" }
|
||||
cities.filter { it != cityToIgnore}.flatMap {
|
||||
city -> city.getMatchingUniquesWithNonLocalEffects(uniqueTemplate)
|
||||
} +
|
||||
policies.policyUniques.getUniques(uniqueTemplate) +
|
||||
tech.getTechUniques().filter { it.placeholderText == uniqueTemplate } +
|
||||
|
@ -225,11 +225,13 @@ open class TileInfo {
|
||||
}
|
||||
|
||||
if (city != null) {
|
||||
val cityWideUniques = city.cityConstructions.builtBuildingUniqueMap.getUniques("[] from [] tiles in this city")
|
||||
val civWideUniques = city.civInfo.getMatchingUniques("[] from every []")
|
||||
val religionUniques = city.religion.getMatchingUniques( "[] from every []")
|
||||
// Should be refactored to use city.getUniquesForThisCity(), probably
|
||||
for (unique in cityWideUniques + civWideUniques + religionUniques) {
|
||||
var tileUniques = city.getMatchingUniques("[] from [] tiles []")
|
||||
.filter { city.matchesFilter(it.params[2]) }
|
||||
// Deprecated since 3.15.9
|
||||
tileUniques += city.getLocalMatchingUniques("[] from [] tiles in this city")
|
||||
//
|
||||
tileUniques += city.getMatchingUniques("[] from every []")
|
||||
for (unique in tileUniques) {
|
||||
val tileType = unique.params[1]
|
||||
if (tileType == improvement) continue // This is added to the calculation in getImprovementStats. we don't want to add it twice
|
||||
if (matchesTerrainFilter(tileType, observingCiv))
|
||||
@ -278,12 +280,16 @@ open class TileInfo {
|
||||
stats.add(unique.stats)
|
||||
|
||||
if (city != null) {
|
||||
val cityWideUniques = city.cityConstructions.builtBuildingUniqueMap.getUniques("[] from [] tiles in this city")
|
||||
var tileUniques = city.getMatchingUniques("[] from [] tiles []")
|
||||
.filter { city.matchesFilter(it.params[2]) }
|
||||
// Deprecated since 3.15.9
|
||||
tileUniques += city.getLocalMatchingUniques("[] from [] tiles in this city")
|
||||
//
|
||||
val improvementUniques = improvement.uniqueObjects.filter {
|
||||
it.placeholderText == "[] on [] tiles once [] is discovered"
|
||||
&& observingCiv.tech.isResearched(it.params[2])
|
||||
}
|
||||
for (unique in cityWideUniques + improvementUniques) {
|
||||
for (unique in tileUniques + improvementUniques) {
|
||||
if (improvement.matchesFilter(unique.params[1])
|
||||
// Freshwater and non-freshwater cannot be moved to matchesUniqueFilter since that creates an endless feedback.
|
||||
// If you're attempting that, check that it works!
|
||||
@ -292,7 +298,7 @@ open class TileInfo {
|
||||
stats.add(unique.stats)
|
||||
}
|
||||
|
||||
for (unique in city.civInfo.getMatchingUniques("[] from every []") + city.religion.getMatchingUniques("[] from every []")) {
|
||||
for (unique in city.getMatchingUniques("[] from every []")) {
|
||||
if (improvement.matchesFilter(unique.params[1])) {
|
||||
stats.add(unique.stats)
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ class Building : NamedStats(), IConstruction {
|
||||
val tileBonusHashmap = HashMap<String, ArrayList<String>>()
|
||||
val finalUniques = ArrayList<String>()
|
||||
for (unique in uniqueObjects)
|
||||
if (unique.placeholderText == "[] from [] tiles in this city") {
|
||||
if (unique.placeholderText == "[] from [] tiles []" && unique.params[2] == "in this city") {
|
||||
val stats = unique.params[0]
|
||||
if (!tileBonusHashmap.containsKey(stats)) tileBonusHashmap[stats] = ArrayList()
|
||||
tileBonusHashmap[stats]!!.add(unique.params[1])
|
||||
@ -155,30 +155,27 @@ class Building : NamedStats(), IConstruction {
|
||||
|
||||
fun getStats(city: CityInfo?): Stats {
|
||||
val stats = this.clone()
|
||||
val civInfo = city?.civInfo
|
||||
if (civInfo != null) {
|
||||
val baseBuildingName = getBaseBuilding(civInfo.gameInfo.ruleSet).name
|
||||
if (city == null) return stats
|
||||
val civInfo = city.civInfo
|
||||
|
||||
// We don't have to check whether 'city' is null, as if it was, cityInfo would also be null, and we wouldn't be here.
|
||||
for (unique in civInfo.getMatchingUniques("[] from every []") + city.religion.getMatchingUniques("[] from every []")) {
|
||||
if (unique.params[1] != baseBuildingName) continue
|
||||
stats.add(unique.stats)
|
||||
}
|
||||
|
||||
for (unique in uniqueObjects)
|
||||
if (unique.placeholderText == "[] with []" && civInfo.hasResource(unique.params[1])
|
||||
&& Stats.isStats(unique.params[0]))
|
||||
stats.add(unique.stats)
|
||||
|
||||
if (!isWonder)
|
||||
for (unique in civInfo.getMatchingUniques("[] from all [] buildings")) {
|
||||
if (isStatRelated(Stat.valueOf(unique.params[1])))
|
||||
stats.add(unique.stats)
|
||||
}
|
||||
else
|
||||
for (unique in civInfo.getMatchingUniques("[] from every Wonder"))
|
||||
stats.add(unique.stats)
|
||||
for (unique in city.getMatchingUniques("[] from every []")) {
|
||||
if (!matchesFilter(unique.params[1])) continue
|
||||
stats.add(unique.stats)
|
||||
}
|
||||
|
||||
for (unique in uniqueObjects)
|
||||
if (unique.placeholderText == "[] with []" && civInfo.hasResource(unique.params[1])
|
||||
&& Stats.isStats(unique.params[0]))
|
||||
stats.add(unique.stats)
|
||||
|
||||
if (!isWonder)
|
||||
for (unique in city.getMatchingUniques("[] from all [] buildings")) {
|
||||
if (isStatRelated(Stat.valueOf(unique.params[1])))
|
||||
stats.add(unique.stats)
|
||||
}
|
||||
else
|
||||
for (unique in city.getMatchingUniques("[] from every Wonder"))
|
||||
stats.add(unique.stats)
|
||||
return stats
|
||||
}
|
||||
|
||||
|
@ -286,22 +286,40 @@ class BaseUnit : INamed, IConstruction, CivilopediaText() {
|
||||
var XP = cityConstructions.getBuiltBuildings().sumBy { it.xpForNewUnits }
|
||||
|
||||
|
||||
for (unique in cityConstructions.builtBuildingUniqueMap
|
||||
.getUniques("New [] units start with [] Experience in this city")
|
||||
+ civInfo.getMatchingUniques("New [] units start with [] Experience")) {
|
||||
for (unique in
|
||||
cityConstructions.cityInfo.getMatchingUniques("New [] units start with [] Experience") +
|
||||
cityConstructions.cityInfo.getMatchingUniques("New [] units start with [] Experience []")
|
||||
.filter { cityConstructions.cityInfo.matchesFilter(it.params[2]) } +
|
||||
// Deprecated since 3.15.9
|
||||
cityConstructions.cityInfo.getLocalMatchingUniques("New [] units start with [] Experience in this city")
|
||||
//
|
||||
) {
|
||||
if (unit.matchesFilter(unique.params[0]))
|
||||
XP += unique.params[1].toInt()
|
||||
}
|
||||
unit.promotions.XP = XP
|
||||
|
||||
for (unique in cityConstructions.builtBuildingUniqueMap
|
||||
.getUniques("All newly-trained [] units in this city receive the [] promotion")) {
|
||||
for (unique in
|
||||
cityConstructions.cityInfo.getMatchingUniques("All newly-trained [] units [] receive the [] promotion")
|
||||
.filter { cityConstructions.cityInfo.matchesFilter(it.params[1]) } +
|
||||
// Deprecated since 3.15.9
|
||||
cityConstructions.cityInfo.getLocalMatchingUniques("All newly-trained [] units in this city receive the [] promotion")
|
||||
//
|
||||
) {
|
||||
val filter = unique.params[0]
|
||||
val promotion = unique.params[1]
|
||||
val promotion = unique.params.last()
|
||||
|
||||
if (unit.matchesFilter(filter) || (filter == "relevant" && civInfo.gameInfo.ruleSet.unitPromotions.values
|
||||
.any { unit.type.name in it.unitTypes && it.name == promotion }))
|
||||
if (unit.matchesFilter(filter) ||
|
||||
(
|
||||
filter == "relevant" &&
|
||||
civInfo.gameInfo.ruleSet.unitPromotions.values
|
||||
.any {
|
||||
it.name == promotion && unit.type.name in it.unitTypes
|
||||
}
|
||||
)
|
||||
) {
|
||||
unit.promotions.addPromotion(promotion, isFree = true)
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
|
Reference in New Issue
Block a user