Typed all remaining uniques using CityInfo.GetMatchingUniques and removed that function (#6071)

* Typed all remaining uniques using CityInfo.GetMatchingUniques and removed that function

* Fixed two NullPtrExceptions

* Fixed syntax
This commit is contained in:
Xander Lenstra
2022-01-29 22:27:48 +01:00
committed by GitHub
parent 39483d78bd
commit a237e7bf82
18 changed files with 205 additions and 103 deletions

View File

@ -123,7 +123,7 @@
{
"name": "Asceticism",
"type": "Follower",
"uniques": ["[+1 Happiness] from every [Shrine] in cities where this religion has at least [3] followers"]
"uniques": ["[+1 Happiness] from every [Shrine] <in cities where this religion has at least [3] followers>"]
},
{
"name": "Cathedrals",
@ -133,7 +133,7 @@
{
"name": "Choral Music",
"type": "Follower",
"uniques": ["[+2 Culture] from every [Temple] in cities where this religion has at least [5] followers"]
"uniques": ["[+2 Culture] from every [Temple] <in cities where this religion has at least [5] followers>"]
},
{
"name": "Divine inspiration",
@ -158,7 +158,7 @@
{
"name": "Liturgical Drama",
"type": "Follower",
"uniques": ["[+1 Faith] from every [Amphitheatre] in cities where this religion has at least [3] followers"]
"uniques": ["[+1 Faith] from every [Amphitheatre] <in cities where this religion has at least [3] followers>"]
},
{
"name": "Monasteries",
@ -188,7 +188,7 @@
{
"name": "Religious Center",
"type": "Follower",
"uniques": ["[+2 Happiness] from every [Temple] in cities where this religion has at least [5] followers"]
"uniques": ["[+2 Happiness] from every [Temple] <in cities where this religion has at least [5] followers>"]
},
{
"name": "Religious Community",
@ -285,12 +285,12 @@
{
"name": "Religious Texts",
"type": "Enhancer",
"uniques": ["[+34]% Natural religion spread [in all cities]", "[+34]% Natural religion spread [in all cities] with [Printing Press]"]
"uniques": ["[+34]% Natural religion spread [in all cities]", "[+34]% Natural religion spread [in all cities] <after discovering [Printing Press]>"]
},
{
"name": "Religious Unity",
"type": "Enhancer",
"uniques": ["[+100]% Natural religion spread to [in City-State cities]"]
"uniques": ["[+100]% Natural religion spread [in City-State cities]"]
},
{
"name": "Reliquary",

View File

@ -222,7 +222,7 @@
"innerColor": [238,201,9],
"favoredReligion": "Christianity",
"uniqueName": "The Glory of Rome",
"uniques": ["+25% Production towards any buildings that already exist in the Capital"],
"uniques": ["[+25]% Production towards any buildings that already exist in the Capital"],
"cities": ["Rome","Antium","Cumae","Neapolis","Ravenna","Arretium","Mediolanum","Arpinum","Circei","Setia",
"Satricum","Ardea","Ostia","Velitrae","Viroconium","Tarentum","Brundisium","Caesaraugusta","Caesarea","Palmyra",
"Signia","Aquileia","Clusium","Sutrium","Cremona","Placentia","Hispalis","Artaxata","Aurelianorum","Nicopolis",

View File

@ -214,7 +214,7 @@
"outerColor": [ 53,0,87],
"innerColor": [238,201,9],
"uniqueName": "The Glory of Rome",
"uniques": ["+25% Production towards any buildings that already exist in the Capital"],
"uniques": ["[+25]% Production towards any buildings that already exist in the Capital"],
"cities": ["Rome","Antium","Cumae","Neapolis","Ravenna","Arretium","Mediolanum","Arpinum","Circei","Setia",
"Satricum","Ardea","Ostia","Velitrae","Viroconium","Tarentum","Brundisium","Caesaraugusta","Caesarea","Palmyra",
"Signia","Aquileia","Clusium","Sutrium","Cremona","Placentia","Hispalis","Artaxata","Aurelianorum","Nicopolis",

View File

@ -67,7 +67,7 @@ class ConstructionAutomation(val cityConstructions: CityConstructions){
addCultureBuildingChoice()
addSpaceshipPartChoice()
addOtherBuildingChoice()
addReligousUnit()
addReligiousUnit()
if (!cityInfo.isPuppet) {
addWondersChoice()
@ -342,9 +342,7 @@ class ConstructionAutomation(val cityConstructions: CityConstructions){
}
}
private fun addReligousUnit(){
private fun addReligiousUnit() {
// these 4 if conditions are used to determine if an AI should buy units to spread religion, or spend faith to buy things like new military units or new buildings.
// currently this AI can only buy inquisitors and missionaries with faith
// this system will have to be reengineered to support buying other stuff with faith

View File

@ -734,11 +734,11 @@ object Battle {
else -> 1f
}
// Deprecated since 3.16.11
for (unique in targetedCity.getLocalMatchingUniques("Population loss from nuclear attacks -[]%")) {
for (unique in targetedCity.getLocalMatchingUniques(UniqueType.PopulationLossFromNukesDeprecated)) {
populationLoss *= 1 - unique.params[0].toFloat() / 100f
}
//
for (unique in targetedCity.getMatchingUniques("Population loss from nuclear attacks []% []")) {
for (unique in targetedCity.getMatchingUniques(UniqueType.PopulationLossFromNukes)) {
if (!targetedCity.matchesFilter(unique.params[1])) continue
populationLoss *= unique.params[0].toPercent()
}

View File

@ -435,7 +435,9 @@ class CityInfo {
}
var allGppPercentageBonus = 0
for (unique in getMatchingUniques("[]% great person generation []")) {
for (unique in getMatchingUniques(UniqueType.GreatPersonPointPercentage)
+ getMatchingUniques(UniqueType.GreatPersonPointPercentageDeprecated)
) {
if (!matchesFilter(unique.params[1])) continue
allGppPercentageBonus += unique.params[0].toInt()
}
@ -484,6 +486,33 @@ class CityInfo {
200 + cityConstructions.getBuiltBuildings().sumOf { it.cityHealth }
override fun toString() = name // for debug
fun isHolyCity(): Boolean = religion.religionThisIsTheHolyCityOf != null
fun canBeDestroyed(justCaptured: Boolean = false): Boolean {
return !isOriginalCapital && !isHolyCity() && (!isCapital() || justCaptured)
}
fun getForceEvaluation(): Int {
// Same as for units, so higher values count more
return CityCombatant(this).getDefendingStrength().toFloat().pow(1.5f).toInt()
}
fun getNeighbouringCivs(): Set<String> {
val tilesList: HashSet<TileInfo> = getTiles().toHashSet()
val cityPositionList: ArrayList<TileInfo> = arrayListOf()
for (tiles in tilesList)
for (tile in tiles.neighbors)
if (!tilesList.contains(tile))
cityPositionList.add(tile)
return cityPositionList
.asSequence()
.mapNotNull { it.getOwner()?.civName }
.toSet()
}
//endregion
//region state-changing functions
@ -799,19 +828,6 @@ class CityInfo {
// 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 }
}
// Finds matching uniques provided from both local and non-local sources.
fun getMatchingUniques(
uniqueType: UniqueType,
@ -822,13 +838,6 @@ class CityInfo {
localUniques.filter { it.isOfType(uniqueType) && it.conditionalsApply(stateForConditionals) }
}
// Matching uniques provided by sources in the city itself
fun getLocalMatchingUniques(placeholderText: String): Sequence<Unique> {
return cityConstructions.builtBuildingUniqueMap.getUniques(placeholderText)
.filter { !it.isAntiLocalEffect } +
religion.getUniques().filter { it.placeholderText == placeholderText }
}
fun getLocalMatchingUniques(uniqueType: UniqueType, stateForConditionals: StateForConditionals? = null): Sequence<Unique> {
return (
cityConstructions.builtBuildingUniqueMap.getUniques(uniqueType)
@ -859,33 +868,6 @@ class CityInfo {
.filter { !it.isLocalEffect }
// Note that we don't query religion here, as those only have local effects
}
fun isHolyCity(): Boolean = religion.religionThisIsTheHolyCityOf != null
fun canBeDestroyed(justCaptured: Boolean = false): Boolean {
return !isOriginalCapital && !isHolyCity() && (!isCapital() || justCaptured)
}
fun getForceEvaluation(): Int {
// Same as for units, so higher values count more
return CityCombatant(this).getDefendingStrength().toFloat().pow(1.5f).toInt()
}
fun getNeighbouringCivs(): Set<String> {
val tilesList: HashSet<TileInfo> = getTiles().toHashSet()
val cityPositionList: ArrayList<TileInfo> = arrayListOf()
for (tiles in tilesList)
for (tile in tiles.neighbors)
if (!tilesList.contains(tile))
cityPositionList.add(tile)
return cityPositionList
.asSequence()
.mapNotNull { it.getOwner()?.civName }
.toSet()
}
//endregion
}

View File

@ -6,6 +6,8 @@ import com.unciv.models.Counter
import com.unciv.models.Religion
import com.unciv.models.metadata.GameSpeed
import com.unciv.models.ruleset.unique.Unique
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.ui.utils.toPercent
class CityInfoReligionManager {
@Transient
@ -113,7 +115,7 @@ class CityInfoReligionManager {
if (newMajorityReligion in religionsAtSomePointAdopted) return
val religionOwningCiv = cityInfo.civInfo.gameInfo.getCivilization(newMajorityReligionObject.foundingCivName)
val religionOwningCiv = newMajorityReligionObject.getFounder()
for (unique in newMajorityReligionObject.getFounderUniques()) {
val statsGranted = when (unique.placeholderText) {
"[] when a city adopts this religion for the first time (modified by game speed)" ->
@ -254,13 +256,15 @@ class CityInfoReligionManager {
private fun getSpreadRange(): Int {
var spreadRange = 10
for (unique in cityInfo.getMatchingUniques("Religion naturally spreads to cities [] tiles away"))
spreadRange += unique.params[0].toInt()
if (getMajorityReligion() != null)
for (unique in getMajorityReligion()!!.getFounderUniques()
.filter { it.placeholderText == "Religion naturally spreads to cities [] tiles away"}
) spreadRange += unique.params[0].toInt()
for (unique in cityInfo.getLocalMatchingUniques(UniqueType.ReligionSpreadDistance)) {
spreadRange += unique.params[0].toInt()
}
if (getMajorityReligion() != null) {
for (unique in getMajorityReligion()!!.getFounder().getMatchingUniques(UniqueType.ReligionSpreadDistance))
spreadRange += unique.params[0].toInt()
}
return spreadRange
}
@ -295,17 +299,27 @@ class CityInfoReligionManager {
private fun pressureAmountToAdjacentCities(pressuredCity: CityInfo): Int {
var pressure = pressureFromAdjacentCities.toFloat()
for (unique in cityInfo.getMatchingUniques("[]% Natural religion spread []")) {
// Follower beliefs of this religion
for (unique in cityInfo.getLocalMatchingUniques(UniqueType.NaturalReligionSpreadStrength)) {
if (pressuredCity.matchesFilter(unique.params[1]))
pressure *= 1f + unique.params[0].toFloat() / 100f
pressure *= unique.params[0].toPercent()
}
for (unique in cityInfo.getMatchingUniques("[]% Natural religion spread [] with []"))
if (pressuredCity.matchesFilter(unique.params[1])
&& cityInfo.civInfo.hasTechOrPolicy(unique.params[2])
) pressure *= 1f + unique.params[0].toFloat() / 100f
// Founder beliefs of this religion
if (getMajorityReligion() != null) {
for (unique in getMajorityReligion()!!.getFounder().getMatchingUniques(UniqueType.NaturalReligionSpreadStrength))
if (pressuredCity.matchesFilter(unique.params[1]))
pressure *= unique.params[0].toPercent()
}
// Deprecated since 3.19.3
for (unique in cityInfo.getLocalMatchingUniques(UniqueType.NaturalReligionSpreadStrengthWith))
if (pressuredCity.matchesFilter(unique.params[1])
&& cityInfo.civInfo.hasTechOrPolicy(unique.params[2])
) pressure *= unique.params[0].toPercent()
//
return pressure.toInt()
}
}

View File

@ -88,7 +88,7 @@ class CityStats(val cityInfo: CityInfo) {
if (!cityInfo.isCapital() && cityInfo.isConnectedToCapital()) {
val civInfo = cityInfo.civInfo
stats.gold = civInfo.getCapital().population.population * 0.15f + cityInfo.population.population * 1.1f - 1 // Calculated by http://civilization.wikia.com/wiki/Trade_route_(Civ5)
for (unique in cityInfo.getMatchingUniques("[] from each Trade Route"))
for (unique in cityInfo.getMatchingUniques(UniqueType.StatsFromTradeRoute))
stats.add(unique.stats)
if (civInfo.hasUnique("Gold from all trade routes +25%")) stats.gold *= 1.25f // Machu Picchu speciality
}
@ -314,13 +314,17 @@ class CityStats(val cityInfo: CityInfo) {
unique.params[0].toFloat() * cityInfo.religion.getFollowersOfMajorityReligion(),
unique.params[2].toFloat()
))
if (currentConstruction is Building
&& cityInfo.civInfo.cities.isNotEmpty()
&& cityInfo.civInfo.getCapital().cityConstructions.builtBuildings.contains(currentConstruction.name)
) {
for (unique in cityInfo.getMatchingUniques("+25% Production towards any buildings that already exist in the Capital"))
addUniqueStats(unique, Stat.Production, 25f)
// Deprecated since 3.19.3
for (unique in cityInfo.getMatchingUniques(UniqueType.PercentProductionBuildingsInCapitalDeprecated))
addUniqueStats(unique, Stat.Production, 25f)
//
for (unique in cityInfo.getMatchingUniques(UniqueType.PercentProductionBuildingsInCapital))
addUniqueStats(unique, Stat.Production, unique.params[0].toFloat())
}
return sourceToStats
@ -361,7 +365,7 @@ class CityStats(val cityInfo: CityInfo) {
// e.g. "-[50]% maintenance costs for buildings [in this city]"
// Deprecated since 3.18.17
for (unique in cityInfo.getMatchingUniques(UniqueType.DecrasedBuildingMaintenanceDeprecated)) {
for (unique in cityInfo.getMatchingUniques(UniqueType.DecreasedBuildingMaintenanceDeprecated)) {
buildingsMaintenance *= (1f - unique.params[0].toFloat() / 100)
}
//

View File

@ -739,10 +739,10 @@ class MapUnit {
}
val healingCity = tileInfo.getTilesInDistance(1).firstOrNull {
it.isCityCenter() && it.getCity()!!.getMatchingUniques("[] Units adjacent to this city heal [] HP per turn when healing").any()
it.isCityCenter() && it.getCity()!!.getMatchingUniques(UniqueType.CityHealingUnits).any()
}?.getCity()
if (healingCity != null) {
for (unique in healingCity.getMatchingUniques("[] Units adjacent to this city heal [] HP per turn when healing")) {
for (unique in healingCity.getMatchingUniques(UniqueType.CityHealingUnits)) {
if (!matchesFilter(unique.params[0])) continue
healing += unique.params[1].toInt()
}
@ -1160,7 +1160,7 @@ class MapUnit {
val baseAmount = getBaseMaxActionUses(action)
val additional =
if (buildCity == null) 0
else buildCity.getMatchingUniques("[] units built [] can [] [] extra times")
else buildCity.getMatchingUniques(UniqueType.UnitStartingActions)
.filter { matchesFilter(it.params[0]) && buildCity.matchesFilter(it.params[1]) && it.params[2] == action }
.sumOf { it.params[3].toInt() }

View File

@ -91,4 +91,6 @@ class Religion() : INamed {
fun isMajorReligion() = getBeliefs(BeliefType.Founder).any()
fun isEnhancedReligion() = getBeliefs(BeliefType.Enhancer).any()
fun getFounder() = gameInfo.civilizations.first { it.civName == foundingCivName }
}

View File

@ -173,9 +173,11 @@ class Building : RulesetStatsObject(), INonPerpetualConstruction {
stats.add(unique.stats)
}
for (unique in city.getMatchingUniques("[] from every [] in cities where this religion has at least [] followers"))
if (unique.params[2].toInt() <= city.religion.getFollowersOfMajorityReligion() && matchesFilter(unique.params[1]))
stats.add(unique.stats)
// Deprecated since 3.19.3
for (unique in city.getMatchingUniques(UniqueType.StatsForBuildingsWithFollowers))
if (unique.params[2].toInt() <= city.religion.getFollowersOfMajorityReligion() && matchesFilter(unique.params[1]))
stats.add(unique.stats)
//
@Suppress("RemoveRedundantQualifierName") // make it clearer Building inherits Stats
for (unique in getMatchingUniques(UniqueType.StatsWithResource))

View File

@ -83,6 +83,8 @@ class Unique(val text: String, val sourceObjectType: UniqueTarget? = null, val s
UniqueType.ConditionalSpecialistCount ->
state.cityInfo != null && state.cityInfo.population.getNumberOfSpecialists() >= condition.params[0].toInt()
UniqueType.ConditionalFollowerCount ->
state.cityInfo != null && state.cityInfo.religion.getFollowersOfMajorityReligion() >= condition.params[0].toInt()
UniqueType.ConditionalWhenGarrisoned ->
state.cityInfo != null && state.cityInfo.getCenterTile().militaryUnit != null && state.cityInfo.getCenterTile().militaryUnit!!.canGarrison()

View File

@ -1,5 +1,6 @@
package com.unciv.models.ruleset.unique
import com.unciv.Constants
import com.unciv.models.ruleset.BeliefType
import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.VictoryType
@ -302,6 +303,16 @@ enum class UniqueParameterType(val parameterName:String) {
else UniqueType.UniqueComplianceErrorSeverity.RulesetInvariant
}
},
Action("action") {
private val knownValues = setOf(Constants.spreadReligionAbilityCount, Constants.removeHeresyAbilityCount)
override fun getErrorSeverity(
parameterText: String,
ruleset: Ruleset
): UniqueType.UniqueComplianceErrorSeverity? {
return if (parameterText in knownValues) null
else UniqueType.UniqueComplianceErrorSeverity.RulesetInvariant
}
},
/** Behaves like [Unknown], but states explicitly the parameter is OK and its contents are ignored */
Comment("comment") {
override fun getErrorSeverity(parameterText: String, ruleset: Ruleset):

View File

@ -70,9 +70,10 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
StatsPerCity("[stats] [cityFilter]", UniqueTarget.Global, UniqueTarget.FollowerBelief),
StatsFromSpecialist("[stats] from every specialist [cityFilter]", UniqueTarget.Global, UniqueTarget.FollowerBelief),
StatsPerPopulation("[stats] per [amount] population [cityFilter]", UniqueTarget.Global, UniqueTarget.FollowerBelief),
// ToDo: Reword to `[stats] <in cities with [amount] or more population>` for consistency with other conditionals
StatsFromXPopulation("[stats] in cities with [amount] or more population", UniqueTarget.Global, UniqueTarget.FollowerBelief),
StatsFromCitiesOnSpecificTiles("[stats] in cities on [terrainFilter] tiles", UniqueTarget.Global, UniqueTarget.FollowerBelief),
@Deprecated("As of 3.18.14", ReplaceWith("[stats] [in all cities] <before discovering [tech]> OR [stats] [in all cities] <before adopting [policy]>"))
StatsFromCitiesBefore("[stats] per turn from cities before [tech/policy]", UniqueTarget.Global, UniqueTarget.FollowerBelief),
@ -84,7 +85,9 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
StatsFromTilesWithout("[stats] from [tileFilter] tiles without [tileFilter] [cityFilter]", UniqueTarget.Global, UniqueTarget.FollowerBelief),
// This is a doozy
StatsFromObject("[stats] from every [tileFilter/specialist/buildingFilter]", UniqueTarget.Global, UniqueTarget.FollowerBelief),
@Deprecated("As of 3.19.3", ReplaceWith("[stats] from every [buildingFilter] <in cities where this religion has at least [amount] followers>"))
StatsForBuildingsWithFollowers("[stats] from every [buildingFilter] in cities where this religion has at least [amount] followers", UniqueTarget.Global, UniqueTarget.FollowerBelief),
StatsFromTradeRoute("[stats] from each Trade Route", UniqueTarget.Global, UniqueTarget.FollowerBelief),
// Stat percentage boosts
StatPercentBonus("[amount]% [stat]", UniqueTarget.Global, UniqueTarget.FollowerBelief),
@ -97,12 +100,16 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
AllStatsSignedPercentFromObject("+[amount]% yield from every [tileFilter]", UniqueTarget.Global, UniqueTarget.FollowerBelief),
StatPercentFromReligionFollowers("[amount]% [stat] from every follower, up to [amount]%", UniqueTarget.FollowerBelief),
BonusStatsFromCityStates("[amount]% [stat] from City-States", UniqueTarget.Global),
NullifiesStat("Nullifies [stat] [cityFilter]", UniqueTarget.Global),
NullifiesGrowth("Nullifies Growth [cityFilter]", UniqueTarget.Global),
PercentProductionWonders("[amount]% Production when constructing [buildingFilter] wonders [cityFilter]", UniqueTarget.Global, UniqueTarget.FollowerBelief),
PercentProductionBuildings("[amount]% Production when constructing [buildingFilter] buildings [cityFilter]", UniqueTarget.Global, UniqueTarget.FollowerBelief),
PercentProductionUnits("[amount]% Production when constructing [baseUnitFilter] units [cityFilter]", UniqueTarget.Global, UniqueTarget.FollowerBelief),
PercentProductionBuildingsInCapital("[amount]% Production towards any buildings that already exist in the Capital", UniqueTarget.Global, UniqueTarget.FollowerBelief),
@Deprecated("As of 3.19.3", ReplaceWith("[amount]% Production towards any buildings that already exist in the Capital"))
PercentProductionBuildingsInCapitalDeprecated("+25% Production towards any buildings that already exist in the Capital", UniqueTarget.Global, UniqueTarget.FollowerBelief),
//endregion Stat providing uniques
@ -143,6 +150,7 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
/////// region Other global uniques
FreeUnits("[amount] units cost no maintenance", UniqueTarget.Global),
CannotBuildUnits("Cannot build [baseUnitFilter] units", UniqueTarget.Global),
ConsumesResources("Consumes [amount] [resource]", UniqueTarget.Improvement, UniqueTarget.Building, UniqueTarget.Unit),
ProvidesResources("Provides [amount] [resource]", UniqueTarget.Improvement, UniqueTarget.Building),
@ -155,6 +163,8 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
CarryOverFoodAlsoDeprecated("[amount]% of food is carried over [cityFilter] after population increases", UniqueTarget.Global, UniqueTarget.FollowerBelief),
GainFreeBuildings("Gain a free [buildingName] [cityFilter]", UniqueTarget.Global),
GreatPersonPointPercentage("[amount]% Great Person generation [cityFilter]", UniqueTarget.Global, UniqueTarget.FollowerBelief),
GreatPersonPointPercentageDeprecated("[amount]% great person generation [cityFilter]", UniqueTarget.Global, UniqueTarget.FollowerBelief),
FreeExtraBeliefs("May choose [amount] additional [beliefType] beliefs when [foundingOrEnhancing] a religion", UniqueTarget.Global),
FreeExtraAnyBeliefs("May choose [amount] additional belief(s) of any type when [foundingOrEnhancing] a religion", UniqueTarget.Global),
@ -209,7 +219,7 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
BuildingMaintenance("[amount]% maintenance cost for buildings [cityFilter]", UniqueTarget.Global, UniqueTarget.FollowerBelief),
@Deprecated("As of 3.18.17", ReplaceWith("[-amount]% maintenace cost for buildings [cityFilter]"))
DecrasedBuildingMaintenanceDeprecated("-[amount]% maintenance cost for buildings [cityFilter]", UniqueTarget.Global, UniqueTarget.FollowerBelief),
DecreasedBuildingMaintenanceDeprecated("-[amount]% maintenance cost for buildings [cityFilter]", UniqueTarget.Global, UniqueTarget.FollowerBelief),
// This should probably support conditionals, e.g. <after discovering [tech]>
MayanGainGreatPerson("Receive a free Great Person at the end of every [comment] (every 394 years), after researching [tech]. Each bonus person can only be chosen once.", UniqueTarget.Global),
@ -233,14 +243,14 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
TriggersVictory("Triggers victory", UniqueTarget.Global),
TriggersCulturalVictory("Triggers a Cultural Victory upon completion", UniqueTarget.Global),
CannotBuildUnits("Cannot build [baseUnitFilter] units", UniqueTarget.Global),
BetterDefensiveBuildings("[amount]% City Strength from defensive buildings", UniqueTarget.Global),
@Deprecated("As of 3.18.17", ReplaceWith("[+25]% City Strength from defensive buildings"))
DefensiveBuilding25("Defensive buildings in all cities are 25% more effective", UniqueTarget.Global),
TileImprovementTime("[amount]% tile improvement construction time", UniqueTarget.Global),
PercentGoldFromTradeMissions("[amount]% Gold from Great Merchant trade missions", UniqueTarget.Global),
// Todo: Lowercase the 'U' of 'Units' in this unique
CityHealingUnits("[mapUnitFilter] Units adjacent to this city heal [amount] HP per turn when healing", UniqueTarget.Global, UniqueTarget.FollowerBelief),
@Deprecated("As of 3.18.17", ReplaceWith("[amount]% Strength <for [mapUnitFilter] units> <when adjacent to a [mapUnitFilter] unit>"))
StrengthFromAdjacentUnits("[amount]% Strength for [mapUnitFilter] units which have another [mapUnitFilter] unit in an adjacent tile", UniqueTarget.Unit, UniqueTarget.Global),
@ -262,10 +272,21 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
StrengthForGarrisonedCitiesAttacking("+[amount]% attacking strength for cities with garrisoned units", UniqueTarget.Global),
UnitStartingExperience("New [baseUnitFilter] units start with [amount] Experience [cityFilter]", UniqueTarget.Global, UniqueTarget.FollowerBelief),
UnitStartingPromotions("All newly-trained [baseUnitFilter] units [cityFilter] receive the [promotion] promotion", UniqueTarget.Global, UniqueTarget.FollowerBelief),
UnitStartingActions("[baseUnitFilter] units built [cityFilter] can [action] [amount] extra times", UniqueTarget.Global, UniqueTarget.FollowerBelief),
// ToDo: make per unit and use unit filters?
LandUnitEmbarkation("Enables embarkation for land units", UniqueTarget.Global),
EmbarkedUnitsMayEnterOcean("Enables embarked units to enter ocean tiles", UniqueTarget.Global),
PopulationLossFromNukes("Population loss from nuclear attacks [amount]% [cityFilter]", UniqueTarget.Global),
@Deprecated("As of 3.19.2", ReplaceWith("Population loss from nuclear attacks [-amount]% [in this city]"))
PopulationLossFromNukesDeprecated("Population loss from nuclear attacks -[amount]%", UniqueTarget.Global),
NaturalReligionSpreadStrength("[amount]% Natural religion spread [cityFilter]", UniqueTarget.FollowerBelief, UniqueTarget.Global),
@Deprecated("As of 3.19.3", ReplaceWith("[amount]% Natural religion spread [cityFilter] <after discovering [tech]> OR [amount]% natural religion spread [cityFilter] <after adopting [policy]>"))
NaturalReligionSpreadStrengthWith("[amount]% Natural religion spread [cityFilter] with [tech/policy]", UniqueTarget.Global, UniqueTarget.FollowerBelief),
ReligionSpreadDistance("Religion naturally spreads to cities [amount] tiles away", UniqueTarget.Global, UniqueTarget.FollowerBelief),
IncompatibleWith("Incompatible with [policy/tech/promotion]", UniqueTarget.Policy, UniqueTarget.Tech, UniqueTarget.Promotion),
StartingTech("Starting tech", UniqueTarget.Tech),
StartsWithTech("Starts with [tech]", UniqueTarget.Nation),
@ -538,6 +559,7 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
/////// city conditionals
ConditionalSpecialistCount("if this city has at least [amount] specialists", UniqueTarget.Conditional),
ConditionalFollowerCount("in cities where this religion has at least [amount] followers", UniqueTarget.Conditional),
ConditionalWhenGarrisoned("with a garrison", UniqueTarget.Conditional),
/////// unit conditionals

View File

@ -482,7 +482,7 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction {
}
unit.promotions.XP = XP
for (unique in cityConstructions.cityInfo.getMatchingUniques("All newly-trained [] units [] receive the [] promotion")
for (unique in cityConstructions.cityInfo.getMatchingUniques(UniqueType.UnitStartingPromotions)
.filter { cityConstructions.cityInfo.matchesFilter(it.params[1]) }) {
val filter = unique.params[0]
val promotion = unique.params.last()

View File

@ -74,7 +74,7 @@ class ReligionOverviewTable(
val button: Button
if (religion.isPantheon()) {
val image = if (viewingPlayer.knows(religion.foundingCivName) || viewingPlayer.civName == religion.foundingCivName)
ImageGetter.getNationIndicator(gameInfo.getCivilization(religion.foundingCivName).nation, 60f)
ImageGetter.getNationIndicator(religion.getFounder().nation, 60f)
else
ImageGetter.getRandomNationIndicator(60f)
button = Button(image, BaseScreen.skin)
@ -126,7 +126,7 @@ class ReligionOverviewTable(
}
}
statsTable.add("Cities following this religion:".toLabel()).left()
statsTable.add(gameInfo.getCivilization(religion.foundingCivName).religionManager.numberOfCitiesFollowingThisReligion().toString()).right().pad(5f).row()
statsTable.add(religion.getFounder().religionManager.numberOfCitiesFollowingThisReligion().toString()).right().pad(5f).row()
val minWidth = max(statsTable.minWidth, beliefsTable.minWidth) + 5

View File

@ -6,6 +6,12 @@ These are split into two categories:
Note that all of these are case-sensitive!
## action
An action that a unit can preform. Currently, there are only two actions part of this:
- `Spread Religion`
- `Remove Foreign religions from your own cities`
## amount
This indicates a whole number, possibly with a + or - sign, such as `2`, `+13`, or `-3`.

View File

@ -71,6 +71,11 @@ Example: "[+1 Gold, +2 Production] from every [tileFilter/specialist/buildingFil
Applicable to: Global, FollowerBelief
#### [stats] from each Trade Route
Example: "[+1 Gold, +2 Production] from each Trade Route"
Applicable to: Global, FollowerBelief
#### [amount]% [stat]
Example: "[20]% [Culture]"
@ -121,6 +126,11 @@ Example: "[20]% Production when constructing [Melee] units [in all cities]"
Applicable to: Global, FollowerBelief
#### [amount]% Production towards any buildings that already exist in the Capital
Example: "[20]% Production towards any buildings that already exist in the Capital"
Applicable to: Global, FollowerBelief
#### Military Units gifted from City-States start with [amount] XP
Example: "Military Units gifted from City-States start with [20] XP"
@ -177,6 +187,11 @@ Example: "[20] units cost no maintenance"
Applicable to: Global
#### Cannot build [baseUnitFilter] units
Example: "Cannot build [Melee] units"
Applicable to: Global
#### [amount]% growth [cityFilter]
Example: "[20]% growth [in all cities]"
@ -192,6 +207,16 @@ Example: "Gain a free [Library] [in all cities]"
Applicable to: Global
#### [amount]% Great Person generation [cityFilter]
Example: "[20]% Great Person generation [in all cities]"
Applicable to: Global, FollowerBelief
#### [amount]% great person generation [cityFilter]
Example: "[20]% great person generation [in all cities]"
Applicable to: Global, FollowerBelief
#### May choose [amount] additional [beliefType] beliefs when [foundingOrEnhancing] a religion
Example: "May choose [20] additional [Follower] beliefs when [founding] a religion"
@ -354,11 +379,6 @@ Applicable to: Global
#### Triggers a Cultural Victory upon completion
Applicable to: Global
#### Cannot build [baseUnitFilter] units
Example: "Cannot build [Melee] units"
Applicable to: Global
#### [amount]% City Strength from defensive buildings
Example: "[20]% City Strength from defensive buildings"
@ -374,6 +394,11 @@ Example: "[20]% Gold from Great Merchant trade missions"
Applicable to: Global
#### [mapUnitFilter] Units adjacent to this city heal [amount] HP per turn when healing
Example: "[Wounded] Units adjacent to this city heal [20] HP per turn when healing"
Applicable to: Global, FollowerBelief
#### [amount]% Golden Age length
Example: "[20]% Golden Age length"
@ -389,12 +414,37 @@ Example: "New [Melee] units start with [20] Experience [in all cities]"
Applicable to: Global, FollowerBelief
#### All newly-trained [baseUnitFilter] units [cityFilter] receive the [promotion] promotion
Example: "All newly-trained [Melee] units [in all cities] receive the [Shock I] promotion"
Applicable to: Global, FollowerBelief
#### [baseUnitFilter] units built [cityFilter] can [action] [amount] extra times
Example: "[Melee] units built [in all cities] can [action] [20] extra times"
Applicable to: Global, FollowerBelief
#### Enables embarkation for land units
Applicable to: Global
#### Enables embarked units to enter ocean tiles
Applicable to: Global
#### Population loss from nuclear attacks [amount]% [cityFilter]
Example: "Population loss from nuclear attacks [20]% [in all cities]"
Applicable to: Global
#### [amount]% Natural religion spread [cityFilter]
Example: "[20]% Natural religion spread [in all cities]"
Applicable to: Global, FollowerBelief
#### Religion naturally spreads to cities [amount] tiles away
Example: "Religion naturally spreads to cities [20] tiles away"
Applicable to: Global, FollowerBelief
#### Can be continually researched
Applicable to: Global
@ -1275,6 +1325,11 @@ Example: "<if this city has at least [20] specialists>"
Applicable to: Conditional
#### <in cities where this religion has at least [amount] followers>
Example: "<in cities where this religion has at least [20] followers>"
Applicable to: Conditional
#### <with a garrison>
Applicable to: Conditional
@ -1364,8 +1419,10 @@ Applicable to: Conditional
## Deprecated uniques
- "[stats] per turn from cities before [tech/policy]" - Deprecated As of 3.18.14, replace with "[stats] [in all cities] <before discovering [tech]> OR [stats] [in all cities] <before adopting [policy]>"
- "[stats] from every Wonder" - Deprecated As of 3.19.1, replace with "[stats] from every [Wonder]"
- "[stats] from every [buildingFilter] in cities where this religion has at least [amount] followers" - Deprecated As of 3.19.3, replace with "[stats] from every [buildingFilter] <in cities where this religion has at least [amount] followers>"
- "+[amount]% [stat] from every [tileFilter/specialist/buildingName]" - Deprecated As of 3.18.17, replace with "[amount]% [stat] from every [tileFilter/specialist/buildingName]"
- "+[amount]% yield from every [tileFilter]" - Deprecated As of 3.18.17, replace with "[+amount]% Yield from every [tileFilter]"
- "+25% Production towards any buildings that already exist in the Capital" - Deprecated As of 3.19.3, replace with "[amount]% Production towards any buildings that already exist in the Capital"
- "City-State Influence degrades [amount]% slower" - Deprecated As of 3.18.17, replace with "[-amount]% City-State Influence degradation"
- "Quantity of Resources gifted by City-States increased by [amount]%" - Deprecated As of 3.18.17, replace with "[+amount]% resources gifted by City-States"
- "Happiness from Luxury Resources gifted by City-States increased by [amount]%" - Deprecated As of 3.18.17, replace with "[+amount]% Happiness from luxury resources gifted by City-States"
@ -1390,6 +1447,8 @@ Applicable to: Conditional
- "+[amount]% Defensive Strength for cities" - Deprecated As of 3.18.17, replace with "[+amount]% Strength for cities <when defending>"
- "[amount]% Attacking Strength for cities" - Deprecated As of 3.18.17, replace with "[amount]% Strength for cities <when attacking>"
- "+[amount]% attacking strength for cities with garrisoned units" - Deprecated As of 3.19.1, replace with "[amount]% Strength for cities <with a garrison> <when attacking>"
- "Population loss from nuclear attacks -[amount]%" - Deprecated As of 3.19.2, replace with "Population loss from nuclear attacks [-amount]% [in this city]"
- "[amount]% Natural religion spread [cityFilter] with [tech/policy]" - Deprecated As of 3.19.3, replace with "[amount]% Natural religion spread [cityFilter] <after discovering [tech]> OR [amount]% natural religion spread [cityFilter] <after adopting [policy]>"
- "Melee units pay no movement cost to pillage" - Deprecated As of 3.18.17, replace with "No movement cost to pillage <for [Melee] units>"
- "[mapUnitFilter] units gain [amount]% more Experience from combat" - Deprecated As of 3.18.12, replace with "[amount]% XP gained from combat <for [mapUnitFilter] units>"
- "[amount]% maintenance costs for [mapUnitFilter] units" - Deprecated As of 3.18.14, replace with "[amount]% maintenance costs <for [mapUnitFilter] units>"