Allow determining *if* a unique can trigger a triggerable effect, *without* actually doing so

This commit is contained in:
Yair Morgenstern 2024-02-20 10:52:28 +02:00
parent d51d032e18
commit 27465425b0

View File

@ -61,6 +61,20 @@ object UniqueTriggerActivation {
notification: String? = null,
triggerNotificationText: String? = null
): Boolean {
val function = getTriggerFunction(unique, civInfo, city, unit, tile, notification, triggerNotificationText) ?: return false
return function.invoke()
}
/** @return The action to be performed if possible, else null */
fun getTriggerFunction(
unique: Unique,
civInfo: Civilization,
city: City? = null,
unit: MapUnit? = null,
tile: Tile? = city?.getCenterTile() ?: unit?.currentTile,
notification: String? = null,
triggerNotificationText: String? = null
): (()->Boolean)? {
val relevantCity by lazy {
city?: tile?.getCity()
@ -68,11 +82,10 @@ object UniqueTriggerActivation {
val timingConditional = unique.conditionals.firstOrNull { it.type == UniqueType.ConditionalTimedUnique }
if (timingConditional != null) {
civInfo.temporaryUniques.add(TemporaryUnique(unique, timingConditional.params[0].toInt()))
return true
return { civInfo.temporaryUniques.add(TemporaryUnique(unique, timingConditional.params[0].toInt())) }
}
if (!unique.conditionalsApply(StateForConditionals(civInfo, city, unit, tile))) return false
if (!unique.conditionalsApply(StateForConditionals(civInfo, city, unit, tile))) return null
val chosenCity = relevantCity ?:
civInfo.cities.firstOrNull { it.isCapital() }
@ -85,16 +98,17 @@ object UniqueTriggerActivation {
when (unique.type) {
UniqueType.OneTimeFreeUnit -> {
val unitName = unique.params[0]
val baseUnit = ruleSet.units[unitName] ?: return false
val baseUnit = ruleSet.units[unitName] ?: return null
val civUnit = civInfo.getEquivalentUnit(baseUnit)
if (civUnit.isCityFounder() && civInfo.isOneCityChallenger())
return false
return null
val limit = civUnit.getMatchingUniques(UniqueType.MaxNumberBuildable)
.map { it.params[0].toInt() }.minOrNull()
if (limit != null && limit <= civInfo.units.getCivUnits().count { it.name == civUnit.name })
return false
return null
fun placeUnit(): Boolean {
val placedUnit = when {
// Set unit at city if there's an explict city or if there's no tile to set at
relevantCity != null || (tile == null && civInfo.cities.isNotEmpty()) ->
@ -104,12 +118,14 @@ object UniqueTriggerActivation {
// Else set unit unit near other units if we have no cities
civInfo.units.getCivUnits().any() ->
civInfo.units.placeUnitNearTile(civInfo.units.getCivUnits().first().currentTile.position, civUnit) ?: return false
else -> return false
}
val notificationText = getNotificationText(notification, triggerNotificationText,
"Gained [1] [${civUnit.name}] unit(s)")
?: return true
val notificationText = getNotificationText(
notification, triggerNotificationText,
"Gained [1] [${civUnit.name}] unit(s)"
)
if (notificationText != null)
civInfo.addNotification(
notificationText,
MapUnitAction(placedUnit),
@ -118,12 +134,15 @@ object UniqueTriggerActivation {
)
return true
}
return { placeUnit() }
}
UniqueType.OneTimeAmountFreeUnits -> {
val unitName = unique.params[1]
val baseUnit = ruleSet.units[unitName] ?: return false
val baseUnit = ruleSet.units[unitName] ?: return null
val civUnit = civInfo.getEquivalentUnit(baseUnit)
if (civUnit.isCityFounder() && civInfo.isOneCityChallenger())
return false
return null
val limit = civUnit.getMatchingUniques(UniqueType.MaxNumberBuildable)
.map { it.params[0].toInt() }.minOrNull()
@ -135,8 +154,9 @@ object UniqueTriggerActivation {
else -> amountFromTriggerable
}
if (actualAmount <= 0) return false
if (actualAmount <= 0) return null
fun placeUnits():Boolean {
val tilesUnitsWerePlacedOn: MutableList<Vector2> = mutableListOf()
repeat(actualAmount) {
val placedUnit = when {
@ -148,6 +168,7 @@ object UniqueTriggerActivation {
// Else set unit unit near other units if we have no cities
civInfo.units.getCivUnits().any() ->
civInfo.units.placeUnitNearTile(civInfo.units.getCivUnits().first().currentTile.position, civUnit)
else -> null
}
if (placedUnit != null)
@ -155,10 +176,12 @@ object UniqueTriggerActivation {
}
if (tilesUnitsWerePlacedOn.isEmpty()) return false
val notificationText = getNotificationText(notification, triggerNotificationText,
"Gained [${tilesUnitsWerePlacedOn.size}] [${civUnit.name}] unit(s)")
?: return true
val notificationText = getNotificationText(
notification, triggerNotificationText,
"Gained [${tilesUnitsWerePlacedOn.size}] [${civUnit.name}] unit(s)"
)
if (notificationText != null)
civInfo.addNotification(
notificationText,
MapUnitAction(tilesUnitsWerePlacedOn),
@ -167,6 +190,8 @@ object UniqueTriggerActivation {
)
return true
}
return { placeUnits() }
}
UniqueType.OneTimeFreeUnitRuins -> {
var civUnit = civInfo.getEquivalentUnit(unique.params[0])
if ( civUnit.isCityFounder() && civInfo.isOneCityChallenger()) {
@ -174,13 +199,14 @@ object UniqueTriggerActivation {
.firstOrNull {
it.getMatchingUniques(UniqueType.BuildImprovements)
.any { unique -> unique.params[0] == "Land" }
} ?: return false
} ?: return null
civUnit = civInfo.getEquivalentUnit(replacementUnit.name)
}
val placingTile =
tile ?: civInfo.cities.random().getCenterTile()
fun placeUnit():Boolean {
val placedUnit = civInfo.units.placeUnitNearTile(placingTile.position, civUnit.name)
if (notification != null && placedUnit != null) {
val notificationText =
@ -197,62 +223,78 @@ object UniqueTriggerActivation {
placedUnit.name
)
}
return placedUnit != null
}
return {placeUnit()}
}
UniqueType.OneTimeFreePolicy -> {
// spectators get all techs at start of game, and if (in a mod) a tech gives a free policy, the game gets stuck on the policy picker screen
if (civInfo.isSpectator()) return false
if (civInfo.isSpectator()) return null
return {
civInfo.policies.freePolicies++
val notificationText = getNotificationText(notification, triggerNotificationText,
"You may choose a free Policy")
?: return true
if (notificationText != null)
civInfo.addNotification(notificationText, NotificationCategory.General, NotificationIcon.Culture)
return true
true
}
}
UniqueType.OneTimeAmountFreePolicies -> {
if (civInfo.isSpectator()) return false
if (civInfo.isSpectator()) return null
val newFreePolicies = unique.params[0].toInt()
return {
civInfo.policies.freePolicies += newFreePolicies
val notificationText = getNotificationText(notification, triggerNotificationText,
"You may choose [$newFreePolicies] free Policies")
?: return true
val notificationText = getNotificationText(
notification, triggerNotificationText,
"You may choose [$newFreePolicies] free Policies"
)
if (notificationText != null)
civInfo.addNotification(notificationText, NotificationCategory.General, NotificationIcon.Culture)
return true
true
}
}
UniqueType.OneTimeAdoptPolicy -> {
val policyName = unique.params[0]
if (civInfo.policies.isAdopted(policyName)) return false
val policy = civInfo.gameInfo.ruleset.policies[policyName] ?: return false
if (civInfo.policies.isAdopted(policyName)) return null
val policy = civInfo.gameInfo.ruleset.policies[policyName] ?: return null
return {
civInfo.policies.freePolicies++
civInfo.policies.adopt(policy)
val notificationText = getNotificationText(notification, triggerNotificationText,
"You gain the [$policyName] Policy")
?: return true
val notificationText = getNotificationText(
notification, triggerNotificationText,
"You gain the [$policyName] Policy"
)
if (notificationText != null)
civInfo.addNotification(notificationText, PolicyAction(policyName), NotificationCategory.General, NotificationIcon.Culture)
return true
true
}
}
UniqueType.OneTimeEnterGoldenAge, UniqueType.OneTimeEnterGoldenAgeTurns -> {
return {
if (unique.type == UniqueType.OneTimeEnterGoldenAgeTurns) civInfo.goldenAges.enterGoldenAge(unique.params[0].toInt())
else civInfo.goldenAges.enterGoldenAge()
val notificationText = getNotificationText(notification, triggerNotificationText,
"You enter a Golden Age")
?: return true
val notificationText = getNotificationText(
notification, triggerNotificationText,
"You enter a Golden Age"
)
if (notificationText != null)
civInfo.addNotification(notificationText, NotificationCategory.General, NotificationIcon.Happiness)
return true
true
}
}
UniqueType.OneTimeFreeGreatPerson -> {
if (civInfo.isSpectator()) return false
if (civInfo.isSpectator()) return null
return {
civInfo.greatPeople.freeGreatPeople++
// Anyone an idea for a good icon?
if (notification != null)
@ -261,28 +303,32 @@ object UniqueTriggerActivation {
if (civInfo.isAI() || UncivGame.Current.settings.autoPlay.isAutoPlayingAndFullAI()) {
NextTurnAutomation.chooseGreatPerson(civInfo)
}
return true
true
}
}
UniqueType.OneTimeGainPopulation -> {
val applicableCities =
if (unique.params[1] == "in this city") sequenceOf(relevantCity!!)
else civInfo.cities.asSequence().filter { it.matchesFilter(unique.params[1]) }
if (applicableCities.none()) return null
return {
for (applicableCity in applicableCities) {
applicableCity.population.addPopulation(unique.params[0].toInt())
}
if (notification != null && applicableCities.any())
if (notification != null)
civInfo.addNotification(
notification,
LocationAction(applicableCities.map { it.location }),
NotificationCategory.Cities,
NotificationIcon.Population
)
return applicableCities.any()
true
}
}
UniqueType.OneTimeGainPopulationRandomCity -> {
if (civInfo.cities.isEmpty()) return false
if (civInfo.cities.isEmpty()) return null
return {
val randomCity = civInfo.cities.random(tileBasedRandom)
randomCity.population.addPopulation(unique.params[0].toInt())
if (notification != null) {
@ -297,24 +343,27 @@ object UniqueTriggerActivation {
NotificationIcon.Population
)
}
return true
true
}
}
UniqueType.OneTimeFreeTech -> {
if (civInfo.isSpectator()) return false
if (civInfo.isSpectator()) return null
return {
civInfo.tech.freeTechs += 1
if (notification != null) {
if (notification != null)
civInfo.addNotification(notification, NotificationCategory.General, NotificationIcon.Science)
true
}
return true
}
UniqueType.OneTimeAmountFreeTechs -> {
if (civInfo.isSpectator()) return false
if (civInfo.isSpectator()) return null
return {
civInfo.tech.freeTechs += unique.params[0].toInt()
if (notification != null) {
if (notification != null)
civInfo.addNotification(notification, NotificationCategory.General, NotificationIcon.Science)
true
}
return true
}
UniqueType.OneTimeFreeTechRuins -> {
val researchableTechsFromThatEra = ruleSet.technologies.values
@ -322,8 +371,9 @@ object UniqueTriggerActivation {
(it.column!!.era == unique.params[1] || unique.params[1] == "any era")
&& civInfo.tech.canBeResearched(it.name)
}
if (researchableTechsFromThatEra.isEmpty()) return false
if (researchableTechsFromThatEra.isEmpty()) return null
return {
val techsToResearch = researchableTechsFromThatEra.shuffled(tileBasedRandom)
.take(unique.params[0].toInt())
for (tech in techsToResearch)
@ -339,93 +389,110 @@ object UniqueTriggerActivation {
// Relies on RulesetValidator catching <= 0!
val notificationActions: Sequence<NotificationAction> =
LocationAction(tile?.position) + TechAction(techsToResearch.first().name)
civInfo.addNotification(notificationText, notificationActions,
NotificationCategory.General, NotificationIcon.Science)
civInfo.addNotification(
notificationText, notificationActions,
NotificationCategory.General, NotificationIcon.Science
)
}
true
}
return true
}
UniqueType.OneTimeDiscoverTech -> {
val techName = unique.params[0]
if (civInfo.tech.isResearched(techName)) return false
if (civInfo.tech.isResearched(techName)) return null
return {
civInfo.tech.addTechnology(techName)
val notificationText = getNotificationText(notification, triggerNotificationText,
"You have discovered the secrets of [$techName]")
?: return true
val notificationText = getNotificationText(
notification, triggerNotificationText,
"You have discovered the secrets of [$techName]"
)
if (notificationText != null)
civInfo.addNotification(notificationText, TechAction(techName), NotificationCategory.General, NotificationIcon.Science)
return true
true
}
}
UniqueType.StrategicResourcesIncrease -> {
return {
civInfo.cache.updateCivResources()
if (notification != null) {
if (notification != null)
civInfo.addNotification(
notification,
NotificationCategory.General,
NotificationIcon.Construction
)
true
}
return true
}
UniqueType.OneTimeProvideResources -> {
val resourceName = unique.params[1]
val resource = ruleSet.tileResources[resourceName] ?: return false
if (!resource.isStockpiled()) return false
val resource = ruleSet.tileResources[resourceName] ?: return null
if (!resource.isStockpiled()) return null
return {
val amount = unique.params[0].toInt()
civInfo.resourceStockpiles.add(resourceName, amount)
val notificationText = getNotificationText(notification, triggerNotificationText,
"You have gained [$amount] [$resourceName]")
?: return true
val notificationText = getNotificationText(
notification, triggerNotificationText,
"You have gained [$amount] [$resourceName]"
)
if (notificationText != null)
civInfo.addNotification(notificationText, NotificationCategory.General, NotificationIcon.Science, "ResourceIcons/$resourceName")
return true
true
}
}
UniqueType.OneTimeConsumeResources -> {
val resourceName = unique.params[1]
val resource = ruleSet.tileResources[resourceName] ?: return false
if (!resource.isStockpiled()) return false
val resource = ruleSet.tileResources[resourceName] ?: return null
if (!resource.isStockpiled()) return null
return {
val amount = unique.params[0].toInt()
civInfo.resourceStockpiles.add(resourceName, -amount)
val notificationText = getNotificationText(notification, triggerNotificationText,
"You have lost [$amount] [$resourceName]")
?: return true
val notificationText = getNotificationText(
notification, triggerNotificationText,
"You have lost [$amount] [$resourceName]"
)
if (notificationText != null)
civInfo.addNotification(notificationText, NotificationCategory.General, NotificationIcon.Science, "ResourceIcons/$resourceName")
return true
true
}
}
UniqueType.OneTimeRevealEntireMap -> {
return {
if (notification != null) {
civInfo.addNotification(notification, LocationAction(tile?.position), NotificationCategory.General, NotificationIcon.Scout)
}
civInfo.gameInfo.tileMap.values.asSequence()
.forEach { it.setExplored(civInfo, true) }
return true
true
}
}
UniqueType.UnitsGainPromotion -> {
val filter = unique.params[0]
val promotion = unique.params[1]
val promotedUnitLocations: MutableList<Vector2> = mutableListOf()
for (civUnit in civInfo.units.getCivUnits()) {
if (civUnit.matchesFilter(filter)
&& ruleSet.unitPromotions.values.any {
it.name == promotion && civUnit.type.name in it.unitTypes
val unitsToPromote = civInfo.units.getCivUnits().filter { it.matchesFilter(filter) }
.filter { unitToPromote ->
ruleSet.unitPromotions.values.any {
it.name == promotion && unitToPromote.type.name in it.unitTypes
}
) {
}.toList()
if (unitsToPromote.isEmpty()) return null
return {
val promotedUnitLocations: MutableList<Vector2> = mutableListOf()
for (civUnit in unitsToPromote) {
civUnit.promotions.addPromotion(promotion, isFree = true)
promotedUnitLocations.add(civUnit.getTile().position)
}
}
if (notification != null) {
civInfo.addNotification(
@ -435,7 +502,8 @@ object UniqueTriggerActivation {
"unitPromotionIcons/${unique.params[1]}"
)
}
return promotedUnitLocations.isNotEmpty()
true
}
}
/**
@ -454,93 +522,106 @@ object UniqueTriggerActivation {
* I could parametrize the 'Allied' of the Unique text, but eh.
*/
UniqueType.CityStateCanGiftGreatPeople -> {
return {
civInfo.addFlag(
CivFlags.CityStateGreatPersonGift.name,
civInfo.cityStateFunctions.turnsForGreatPersonFromCityState() / 2
)
if (notification != null) {
if (notification != null)
civInfo.addNotification(notification, NotificationCategory.Diplomacy, NotificationIcon.CityState)
true
}
return true
}
UniqueType.OneTimeGainStat -> {
val stat = Stat.safeValueOf(unique.params[1]) ?: return false
val stat = Stat.safeValueOf(unique.params[1]) ?: return null
if (stat !in Stat.statsWithCivWideField
|| unique.params[0].toIntOrNull() == null
) return false
) return null
return {
val statAmount = unique.params[0].toInt()
val stats = Stats().add(stat, statAmount.toFloat())
civInfo.addStats(stats)
val filledNotification = if(notification!=null && notification.hasPlaceholderParameters())
val filledNotification = if (notification != null && notification.hasPlaceholderParameters())
notification.fillPlaceholders(statAmount.toString())
else notification
val notificationText = getNotificationText(filledNotification, triggerNotificationText,
"Gained [${stats.toStringForNotifications()}]")
?: return true
val notificationText = getNotificationText(
filledNotification, triggerNotificationText,
"Gained [${stats.toStringForNotifications()}]"
)
if (notificationText != null)
civInfo.addNotification(notificationText, LocationAction(tile?.position), NotificationCategory.General, stat.notificationIcon)
return true
true
}
}
UniqueType.OneTimeGainStatSpeed -> {
val stat = Stat.safeValueOf(unique.params[1]) ?: return false
val stat = Stat.safeValueOf(unique.params[1]) ?: return null
if (stat !in Stat.statsWithCivWideField
|| unique.params[0].toIntOrNull() == null
) return false
) return null
return {
val statAmount = (unique.params[0].toInt() * (civInfo.gameInfo.speed.statCostModifiers[stat]!!)).roundToInt()
val stats = Stats().add(stat, statAmount.toFloat())
civInfo.addStats(stats)
val filledNotification = if(notification!=null && notification.hasPlaceholderParameters())
val filledNotification = if (notification != null && notification.hasPlaceholderParameters())
notification.fillPlaceholders(statAmount.toString())
else notification
val notificationText = getNotificationText(filledNotification, triggerNotificationText,
"Gained [${stats.toStringForNotifications()}]")
?: return true
val notificationText = getNotificationText(
filledNotification, triggerNotificationText,
"Gained [${stats.toStringForNotifications()}]"
)
if (notificationText != null)
civInfo.addNotification(notificationText, LocationAction(tile?.position), NotificationCategory.General, stat.notificationIcon)
return true
true
}
}
UniqueType.OneTimeGainStatRange -> {
val stat = Stat.safeValueOf(unique.params[2]) ?: return false
val stat = Stat.safeValueOf(unique.params[2]) ?: return null
if (stat !in Stat.statsWithCivWideField
|| unique.params[0].toIntOrNull() == null
|| unique.params[1].toIntOrNull() == null
) return false
) return null
val finalStatAmount = (tileBasedRandom.nextInt(unique.params[0].toInt(), unique.params[1].toInt()) *
civInfo.gameInfo.speed.statCostModifiers[stat]!!).roundToInt()
return {
val stats = Stats().add(stat, finalStatAmount.toFloat())
civInfo.addStats(stats)
val filledNotification = if (notification!=null && notification.hasPlaceholderParameters())
val filledNotification = if (notification != null && notification.hasPlaceholderParameters())
notification.fillPlaceholders(finalStatAmount.toString())
else notification
val notificationText = getNotificationText(filledNotification, triggerNotificationText,
"Gained [${stats.toStringForNotifications()}]")
?: return true
val notificationText = getNotificationText(
filledNotification, triggerNotificationText,
"Gained [${stats.toStringForNotifications()}]"
)
if (notificationText != null)
civInfo.addNotification(notificationText, LocationAction(tile?.position), NotificationCategory.General, stat.notificationIcon)
return true
true
}
}
UniqueType.OneTimeGainPantheon -> {
if (civInfo.religionManager.religionState != ReligionState.None) return false
if (civInfo.religionManager.religionState != ReligionState.None) return null
val gainedFaith = civInfo.religionManager.faithForPantheon(2)
if (gainedFaith == 0) return false
if (gainedFaith == 0) return null
return {
civInfo.addStat(Stat.Faith, gainedFaith)
if (notification != null) {
@ -550,15 +631,16 @@ object UniqueTriggerActivation {
else notification
civInfo.addNotification(notificationText, LocationAction(tile?.position), NotificationCategory.Religion, NotificationIcon.Faith)
}
return true
true
}
}
UniqueType.OneTimeGainProphet -> {
if (civInfo.religionManager.getGreatProphetEquivalent() == null) return false
if (civInfo.religionManager.getGreatProphetEquivalent() == null) return null
val gainedFaith =
(civInfo.religionManager.faithForNextGreatProphet() * (unique.params[0].toFloat() / 100f)).toInt()
if (gainedFaith == 0) return false
if (gainedFaith == 0) return null
return {
civInfo.addStat(Stat.Faith, gainedFaith)
if (notification != null) {
@ -568,30 +650,30 @@ object UniqueTriggerActivation {
else notification
civInfo.addNotification(notificationText, LocationAction(tile?.position), NotificationCategory.Religion, NotificationIcon.Faith)
}
return true
true
}
}
UniqueType.OneTimeFreeBelief -> {
if (!civInfo.isMajorCiv()) return false
if (!civInfo.isMajorCiv()) return null
val beliefType = BeliefType.valueOf(unique.params[0])
val religionManager = civInfo.religionManager
if ((beliefType != BeliefType.Pantheon && beliefType != BeliefType.Any)
&& religionManager.religionState <= ReligionState.Pantheon)
return false // situation where we're trying to add a formal religion belief to a civ that hasn't founded a religion
return null // situation where we're trying to add a formal religion belief to a civ that hasn't founded a religion
if (religionManager.numberOfBeliefsAvailable(beliefType) == 0)
return false // no more available beliefs of this type
return null // no more available beliefs of this type
return {
if (beliefType == BeliefType.Any && religionManager.religionState <= ReligionState.Pantheon)
religionManager.freeBeliefs.add(BeliefType.Pantheon.name, 1) // add pantheon instead of any type
else
religionManager.freeBeliefs.add(beliefType.name, 1)
return true
true
}
}
UniqueType.OneTimeRevealSpecificMapTiles -> {
if (tile == null)
return false
if (tile == null) return null
// "Reveal up to [amount/'all'] [tileFilter] within a [amount] tile radius"
val amount = unique.params[0]
@ -605,13 +687,14 @@ object UniqueTriggerActivation {
.filter { !it.isExplored(civInfo) && it.matchesFilter(filter) }
if (explorableTiles.none())
return false
return null
if (!isAll) {
explorableTiles.shuffled(tileBasedRandom)
explorableTiles = explorableTiles.take(amount.toInt())
}
return {
for (explorableTile in explorableTiles) {
explorableTile.setExplored(civInfo, true)
positions += explorableTile.position
@ -630,16 +713,14 @@ object UniqueTriggerActivation {
NotificationIcon.Barbarians else NotificationIcon.Scout
)
}
return true
true
}
}
UniqueType.OneTimeRevealCrudeMap -> {
if (tile == null)
return false
if (tile == null) return null
// "From a randomly chosen tile [amount] tiles away from the ruins,
// reveal tiles up to [amount] tiles away with [amount]% chance"
val distance = unique.params[0].toInt()
val radius = unique.params[1].toInt()
val chance = unique.params[2].toFloat() / 100f
@ -648,7 +729,9 @@ object UniqueTriggerActivation {
.filter { !it.isExplored(civInfo) }
.toList()
.randomOrNull(tileBasedRandom)
?: return false
?: return null
return {
revealCenter.getTilesInDistance(radius)
.filter { tileBasedRandom.nextFloat() < chance }
.forEach { it.setExplored(civInfo, true) }
@ -660,10 +743,12 @@ object UniqueTriggerActivation {
NotificationCategory.General,
NotificationIcon.Ruins
)
return true
true
}
}
UniqueType.OneTimeTriggerVoting -> {
return {
for (civ in civInfo.gameInfo.civilizations)
if (!civ.isBarbarian() && !civ.isSpectator())
civ.addFlag(
@ -672,12 +757,15 @@ object UniqueTriggerActivation {
)
if (notification != null)
civInfo.addNotification(notification, NotificationCategory.General, NotificationIcon.Diplomacy)
return true
true
}
}
UniqueType.OneTimeGlobalSpiesWhenEnteringEra -> {
if (!civInfo.isMajorCiv()) return false
if (!civInfo.gameInfo.isEspionageEnabled()) return false
if (!civInfo.isMajorCiv()) return null
if (!civInfo.gameInfo.isEspionageEnabled()) return null
return {
val currentEra = civInfo.getEra().name
for (otherCiv in civInfo.gameInfo.getAliveMajorCivs()) {
if (currentEra !in otherCiv.espionageManager.erasSpyEarnedFor) {
@ -687,10 +775,15 @@ object UniqueTriggerActivation {
// We don't tell which civilization entered the new era, as that is done in the notification directly above this one
otherCiv.addNotification("We have recruited [${spyName}] as a spy!", NotificationCategory.Espionage, NotificationIcon.Spy)
else
otherCiv.addNotification("After an unknown civilization entered the [${currentEra}], we have recruited [${spyName}] as a spy!", NotificationCategory.Espionage, NotificationIcon.Spy)
otherCiv.addNotification(
"After an unknown civilization entered the [${currentEra}], we have recruited [${spyName}] as a spy!",
NotificationCategory.Espionage,
NotificationIcon.Spy
)
}
}
return true
true
}
}
UniqueType.GainFreeBuildings -> {
@ -698,119 +791,144 @@ object UniqueTriggerActivation {
val applicableCities =
if (unique.params[1] == "in this city") sequenceOf(relevantCity!!)
else civInfo.cities.asSequence().filter { it.matchesFilter(unique.params[1]) }
if (applicableCities.none()) return null
return {
for (applicableCity in applicableCities) {
applicableCity.cityConstructions.freeBuildingsProvidedFromThisCity.addToMapOfSets(applicableCity.id, freeBuilding.name)
if (applicableCity.cityConstructions.containsBuildingOrEquivalent(freeBuilding.name)) continue
applicableCity.cityConstructions.constructionComplete(freeBuilding)
}
return true
true
}
}
UniqueType.FreeStatBuildings -> {
val stat = Stat.safeValueOf(unique.params[0]) ?: return false
val stat = Stat.safeValueOf(unique.params[0]) ?: return null
return {
civInfo.civConstructions.addFreeStatBuildings(stat, unique.params[1].toInt())
return true
true
}
}
UniqueType.FreeSpecificBuildings ->{
val building = ruleSet.buildings[unique.params[0]] ?: return false
val building = ruleSet.buildings[unique.params[0]] ?: return null
return {
civInfo.civConstructions.addFreeBuildings(building, unique.params[1].toInt())
return true
true
}
}
UniqueType.RemoveBuilding -> {
val applicableCities =
if (unique.params[1] == "in this city") sequenceOf(relevantCity!!)
else civInfo.cities.asSequence().filter { it.matchesFilter(unique.params[1]) }
if (applicableCities.none()) return null
return {
for (applicableCity in applicableCities) {
val buildingsToRemove = applicableCity.cityConstructions.getBuiltBuildings().filter {
it.matchesFilter(unique.params[0])
}.toSet()
applicableCity.cityConstructions.removeBuildings(buildingsToRemove)
}
return true
true
}
}
UniqueType.SellBuilding -> {
val applicableCities =
if (unique.params[1] == "in this city") sequenceOf(relevantCity!!)
else civInfo.cities.asSequence().filter { it.matchesFilter(unique.params[1]) }
if (applicableCities.none()) return null
return {
for (applicableCity in applicableCities) {
val buildingsToSell = applicableCity.cityConstructions.getBuiltBuildings().filter {
it.matchesFilter(unique.params[0]) && it.isSellable()
}
for (building in buildingsToSell) {
applicableCity.sellBuilding(building)
for (building in buildingsToSell) applicableCity.sellBuilding(building)
}
true
}
return true
}
UniqueType.OneTimeUnitHeal -> {
if (unit == null) return false
if (unit == null) return null
if (unit.health == 100)
return {
unit.healBy(unique.params[0].toInt())
if (notification != null)
unit.civ.addNotification(notification, unit.getTile().position, NotificationCategory.Units) // Do we have a heal icon?
return true
true
}
}
UniqueType.OneTimeUnitDamage -> {
if (unit == null) return false
if (unit == null) return null
return {
MapUnitCombatant(unit).takeDamage(unique.params[0].toInt())
if (notification != null)
unit.civ.addNotification(notification, unit.getTile().position, NotificationCategory.Units) // Do we have a heal icon?
return true
true
}
}
UniqueType.OneTimeUnitGainXP -> {
if (unit == null) return false
if (!unit.baseUnit.isMilitary()) return false
if (unit == null) return null
if (!unit.baseUnit.isMilitary()) return null
return {
unit.promotions.XP += unique.params[0].toInt()
if (notification != null)
unit.civ.addNotification(notification, unit.getTile().position, NotificationCategory.Units)
return true
true
}
}
UniqueType.OneTimeUnitUpgrade -> {
if (unit == null) return false
if (unit == null) return null
val upgradeAction = UnitActionsUpgrade.getFreeUpgradeAction(unit)
if (upgradeAction.none()) return false
if (upgradeAction.none()) return null
return {
(upgradeAction.minBy { (it as UpgradeUnitAction).unitToUpgradeTo.cost }).action!!()
if (notification != null)
unit.civ.addNotification(notification, unit.getTile().position, NotificationCategory.Units)
return true
true
}
}
UniqueType.OneTimeUnitSpecialUpgrade -> {
if (unit == null) return false
if (unit == null) return null
val upgradeAction = UnitActionsUpgrade.getAncientRuinsUpgradeAction(unit)
if (upgradeAction.none()) return false
if (upgradeAction.none()) return null
return {
(upgradeAction.minBy { (it as UpgradeUnitAction).unitToUpgradeTo.cost }).action!!()
if (notification != null)
unit.civ.addNotification(notification, unit.getTile().position, NotificationCategory.Units)
return true
true
}
}
UniqueType.OneTimeUnitGainPromotion -> {
if (unit == null) return false
if (unit == null) return null
val promotion = unit.civ.gameInfo.ruleset.unitPromotions.keys
.firstOrNull { it == unique.params[0] }
?: return false
?: return null
return {
unit.promotions.addPromotion(promotion, true)
if (notification != null)
unit.civ.addNotification(notification, unit.getTile().position, NotificationCategory.Units, unit.name)
return true
true
}
}
UniqueType.OneTimeUnitRemovePromotion -> {
if (unit == null) return false
if (unit == null) return null
val promotion = unit.civ.gameInfo.ruleset.unitPromotions.keys
.firstOrNull { it == unique.params[0]}
?: return false
?: return null
return {
unit.promotions.removePromotion(promotion)
return true
true
}
}
else -> {}
}
return false
return null
}
private fun getNotificationText(notification: String?, triggerNotificationText: String?, effectNotificationText: String): String? {