diff --git a/android/assets/jsons/Civ V - Gods & Kings/Nations.json b/android/assets/jsons/Civ V - Gods & Kings/Nations.json index b9fb2c6db0..1394a34674 100644 --- a/android/assets/jsons/Civ V - Gods & Kings/Nations.json +++ b/android/assets/jsons/Civ V - Gods & Kings/Nations.json @@ -92,7 +92,8 @@ "favouredReligion": "Taoism", "uniqueName": "Art of War", - "uniques": ["Great General provides double combat bonus", "[Great General] is earned [50]% faster"], + "uniques": ["Great General provides double combat bonus", "[Great General] is earned [50]% faster", + "Gain [1000] [Faith] "], "cities": ["Beijing","Shanghai","Guangzhou","Nanjing","Xian","Chengdu","Hangzhou","Tianjin","Macau","Shandong", "Kaifeng","Ningbo","Baoding","Yangzhou","Harbin","Chongqing","Luoyang","Kunming","Taipei","Shenyang", "Taiyuan","Tainan","Dalian","Lijiang","Wuxi","Suzhou","Maoming","Shaoguan","Yangjiang","Heyuan","Huangshi", diff --git a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt index f6146e7cb4..9ddd5c9131 100644 --- a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt +++ b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt @@ -486,6 +486,17 @@ class CivilizationInfo : IsPartOfGameInfoSerialization { yieldAll(gameInfo.ruleSet.globalUniques.getMatchingUniques(uniqueType, stateForConditionals)) } + fun getTriggeredUniques(trigger: UniqueType, stateForConditionals: StateForConditionals = StateForConditionals(this)) : Sequence = sequence{ + yieldAll(nation.uniqueMap.getTriggeredUniques(trigger, stateForConditionals)) + yieldAll(cities.asSequence() + .flatMap { city -> city.cityConstructions.builtBuildingUniqueMap.getTriggeredUniques(trigger, stateForConditionals) } + ) + yieldAll(policies.policyUniques.getTriggeredUniques(trigger, stateForConditionals)) + yieldAll(tech.techUniques.getTriggeredUniques(trigger, stateForConditionals)) + yieldAll(getEra().uniqueMap.getTriggeredUniques (trigger, stateForConditionals)) + yieldAll(gameInfo.ruleSet.globalUniques.uniqueMap.getTriggeredUniques(trigger, stateForConditionals)) + } + //region Units fun getCivUnitsSize(): Int = units.size diff --git a/core/src/com/unciv/logic/civilization/TechManager.kt b/core/src/com/unciv/logic/civilization/TechManager.kt index 05541ab6da..214079d4bf 100644 --- a/core/src/com/unciv/logic/civilization/TechManager.kt +++ b/core/src/com/unciv/logic/civilization/TechManager.kt @@ -342,6 +342,11 @@ class TechManager : IsPartOfGameInfoSerialization { for (unique in era.uniqueObjects) UniqueTriggerActivation.triggerCivwideUnique(unique, civInfo) } + + val triggerableUniques = civInfo.getTriggeredUniques(UniqueType.TriggerUponResearch) + for (unique in triggerableUniques) + if (unique.conditionals.any {it.type == UniqueType.TriggerUponResearch && it.params[0] == techName}) + UniqueTriggerActivation.triggerCivwideUnique(unique, civInfo) } fun updateEra() { diff --git a/core/src/com/unciv/models/Religion.kt b/core/src/com/unciv/models/Religion.kt index 91233f3b00..aae823e9a8 100644 --- a/core/src/com/unciv/models/Religion.kt +++ b/core/src/com/unciv/models/Religion.kt @@ -86,8 +86,7 @@ class Religion() : INamed, IsPartOfGameInfoSerialization { } private fun getUniquesOfBeliefs(beliefs: HashSet): Sequence { - val result = mapToExistingBeliefs(beliefs).asSequence().flatMap { it.uniqueObjects } - return result + return mapToExistingBeliefs(beliefs).asSequence().flatMap { it.uniqueObjects } } fun getFollowerUniques() = getUniquesOfBeliefs(followerBeliefs) diff --git a/core/src/com/unciv/models/ruleset/RulesetObject.kt b/core/src/com/unciv/models/ruleset/RulesetObject.kt index 7aba378231..735c32e2b5 100644 --- a/core/src/com/unciv/models/ruleset/RulesetObject.kt +++ b/core/src/com/unciv/models/ruleset/RulesetObject.kt @@ -2,6 +2,7 @@ package com.unciv.models.ruleset import com.unciv.models.ruleset.unique.IHasUniques import com.unciv.models.ruleset.unique.Unique +import com.unciv.models.ruleset.unique.UniqueMap import com.unciv.models.stats.INamed import com.unciv.models.stats.NamedStats import com.unciv.ui.civilopedia.FormattedLine @@ -18,10 +19,13 @@ abstract class RulesetObject: IRulesetObject { else uniques.map { Unique(it, getUniqueTarget(), name) } } @delegate:Transient - override val uniqueMap: Map> by lazy { - if (uniques.isEmpty()) emptyMap() - else uniqueObjects.groupBy { it.placeholderText } + override val uniqueMap: UniqueMap by lazy { + if (uniques.isEmpty()) UniqueMap() + val newUniqueMap = UniqueMap() + newUniqueMap.addUniques(uniqueObjects) + newUniqueMap } + override var civilopediaText = listOf() override fun toString() = name } @@ -39,5 +43,6 @@ abstract class RulesetStatsObject: NamedStats(), IRulesetObject { if (uniques.isEmpty()) emptyMap() else uniqueObjects.groupBy { it.placeholderText } } + override var civilopediaText = listOf() } diff --git a/core/src/com/unciv/models/ruleset/unique/Unique.kt b/core/src/com/unciv/models/ruleset/unique/Unique.kt index 59990f2a94..ec560c7d6d 100644 --- a/core/src/com/unciv/models/ruleset/unique/Unique.kt +++ b/core/src/com/unciv/models/ruleset/unique/Unique.kt @@ -125,6 +125,9 @@ class Unique(val text: String, val sourceObjectType: UniqueTarget? = null, val s state: StateForConditionals ): Boolean { + if (condition.type!!.targetTypes.contains(UniqueTarget.TriggerCondition)) + return true // not a filtering condition + fun ruleset() = state.civInfo!!.gameInfo.ruleSet val relevantUnit by lazy { @@ -322,6 +325,10 @@ class UniqueMap: HashMap>() { .filter { it.conditionalsApply(state) } fun getAllUniques() = this.asSequence().flatMap { it.value.asSequence() } + + fun getTriggeredUniques(trigger: UniqueType, stateForConditionals: StateForConditionals) = + getAllUniques().filter { it.conditionals.any { it.type == trigger } } + .filter { it.conditionalsApply(stateForConditionals) } } diff --git a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt index 216db8bca8..af50092e15 100644 --- a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt +++ b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt @@ -50,7 +50,7 @@ enum class UniqueTarget(val inheritsFrom: UniqueTarget? = null) { CityState(Global), ModOptions, Conditional, - TriggerCondition + TriggerCondition(Global) ; fun canAcceptUniqueTarget(uniqueTarget: UniqueTarget): Boolean { @@ -696,6 +696,13 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags: //endregion + + ///////////////////////////////////////// region TRIGGERS ///////////////////////////////////////// + + TriggerUponResearch("upon discovering [tech]", UniqueTarget.TriggerCondition), + + //endregion + ///////////////////////////////////////////// region META ///////////////////////////////////////////// HiddenWithoutReligion("Hidden when religion is disabled", UniqueTarget.Unit, UniqueTarget.Building, UniqueTarget.Ruins, flags = UniqueFlag.setOfHiddenToUsers), diff --git a/docs/Modders/uniques.md b/docs/Modders/uniques.md index 0797f3fd2e..a235fd23ff 100644 --- a/docs/Modders/uniques.md +++ b/docs/Modders/uniques.md @@ -30,6 +30,11 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl Applicable to: Triggerable +??? example "[amount] population in a random city" + Example: "[3] population in a random city" + + Applicable to: Triggerable + ??? example "Free Technology" Applicable to: Triggerable @@ -38,6 +43,11 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl Applicable to: Triggerable +??? example "[amount] free random researchable Tech(s) from the [era]" + Example: "[3] free random researchable Tech(s) from the [Ancient era]" + + Applicable to: Triggerable + ??? example "Reveals the entire map" Applicable to: Triggerable @@ -49,6 +59,24 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl ??? example "Triggers voting for the Diplomatic Victory" Applicable to: Triggerable +??? example "Gain [amount] [stat]" + Example: "Gain [3] [Culture]" + + Applicable to: Triggerable + +??? example "Gain [amount]-[amount] [stat]" + Example: "Gain [3]-[3] [Culture]" + + Applicable to: Triggerable + +??? example "Gain enough Faith for a Pantheon" + Applicable to: Triggerable + +??? example "Gain enough Faith for [amount]% of a Great Prophet" + Example: "Gain enough Faith for [3]% of a Great Prophet" + + Applicable to: Triggerable + ??? example "This Unit gains the [promotion] promotion" Example: "This Unit gains the [Shock I] promotion" @@ -70,7 +98,7 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl Applicable to: Triggerable ??? example "Will not be displayed in Civilopedia" - Applicable to: Triggerable, Global, Nation, Era, Tech, Policy, FounderBelief, FollowerBelief, Building, Wonder, Unit, UnitType, Promotion, Terrain, Improvement, Resource, Ruins, Speed, Tutorial, CityState, ModOptions, Conditional + Applicable to: Triggerable, Global, Nation, Era, Tech, Policy, FounderBelief, FollowerBelief, Building, Wonder, Unit, UnitType, Promotion, Terrain, Improvement, Resource, Ruins, Speed, Tutorial, CityState, ModOptions, Conditional, TriggerCondition ## Global uniques ??? example "[stats]" @@ -1579,34 +1607,6 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl Applicable to: Ruins -??? example "[amount] population in a random city" - Example: "[3] population in a random city" - - Applicable to: Ruins - -??? example "[amount] free random researchable Tech(s) from the [era]" - Example: "[3] free random researchable Tech(s) from the [Ancient era]" - - Applicable to: Ruins - -??? example "Gain [amount] [stat]" - Example: "Gain [3] [Culture]" - - Applicable to: Ruins - -??? example "Gain [amount]-[amount] [stat]" - Example: "Gain [3]-[3] [Culture]" - - Applicable to: Ruins - -??? example "Gain enough Faith for a Pantheon" - Applicable to: Ruins - -??? example "Gain enough Faith for [amount]% of a Great Prophet" - Example: "Gain enough Faith for [3]% of a Great Prophet" - - Applicable to: Ruins - ??? example "Reveal up to [amount/'all'] [tileFilter] within a [amount] tile radius" Example: "Reveal up to [3] [Farm] within a [3] tile radius" @@ -1869,6 +1869,12 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl Applicable to: Conditional +## TriggerCondition uniques +??? example "upon discovering [tech]" + Example: "upon discovering [Agriculture]" + + Applicable to: TriggerCondition + *[action]: An action that a unit can perform. Currently, there are only two actions part of this: 'Spread Religion' and 'Remove Foreign religions from your own cities' *[amount]: This indicates a whole number, possibly with a + or - sign, such as `2`, `+13`, or `-3`.