Unique target compliance test v2 (#9802)

* Split off some UniqueType helper classes, make regions work in Android Studio and linting

* Fix wrong UniqueType.Stats target

* Fix two Pantheon uniques

* BeliefType a little nicer to read

* More linting

* Implement UniqueTarget validation

* Validation of UniqueTypes allowed as conditionals
This commit is contained in:
SomeTroglodyte 2023-07-15 21:06:12 +02:00 committed by GitHub
parent 00e008b656
commit a29cdc91e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 149 additions and 119 deletions

View File

@ -30,7 +30,7 @@
{
"name": "God of Craftsman",
"type": "Pantheon",
"uniques": ["[+1 Production] <in cities with at least [3] [Population]>"]
"uniques": ["[+1 Production] [in cities following this religion] <in cities with at least [3] [Population]>"]
},
{
"name": "God of the Open Sky",
@ -55,7 +55,7 @@
{
"name": "Goddess of Love",
"type": "Pantheon",
"uniques": ["[+1 Happiness] <in cities with at least [6] [Population]>"]
"uniques": ["[+1 Happiness] [in cities following this religion] <in cities with at least [6] [Population]>"]
},
{
"name": "Goddess of Protection",

View File

@ -840,7 +840,7 @@ object NextTurnAutomation {
val baseForce = 30f
var ourCombatStrength = civInfo.getStatForRanking(RankingType.Force).toFloat() + baseForce
if (civInfo.getCapital()!= null) ourCombatStrength += CityCombatant(civInfo.getCapital()!!).getCityStrength()
if (civInfo.getCapital() != null) ourCombatStrength += CityCombatant(civInfo.getCapital()!!).getCityStrength()
var theirCombatStrength = otherCiv.getStatForRanking(RankingType.Force).toFloat() + baseForce
if(otherCiv.getCapital() != null) theirCombatStrength += CityCombatant(otherCiv.getCapital()!!).getCityStrength()

View File

@ -65,11 +65,9 @@ class Religion() : INamed, IsPartOfGameInfoSerialization {
return mapToExistingBeliefs((founderBeliefs + followerBeliefs).toHashSet()).asSequence()
val beliefs =
when (beliefType) {
BeliefType.Pantheon -> followerBeliefs
BeliefType.Follower -> followerBeliefs
BeliefType.Founder -> founderBeliefs
BeliefType.Enhancer -> founderBeliefs
when {
beliefType.isFollower -> followerBeliefs
beliefType.isFounder -> founderBeliefs
else -> null!! // This is fine...
}

View File

@ -17,7 +17,7 @@ class Belief() : RulesetObject() {
}
override fun getUniqueTarget() =
if (type == BeliefType.Founder || type == BeliefType.Enhancer) UniqueTarget.FounderBelief
if (type.isFounder) UniqueTarget.FounderBelief
else UniqueTarget.FollowerBelief
override fun makeLink() = "Belief/$name"
@ -79,11 +79,15 @@ class Belief() : RulesetObject() {
}
}
enum class BeliefType(val color: String) {
/** Subtypes of Beliefs - directly deserialized.
* @param isFollower - Behaves as "follower" belief, Uniques processed per city
* @param isFounder - Behaves as "founder" belief, Uniques processed globally for founding civ only
* */
enum class BeliefType(val color: String, val isFollower: Boolean = false, val isFounder: Boolean = false) {
None(""),
Pantheon("#44c6cc"),
Founder("#c00000"),
Follower("#ccaa44"),
Enhancer("#72cc45"),
Pantheon("#44c6cc", isFollower = true),
Founder("#c00000", isFounder = true),
Follower("#ccaa44", isFollower = true),
Enhancer("#72cc45", isFounder = true),
Any(""),
}

View File

@ -9,6 +9,7 @@ import com.unciv.models.ruleset.tile.TerrainType
import com.unciv.models.ruleset.unique.IHasUniques
import com.unciv.models.ruleset.unique.StateForConditionals
import com.unciv.models.ruleset.unique.Unique
import com.unciv.models.ruleset.unique.UniqueTarget
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.ruleset.unit.Promotion
import com.unciv.models.stats.INamed
@ -471,7 +472,7 @@ class RulesetValidator(val ruleset: Ruleset) {
severityToReport: UniqueType.UniqueComplianceErrorSeverity
): List<RulesetError> {
var name = namedObj?.name ?: ""
if (namedObj!=null && namedObj is IRulesetObject) name = "${namedObj.originRuleset}: $name"
if (namedObj != null && namedObj is IRulesetObject) name = "${namedObj.originRuleset}: $name"
if (unique.type == null) {
if (!tryFixUnknownUniques) return emptyList()
val similarUniques = UniqueType.values().filter {
@ -515,6 +516,9 @@ class RulesetValidator(val ruleset: Ruleset) {
val rulesetErrors = RulesetErrorList()
if (namedObj is IHasUniques && !unique.type.canAcceptUniqueTarget(namedObj.getUniqueTarget()))
rulesetErrors.add(RulesetError("$name's unique \"${unique.text}\" is not allowed on its target type", RulesetErrorSeverity.Warning))
val typeComplianceErrors = unique.type.getComplianceErrors(unique, ruleset)
for (complianceError in typeComplianceErrors) {
if (complianceError.errorSeverity <= severityToReport)
@ -533,6 +537,11 @@ class RulesetValidator(val ruleset: Ruleset) {
RulesetErrorSeverity.Warning
)
} else {
if (conditional.type.targetTypes.none { it.modifierType != UniqueTarget.ModifierType.None })
rulesetErrors.add("$name's unique \"${unique.text}\" contains the conditional \"${conditional.text}\"," +
" which is a Unique type not allowed as conditional or trigger.",
RulesetErrorSeverity.Warning)
val conditionalComplianceErrors =
conditional.type.getComplianceErrors(conditional, ruleset)
for (complianceError in conditionalComplianceErrors) {

View File

@ -44,9 +44,11 @@ class Unique(val text: String, val sourceObjectType: UniqueTarget? = null, val s
fun hasTriggerConditional(): Boolean {
if(conditionals.none()) return false
return conditionals.any{ conditional -> conditional.type?.targetTypes
?.any{ it.canAcceptUniqueTarget(UniqueTarget.TriggerCondition) || it.canAcceptUniqueTarget(UniqueTarget.UnitActionModifier) }
?: false
return conditionals.any { conditional ->
conditional.type?.targetTypes?.any {
it.canAcceptUniqueTarget(UniqueTarget.TriggerCondition) || it.canAcceptUniqueTarget(UniqueTarget.UnitActionModifier)
}
?: false
}
}
@ -134,8 +136,7 @@ class Unique(val text: String, val sourceObjectType: UniqueTarget? = null, val s
state: StateForConditionals
): Boolean {
val nonConditionalConditionTypes = setOf(UniqueTarget.TriggerCondition, UniqueTarget.UnitTriggerCondition, UniqueTarget.UnitActionModifier)
if (condition.type?.targetTypes?.any { it in nonConditionalConditionTypes } == true)
if (condition.type?.targetTypes?.any { it.modifierType == UniqueTarget.ModifierType.Other } == true)
return true // not a filtering condition
fun ruleset() = state.civInfo!!.gameInfo.ruleset

View File

@ -0,0 +1,9 @@
package com.unciv.models.ruleset.unique
enum class UniqueFlag {
HiddenToUsers,
;
companion object {
val setOfHiddenToUsers = listOf(HiddenToUsers)
}
}

View File

@ -0,0 +1,79 @@
package com.unciv.models.ruleset.unique
/**
* Expresses which RulesetObject types a UniqueType is applicable to.
*
* @param documentationString Copied to uniques.md by `UniqueDocsWriter`
* @param inheritsFrom means that all such uniques are acceptable as well. For example, all Global uniques are acceptable for Nations, Eras, etc.
*/
enum class UniqueTarget(
val documentationString:String = "",
val inheritsFrom: UniqueTarget? = null,
val modifierType: ModifierType = ModifierType.None
) {
/** Only includes uniques that have immediate effects, caused by UniqueTriggerActivation */
Triggerable("Uniques that have immediate, one-time effects. " +
"These can be added to techs to trigger when researched, to policies to trigger when adopted, " +
"to eras to trigger when reached, to buildings to trigger when built. " +
"Alternatively, you can add a TriggerCondition to them to make them into Global uniques that activate upon a specific event." +
"They can also be added to units to grant them the ability to trigger this effect as an action, " +
"which can be modified with UnitActionModifier and UnitTriggerCondition conditionals."),
UnitTriggerable("Uniques that have immediate, one-time effects on a unit." +
"They can be added to units (on unit, unit type, or promotion) to grant them the ability to trigger this effect as an action, " +
"which can be modified with UnitActionModifier and UnitTriggerCondition conditionals.", Triggerable),
Global("Uniques that apply globally. " +
"Civs gain the abilities of these uniques from nation uniques, reached eras, researched techs, adopted policies, " +
"built buildings, religion 'founder' uniques, owned resources, and ruleset-wide global uniques.", Triggerable),
// Civilization-specific
Nation(inheritsFrom = Global),
Era(inheritsFrom = Global),
Tech(inheritsFrom = Global),
Policy(inheritsFrom = Global),
FounderBelief("Uniques for Founder and Enhancer type Beliefs, that will apply to the founder of this religion", inheritsFrom = Global),
FollowerBelief("Uniques for Pantheon and Follower type beliefs, that will apply to each city where the religion is the majority religion"),
// City-specific
Building(inheritsFrom = Global),
Wonder(inheritsFrom = Building),
// Unit-specific
Unit("Uniques that can be added to units, unit types, or promotions", inheritsFrom = UnitTriggerable),
UnitType(inheritsFrom = Unit),
Promotion(inheritsFrom = Unit),
// Tile-specific
Terrain,
Improvement,
Resource(inheritsFrom = Global),
Ruins(inheritsFrom = UnitTriggerable),
// Other
Speed,
Tutorial,
CityState(inheritsFrom = Global),
ModOptions,
// Modifiers
Conditional("Modifiers that can be added to other uniques to limit when they will be active", modifierType = ModifierType.Conditional),
TriggerCondition("Special conditionals that can be added to Triggerable uniques, to make them activate upon specific actions.", inheritsFrom = Global, modifierType = ModifierType.Other),
UnitTriggerCondition("Special conditionals that can be added to UnitTriggerable uniques, to make them activate upon specific actions.", inheritsFrom = TriggerCondition, modifierType = ModifierType.Other),
UnitActionModifier("Modifiers that can be added to unit action uniques as conditionals", modifierType = ModifierType.Other),
;
/** Whether a UniqueType is allowed in the `<conditional or trigger>` part - or not.
* [None] ensures use *only* as leading Unique, [Conditional] / [Other] disallow use as leading Unique. */
enum class ModifierType { None, Conditional, Other }
/** Checks whether a specific UniqueTarget `this` as e.g. given by [IHasUniques.getUniqueTarget] works with [uniqueTarget] as e.g. declared in UniqueType */
// Building.canAcceptUniqueTarget(Global) == true
// Global.canAcceptUniqueTarget(Building) == false
fun canAcceptUniqueTarget(uniqueTarget: UniqueTarget): Boolean {
if (this == uniqueTarget) return true
if (inheritsFrom != null) return inheritsFrom.canAcceptUniqueTarget(uniqueTarget)
return false
}
}

View File

@ -6,86 +6,17 @@ import com.unciv.models.ruleset.RulesetErrorSeverity
import com.unciv.models.translations.getPlaceholderParameters
import com.unciv.models.translations.getPlaceholderText
/** inheritsFrom means that all such uniques are acceptable as well.
* For example, all Global uniques are acceptable for Nations, Eras, etc. */
enum class UniqueTarget(val documentationString:String = "", val inheritsFrom: UniqueTarget? = null) {
/** Only includes uniques that have immediate effects, caused by UniqueTriggerActivation */
Triggerable("Uniques that have immediate, one-time effects. " +
"These can be added to techs to trigger when researched, to policies to trigger when adpoted, " +
"to eras to trigger when reached, to buildings to trigger when built. " +
"Alternatively, you can add a TriggerCondition to them to make them into Global uniques that activate upon a specific event." +
"They can also be added to units to grant them the ability to trigger this effect as an action, " +
"which can be modified with UnitActionModifier and UnitTriggerCondition conditionals."),
UnitTriggerable("Uniques that have immediate, one-time effects on a unit." +
"They can be added to units (on unit, unit type, or promotion) to grant them the ability to trigger this effect as an action, " +
"which can be modified with UnitActionModifier and UnitTriggerCondition conditionals.", Triggerable),
Global("Uniques that apply globally. " +
"Civs gain the abilities of these uniques from nation uniques, reached eras, researched techs, adopted policies, " +
"built buildings, religion 'founder' uniques, owned resources, and ruleset-wide global uniques.", Triggerable),
// Civilization-specific
Nation(inheritsFrom = Global),
Era(inheritsFrom = Global),
Tech(inheritsFrom = Global),
Policy(inheritsFrom = Global),
FounderBelief("Uniques for Founder and Enhancer type Beliefs, that will apply to the founder of this religion", inheritsFrom = Global),
FollowerBelief("Uniques for Pantheon and Follower type beliefs, that will apply to each city where the religion is the majority religion"),
// City-specific
Building(inheritsFrom = Global),
Wonder(inheritsFrom = Building),
// Unit-specific
Unit("Uniques that can be added to units, unit types, or promotions", inheritsFrom = UnitTriggerable),
UnitType(inheritsFrom = Unit),
Promotion(inheritsFrom = Unit),
// Tile-specific
Terrain,
Improvement,
Resource(inheritsFrom = Global),
Ruins(inheritsFrom = UnitTriggerable),
// Other
Speed,
Tutorial,
CityState(inheritsFrom = Global),
ModOptions,
Conditional("Modifiers that can be added to other uniques to limit when they will be active"),
TriggerCondition("Special conditionals that can be added to Triggerable uniques, to make them activate upon specific actions.", inheritsFrom = Global),
UnitTriggerCondition("Special conditionals that can be added to UnitTriggerable uniques, to make them activate upon specific actions.", inheritsFrom = TriggerCondition),
UnitActionModifier("Modifiers that can be added to unit action uniques as conditionals"),
;
fun canAcceptUniqueTarget(uniqueTarget: UniqueTarget): Boolean {
if (this == uniqueTarget) return true
if (inheritsFrom != null) return inheritsFrom.canAcceptUniqueTarget(uniqueTarget)
return false
}
}
enum class UniqueFlag {
HiddenToUsers,
;
companion object {
val setOfHiddenToUsers = listOf(HiddenToUsers)
}
}
// I didn't put this in a companion object because APPARENTLY doing that means you can't use it in the init function.
val numberRegex = Regex("\\d+$") // Any number of trailing digits
private val numberRegex = Regex("\\d+$") // Any number of trailing digits
enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags: List<UniqueFlag> = emptyList()) {
//////////////////////////////////////// region GLOBAL UNIQUES ////////////////////////////////////////
//////////////////////////////////////// region 01 GLOBAL UNIQUES ////////////////////////////////////////
// region Stat providing uniques
// Used for *global* bonuses and improvement/terrain bonuses
Stats("[stats]", UniqueTarget.Global, UniqueTarget.FollowerBelief, UniqueTarget.Improvement, UniqueTarget.Terrain),
Stats("[stats]", UniqueTarget.Global, UniqueTarget.Improvement, UniqueTarget.Terrain),
// Used for city-wide bonuses
StatsPerCity("[stats] [cityFilter]", UniqueTarget.Global, UniqueTarget.FollowerBelief),
@ -121,8 +52,7 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
PercentProductionWonders("[relativeAmount]% Production when constructing [buildingFilter] wonders [cityFilter]", UniqueTarget.Global, UniqueTarget.FollowerBelief),
PercentProductionBuildingsInCapital("[relativeAmount]% Production towards any buildings that already exist in the Capital", UniqueTarget.Global, UniqueTarget.FollowerBelief),
//endregion Stat providing uniques
// endregion Stat providing uniques
// region City-State related uniques
@ -146,8 +76,8 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
CityStateResources("[relativeAmount]% resources gifted by City-States", UniqueTarget.Global),
CityStateLuxuryHappiness("[relativeAmount]% Happiness from luxury resources gifted by City-States", UniqueTarget.Global),
CityStateInfluenceRecoversTwiceNormalRate("City-State Influence recovers at twice the normal rate", UniqueTarget.Global),
// endregion
// endregion
/////// region Other global uniques
@ -314,13 +244,12 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
SpawnRebels("Rebel units may spawn", UniqueTarget.Global),
// endregion Other global uniques
//endregion
// endregion 01 Global uniques
//endregion Global uniques
///////////////////////////////////////// region CONSTRUCTION UNIQUES /////////////////////////////////////////
///////////////////////////////////////// region 02 CONSTRUCTION UNIQUES /////////////////////////////////////////
Unbuildable("Unbuildable", UniqueTarget.Building, UniqueTarget.Unit, UniqueTarget.Improvement),
CannotBePurchased("Cannot be purchased", UniqueTarget.Building, UniqueTarget.Unit),
@ -339,7 +268,7 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
TriggersAlertOnCompletion("Triggers a global alert upon completion", UniqueTarget.Building, UniqueTarget.Unit),
//endregion
///////////////////////////////////////// region BUILDING UNIQUES /////////////////////////////////////////
///////////////////////////////////////// region 03 BUILDING UNIQUES /////////////////////////////////////////
CostIncreasesPerCity("Cost increases by [amount] per owned city", UniqueTarget.Building),
@ -376,7 +305,7 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
CreatesOneImprovement("Creates a [improvementName] improvement on a specific tile", UniqueTarget.Building),
//endregion
///////////////////////////////////////// region UNIT UNIQUES /////////////////////////////////////////
///////////////////////////////////////// region 04 UNIT UNIQUES /////////////////////////////////////////
// Unit action uniques
// Unit actions should look like: "Can {action description}, to allow them to be combined with modifiers
@ -538,7 +467,7 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
//endregion
///////////////////////////////////////// region UNIT ACTION MODIFIERS /////////////////////////////////////////
///////////////////////////////////////// region 05 UNIT ACTION MODIFIERS /////////////////////////////////////////
UnitActionConsumeUnit("by consuming this unit", UniqueTarget.UnitActionModifier),
UnitActionMovementCost("for [amount] movement", UniqueTarget.UnitActionModifier),
@ -549,7 +478,7 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
// endregion
///////////////////////////////////////// region TILE UNIQUES /////////////////////////////////////////
///////////////////////////////////////// region 06 TILE UNIQUES /////////////////////////////////////////
// Natural wonders
NaturalWonderNeighborCount("Must be adjacent to [amount] [simpleTerrain] tiles", UniqueTarget.Terrain, flags = UniqueFlag.setOfHiddenToUsers),
@ -650,7 +579,7 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
AutomatedWorkersWillReplace("Will be replaced by automated workers", UniqueTarget.Improvement),
//endregion
///////////////////////////////////////// region CONDITIONALS /////////////////////////////////////////
///////////////////////////////////////// region 07 CONDITIONALS /////////////////////////////////////////
/////// general conditionals
@ -739,7 +668,7 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
//endregion
///////////////////////////////////////// region TRIGGERED ONE-TIME /////////////////////////////////////////
///////////////////////////////////////// region 08 TRIGGERED ONE-TIME /////////////////////////////////////////
OneTimeFreeUnit("Free [unit] appears", UniqueTarget.Triggerable), // used in Policies, Buildings
@ -789,7 +718,7 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
//endregion
///////////////////////////////////////// region TRIGGERS /////////////////////////////////////////
///////////////////////////////////////// region 09 TRIGGERS /////////////////////////////////////////
TriggerUponResearch("upon discovering [tech]", UniqueTarget.TriggerCondition),
TriggerUponEnteringEra("upon entering the [era]", UniqueTarget.TriggerCondition),
@ -813,7 +742,7 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
//endregion
///////////////////////////////////////// region UNIT TRIGGERS /////////////////////////////////////////
///////////////////////////////////////// region 10 UNIT TRIGGERS /////////////////////////////////////////
TriggerUponDefeatingUnit("upon defeating a [mapUnitFilter] unit", UniqueTarget.UnitTriggerCondition),
TriggerUponDefeat("upon being defeated", UniqueTarget.UnitTriggerCondition),
@ -823,7 +752,7 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
//endregion
///////////////////////////////////////////// region META /////////////////////////////////////////////
///////////////////////////////////////////// region 90 META /////////////////////////////////////////////
HiddenWithoutReligion("Hidden when religion is disabled", UniqueTarget.Unit, UniqueTarget.Building, UniqueTarget.Ruins, flags = UniqueFlag.setOfHiddenToUsers),
HiddenAfterGreatProphet("Hidden after generating a Great Prophet", UniqueTarget.Ruins),
@ -834,7 +763,7 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
// endregion
// region DEPRECATED AND REMOVED
///////////////////////////////////////////// region 99 DEPRECATED AND REMOVED /////////////////////////////////////////////
@Deprecated("as of 4.5.3", ReplaceWith("Empire enters a [amount]-turn Golden Age <by consuming this unit>"), DeprecationLevel.ERROR)
StartGoldenAge("Can start an [amount]-turn golden age", UniqueTarget.Unit),
@ -1184,9 +1113,9 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
@Deprecated("Extremely old - used for auto-updates only", ReplaceWith("[+50]% Strength for cities <with a garrison> <when attacking>"), DeprecationLevel.ERROR)
StrengthForGarrisonedCitiesAttackingDeprecated("+50% attacking strength for cities with garrisoned units", UniqueTarget.Global),
// endregion
// Keep the endregion after the semicolon or it won't work
;
// endregion
/** A map of allowed [UniqueParameterType]s per parameter position. Initialized from overridable function [parameterTypeMapInitializer]. */
val parameterTypeMap = parameterTypeMapInitializer()
@ -1203,7 +1132,8 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
}
return map
}
val targetTypes = HashSet<UniqueTarget>()
val targetTypes = HashSet<UniqueTarget>(targets.size)
init {
targetTypes.addAll(targets)
@ -1264,4 +1194,7 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
fun getDeprecationAnnotation(): Deprecated? = declaringJavaClass.getField(name)
.getAnnotation(Deprecated::class.java)
/** Checks whether a specific [uniqueTarget] as e.g. given by [IHasUniques.getUniqueTarget] works with `this` UniqueType */
fun canAcceptUniqueTarget(uniqueTarget: UniqueTarget) =
targetTypes.any { uniqueTarget.canAcceptUniqueTarget(it) }
}

View File

@ -57,9 +57,6 @@ class UniqueDocsWriter {
lines += "# Uniques"
lines += "Simple unique parameters are explained by mouseover. Complex parameters are explained in [Unique parameter types](../Unique-parameters)"
val conditionalLikeUniqueTargets = setOf(UniqueTarget.Conditional, UniqueTarget.TriggerCondition,
UniqueTarget.UnitTriggerCondition, UniqueTarget.UnitActionModifier)
for ((targetType, uniqueTypes) in targetTypesToUniques) {
if (uniqueTypes.isEmpty()) continue
lines += "## " + targetType.name + " uniques"
@ -70,7 +67,7 @@ class UniqueDocsWriter {
for (uniqueType in uniqueTypes) {
if (uniqueType.getDeprecationAnnotation() != null) continue
val uniqueText = if (targetType in conditionalLikeUniqueTargets)
val uniqueText = if (targetType.modifierType != UniqueTarget.ModifierType.None)
"&lt;${uniqueType.text}&gt;"
else uniqueType.text
lines += "??? example \"$uniqueText\"" // collapsable material mkdocs block, see https://squidfunk.github.io/mkdocs-material/reference/admonitions/?h=%3F%3F%3F#collapsible-blocks

View File

@ -3,7 +3,7 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
## Triggerable uniques
!!! note ""
Uniques that have immediate, one-time effects. These can be added to techs to trigger when researched, to policies to trigger when adpoted, to eras to trigger when reached, to buildings to trigger when built. Alternatively, you can add a TriggerCondition to them to make them into Global uniques that activate upon a specific event.They can also be added to units to grant them the ability to trigger this effect as an action, which can be modified with UnitActionModifier and UnitTriggerCondition conditionals.
Uniques that have immediate, one-time effects. These can be added to techs to trigger when researched, to policies to trigger when adopted, to eras to trigger when reached, to buildings to trigger when built. Alternatively, you can add a TriggerCondition to them to make them into Global uniques that activate upon a specific event.They can also be added to units to grant them the ability to trigger this effect as an action, which can be modified with UnitActionModifier and UnitTriggerCondition conditionals.
??? example "Free [unit] appears"
Example: "Free [Musketman] appears"
@ -165,7 +165,7 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
??? example "[stats]"
Example: "[+1 Gold, +2 Production]"
Applicable to: Global, FollowerBelief, Terrain, Improvement
Applicable to: Global, Terrain, Improvement
??? example "[stats] [cityFilter]"
Example: "[+1 Gold, +2 Production] [in all cities]"