getModifiers(uniqueType) and hasModifier(uniqueType) helper functions

This commit is contained in:
yairm210 2024-08-04 17:14:16 +03:00
parent cf2b1cdf8e
commit 8d2ebc69f1
17 changed files with 59 additions and 66 deletions

View File

@ -329,7 +329,7 @@ object ReligionAutomation {
for (unique in belief.uniqueObjects) {
val modifier =
if (unique.modifiers.any { it.type == UniqueType.ConditionalOurUnit && it.params[0] == civInfo.religionManager.getGreatProphetEquivalent()?.name }) 1/2f
if (unique.getModifiers(UniqueType.ConditionalOurUnit).any { it.params[0] == civInfo.religionManager.getGreatProphetEquivalent()?.name }) 1/2f
else 1f
// Some city-filters are modified by personality (non-enemy foreign cities)
score += modifier * when (unique.type) {

View File

@ -179,8 +179,7 @@ object Battle {
val stateForConditionals = StateForConditionals(civInfo = ourUnit.getCivInfo(),
ourCombatant = ourUnit, theirCombatant = enemy, tile = attackedTile)
for (unique in ourUnit.unit.getTriggeredUniques(UniqueType.TriggerUponDefeatingUnit, stateForConditionals))
if (unique.modifiers.any { it.type == UniqueType.TriggerUponDefeatingUnit
&& enemy.unit.matchesFilter(it.params[0]) })
if (unique.getModifiers(UniqueType.TriggerUponDefeatingUnit).any { enemy.unit.matchesFilter(it.params[0]) })
UniqueTriggerActivation.triggerUnique(unique, ourUnit.unit, triggerNotificationText = "due to our [${ourUnit.getName()}] defeating a [${enemy.getName()}]")
}

View File

@ -562,13 +562,12 @@ class CityConstructions : IsPartOfGameInfoSerialization {
UniqueTriggerActivation.triggerUnique(unique, city, triggerNotificationText = triggerNotificationText)
for (unique in city.civ.getTriggeredUniques(UniqueType.TriggerUponConstructingBuilding, stateForConditionals))
if (unique.modifiers.any {it.type == UniqueType.TriggerUponConstructingBuilding && building.matchesFilter(it.params[0])})
if (unique.getModifiers(UniqueType.TriggerUponConstructingBuilding).any { building.matchesFilter(it.params[0])} )
UniqueTriggerActivation.triggerUnique(unique, city, triggerNotificationText = triggerNotificationText)
for (unique in city.civ.getTriggeredUniques(UniqueType.TriggerUponConstructingBuildingCityFilter, stateForConditionals))
if (unique.modifiers.any {it.type == UniqueType.TriggerUponConstructingBuildingCityFilter
&& building.matchesFilter(it.params[0])
&& city.matchesFilter(it.params[1])})
if (unique.getModifiers(UniqueType.TriggerUponConstructingBuildingCityFilter).any {
building.matchesFilter(it.params[0]) && city.matchesFilter(it.params[1]) })
UniqueTriggerActivation.triggerUnique(unique, city, triggerNotificationText = triggerNotificationText)
}

View File

@ -233,7 +233,7 @@ class PolicyManager : IsPartOfGameInfoSerialization {
UniqueTriggerActivation.triggerUnique(unique, civInfo, triggerNotificationText = triggerNotificationText)
for (unique in civInfo.getTriggeredUniques(UniqueType.TriggerUponAdoptingPolicyOrBelief))
if (unique.modifiers.any {it.type == UniqueType.TriggerUponAdoptingPolicyOrBelief && it.params[0] == policy.name})
if (unique.getModifiers(UniqueType.TriggerUponAdoptingPolicyOrBelief).any { it.params[0] == policy.name })
UniqueTriggerActivation.triggerUnique(unique, civInfo, triggerNotificationText = triggerNotificationText)
civInfo.cache.updateCivResources()

View File

@ -398,7 +398,7 @@ class ReligionManager : IsPartOfGameInfoSerialization {
for (unique in civInfo.getTriggeredUniques(UniqueType.TriggerUponAdoptingPolicyOrBelief))
for (belief in beliefs)
if (unique.modifiers.any {it.type == UniqueType.TriggerUponAdoptingPolicyOrBelief && it.params[0] == belief.name})
if (unique.getModifiers(UniqueType.TriggerUponAdoptingPolicyOrBelief).any { it.params[0] == belief.name})
UniqueTriggerActivation.triggerUnique(unique, civInfo,
triggerNotificationText = "due to adopting [${belief.name}]")

View File

@ -309,7 +309,7 @@ class TechManager : IsPartOfGameInfoSerialization {
UniqueTriggerActivation.triggerUnique(unique, civInfo, triggerNotificationText = triggerNotificationText)
for (unique in civInfo.getTriggeredUniques(UniqueType.TriggerUponResearch))
if (unique.modifiers.any {it.type == UniqueType.TriggerUponResearch && newTech.matchesFilter(it.params[0]) })
if (unique.getModifiers(UniqueType.TriggerUponResearch).any { newTech.matchesFilter(it.params[0]) })
UniqueTriggerActivation.triggerUnique(unique, civInfo, triggerNotificationText = triggerNotificationText)

View File

@ -99,10 +99,11 @@ class UnitManager(val civInfo: Civilization) {
for (unique in unit.getUniques())
if (!unique.hasTriggerConditional() && unique.conditionalsApply(StateForConditionals(civInfo, unit = unit)))
UniqueTriggerActivation.triggerUnique(unique, unit, triggerNotificationText = triggerNotificationText)
for (unique in civInfo.getTriggeredUniques(UniqueType.TriggerUponGainingUnit))
if (unique.modifiers.any { it.type == UniqueType.TriggerUponGainingUnit &&
unit.matchesFilter(it.params[0]) })
if (unique.getModifiers(UniqueType.TriggerUponGainingUnit).any { unit.matchesFilter(it.params[0]) })
UniqueTriggerActivation.triggerUnique(unique, unit, triggerNotificationText = triggerNotificationText)
if (unit.getResourceRequirementsPerTurn().isNotEmpty())
civInfo.cache.updateCivResources()

View File

@ -285,7 +285,7 @@ class MapUnit : IsPartOfGameInfoSerialization {
stateForConditionals: StateForConditionals = StateForConditionals(civInfo = civ, unit = this)
): Sequence<Unique> {
return getUniques().filter { unique ->
unique.modifiers.any { it.type == trigger }
unique.hasModifier(trigger)
&& unique.conditionalsApply(stateForConditionals)
}
}
@ -689,10 +689,9 @@ class MapUnit : IsPartOfGameInfoSerialization {
// Include tile in the state for correct RNG seeding
val state = StateForConditionals(civInfo = civ, unit = this, tile = tile)
for (unique in unfilteredTriggeredUniques) {
if (unique.modifiers.any {
it.type == UniqueType.TriggerUponDiscoveringTile
&& tile.matchesFilter(it.params[0], civ)
} && unique.conditionalsApply(state)
if (unique.getModifiers(UniqueType.TriggerUponDiscoveringTile)
.any { tile.matchesFilter(it.params[0], civ) }
&& unique.conditionalsApply(state)
)
UniqueTriggerActivation.triggerUnique(unique, this)
}
@ -815,7 +814,7 @@ class MapUnit : IsPartOfGameInfoSerialization {
/** Destroys the unit and gives stats if its a great person */
fun consume() {
for (unique in civ.getTriggeredUniques(UniqueType.TriggerUponExpendingUnit))
if (unique.modifiers.any { it.type == UniqueType.TriggerUponExpendingUnit && matchesFilter(it.params[0]) })
if (unique.getModifiers(UniqueType.TriggerUponExpendingUnit).any { matchesFilter(it.params[0]) })
UniqueTriggerActivation.triggerUnique(unique, this,
triggerNotificationText = "due to expending our [${this.name}]")
destroy()

View File

@ -65,8 +65,8 @@ class UnitTurnManager(val unit: MapUnit) {
unit.addMovementMemory()
for (unique in unit.getTriggeredUniques(UniqueType.TriggerUponEndingTurnInTile))
if (unique.modifiers.any { it.type == UniqueType.TriggerUponEndingTurnInTile
&& unit.getTile().matchesFilter(it.params[0], unit.civ) })
if (unique.getModifiers(UniqueType.TriggerUponEndingTurnInTile).any {
unit.getTile().matchesFilter(it.params[0], unit.civ) })
UniqueTriggerActivation.triggerUnique(unique, unit)
}

View File

@ -106,11 +106,11 @@ open class Policy : RulesetObject() {
}
fun isEnabledByPolicy(rulesetObject: IRulesetObject) =
rulesetObject.getMatchingUniques(UniqueType.OnlyAvailable, StateForConditionals.IgnoreConditionals).any { it.modifiers.any {
it.type == UniqueType.ConditionalAfterPolicyOrBelief && it.params[0] == name
} } || rulesetObject.getMatchingUniques(UniqueType.Unavailable).any { it.modifiers.any {
it.type == UniqueType.ConditionalBeforePolicyOrBelief && it.params[0] == name
}}
rulesetObject.getMatchingUniques(UniqueType.OnlyAvailable, StateForConditionals.IgnoreConditionals).any {
it.getModifiers(UniqueType.ConditionalAfterPolicyOrBelief).any { it.params[0] == name } }
|| rulesetObject.getMatchingUniques(UniqueType.Unavailable).any {
it.getModifiers(UniqueType.ConditionalBeforePolicyOrBelief).any { it.params[0] == name }
}
val enabledBuildings = ruleset.buildings.values.filter { isEnabledByPolicy(it) }
val enabledUnits = ruleset.units.values.filter { isEnabledByPolicy(it) }

View File

@ -29,7 +29,7 @@ class Unique(val text: String, val sourceObjectType: UniqueTarget? = null, val s
}
val modifiers: List<Unique> = text.getConditionals()
val isTimedTriggerable = modifiers.any { it.type == UniqueType.ConditionalTimedUnique }
val isTimedTriggerable = hasModifier(UniqueType.ConditionalTimedUnique)
val isTriggerable = type != null && (
type.targetTypes.contains(UniqueTarget.Triggerable)
@ -40,11 +40,14 @@ class Unique(val text: String, val sourceObjectType: UniqueTarget? = null, val s
/** Includes conditional params */
val allParams = params + modifiers.flatMap { it.params }
val isLocalEffect = params.contains("in this city") || modifiers.any { it.type == UniqueType.ConditionalInThisCity }
val isLocalEffect = params.contains("in this city") || hasModifier(UniqueType.ConditionalInThisCity)
fun hasFlag(flag: UniqueFlag) = type != null && type.flags.contains(flag)
fun isHiddenToUsers() = hasFlag(UniqueFlag.HiddenToUsers) || modifiers.any { it.type == UniqueType.ModifierHiddenFromUsers }
fun isModifiedByGameSpeed() = modifiers.any { it.type == UniqueType.ModifiedByGameSpeed }
fun isHiddenToUsers() = hasFlag(UniqueFlag.HiddenToUsers) || hasModifier(UniqueType.ModifierHiddenFromUsers)
fun getModifiers(type: UniqueType) = modifiers.filter { it.type == type }
fun hasModifier(type: UniqueType) = getModifiers(type).any()
fun isModifiedByGameSpeed() = hasModifier(UniqueType.ModifiedByGameSpeed)
fun hasTriggerConditional(): Boolean {
if (modifiers.none()) return false
return modifiers.any { conditional ->
@ -70,8 +73,8 @@ class Unique(val text: String, val sourceObjectType: UniqueTarget? = null, val s
}
private fun getUniqueMultiplier(stateForConditionals: StateForConditionals = StateForConditionals()): Int {
val forEveryModifiers = modifiers.filter { it.type == UniqueType.ForEveryCountable }
val forEveryAmountModifiers = modifiers.filter { it.type == UniqueType.ForEveryAmountCountable }
val forEveryModifiers = getModifiers(UniqueType.ForEveryCountable)
val forEveryAmountModifiers = getModifiers(UniqueType.ForEveryAmountCountable)
var amount = 1
for (conditional in forEveryModifiers) { // multiple multipliers DO multiply.
val multiplier = Countables.getCountableAmount(conditional.params[0], stateForConditionals)
@ -275,8 +278,7 @@ class UniqueMap() : HashMap<String, ArrayList<Unique>>() {
fun getTriggeredUniques(trigger: UniqueType, stateForConditionals: StateForConditionals): Sequence<Unique> {
return getAllUniques().filter { unique ->
unique.modifiers.any { it.type == trigger }
&& unique.conditionalsApply(stateForConditionals)
unique.hasModifier(trigger) && unique.conditionalsApply(stateForConditionals)
}.flatMap { it.getMultiplied(stateForConditionals) }
}
}
@ -285,7 +287,7 @@ class UniqueMap() : HashMap<String, ArrayList<Unique>>() {
class TemporaryUnique() : IsPartOfGameInfoSerialization {
constructor(uniqueObject: Unique, turns: Int) : this() {
val turnsText = uniqueObject.modifiers.first { it.type == UniqueType.ConditionalTimedUnique }.text
val turnsText = uniqueObject.getModifiers(UniqueType.ConditionalTimedUnique).first().text
unique = uniqueObject.text.replaceFirst("<$turnsText>", "").trim()
sourceObjectType = uniqueObject.sourceObjectType
sourceObjectName = uniqueObject.sourceObjectName

View File

@ -91,7 +91,7 @@ object UniqueTriggerActivation {
city?: tile?.getCity()
}
val timingConditional = unique.modifiers.firstOrNull { it.type == UniqueType.ConditionalTimedUnique }
val timingConditional = unique.getModifiers(UniqueType.ConditionalTimedUnique).firstOrNull()
if (timingConditional != null) {
return {
civInfo.temporaryUniques.add(TemporaryUnique(unique, timingConditional.params[0].toInt()))

View File

@ -238,9 +238,8 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction {
for (unique in civ.getMatchingUniques(UniqueType.CannotBuildUnits, stateForConditionals))
if (this@BaseUnit.matchesFilter(unique.params[0])) {
val hasHappinessCondition = unique.modifiers.any {
it.type == UniqueType.ConditionalBelowHappiness || it.type == UniqueType.ConditionalBetweenHappiness
}
val hasHappinessCondition = unique.hasModifier(UniqueType.ConditionalBelowHappiness)
|| unique.hasModifier(UniqueType.ConditionalBetweenHappiness)
if (hasHappinessCondition)
yield(RejectionReasonType.CannotBeBuiltUnhappiness.toInstance(unique.getDisplayText()))
else yield(RejectionReasonType.CannotBeBuilt.toInstance())
@ -487,7 +486,7 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction {
when (unique.type) {
UniqueType.Strength -> {
if (unique.params[0].toInt() <= 0) continue
if (unique.modifiers.any { it.type == UniqueType.ConditionalVsUnits }) { // Bonus vs some units - a quarter of the bonus
if (unique.hasModifier(UniqueType.ConditionalVsUnits)) { // Bonus vs some units - a quarter of the bonus
power *= (unique.params[0].toInt() / 4f).toPercent()
} else if (
unique.modifiers.any {

View File

@ -88,10 +88,8 @@ object BuildingDescriptions {
// Inefficient in theory. In practice, buildings seem to have only a small handful of uniques.
for (unique in building.uniqueObjects) {
if (unique.type == UniqueType.OnlyAvailable || unique.type == UniqueType.CanOnlyBeBuiltWhen)
for (conditional in unique.modifiers) {
if (conditional.type == UniqueType.ConditionalBuildingBuiltAll) {
missingCityText(conditional.params[0], city, conditional.params[1], lines)
}
for (conditional in unique.getModifiers(UniqueType.ConditionalBuildingBuiltAll)) {
missingCityText(conditional.params[0], city, conditional.params[1], lines)
}
}
}

View File

@ -334,9 +334,7 @@ object TechnologyDescriptions {
/** Tests whether a Unique means bonus Stats enabled by [techName] */
private fun Unique.isImprovementStatsEnabledByTech(techName: String) =
(type == UniqueType.Stats || type == UniqueType.ImprovementStatsOnTile) &&
modifiers.any {
it.type == UniqueType.ConditionalTech && it.params[0] == techName
}
getModifiers(UniqueType.ConditionalTech).any { it.params[0] == techName }
/** Tests whether a Unique Conditional is enabling or disabling its parent by a tech */
private fun Unique.isTechConditional() =

View File

@ -18,11 +18,11 @@ object UnitActionModifiers {
fun getUsableUnitActionUniques(unit: MapUnit, actionUniqueType: UniqueType) =
unit.getMatchingUniques(actionUniqueType)
.filter { unique -> unique.modifiers.none { it.type == UniqueType.UnitActionExtraLimitedTimes } }
.filter { unique -> !unique.hasModifier(UniqueType.UnitActionExtraLimitedTimes) }
.filter { canUse(unit, it) }
private fun getMovementPointsToUse(unit: MapUnit, actionUnique: Unique, defaultAllMovement: Boolean = false): Int {
if (actionUnique.modifiers.any { it.type == UniqueType.UnitActionMovementCostAll })
if (actionUnique.hasModifier(UniqueType.UnitActionMovementCostAll))
return unit.getMaxMovement()
val movementCost = actionUnique.modifiers
.filter { it.type == UniqueType.UnitActionMovementCost || it.type == UniqueType.UnitActionMovementCostRequired }
@ -34,10 +34,9 @@ object UnitActionModifiers {
}
private fun getMovementPointsRequired(actionUnique: Unique): Int {
if (actionUnique.modifiers.any { it.type == UniqueType.UnitActionMovementCostAll })
if (actionUnique.hasModifier(UniqueType.UnitActionMovementCostAll))
return 1
val movementCostRequired = actionUnique.modifiers
.filter { it.type == UniqueType.UnitActionMovementCostRequired }
val movementCostRequired = actionUnique.getModifiers(UniqueType.UnitActionMovementCostRequired)
.minOfOrNull { it.params[0].toInt() }
return movementCostRequired ?: 1
}
@ -47,7 +46,7 @@ object UnitActionModifiers {
* @return Boolean
*/
private fun canSpendStatsCost(unit: MapUnit, actionUnique: Unique): Boolean {
for (conditional in actionUnique.modifiers.filter { it.type == UniqueType.UnitActionStatsCost }) {
for (conditional in actionUnique.getModifiers(UniqueType.UnitActionStatsCost)) {
for ((stat, value) in conditional.stats) {
if (unit.getClosestCity() != null) {
if (!unit.getClosestCity()!!.hasStatToBuy(stat, value.toInt())) {
@ -64,7 +63,7 @@ object UnitActionModifiers {
}
private fun canSpendStockpileCost(unit: MapUnit, actionUnique: Unique): Boolean {
for (conditional in actionUnique.modifiers.filter { it.type == UniqueType.UnitActionStockpileCost }) {
for (conditional in actionUnique.getModifiers(UniqueType.UnitActionStockpileCost)) {
val amount = conditional.params[0].toInt()
val resourceName = conditional.params[1]
if (unit.civ.getResourceAmount(resourceName) < amount) {
@ -95,7 +94,7 @@ object UnitActionModifiers {
UniqueType.UnitActionConsumeUnit -> unit.consume()
UniqueType.UnitActionLimitedTimes, UniqueType.UnitActionOnce -> {
if (usagesLeft(unit, actionUnique) == 1
&& actionUnique.modifiers.any { it.type== UniqueType.UnitActionAfterWhichConsumed }) {
&& actionUnique.hasModifier(UniqueType.UnitActionAfterWhichConsumed)) {
unit.consume()
continue
}
@ -132,14 +131,13 @@ object UnitActionModifiers {
private fun getMaxUsages(unit: MapUnit, actionUnique: Unique): Int? {
val extraTimes = unit.getMatchingUniques(actionUnique.type!!)
.filter { it.text.removeConditionals() == actionUnique.text.removeConditionals() }
.flatMap { unique -> unique.modifiers.filter { it.type == UniqueType.UnitActionExtraLimitedTimes } }
.flatMap { unique -> unique.getModifiers(UniqueType.UnitActionExtraLimitedTimes) }
.sumOf { it.params[0].toInt() }
val times = actionUnique.modifiers
.filter { it.type == UniqueType.UnitActionLimitedTimes }
val times = actionUnique.getModifiers(UniqueType.UnitActionLimitedTimes)
.maxOfOrNull { it.params[0].toInt() }
if (times != null) return times + extraTimes
if (actionUnique.modifiers.any { it.type == UniqueType.UnitActionOnce }) return 1 + extraTimes
if (actionUnique.hasModifier(UniqueType.UnitActionOnce)) return 1 + extraTimes
return null
}
@ -156,22 +154,22 @@ object UnitActionModifiers {
val maxUsages = getMaxUsages(unit, actionUnique)
if (maxUsages!=null) effects += "${usagesLeft(unit, actionUnique)}/$maxUsages"
if (actionUnique.modifiers.any { it.type == UniqueType.UnitActionStatsCost}) {
if (actionUnique.hasModifier(UniqueType.UnitActionStatsCost)) {
val statCost = Stats()
for (conditional in actionUnique.modifiers.filter { it.type == UniqueType.UnitActionStatsCost })
for (conditional in actionUnique.getModifiers(UniqueType.UnitActionStatsCost))
statCost.add(conditional.stats)
effects += statCost.toStringOnlyIcons(false)
}
if (actionUnique.modifiers.any { it.type == UniqueType.UnitActionStockpileCost }) {
if (actionUnique.hasModifier(UniqueType.UnitActionStockpileCost)) {
var stockpileString = ""
for (conditionals in actionUnique.modifiers.filter { it.type == UniqueType.UnitActionStockpileCost })
for (conditionals in actionUnique.getModifiers(UniqueType.UnitActionStockpileCost))
stockpileString += " ${conditionals.params[0].toInt()} {${conditionals.params[1]}}"
effects += stockpileString.removePrefix(" ") // drop leading space
}
if (actionUnique.modifiers.any { it.type == UniqueType.UnitActionConsumeUnit }
|| actionUnique.modifiers.any { it.type == UniqueType.UnitActionAfterWhichConsumed } && usagesLeft(unit, actionUnique) == 1
if (actionUnique.hasModifier(UniqueType.UnitActionConsumeUnit)
|| actionUnique.hasModifier(UniqueType.UnitActionAfterWhichConsumed) && usagesLeft(unit, actionUnique) == 1
) effects += Fonts.death.toString()
else effects += getMovementPointsToUse(
unit,

View File

@ -170,7 +170,7 @@ object UnitActionsFromUniques {
// not a unit action
if (unique.modifiers.none { it.type?.targetTypes?.contains(UniqueTarget.UnitActionModifier) == true }) continue
// extends an existing unit action
if (unique.modifiers.any { it.type == UniqueType.UnitActionExtraLimitedTimes }) continue
if (unique.hasModifier(UniqueType.UnitActionExtraLimitedTimes)) continue
if (!unique.isTriggerable) continue
if (!unique.conditionalsApply(StateForConditionals(civInfo = unit.civ, unit = unit, tile = unit.currentTile))) continue
if (!UnitActionModifiers.canUse(unit, unique)) continue
@ -182,7 +182,7 @@ object UnitActionsFromUniques {
unique.params[0].toInt()).tr())
}
UniqueType.OneTimeGainStat -> {
if (unique.modifiers.any { it.type == UniqueType.ModifiedByGameSpeed }) {
if (unique.hasModifier(UniqueType.ModifiedByGameSpeed)) {
val stat = unique.params[1]
val modifier = unit.civ.gameInfo.speed.statCostModifiers[Stat.safeValueOf(stat)]
?: unit.civ.gameInfo.speed.modifier