diff --git a/core/src/com/unciv/logic/battle/BattleDamage.kt b/core/src/com/unciv/logic/battle/BattleDamage.kt index 797af6bca2..0d304720f0 100644 --- a/core/src/com/unciv/logic/battle/BattleDamage.kt +++ b/core/src/com/unciv/logic/battle/BattleDamage.kt @@ -209,7 +209,7 @@ object BattleDamage { private fun getTileSpecificModifiers(unit: MapUnitCombatant, tile: TileInfo): Counter { val modifiers = Counter() - for (unique in unit.getCivInfo().getMatchingUniques("+[]% Strength if within [] tiles of a []")) { + for (unique in unit.getCivInfo().getMatchingUniques(UniqueType.StrengthWithinTilesOfTile)) { if (tile.getTilesInDistance(unique.params[1].toInt()) .any { it.matchesFilter(unique.params[2]) } ) diff --git a/core/src/com/unciv/logic/city/CityInfo.kt b/core/src/com/unciv/logic/city/CityInfo.kt index 18cbad3fd2..61a254f2ca 100644 --- a/core/src/com/unciv/logic/city/CityInfo.kt +++ b/core/src/com/unciv/logic/city/CityInfo.kt @@ -442,9 +442,9 @@ class CityInfo { if (!civInfo.getDiplomacyManager(otherCiv).hasFlag(DiplomacyFlags.DeclarationOfFriendship)) continue - for (ourUnique in civInfo.getMatchingUniques("When declaring friendship, both parties gain a []% boost to great person generation")) + for (ourUnique in civInfo.getMatchingUniques(UniqueType.GreatPersonBoostWithFriendship)) allGppPercentageBonus += ourUnique.params[0].toInt() - for (theirUnique in otherCiv.getMatchingUniques("When declaring friendship, both parties gain a []% boost to great person generation")) + for (theirUnique in otherCiv.getMatchingUniques(UniqueType.GreatPersonBoostWithFriendship)) allGppPercentageBonus += theirUnique.params[0].toInt() } @@ -837,13 +837,6 @@ class CityInfo { } } - // Get all matching uniques that don't apply to only this city - fun getMatchingUniquesWithNonLocalEffects(placeholderText: String): Sequence { - return cityConstructions.builtBuildingUniqueMap.getUniques(placeholderText) - .filter { !it.isLocalEffect } - // Note that we don't query religion here, as those only have local effects - } - fun getMatchingUniquesWithNonLocalEffects(uniqueType: UniqueType, stateForConditionals: StateForConditionals): Sequence { return cityConstructions.builtBuildingUniqueMap.getUniques(uniqueType) diff --git a/core/src/com/unciv/logic/city/CityStats.kt b/core/src/com/unciv/logic/city/CityStats.kt index e8770b2651..12e02cb83a 100644 --- a/core/src/com/unciv/logic/city/CityStats.kt +++ b/core/src/com/unciv/logic/city/CityStats.kt @@ -401,11 +401,6 @@ class CityStats(val cityInfo: CityInfo) { var unhappinessFromCitizens = cityInfo.population.population.toFloat() var unhappinessFromSpecialists = cityInfo.population.getNumberOfSpecialists().toFloat() - // Deprecated since 3.16.11 - for (unique in civInfo.getMatchingUniques("Specialists only produce []% of normal unhappiness")) - unhappinessFromSpecialists *= (1f - unique.params[0].toFloat() / 100f) - // - for (unique in cityInfo.getMatchingUniques(UniqueType.UnhappinessFromSpecialistsPercentageChange)) { if (cityInfo.matchesFilter(unique.params[1])) unhappinessFromSpecialists *= unique.params[0].toPercent() diff --git a/core/src/com/unciv/logic/civilization/CivInfoStats.kt b/core/src/com/unciv/logic/civilization/CivInfoStats.kt index 00f1e1068d..f8badc00c8 100644 --- a/core/src/com/unciv/logic/civilization/CivInfoStats.kt +++ b/core/src/com/unciv/logic/civilization/CivInfoStats.kt @@ -79,7 +79,7 @@ class CivInfoStats(val civInfo: CivilizationInfo) { // just to go over them once is a waste of memory - there are low-end phones who don't have much ram val ignoredTileTypes = - civInfo.getMatchingUniques("No Maintenance costs for improvements in [] tiles") + civInfo.getMatchingUniques(UniqueType.NoImprovementMaintenanceInSpecificTiles) .map { it.params[0] }.toHashSet() // needs to be .toHashSet()ed, // Because we go over every tile in every city and check if it's in this list, which can get real heavy. @@ -165,7 +165,7 @@ class CivInfoStats(val civInfo: CivilizationInfo) { } } - for (unique in civInfo.getMatchingUniques("[]% [] from City-States")) { + for (unique in civInfo.getMatchingUniques(UniqueType.StatBonusPercentFromCityStates)) { cityStateBonus[Stat.valueOf(unique.params[1])] *= unique.params[0].toPercent() } @@ -345,7 +345,7 @@ class CivInfoStats(val civInfo: CivilizationInfo) { // Just in case if (cityStatesHappiness > 0) { - for (unique in civInfo.getMatchingUniques("[]% [] from City-States")) { + for (unique in civInfo.getMatchingUniques(UniqueType.StatBonusPercentFromCityStates)) { if (unique.params[1] == Stat.Happiness.name) cityStatesHappiness *= unique.params[0].toPercent() } diff --git a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt index b3ecf7481a..61ecac0a1d 100644 --- a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt +++ b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt @@ -405,27 +405,6 @@ class CivilizationInfo { yieldAll(gameInfo.ruleSet.globalUniques.getMatchingUniques(uniqueType, stateForConditionals)) } - fun getMatchingUniques(uniqueTemplate: String, cityToIgnore: CityInfo? = null) = sequence { - yieldAll(nation.getMatchingUniques(uniqueTemplate)) - yieldAll(cities.asSequence() - .filter { it != cityToIgnore } - .flatMap { city -> city.getMatchingUniquesWithNonLocalEffects(uniqueTemplate) } - ) - yieldAll(policies.policyUniques.getUniques(uniqueTemplate)) - yieldAll(tech.techUniques.getUniques(uniqueTemplate)) - yieldAll(temporaryUniques.asSequence() - .map { it.uniqueObject } - .filter { it.placeholderText == uniqueTemplate } - ) - yieldAll(getEra().getMatchingUniques(uniqueTemplate).asSequence()) - if (religionManager.religion != null) - yieldAll(religionManager.religion!!.getFounderUniques() - .asSequence() - .filter { it.placeholderText == uniqueTemplate } - ) - - yieldAll(gameInfo.ruleSet.globalUniques.getMatchingUniques(uniqueTemplate)) - } //region Units fun getCivUnitsSize(): Int = units.size @@ -1141,7 +1120,7 @@ class CivilizationInfo { placedUnit.setupAbilityUses(cityToAddTo) } - for (unique in getMatchingUniques("Land units may cross [] tiles after the first [] is earned")) { + for (unique in getMatchingUniques(UniqueType.LandUnitsCrossTerrainAfterUnitGained)) { if (unit.matchesFilter(unique.params[1])) { passThroughImpassableUnlocked = true // Update the cached Boolean passableImpassables.add(unique.params[0]) // Add to list of passable impassables diff --git a/core/src/com/unciv/logic/civilization/ReligionManager.kt b/core/src/com/unciv/logic/civilization/ReligionManager.kt index b683561fbd..9f2060e321 100644 --- a/core/src/com/unciv/logic/civilization/ReligionManager.kt +++ b/core/src/com/unciv/logic/civilization/ReligionManager.kt @@ -109,7 +109,7 @@ class ReligionManager { (200 + 100 * greatProphetsEarned * (greatProphetsEarned + 1) / 2f) * civInfo.gameInfo.gameParameters.gameSpeed.modifier - for (unique in civInfo.getMatchingUniques("[]% Faith cost of generating Great Prophet equivalents")) + for (unique in civInfo.getMatchingUniques(UniqueType.FaithCostOfGreatProphetChange)) faithCost *= unique.params[0].toPercent() return faithCost.toInt() diff --git a/core/src/com/unciv/logic/civilization/TechManager.kt b/core/src/com/unciv/logic/civilization/TechManager.kt index 44b91da3a9..8c4078c821 100644 --- a/core/src/com/unciv/logic/civilization/TechManager.kt +++ b/core/src/com/unciv/logic/civilization/TechManager.kt @@ -323,7 +323,7 @@ class TechManager { } } - for (unique in civInfo.getMatchingUniques("Receive free [] when you discover []")) { + for (unique in civInfo.getMatchingUniques(UniqueType.RecieveFreeUnitWhenDiscoveringTech)) { if (unique.params[1] != techName) continue civInfo.addUnit(unique.params[0]) } diff --git a/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt b/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt index 0642447610..2e0faff4df 100644 --- a/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt +++ b/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt @@ -239,7 +239,7 @@ class DiplomacyManager() { restingPoint += unique.params[0].toInt() if (civInfo.cities.any()) // no capital if no cities - for (unique in otherCiv().getMatchingUniques("Resting point for Influence with City-States following this religion []")) + for (unique in otherCiv().getMatchingUniques(UniqueType.RestingPointOfCityStatesFollowingReligionChange)) if (otherCiv().religionManager.religion?.name == civInfo.getCapital().religion.getMajorityReligionName()) restingPoint += unique.params[0].toInt() @@ -270,7 +270,7 @@ class DiplomacyManager() { modifierPercent -= 25f // 25% slower degrade when sharing a religion for (civ in civInfo.gameInfo.civilizations.filter { it.isMajorCiv() && it != otherCiv()}) { - for (unique in civ.getMatchingUniques("Influence of all other civilizations with all city-states degrades []% faster")) { + for (unique in civ.getMatchingUniques(UniqueType.OtherCivsCityStateRelationsDegradeFaster)) { modifierPercent += unique.params[0].toFloat() } } diff --git a/core/src/com/unciv/models/ruleset/unique/Unique.kt b/core/src/com/unciv/models/ruleset/unique/Unique.kt index 912172cd96..73f3892e07 100644 --- a/core/src/com/unciv/models/ruleset/unique/Unique.kt +++ b/core/src/com/unciv/models/ruleset/unique/Unique.kt @@ -26,6 +26,7 @@ class Unique(val text: String, val sourceObjectType: UniqueTarget? = null, val s else Stats.parse(firstStatParam) } val conditionals: List = text.getConditionals() + val isTriggerable = type != null && type.targetTypes.contains(UniqueTarget.Triggerable) // in effect makes any unique become a triggerable unique || conditionals.any { it.type == UniqueType.ConditionalTimedUnique } @@ -237,7 +238,7 @@ class UniqueMap: HashMap>() { this[unique.placeholderText]!!.add(unique) } - fun getUniques(placeholderText: String): Sequence { + private fun getUniques(placeholderText: String): Sequence { return this[placeholderText]?.asSequence() ?: emptySequence() } diff --git a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt index f22d1e52ca..097378877d 100644 --- a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt +++ b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt @@ -246,6 +246,23 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags: ChanceToRecruitNavalBarbarian("50% chance of capturing defeated Barbarian naval units and earning 25 Gold", UniqueTarget.Global), TripleGoldFromEncampmentsAndCities("Receive triple Gold from Barbarian encampments and pillaging Cities", UniqueTarget.Global), CitiesAreRazedXTimesFaster("Cities are razed [amount] times as fast", UniqueTarget.Global), + GreatPersonBoostWithFriendship("When declaring friendship, both parties gain a [amount]% boost to great person generation", UniqueTarget.Global), + NoImprovementMaintenanceInSpecificTiles("No Maintenance costs for improvements in [tileFilter] tiles", UniqueTarget.Global), + OtherCivsCityStateRelationsDegradeFaster("Influence of all other civilizations with all city-states degrades [amount]% faster", UniqueTarget.Global), + LandUnitsCrossTerrainAfterUnitGained("Land units may cross [terrainName] tiles after the first [baseUnitFilter] is earned", UniqueTarget.Global), + GainInfluenceWithUnitGiftToCityState("Gain [amount] Influence with a [baseUnitFilter] gift to a City-State", UniqueTarget.Global), + FaithCostOfGreatProphetChange("[amount]% Faith cost of generating Great Prophet equivalents", UniqueTarget.Global), + RestingPointOfCityStatesFollowingReligionChange("Resting point for Influence with City-States following this religion [amount]", UniqueTarget.Global), + // Todo can be replaced with a conditional + StrengthWithinTilesOfTile("+[amount]% Strength if within [amount] tiles of a [tileFilter]", UniqueTarget.Global), + StatBonusPercentFromCityStates("[amount]% [stat] from City-States", UniqueTarget.Global), + + ProvidesGoldWheneverGreatPersonExpended("Provides a sum of gold each time you spend a Great Person", UniqueTarget.Global), + ProvidesStatsWheneverGreatPersonExpended("[stats] whenever a Great Person is expended", UniqueTarget.Global), + + // Acts as a trigger - this should be generalized somehow but the current setup does not allow this + // It would currently mean cycling through EVERY unique type to find ones with a specific conditional... + RecieveFreeUnitWhenDiscoveringTech("Receive free [baseUnitFilter] when you discover [tech]", UniqueTarget.Global), EnablesOpenBorders("Enables Open Borders agreements", UniqueTarget.Global), // Should the 'R' in 'Research agreements' be capitalized? @@ -599,6 +616,7 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags: ConditionalFirstCivToResearch("if no other Civilization has researched this", UniqueTarget.Conditional), ConditionalTech("after discovering [tech]", UniqueTarget.Conditional), ConditionalNoTech("before discovering [tech]", UniqueTarget.Conditional), + ConditionalWhenTech("upon discovering [tech]", UniqueTarget.Conditional), ConditionalPolicy("after adopting [policy]", UniqueTarget.Conditional), ConditionalNoPolicy("before adopting [policy]", UniqueTarget.Conditional), ConditionalBuildingBuilt("if [buildingName] is constructed", UniqueTarget.Conditional), diff --git a/core/src/com/unciv/ui/trade/DiplomacyScreen.kt b/core/src/com/unciv/ui/trade/DiplomacyScreen.kt index 36b9390896..605b6073ba 100644 --- a/core/src/com/unciv/ui/trade/DiplomacyScreen.kt +++ b/core/src/com/unciv/ui/trade/DiplomacyScreen.kt @@ -243,7 +243,7 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo): BaseScreen() { val bonusStrings = ArrayList() for (bonus in bonuses) { var improved = false - for (unique in viewingCiv.getMatchingUniques("[]% [] from City-States")) { + for (unique in viewingCiv.getMatchingUniques(UniqueType.StatBonusPercentFromCityStates)) { val boostAmount = unique.params[0].toPercent() val boostedStat = Stat.valueOf(unique.params[1]) when (bonus.type) { diff --git a/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt b/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt index 1aca2395fd..55c61b29f0 100644 --- a/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt +++ b/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt @@ -711,10 +711,10 @@ object UnitActions { val civInfo = unit.civInfo val gainedStats = Stats() - for (unique in civInfo.getMatchingUniques("Provides a sum of gold each time you spend a Great Person")) { + for (unique in civInfo.getMatchingUniques(UniqueType.ProvidesGoldWheneverGreatPersonExpended)) { gainedStats.gold += (100 * civInfo.gameInfo.gameParameters.gameSpeed.modifier).toInt() } - for (unique in civInfo.getMatchingUniques("[] whenever a Great Person is expended")) { + for (unique in civInfo.getMatchingUniques(UniqueType.ProvidesStatsWheneverGreatPersonExpended)) { gainedStats.add(unique.stats) } @@ -804,7 +804,7 @@ object UnitActions { val giftAction = { if (recipient.isCityState()) { - for (unique in unit.civInfo.getMatchingUniques("Gain [] Influence with a [] gift to a City-State")) { + for (unique in unit.civInfo.getMatchingUniques(UniqueType.GainInfluenceWithUnitGiftToCityState)) { if (unit.matchesFilter(unique.params[1])) { recipient.getDiplomacyManager(unit.civInfo) .addInfluence(unique.params[0].toFloat() - 5f)