diff --git a/android/assets/jsons/translations/template.properties b/android/assets/jsons/translations/template.properties index 15273b2b82..144b0489a9 100644 --- a/android/assets/jsons/translations/template.properties +++ b/android/assets/jsons/translations/template.properties @@ -1177,7 +1177,7 @@ Cities following this religion: = Click an icon to see the stats of this religion = Religion: Off = Minimal faith required for\nthe next [Great Prophet]: = -Religions founded: = +Religions to be founded: = Religious status: = None = diff --git a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt index 07d78fa219..6917f2a7aa 100644 --- a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt +++ b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt @@ -19,6 +19,7 @@ import com.unciv.models.ruleset.tile.ResourceSupplyList 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 @@ -142,12 +143,12 @@ class CivilizationInfo { /** See DiplomacyManager.flagsCountdown for why this does not map Enums to ints */ private var flagsCountdown = HashMap() - /** Arraylist instead of HashMap as there might be doubles - * Pairs of Uniques and the amount of turns they are still active - * If the counter reaches 0 at the end of a turn, it is removed immediately + + /** 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 */ - val temporaryUniques = ArrayList>() - + val temporaryUniques = ArrayList() + // if we only use lists, and change the list each time the cities are changed, // we won't get concurrent modification exceptions. // This is basically a way to ensure our lists are immutable. @@ -358,7 +359,7 @@ class CivilizationInfo { // Does not return local uniques, only global ones. /** Destined to replace getMatchingUniques, gradually, as we fill the enum */ fun getMatchingUniques(uniqueType: UniqueType, stateForConditionals: StateForConditionals? = null, cityToIgnore: CityInfo? = null) = sequence { - yieldAll(nation.uniqueObjects.asSequence().filter {it.isOfType(uniqueType) }) + yieldAll(nation.uniqueObjects.asSequence().filter { it.isOfType(uniqueType) }) yieldAll(cities.asSequence() .filter { it != cityToIgnore } .flatMap { city -> city.getMatchingUniquesWithNonLocalEffects(uniqueType) } @@ -366,7 +367,7 @@ class CivilizationInfo { yieldAll(policies.policyUniques.getUniques(uniqueType)) yieldAll(tech.techUniques.getUniques(uniqueType)) yieldAll(temporaryUniques.asSequence() - .map { it.first } + .map { it.uniqueObject } .filter { it.isOfType(uniqueType) } ) yieldAll(getEra().getMatchingUniques(uniqueType, stateForConditionals)) @@ -385,7 +386,8 @@ class CivilizationInfo { yieldAll(policies.policyUniques.getUniques(uniqueTemplate)) yieldAll(tech.techUniques.getUniques(uniqueTemplate)) yieldAll(temporaryUniques.asSequence() - .filter { it.first.placeholderText == uniqueTemplate }.map { it.first } + .map { it.uniqueObject } + .filter { it.placeholderText == uniqueTemplate } ) yieldAll(getEra().getMatchingUniques(uniqueTemplate).asSequence()) if (religionManager.religion != null) @@ -725,7 +727,7 @@ class CivilizationInfo { tech.setTransients() ruinsManager.setTransients(this) - + for (diplomacyManager in diplomacy.values) { diplomacyManager.civInfo = this diplomacyManager.updateHasOpenBorders() @@ -852,10 +854,10 @@ class CivilizationInfo { } // Update turn counter for temporary uniques - for (unique in temporaryUniques.toList()) { - temporaryUniques.remove(unique) - if (unique.second > 1) temporaryUniques.add(Pair(unique.first, unique.second - 1)) + for (unique in temporaryUniques) { + unique.turnsLeft -= 1 } + 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 0af9cdc1e2..d5a23ff0dc 100644 --- a/core/src/com/unciv/logic/civilization/PolicyManager.kt +++ b/core/src/com/unciv/logic/civilization/PolicyManager.kt @@ -28,7 +28,11 @@ class PolicyManager { var shouldOpenPolicyPicker = false get() = field && canAdoptPolicy() - + // Only instantiate a single value for all policy managers + companion object { + private val turnCountRegex by lazy { Regex("for \\[[0-9]*\\] turns") } + } + fun clone(): PolicyManager { val toReturn = PolicyManager() toReturn.numberOfAdoptedPolicies = numberOfAdoptedPolicies @@ -47,8 +51,11 @@ class PolicyManager { } fun addPolicyToTransients(policy: Policy) { - for (unique in policy.uniqueObjects) - policyUniques.addUnique(unique) + for (unique in policy.uniqueObjects) { + // Should be replaced with a conditional of the same form later + if (!unique.text.contains(turnCountRegex)) + policyUniques.addUnique(unique) + } } fun addCulture(culture: Int) { diff --git a/core/src/com/unciv/models/ruleset/unique/Unique.kt b/core/src/com/unciv/models/ruleset/unique/Unique.kt index 5bfb4079ce..171a94c482 100644 --- a/core/src/com/unciv/models/ruleset/unique/Unique.kt +++ b/core/src/com/unciv/models/ruleset/unique/Unique.kt @@ -88,16 +88,16 @@ class Unique(val text: String, val sourceObjectType: UniqueTarget? = null, val s UniqueType.ConditionalBelowHP -> state.ourCombatant != null && state.ourCombatant.getHealth() < condition.params[0].toInt() UniqueType.ConditionalInTiles -> - (state.attackedTile != null && state.attackedTile.matchesFilter(condition.params[0])) - || (state.unit != null && state.unit.getTile().matchesFilter(condition.params[0])) + (state.attackedTile != null && state.attackedTile.matchesFilter(condition.params[0], state.civInfo)) + || (state.unit != null && state.unit.getTile().matchesFilter(condition.params[0], state.civInfo)) UniqueType.ConditionalFightingInTiles -> - state.attackedTile != null && state.attackedTile.matchesFilter(condition.params[0]) + state.attackedTile != null && state.attackedTile.matchesFilter(condition.params[0], state.civInfo) UniqueType.ConditionalInTilesAnd -> - (state.attackedTile != null && state.attackedTile.matchesFilter(condition.params[0]) && state.attackedTile.matchesFilter(condition.params[1])) - || (state.unit != null && state.unit.getTile().matchesFilter(condition.params[0]) && state.unit.getTile().matchesFilter(condition.params[1])) + (state.attackedTile != null && state.attackedTile.matchesFilter(condition.params[0], state.civInfo) && state.attackedTile.matchesFilter(condition.params[1], state.civInfo)) + || (state.unit != null && state.unit.getTile().matchesFilter(condition.params[0], state.civInfo) && state.unit.getTile().matchesFilter(condition.params[1], state.civInfo)) UniqueType.ConditionalInTilesNot -> - state.attackedTile != null && !state.attackedTile.matchesFilter(condition.params[0]) - || (state.unit != null && !state.unit.getTile().matchesFilter(condition.params[0])) + state.attackedTile != null && !state.attackedTile.matchesFilter(condition.params[0], state.civInfo) + || (state.unit != null && !state.unit.getTile().matchesFilter(condition.params[0], state.civInfo)) UniqueType.ConditionalVsLargerCiv -> { val yourCities = state.civInfo?.cities?.size ?: 1 val theirCities = state.theirCombatant?.getCivInfo()?.cities?.size ?: 0 @@ -159,4 +159,21 @@ class UniqueMapTyped: EnumMap>(UniqueType::class.j fun getUniques(uniqueType: UniqueType): Sequence = this[uniqueType]?.asSequence() ?: sequenceOf() +} + + +// 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() { + unique = uniqueObject.text + turnsLeft = turns + } + + var unique: String = "" + + @delegate:Transient + val uniqueObject: Unique by lazy { Unique(unique) } + + var turnsLeft: Int = 0 } \ No newline at end of file diff --git a/core/src/com/unciv/models/ruleset/unique/UniqueTriggerActivation.kt b/core/src/com/unciv/models/ruleset/unique/UniqueTriggerActivation.kt index cf198ff3bb..3bb31ef9b4 100644 --- a/core/src/com/unciv/models/ruleset/unique/UniqueTriggerActivation.kt +++ b/core/src/com/unciv/models/ruleset/unique/UniqueTriggerActivation.kt @@ -246,7 +246,8 @@ object UniqueTriggerActivation { } TimedAttackStrength -> { - civInfo.temporaryUniques.add(Pair(unique, unique.params[2].toInt())) + val temporaryUnique = TemporaryUnique(unique, unique.params[2].toInt()) + civInfo.temporaryUniques.add(temporaryUnique) if (notification != null) { civInfo.addNotification(notification, NotificationIcon.War) } diff --git a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt index d72812f2e1..433de055a2 100644 --- a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt +++ b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt @@ -451,7 +451,8 @@ enum class UniqueType(val text:String, vararg targets: UniqueTarget, val flags: // todo: remove forced sign StrategicResourcesIncrease("Quantity of strategic resources produced by the empire +[amount]%", UniqueTarget.Global), // used in Policy // todo: remove forced sign - TimedAttackStrength("+[amount]% attack strength to all [mapUnitFilter] Units for [amount] turns", UniqueTarget.Global), // used in Policy + // todo: convert to "[amount]% Strength " + TimedAttackStrength("+[amount]% attack strength to all [mapUnitFilter] units for [amount] 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 diff --git a/core/src/com/unciv/ui/overviewscreen/ReligionOverviewTable.kt b/core/src/com/unciv/ui/overviewscreen/ReligionOverviewTable.kt index 41cf905bb2..7dadc2a381 100644 --- a/core/src/com/unciv/ui/overviewscreen/ReligionOverviewTable.kt +++ b/core/src/com/unciv/ui/overviewscreen/ReligionOverviewTable.kt @@ -57,7 +57,7 @@ class ReligionOverviewTable( ).right().pad(5f).row() } - statsTable.add("Religions founded:".toLabel()).left() + statsTable.add("Religions to be founded:".toLabel()).left() val foundedReligions = viewingPlayer.gameInfo.civilizations.count { it.religionManager.religionState >= ReligionState.Religion } statsTable.add((viewingPlayer.religionManager.amountOfFoundableReligions() - foundedReligions).toLabel()).right().pad(5f).row() diff --git a/docs/uniques.md b/docs/uniques.md index 722e5f60fe..c2bfe7d8b8 100644 --- a/docs/uniques.md +++ b/docs/uniques.md @@ -334,8 +334,8 @@ 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" +#### +[amount]% attack strength to all [mapUnitFilter] units for [amount] turns +Example: "+[20]% attack strength to all [Wounded] units for [20] turns" Applicable to: Global