Finishing the later five policy trees now allows you to buy great people with faith (#5038)

This commit is contained in:
Xander Lenstra
2021-09-01 08:46:27 +02:00
committed by GitHub
parent 634f4a3533
commit cffe8e441e
8 changed files with 130 additions and 70 deletions

View File

@ -275,7 +275,9 @@
}, },
{ {
"name": "Commerce Complete", "name": "Commerce Complete",
"uniques": ["[+1 Gold] from every [Trading post]", "Double gold from Great Merchant trade missions"] "uniques": ["[+1 Gold] from every [Trading post]", "Double gold from Great Merchant trade missions",
"May buy [Great Merchant] units for [1000] [Faith] [in all cities in which the majority religion is a major religion] starting from the [Industrial era] at an increasing price ([500])"
]
} }
] ]
}, },
@ -320,7 +322,9 @@
}, },
{ {
"name": "Rationalism Complete", "name": "Rationalism Complete",
"uniques": ["[2] Free Technologies"] "uniques": ["[2] Free Technologies",
"May buy [Great Scientist] units for [1000] [Faith] [in all cities in which the majority religion is a major religion] starting from the [Industrial era] at an increasing price ([500])"
]
} }
] ]
}, },
@ -363,7 +367,9 @@
}, },
{ {
"name": "Freedom Complete", "name": "Freedom Complete",
"uniques": ["+[100]% yield from every [Great Improvement]", "Golden Age length increased by [50]%"] "uniques": ["+[100]% yield from every [Great Improvement]", "Golden Age length increased by [50]%",
"May buy [Great Artist] units for [1000] [Faith] [in all cities in which the majority religion is a major religion] starting from the [Industrial era] at an increasing price ([500])"
]
} }
] ]
}, },
@ -409,7 +415,10 @@
}, },
{ {
"name": "Autocracy Complete", "name": "Autocracy Complete",
"uniques": ["+[25]% attack strength to all [Military] units for [50] turns"] "uniques": ["+[25]% attack strength to all [Military] units for [50] turns",
"May buy [Great General] units for [1000] [Faith] [in all cities in which the majority religion is a major religion] starting from the [Industrial era] at an increasing price ([500])",
"May buy [Great Admiral] units for [1000] [Faith] [in all cities in which the majority religion is a major religion] starting from the [Industrial era] at an increasing price ([500])"
]
} }
] ]
}, },
@ -452,7 +461,9 @@
}, },
{ {
"name": "Order Complete", "name": "Order Complete",
"uniques": ["[+2 Food, +2 Production, +2 Science, +2 Gold, +2 Culture] [in all cities]"] "uniques": ["[+2 Food, +2 Production, +2 Science, +2 Gold, +2 Culture] [in all cities]",
"May buy [Great Engineer] units for [1000] [Faith] [in all cities in which the majority religion is a major religion] starting from the [Industrial era] at an increasing price ([500])"
]
} }
] ]
} }

View File

@ -328,16 +328,12 @@ object NextTurnAutomation {
} }
private fun foundReligion(civInfo: CivilizationInfo) { private fun foundReligion(civInfo: CivilizationInfo) {
println("Founding check?")
if (civInfo.religionManager.religionState != ReligionState.FoundingReligion) return if (civInfo.religionManager.religionState != ReligionState.FoundingReligion) return
println("Founding check!!")
val religionIcon = civInfo.gameInfo.ruleSet.religions val religionIcon = civInfo.gameInfo.ruleSet.religions
.filterNot { civInfo.gameInfo.religions.values.map { religion -> religion.iconName }.contains(it) } .filterNot { civInfo.gameInfo.religions.values.map { religion -> religion.iconName }.contains(it) }
.randomOrNull() .randomOrNull()
?: return // Wait what? How did we pass the checking when using a great prophet but not this? ?: return // Wait what? How did we pass the checking when using a great prophet but not this?
println("Icon has been chosen")
val chosenBeliefs = chooseBeliefs(civInfo, civInfo.religionManager.getBeliefsToChooseAtFounding()).toList() val chosenBeliefs = chooseBeliefs(civInfo, civInfo.religionManager.getBeliefsToChooseAtFounding()).toList()
println("Beliefs have been chosen")
civInfo.religionManager.chooseBeliefs(religionIcon, religionIcon, chosenBeliefs) civInfo.religionManager.chooseBeliefs(religionIcon, religionIcon, chosenBeliefs)
} }

View File

