diff --git a/android/assets/jsons/Civ V - Gods & Kings/Policies.json b/android/assets/jsons/Civ V - Gods & Kings/Policies.json index 8a261c1fdf..31b6edc79b 100644 --- a/android/assets/jsons/Civ V - Gods & Kings/Policies.json +++ b/android/assets/jsons/Civ V - Gods & Kings/Policies.json @@ -407,7 +407,8 @@ }, { "name": "Autocracy Complete", - "uniques": ["+[25]% attack strength to all [Military] units for [50] turns", + "uniques": [ + "[+25]% Strength ", "May buy [Great General] units for [1000] [Faith] [in all cities in which the majority religion is a major religion] 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] at an increasing price ([500]) " ] diff --git a/android/assets/jsons/Civ V - Vanilla/Policies.json b/android/assets/jsons/Civ V - Vanilla/Policies.json index 7310d0fe0e..ee445ecc8a 100644 --- a/android/assets/jsons/Civ V - Vanilla/Policies.json +++ b/android/assets/jsons/Civ V - Vanilla/Policies.json @@ -400,7 +400,7 @@ }, { "name": "Autocracy Complete", - "uniques": ["+[25]% attack strength to all [Military] units for [30] turns"] + "uniques": ["[+25]% Strength "] } ] }, diff --git a/core/src/com/unciv/logic/city/CityConstructions.kt b/core/src/com/unciv/logic/city/CityConstructions.kt index f0e523f486..121d0fee08 100644 --- a/core/src/com/unciv/logic/city/CityConstructions.kt +++ b/core/src/com/unciv/logic/city/CityConstructions.kt @@ -462,7 +462,8 @@ class CityConstructions { builtBuildingUniqueMap.clear() for (building in getBuiltBuildings()) for (unique in building.uniqueObjects) - builtBuildingUniqueMap.addUnique(unique) + if (unique.conditionals.none { it.type == UniqueType.ConditionalTimedUnique }) + builtBuildingUniqueMap.addUnique(unique) } /** diff --git a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt index 2a69b030d4..d0c9a66cb1 100644 --- a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt +++ b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt @@ -21,7 +21,6 @@ import com.unciv.models.ruleset.tile.ResourceType import com.unciv.models.ruleset.tile.TileResource import com.unciv.models.ruleset.unique.StateForConditionals import com.unciv.models.ruleset.unique.TemporaryUnique -import com.unciv.models.ruleset.unique.Unique import com.unciv.models.ruleset.unique.UniqueType import com.unciv.models.ruleset.unit.BaseUnit import com.unciv.models.stats.Stat @@ -150,6 +149,7 @@ class CivilizationInfo { /** Arraylist instead of HashMap as the same unique might appear multiple times * We don't use pairs, as these cannot be serialized due to having no no-arg constructor + * This can also contain NON-temporary uniques but I can't be bothered to do the deprecation dance with this one */ val temporaryUniques = ArrayList() @@ -864,9 +864,10 @@ class CivilizationInfo { // Update turn counter for temporary uniques for (unique in temporaryUniques) { - unique.turnsLeft -= 1 + if (unique.turnsLeft >= 0) + unique.turnsLeft -= 1 } - temporaryUniques.removeAll { it.turnsLeft <= 0 } + temporaryUniques.removeAll { it.turnsLeft == 0 } goldenAges.endTurn(getHappiness()) getCivUnits().forEach { it.endTurn() } // This is the most expensive part of endTurn diff --git a/core/src/com/unciv/logic/civilization/PolicyManager.kt b/core/src/com/unciv/logic/civilization/PolicyManager.kt index c245201a21..434ee5d5c7 100644 --- a/core/src/com/unciv/logic/civilization/PolicyManager.kt +++ b/core/src/com/unciv/logic/civilization/PolicyManager.kt @@ -54,8 +54,9 @@ class PolicyManager { fun addPolicyToTransients(policy: Policy) { for (unique in policy.uniqueObjects) { - // Should be replaced with a conditional of the same form later - if (!unique.text.contains(turnCountRegex)) + // Should be deprecated together with TimedAttackStrength so I'm putting this here so the compiler will complain if we don't + val rememberToDeprecate = UniqueType.TimedAttackStrength + if (!unique.text.contains(turnCountRegex) && unique.conditionals.none { it.type == UniqueType.ConditionalTimedUnique }) policyUniques.addUnique(unique) } } diff --git a/core/src/com/unciv/logic/civilization/TechManager.kt b/core/src/com/unciv/logic/civilization/TechManager.kt index 73ce340473..ab6e051d38 100644 --- a/core/src/com/unciv/logic/civilization/TechManager.kt +++ b/core/src/com/unciv/logic/civilization/TechManager.kt @@ -365,7 +365,8 @@ class TechManager { fun addTechToTransients(tech: Technology) { for (unique in tech.uniqueObjects) - techUniques.addUnique(unique) + if (unique.conditionals.none { it.type == UniqueType.ConditionalTimedUnique }) + techUniques.addUnique(unique) } fun setTransients() { diff --git a/core/src/com/unciv/models/ruleset/unique/Unique.kt b/core/src/com/unciv/models/ruleset/unique/Unique.kt index cadcbdc1a5..1b41928493 100644 --- a/core/src/com/unciv/models/ruleset/unique/Unique.kt +++ b/core/src/com/unciv/models/ruleset/unique/Unique.kt @@ -85,6 +85,7 @@ class Unique(val text: String, val sourceObjectType: UniqueTarget? = null, val s } return when (condition.type) { + UniqueType.ConditionalTimedUnique -> true UniqueType.ConditionalWar -> state.civInfo?.isAtWar() == true UniqueType.ConditionalNotWar -> state.civInfo?.isAtWar() == false UniqueType.ConditionalWithResource -> state.civInfo?.hasResource(condition.params[0]) == true @@ -224,7 +225,6 @@ class UniqueMapTyped: EnumMap>(UniqueType::class.j } -// Will probably be allowed to be used as a conditional when I get the motivation to work on that -xlenstra class TemporaryUnique() { constructor(uniqueObject: Unique, turns: Int) : this() { diff --git a/core/src/com/unciv/models/ruleset/unique/UniqueTriggerActivation.kt b/core/src/com/unciv/models/ruleset/unique/UniqueTriggerActivation.kt index 269da92e8d..f2a97a8d68 100644 --- a/core/src/com/unciv/models/ruleset/unique/UniqueTriggerActivation.kt +++ b/core/src/com/unciv/models/ruleset/unique/UniqueTriggerActivation.kt @@ -31,6 +31,12 @@ object UniqueTriggerActivation { if (!unique.conditionalsApply(StateForConditionals(civInfo, cityInfo))) return false + val timingConditional = unique.conditionals.firstOrNull{it.type == ConditionalTimedUnique} + if (timingConditional!=null) { + civInfo.temporaryUniques.add(TemporaryUnique(unique, timingConditional.params[0].toInt())) + return true + } + @Suppress("NON_EXHAUSTIVE_WHEN") // Yes we're not treating all types here when (unique.type) { OneTimeFreeUnit -> { diff --git a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt index 8b1d3ab454..52b8998f0e 100644 --- a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt +++ b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt @@ -548,6 +548,8 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags: ConditionalPolicy("after adopting [policy]", UniqueTarget.Conditional), ConditionalNoPolicy("before adopting [policy]", UniqueTarget.Conditional), + ConditionalTimedUnique("for [amount] turns", UniqueTarget.Conditional), + /////// 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), @@ -614,9 +616,9 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags: UnitsGainPromotion("[mapUnitFilter] units gain the [promotion] promotion", UniqueTarget.Global), // Not used in Vanilla // todo: remove forced sign StrategicResourcesIncrease("Quantity of strategic resources produced by the empire +[amount]%", UniqueTarget.Global), // used in Policy - // todo: remove forced sign - // todo: convert to "[amount]% Strength " - TimedAttackStrength("+[amount]% attack strength to all [mapUnitFilter] units for [amount] turns", UniqueTarget.Global), // used in Policy + + @Deprecated("as of 3.19.8", ReplaceWith("[+amount]% Strength ")) + TimedAttackStrength("+[amount]% attack strength to all [mapUnitFilter] units for [amount2] turns", UniqueTarget.Global), // used in Policy FreeStatBuildings("Provides the cheapest [stat] building in your first [amount] cities for free", UniqueTarget.Global), // used in Policy FreeSpecificBuildings("Provides a [buildingName] in your first [amount] cities for free", UniqueTarget.Global), // used in Policy @@ -811,7 +813,7 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags: for (placeholder in text.getPlaceholderParameters()) { val matchingParameterTypes = placeholder .split('/') - .map { UniqueParameterType.safeValueOf(it) } + .map { UniqueParameterType.safeValueOf(it.replace(numberRegex, "")) } parameterTypeMap.add(matchingParameterTypes) } targetTypes.addAll(targets) @@ -854,5 +856,9 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags: fun getDeprecationAnnotation(): Deprecated? = declaringClass.getField(name) .getAnnotation(Deprecated::class.java) + } +// I didn't put this is a companion object because APPARENTLY doing that means you can't use it in the init function. +val numberRegex = Regex("\\d") // I really doubt we'll get to double-digit numbers of parameters in a single unique. + diff --git a/docs/uniques.md b/docs/uniques.md index f3b366357e..a4906289cb 100644 --- a/docs/uniques.md +++ b/docs/uniques.md @@ -624,11 +624,6 @@ Example: "Quantity of strategic resources produced by the empire +[20]%" Applicable to: Global -#### +[amount]% attack strength to all [mapUnitFilter] units for [amount] turns -Example: "+[20]% attack strength to all [Wounded] units for [20] turns" - -Applicable to: Global - #### Provides the cheapest [stat] building in your first [amount] cities for free Example: "Provides the cheapest [Culture] building in your first [20] cities for free" @@ -1351,6 +1346,11 @@ Example: "" Applicable to: Conditional +#### +Example: "" + +Applicable to: Conditional + #### Example: "" @@ -1481,6 +1481,7 @@ Applicable to: Conditional - "[amount] HP when healing in [tileFilter] tiles" - Deprecated as of 3.19.4, replace with "[amount] HP when healing " - "Melee units pay no movement cost to pillage" - Deprecated as of 3.18.17, replace with "No movement cost to pillage " - "Heal adjacent units for an additional 15 HP per turn" - Deprecated as of 3.19.3, replace with "All adjacent units heal [+15] HP when healing" + - "+[amount]% attack strength to all [mapUnitFilter] units for [amount2] turns" - Deprecated as of 3.19.8, replace with "[+amount]% Strength " - "[stats] per turn from cities before [tech/policy]" - Deprecated as of 3.18.14, replace with "[stats] [in all cities] OR [stats] [in all cities] " - "[mapUnitFilter] units gain [amount]% more Experience from combat" - Deprecated as of 3.18.12, replace with "[amount]% XP gained from combat " - "[amount]% maintenance costs for [mapUnitFilter] units" - Deprecated as of 3.18.14, replace with "[amount]% maintenance costs "