Arbitrary conditionals can become timed conditionals! (#6134)

* Arbitrary conditionals can become timed conditionals!
triggerCivwideUniques is activated in 3 situations:
- Tech complete
- Policy adopted
- Building complete

So for each of the unique containers for these I added a catch saying 'if this unique is a temporary unique then don't save it yourself

This has been lying around in todos for a while and generalizes one of the nasty hardcoded messes that I hate about Civ V. Why would you introduce ONE timed effect in the whole game?! You can use them all the time like Humankind or never use them like Civ IV, but why have just one whyyy

One more thing in this PR, that needed to be solved by the by, is allowing parameters to have a '2' on the end so we can autoreplace multiple parameters of the same type.
Using a regex is slightly more inefficient, but since this is A. only used once per UniqueType.kt, and B. allows us to have as many 'amount's as we want which is important if we have a lot of conditionals, I feel this is justified.

* Fixed comments from PR
This commit is contained in:
Yair Morgenstern 2022-02-12 19:03:11 +02:00 committed by GitHub
parent 55d92b9735
commit 4fb4722e3a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 37 additions and 19 deletions

View File

@ -407,7 +407,8 @@
},
{
"name": "Autocracy Complete",
"uniques": ["+[25]% attack strength to all [Military] units for [50] turns",
"uniques": [
"[+25]% Strength <when attacking> <for [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] at an increasing price ([500]) <starting from the [Industrial era]>",
"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]) <starting from the [Industrial era]>"
]

View File

@ -400,7 +400,7 @@
},
{
"name": "Autocracy Complete",
"uniques": ["+[25]% attack strength to all [Military] units for [30] turns"]
"uniques": ["[+25]% Strength <when attacking> <for [Military] units> <for [30] turns>"]
}
]
},

View File

@ -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)
}
/**

View File

@ -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<TemporaryUnique>()
@ -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

View File

@ -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)
}
}

View File

@ -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() {

View File

@ -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, ArrayList<Unique>>(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() {

View File

@ -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 -> {

View File

@ -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 <when attacking> <for [baseUnitFilter] units> <for [amount] turns>"
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 <when attacking> <for [mapUnitFilter] units> <for [amount2] turns>"))
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.

View File

@ -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: "<before adopting [Oligarchy]>"
Applicable to: Conditional
#### <for [amount turns>
Example: "<for [amount turns>"
Applicable to: Conditional
#### <if this city has at least [amount] specialists>
Example: "<if this city has at least [20] specialists>"
@ -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 <in [tileFilter] tiles>"
- "Melee units pay no movement cost to pillage" - Deprecated as of 3.18.17, replace with "No movement cost to pillage <for [Melee] units>"
- "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 <when attacking> <for [mapUnitFilter] units> <for [amount2] turns>"
- "[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]>"
- "[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>"