@ -251,8 +251,8 @@ class CityConstructions {
isBuilt(building) || getBuiltBuildings().any { it.replaces == building } isBuilt(building) || getBuiltBuildings().any { it.replaces == building }
fun getWorkDone(constructionName: String): Int { fun getWorkDone(constructionName: String): Int {
if (inProgressConstructions.containsKey(constructionName)) return inProgressConstructions[constructionName]!! return if (inProgressConstructions.containsKey(constructionName)) inProgressConstructions[constructionName]!!
else return 0 else 0
} }
fun getRemainingWork(constructionName: String, useStoredProduction: Boolean = true): Int { fun getRemainingWork(constructionName: String, useStoredProduction: Boolean = true): Int {
@ -425,7 +425,7 @@ class CityConstructions {
} }
} }
private fun constructionComplete(construction: IConstruction) { private fun constructionComplete(construction: INonPerpetualConstruction) {
construction.postBuildEvent(this) construction.postBuildEvent(this)
if (construction.name in inProgressConstructions) if (construction.name in inProgressConstructions)
inProgressConstructions.remove(construction.name) inProgressConstructions.remove(construction.name)
@ -501,7 +501,7 @@ class CityConstructions {
automatic: Boolean, automatic: Boolean,
stat: Stat = Stat.Gold stat: Stat = Stat.Gold
): Boolean { ): Boolean {
if (!getConstruction(constructionName).postBuildEvent(this, true)) if (!(getConstruction(constructionName) as INonPerpetualConstruction).postBuildEvent(this, stat))
return false // nothing built - no pay return false // nothing built - no pay
if (!cityInfo.civInfo.gameInfo.gameParameters.godMode) { if (!cityInfo.civInfo.gameInfo.gameParameters.godMode) {
@ -535,7 +535,7 @@ class CityConstructions {
return null return null
val cultureBuildingToBuild = buildableCultureBuildings.minByOrNull { it.cost }!!.name val cultureBuildingToBuild = buildableCultureBuildings.minByOrNull { it.cost }!!.name
constructionComplete(getConstruction(cultureBuildingToBuild)) constructionComplete(getConstruction(cultureBuildingToBuild) as INonPerpetualConstruction)
return cultureBuildingToBuild return cultureBuildingToBuild
} }

View File

@ -13,7 +13,6 @@ import kotlin.math.roundToInt
interface IConstruction : INamed { interface IConstruction : INamed {
fun isBuildable(cityConstructions: CityConstructions): Boolean fun isBuildable(cityConstructions: CityConstructions): Boolean
fun shouldBeDisplayed(cityConstructions: CityConstructions): Boolean fun shouldBeDisplayed(cityConstructions: CityConstructions): Boolean
fun postBuildEvent(cityConstructions: CityConstructions, wasBought: Boolean = false): Boolean // Yes I'm hilarious.
fun getResourceRequirements(): HashMap<String,Int> fun getResourceRequirements(): HashMap<String,Int>
} }
@ -23,6 +22,7 @@ interface INonPerpetualConstruction : IConstruction, INamed, IHasUniques {
fun getProductionCost(civInfo: CivilizationInfo): Int fun getProductionCost(civInfo: CivilizationInfo): Int
fun getStatBuyCost(cityInfo: CityInfo, stat: Stat): Int? fun getStatBuyCost(cityInfo: CityInfo, stat: Stat): Int?
fun getRejectionReason(cityConstructions: CityConstructions): String fun getRejectionReason(cityConstructions: CityConstructions): String
fun postBuildEvent(cityConstructions: CityConstructions, boughtWith: Stat? = null): Boolean // Yes I'm hilarious.
fun getMatchingUniques(uniqueTemplate: String): Sequence<Unique> { fun getMatchingUniques(uniqueTemplate: String): Sequence<Unique> {
return uniqueObjects.asSequence().filter { it.placeholderText == uniqueTemplate } return uniqueObjects.asSequence().filter { it.placeholderText == uniqueTemplate }
@ -118,9 +118,6 @@ open class PerpetualConstruction(override var name: String, val description: Str
override fun isBuildable(cityConstructions: CityConstructions): Boolean = override fun isBuildable(cityConstructions: CityConstructions): Boolean =
throw Exception("Impossible!") throw Exception("Impossible!")
override fun postBuildEvent(cityConstructions: CityConstructions, wasBought: Boolean) =
throw Exception("Impossible!")
override fun getResourceRequirements(): HashMap<String, Int> = hashMapOf() override fun getResourceRequirements(): HashMap<String, Int> = hashMapOf()
} }

View File

@ -122,7 +122,10 @@ class CivilizationInfo {
* Pairs of Uniques and the amount of turns they are still active * Pairs of Uniques and the amount of turns they are still active
* If the counter reaches 0 at the end of a turn, it is removed immediately * If the counter reaches 0 at the end of a turn, it is removed immediately
*/ */
var temporaryUniques = ArrayList<Pair<Unique, Int>>() val temporaryUniques = ArrayList<Pair<Unique, Int>>()
/** Maps the name of the construction to the amount of times bouhgt */
val boughtConstructionsWithGloballyIncreasingPrice = HashMap<String, Int>()
// if we only use lists, and change the list each time the cities are changed, // if we only use lists, and change the list each time the cities are changed,
// we won't get concurrent modification exceptions. // we won't get concurrent modification exceptions.
@ -174,6 +177,7 @@ class CivilizationInfo {
toReturn.cityStateResource = cityStateResource toReturn.cityStateResource = cityStateResource
toReturn.flagsCountdown.putAll(flagsCountdown) toReturn.flagsCountdown.putAll(flagsCountdown)
toReturn.temporaryUniques.addAll(temporaryUniques) toReturn.temporaryUniques.addAll(temporaryUniques)
toReturn.boughtConstructionsWithGloballyIncreasingPrice.putAll(boughtConstructionsWithGloballyIncreasingPrice)
toReturn.hasEverOwnedOriginalCapital = hasEverOwnedOriginalCapital toReturn.hasEverOwnedOriginalCapital = hasEverOwnedOriginalCapital
return toReturn return toReturn
} }

View File

@ -1,5 +1,6 @@
package com.unciv.logic.civilization package com.unciv.logic.civilization
import com.unciv.logic.city.INonPerpetualConstruction
import com.unciv.logic.map.MapSize import com.unciv.logic.map.MapSize
import com.unciv.models.ruleset.Policy import com.unciv.models.ruleset.Policy
import com.unciv.models.ruleset.Policy.PolicyBranchType import com.unciv.models.ruleset.Policy.PolicyBranchType
@ -214,7 +215,7 @@ class PolicyManager {
} }
for (city in candidateCities) { for (city in candidateCities) {
city.cityConstructions.getConstruction(building).postBuildEvent(city.cityConstructions, false) (city.cityConstructions.getConstruction(building) as INonPerpetualConstruction).postBuildEvent(city.cityConstructions)
citiesAlreadyGivenBuilding.add(city.id) citiesAlreadyGivenBuilding.add(city.id)
} }
} }

View File

@ -205,38 +205,6 @@ class Building : NamedStats(), INonPerpetualConstruction, ICivilopediaText {
return stats return stats
} }
override fun canBePurchasedWithStat(cityInfo: CityInfo, stat: Stat, ignoreCityRequirements: Boolean): Boolean {
if (stat == Stat.Gold && isAnyWonder()) return false
// May buy [buildingFilter] buildings for [amount] [Stat] [cityFilter]
if (!ignoreCityRequirements && cityInfo.getMatchingUniques("May buy [] buildings for [] [] []")
.any { it.params[2] == stat.name && matchesFilter(it.params[0]) && cityInfo.matchesFilter(it.params[3]) }
) return true
return super.canBePurchasedWithStat(cityInfo, stat, ignoreCityRequirements)
}
override fun getBaseBuyCost(cityInfo: CityInfo, stat: Stat): Int? {
if (stat == Stat.Gold) return getBaseGoldCost(cityInfo.civInfo).toInt()
val lowestCostFromUnique =
(
// Can be purchased for [amount] [Stat] [cityFilter]
getMatchingUniques("Can be purchased for [] [] []")
.filter { it.params[1] == stat.name && cityInfo.matchesFilter(it.params[2]) }
.map { it.params[0].toInt() }
// May buy [buildingFilter] buildings for [amount] [Stat] [cityFilter]
+ cityInfo.getMatchingUniques("May buy [] buildings for [] [] []")
.filter { it.params[2] == stat.name && matchesFilter(it.params[0]) && cityInfo.matchesFilter(it.params[3])}
.map { it.params[1].toInt() }
).minOrNull()
if (lowestCostFromUnique != null) return lowestCostFromUnique
// Can be purchased with [Stat] [cityFilter]
if (getMatchingUniques("Can be purchased with [] []")
.any { it.params[0] == stat.name && cityInfo.matchesFilter(it.params[1])}
) return cityInfo.civInfo.gameInfo.ruleSet.eras[cityInfo.civInfo.getEra()]!!.baseUnitBuyCost
return null
}
override fun getCivilopediaTextHeader() = FormattedLine(name, header=2, icon=makeLink()) override fun getCivilopediaTextHeader() = FormattedLine(name, header=2, icon=makeLink())
override fun makeLink() = if (isAnyWonder()) "Wonder/$name" else "Building/$name" override fun makeLink() = if (isAnyWonder()) "Wonder/$name" else "Building/$name"
override fun hasCivilopediaTextLines() = true override fun hasCivilopediaTextLines() = true
@ -385,6 +353,32 @@ class Building : NamedStats(), INonPerpetualConstruction, ICivilopediaText {
return productionCost.toInt() return productionCost.toInt()
} }
override fun canBePurchasedWithStat(cityInfo: CityInfo, stat: Stat, ignoreCityRequirements: Boolean): Boolean {
if (stat == Stat.Gold && isAnyWonder()) return false
// May buy [buildingFilter] buildings for [amount] [Stat] [cityFilter]
if (!ignoreCityRequirements && cityInfo.getMatchingUniques("May buy [] buildings for [] [] []")
.any { it.params[2] == stat.name && matchesFilter(it.params[0]) && cityInfo.matchesFilter(it.params[3]) }
) return true
return super.canBePurchasedWithStat(cityInfo, stat, ignoreCityRequirements)
}
override fun getBaseBuyCost(cityInfo: CityInfo, stat: Stat): Int? {
if (stat == Stat.Gold) return getBaseGoldCost(cityInfo.civInfo).toInt()
return (
sequenceOf(super.getBaseBuyCost(cityInfo, stat)).filterNotNull()
// May buy [buildingFilter] buildings for [amount] [Stat] [cityFilter]
+ cityInfo.getMatchingUniques("May buy [] buildings for [] [] []")
.filter {
it.params[2] == stat.name && matchesFilter(it.params[0]) && cityInfo.matchesFilter(
it.params[3]
)
}
.map { it.params[1].toInt() }
).minOrNull()
}
override fun getStatBuyCost(cityInfo: CityInfo, stat: Stat): Int? { override fun getStatBuyCost(cityInfo: CityInfo, stat: Stat): Int? {
var cost = getBaseBuyCost(cityInfo, stat)?.toDouble() var cost = getBaseBuyCost(cityInfo, stat)?.toDouble()
if (cost == null) return null if (cost == null) return null
@ -603,7 +597,7 @@ class Building : NamedStats(), INonPerpetualConstruction, ICivilopediaText {
override fun isBuildable(cityConstructions: CityConstructions): Boolean = override fun isBuildable(cityConstructions: CityConstructions): Boolean =
getRejectionReason(cityConstructions) == "" getRejectionReason(cityConstructions) == ""
override fun postBuildEvent(cityConstructions: CityConstructions, wasBought: Boolean): Boolean { override fun postBuildEvent(cityConstructions: CityConstructions, boughtWith: Stat?): Boolean {
val civInfo = cityConstructions.cityInfo.civInfo val civInfo = cityConstructions.cityInfo.civInfo
if ("Spaceship part" in uniques) { if ("Spaceship part" in uniques) {
@ -627,7 +621,7 @@ class Building : NamedStats(), INonPerpetualConstruction, ICivilopediaText {
var freeBuildingUniques = uniqueObjects.asSequence().filter { it.placeholderText=="Provides a free [] []" } var freeBuildingUniques = uniqueObjects.asSequence().filter { it.placeholderText=="Provides a free [] []" }
if (providesFreeBuilding!=null) freeBuildingUniques += sequenceOf(Unique("Provides a free [$providesFreeBuilding] [in this city]")) if (providesFreeBuilding!=null) freeBuildingUniques += sequenceOf(Unique("Provides a free [$providesFreeBuilding] [in this city]"))
for(unique in freeBuildingUniques) { for (unique in freeBuildingUniques) {
val affectedCities = val affectedCities =
if (unique.params[1] == "in this city") sequenceOf(cityConstructions.cityInfo) if (unique.params[1] == "in this city") sequenceOf(cityConstructions.cityInfo)
else civInfo.cities.asSequence().filter { it.matchesFilter(unique.params[1]) } else civInfo.cities.asSequence().filter { it.matchesFilter(unique.params[1]) }

View File

@ -15,6 +15,7 @@ import com.unciv.models.translations.tr
import com.unciv.ui.civilopedia.FormattedLine import com.unciv.ui.civilopedia.FormattedLine
import com.unciv.ui.civilopedia.ICivilopediaText import com.unciv.ui.civilopedia.ICivilopediaText
import com.unciv.ui.utils.Fonts import com.unciv.ui.utils.Fonts
import com.unciv.ui.utils.toPercent
import java.util.* import java.util.*
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
import kotlin.collections.HashMap import kotlin.collections.HashMap
@ -212,6 +213,49 @@ class BaseUnit : INamed, INonPerpetualConstruction, ICivilopediaText {
return productionCost.toInt() return productionCost.toInt()
} }
override fun canBePurchasedWithStat(
cityInfo: CityInfo,
stat: Stat,
ignoreCityRequirements: Boolean
): Boolean {
// May buy [unitFilter] units for [amount] [Stat] starting from the [eraName] at an increasing price ([amount])
if (cityInfo.civInfo.getMatchingUniques("May buy [] units for [] [] [] starting from the [] at an increasing price ([])")
.any {
matchesFilter(it.params[0])
&& cityInfo.matchesFilter(it.params[3])
&& cityInfo.civInfo.getEraNumber() >= ruleset.getEraNumber(it.params[4])
&& it.params[2] == stat.name
}
) return true
return super.canBePurchasedWithStat(cityInfo, stat, ignoreCityRequirements)
}
private fun getCostForConstructionsIncreasingInPrice(baseCost: Int, increaseCost: Int, previouslyBought: Int): Int {
return (baseCost + increaseCost / 2f * ( previouslyBought * previouslyBought + previouslyBought )).toInt()
}
override fun getBaseBuyCost(cityInfo: CityInfo, stat: Stat): Int? {
if (stat == Stat.Gold) return getBaseGoldCost(cityInfo.civInfo).toInt()
return (
sequenceOf(super.getBaseBuyCost(cityInfo, stat)).filterNotNull()
// May buy [unitFilter] units for [amount] [Stat] starting from the [eraName] at an increasing price ([amount])
+ cityInfo.civInfo.getMatchingUniques("May buy [] units for [] [] [] starting from the [] at an increasing price ([])")
.filter {
matchesFilter(it.params[0])
&& cityInfo.matchesFilter(it.params[3])
&& cityInfo.civInfo.getEraNumber() >= ruleset.getEraNumber(it.params[4])
&& it.params[2] == stat.name
}.map {
getCostForConstructionsIncreasingInPrice(
it.params[1].toInt(),
it.params[5].toInt(),
cityInfo.civInfo.boughtConstructionsWithGloballyIncreasingPrice[name] ?: 0
)
}
).minOrNull()
}
override fun getStatBuyCost(cityInfo: CityInfo, stat: Stat): Int? { override fun getStatBuyCost(cityInfo: CityInfo, stat: Stat): Int? {
var cost = getBaseBuyCost(cityInfo, stat)?.toDouble() var cost = getBaseBuyCost(cityInfo, stat)?.toDouble()
if (cost == null) return null if (cost == null) return null
@ -226,11 +270,11 @@ class BaseUnit : INamed, INonPerpetualConstruction, ICivilopediaText {
for (unique in cityInfo.getMatchingUniques("[] cost of purchasing [] units []%")) { for (unique in cityInfo.getMatchingUniques("[] cost of purchasing [] units []%")) {
if (stat.name == unique.params[0] && matchesFilter(unique.params[1])) if (stat.name == unique.params[0] && matchesFilter(unique.params[1]))
cost *= 1f + unique.params[2].toFloat() / 100f cost *= unique.params[2].toPercent()
} }
for (unique in cityInfo.getMatchingUniques("[] cost of purchasing items in cities []%")) for (unique in cityInfo.getMatchingUniques("[] cost of purchasing items in cities []%"))
if (stat.name == unique.params[0]) if (stat.name == unique.params[0])
cost *= 1f + (unique.params[1].toFloat() / 100f) cost *= unique.params[1].toPercent()
return (cost / 10f).toInt() * 10 return (cost / 10f).toInt() * 10
} }
@ -316,13 +360,13 @@ class BaseUnit : INamed, INonPerpetualConstruction, ICivilopediaText {
fun isBuildableIgnoringTechs(civInfo: CivilizationInfo) = fun isBuildableIgnoringTechs(civInfo: CivilizationInfo) =
getRejectionReason(civInfo, true) == "" getRejectionReason(civInfo, true) == ""
override fun postBuildEvent(cityConstructions: CityConstructions, wasBought: Boolean): Boolean { override fun postBuildEvent(cityConstructions: CityConstructions, boughtWith: Stat?): Boolean {
val civInfo = cityConstructions.cityInfo.civInfo val civInfo = cityConstructions.cityInfo.civInfo
val unit = civInfo.placeUnitNearTile(cityConstructions.cityInfo.location, name) val unit = civInfo.placeUnitNearTile(cityConstructions.cityInfo.location, name)
?: return false // couldn't place the unit, so there's actually no unit =( ?: return false // couldn't place the unit, so there's actually no unit =(
//movement penalty //movement penalty
if (wasBought && !civInfo.gameInfo.gameParameters.godMode && !unit.hasUnique("Can move immediately once bought")) if (boughtWith != null && !civInfo.gameInfo.gameParameters.godMode && !unit.hasUnique("Can move immediately once bought"))
unit.currentMovement = 0f unit.currentMovement = 0f
// If this unit has special abilities that need to be kept track of, start doing so here // If this unit has special abilities that need to be kept track of, start doing so here
@ -330,6 +374,18 @@ class BaseUnit : INamed, INonPerpetualConstruction, ICivilopediaText {
unit.religion = cityConstructions.cityInfo.religion.getMajorityReligionName() unit.religion = cityConstructions.cityInfo.religion.getMajorityReligionName()
unit.setupAbilityUses(cityConstructions.cityInfo) unit.setupAbilityUses(cityConstructions.cityInfo)
} }
if (boughtWith != null && cityConstructions.cityInfo.civInfo.getMatchingUniques("May buy [] units for [] [] [] starting from the [] at an increasing price ([])")
.filter {
matchesFilter(it.params[0])
&& cityConstructions.cityInfo.matchesFilter(it.params[3])
&& cityConstructions.cityInfo.civInfo.getEraNumber() >= ruleset.getEraNumber(it.params[4])
&& it.params[2] == boughtWith.name
}.any()
) {
cityConstructions.cityInfo.civInfo.boughtConstructionsWithGloballyIncreasingPrice[name] =
(cityConstructions.cityInfo.civInfo.boughtConstructionsWithGloballyIncreasingPrice[name] ?: 0) + 1
}
if (this.isCivilian()) return true // tiny optimization makes save files a few bytes smaller if (this.isCivilian()) return true // tiny optimization makes save files a few bytes smaller
@ -340,6 +396,7 @@ class BaseUnit : INamed, INonPerpetualConstruction, ICivilopediaText {
fun addConstructionBonuses(unit: MapUnit, cityConstructions: CityConstructions) { fun addConstructionBonuses(unit: MapUnit, cityConstructions: CityConstructions) {
val civInfo = cityConstructions.cityInfo.civInfo val civInfo = cityConstructions.cityInfo.civInfo
@Suppress("LocalVariableName")
var XP = 0 var XP = 0
for (unique in for (unique in
@ -354,22 +411,22 @@ class BaseUnit : INamed, INonPerpetualConstruction, ICivilopediaText {
for (unique in for (unique in
cityConstructions.cityInfo.getMatchingUniques("All newly-trained [] units [] receive the [] promotion") cityConstructions.cityInfo.getMatchingUniques("All newly-trained [] units [] receive the [] promotion")
.filter { cityConstructions.cityInfo.matchesFilter(it.params[1]) } + .filter { cityConstructions.cityInfo.matchesFilter(it.params[1]) } +
// Deprecated since 3.15.9 // Deprecated since 3.15.9
cityConstructions.cityInfo.getLocalMatchingUniques("All newly-trained [] units in this city receive the [] promotion") cityConstructions.cityInfo.getLocalMatchingUniques("All newly-trained [] units in this city receive the [] promotion")
// //
) { ) {
val filter = unique.params[0] val filter = unique.params[0]
val promotion = unique.params.last() val promotion = unique.params.last()
if (unit.matchesFilter(filter) || if (unit.matchesFilter(filter)
( || (
filter == "relevant" && filter == "relevant"
civInfo.gameInfo.ruleSet.unitPromotions.values && civInfo.gameInfo.ruleSet.unitPromotions.values
.any { .any {
it.name == promotion it.name == promotion
&& unit.type.name in it.unitTypes && unit.type.name in it.unitTypes
} }
) )
) { ) {
unit.promotions.addPromotion(promotion, isFree = true) unit.promotions.addPromotion(promotion, isFree = true)
} }