diff --git a/android/assets/jsons/translations/template.properties b/android/assets/jsons/translations/template.properties index 5b62a4c6d8..f62d6a3f8a 100644 --- a/android/assets/jsons/translations/template.properties +++ b/android/assets/jsons/translations/template.properties @@ -1027,6 +1027,7 @@ due to adopting [policy] = due to discovering [naturalWonder] = due to entering the [eraName] = due to constructing [buildingName] = +due to gaining a [unitName] = due to founding a city = due to discovering a Natural Wonder = due to our [unitName] defeating a [otherUnitName] = diff --git a/core/src/com/unciv/logic/city/CityConstructions.kt b/core/src/com/unciv/logic/city/CityConstructions.kt index 4ced11d321..a8d97d6cf0 100644 --- a/core/src/com/unciv/logic/city/CityConstructions.kt +++ b/core/src/com/unciv/logic/city/CityConstructions.kt @@ -22,6 +22,7 @@ import com.unciv.models.ruleset.unique.LocalUniqueCache import com.unciv.models.ruleset.unique.StateForConditionals import com.unciv.models.ruleset.unique.UniqueMap import com.unciv.models.ruleset.unique.UniqueType +import com.unciv.models.ruleset.unique.UniqueTriggerActivation import com.unciv.models.ruleset.unit.BaseUnit import com.unciv.models.stats.Stat import com.unciv.models.stats.Stats @@ -479,16 +480,75 @@ class CityConstructions : IsPartOfGameInfoSerialization { } fun addBuilding(buildingName: String) { - val buildingObject = city.getRuleset().buildings[buildingName]!! - builtBuildingObjects = builtBuildingObjects.withItem(buildingObject) + val building = city.getRuleset().buildings[buildingName]!! + val civ = city.civ + + if (building.cityHealth > 0) { + // city built a building that increases health so add a portion of this added health that is + // proportional to the city's current health + city.health += (building.cityHealth.toFloat() * city.health.toFloat() / city.getMaxHealth().toFloat()).toInt() + } + builtBuildingObjects = builtBuildingObjects.withItem(building) builtBuildings.add(buildingName) + + /** Support for [UniqueType.CreatesOneImprovement] */ + applyCreateOneImprovement(building) + + addFreeBuildings() + + triggerNewBuildingUniques(building) + + if (building.hasUnique(UniqueType.EnemyUnitsSpendExtraMovement)) + civ.cache.updateHasActiveEnemyMovementPenalty() + + // Korean unique - apparently gives the same as the research agreement + if (building.isStatRelated(Stat.Science) && civ.hasUnique(UniqueType.TechBoostWhenScientificBuildingsBuiltInCapital)) + civ.tech.addScience(civ.tech.scienceOfLast8Turns.sum() / 8) + + val uniqueTypesModifyingYields = listOf( + UniqueType.StatsFromTiles, UniqueType.StatsFromTilesWithout, UniqueType.StatsFromObject, + UniqueType.StatPercentFromObject, UniqueType.AllStatsPercentFromObject + ) + + // Happiness is global, so it could affect all cities + if(building.isStatRelated(Stat.Happiness)) { + for (city in civ.cities) { + city.reassignPopulationDeferred() + } + } + else if(uniqueTypesModifyingYields.any { building.hasUnique(it) }) + city.reassignPopulationDeferred() + updateUniques() + + civ.cache.updateCivResources() // this building could be a resource-requiring one + civ.cache.updateCitiesConnectedToCapital(false) // could be a connecting building, like a harbor + } + + fun triggerNewBuildingUniques(building: Building) { + val triggerNotificationText ="due to constructing [${building.name}]" + + for (unique in building.uniqueObjects) + if (!unique.hasTriggerConditional()) + UniqueTriggerActivation.triggerCivwideUnique(unique, city.civ, city, triggerNotificationText = triggerNotificationText) + + for (unique in city.civ.getTriggeredUniques(UniqueType.TriggerUponConstructingBuilding, StateForConditionals(city.civ, city))) + if (unique.conditionals.any {it.type == UniqueType.TriggerUponConstructingBuilding && building.matchesFilter(it.params[0])}) + UniqueTriggerActivation.triggerCivwideUnique(unique, city.civ, city, triggerNotificationText = triggerNotificationText) + + for (unique in city.civ.getTriggeredUniques(UniqueType.TriggerUponConstructingBuildingCityFilter, StateForConditionals(city.civ, city))) + if (unique.conditionals.any {it.type == UniqueType.TriggerUponConstructingBuildingCityFilter + && building.matchesFilter(it.params[0]) + && city.matchesFilter(it.params[1])}) + UniqueTriggerActivation.triggerCivwideUnique(unique, city.civ, city, triggerNotificationText = triggerNotificationText) } fun removeBuilding(buildingName: String) { val buildingObject = city.getRuleset().buildings[buildingName]!! builtBuildingObjects = builtBuildingObjects.withoutItem(buildingObject) builtBuildings.remove(buildingName) + city.civ.cache.updateCivResources() // this building could be a resource-requiring one + city.civ.cache.updateCitiesConnectedToCapital(false) // could be a connecting building, like a harbor updateUniques() } diff --git a/core/src/com/unciv/logic/city/managers/CityFounder.kt b/core/src/com/unciv/logic/city/managers/CityFounder.kt index ae4871354e..686c116ddf 100644 --- a/core/src/com/unciv/logic/city/managers/CityFounder.kt +++ b/core/src/com/unciv/logic/city/managers/CityFounder.kt @@ -209,7 +209,6 @@ class CityFounder { } civInfo.civConstructions.tryAddFreeBuildings() - city.cityConstructions.addFreeBuildings() } diff --git a/core/src/com/unciv/logic/civilization/managers/GoldenAgeManager.kt b/core/src/com/unciv/logic/civilization/managers/GoldenAgeManager.kt index 9ec4837fa4..ff6985dbdf 100644 --- a/core/src/com/unciv/logic/civilization/managers/GoldenAgeManager.kt +++ b/core/src/com/unciv/logic/civilization/managers/GoldenAgeManager.kt @@ -49,7 +49,9 @@ class GoldenAgeManager : IsPartOfGameInfoSerialization { for (unique in civInfo.getTriggeredUniques(UniqueType.TriggerUponEnteringGoldenAge)) UniqueTriggerActivation.triggerCivwideUnique(unique, civInfo) - civInfo.updateStatsForNextTurn() + //Golden Age can happen mid turn with Great Artist effects + for (city in civInfo.cities) + city.cityStats.update() } fun endTurn(happiness: Int) { diff --git a/core/src/com/unciv/logic/civilization/managers/UnitManager.kt b/core/src/com/unciv/logic/civilization/managers/UnitManager.kt index dbe996053b..35f3f5bf0c 100644 --- a/core/src/com/unciv/logic/civilization/managers/UnitManager.kt +++ b/core/src/com/unciv/logic/civilization/managers/UnitManager.kt @@ -71,9 +71,13 @@ class UnitManager(val civInfo:Civilization) { val unit = civInfo.gameInfo.tileMap.placeUnitNearTile(location, unitName, civInfo) if (unit != null) { + val triggerNotificationText = "due to gaining a [${unit.name}]" + for (unique in unit.getUniques()) + if (!unique.hasTriggerConditional()) + UniqueTriggerActivation.triggerUnitwideUnique(unique, unit, triggerNotificationText = triggerNotificationText) for (unique in civInfo.getTriggeredUniques(UniqueType.TriggerUponGainingUnit)) if (unit.matchesFilter(unique.params[0])) - UniqueTriggerActivation.triggerCivwideUnique(unique, civInfo) + UniqueTriggerActivation.triggerCivwideUnique(unique, civInfo, triggerNotificationText = triggerNotificationText) if (unit.baseUnit.getResourceRequirementsPerTurn().isNotEmpty()) civInfo.cache.updateCivResources() } diff --git a/core/src/com/unciv/models/ruleset/Building.kt b/core/src/com/unciv/models/ruleset/Building.kt index b2b71bb3cb..e62a2acefe 100644 --- a/core/src/com/unciv/models/ruleset/Building.kt +++ b/core/src/com/unciv/models/ruleset/Building.kt @@ -643,75 +643,14 @@ class Building : RulesetStatsObject(), INonPerpetualConstruction { getRejectionReasons(cityConstructions).none() override fun postBuildEvent(cityConstructions: CityConstructions, boughtWith: Stat?): Boolean { - val city = cityConstructions.city - val civInfo = city.civ - + val civInfo = cityConstructions.city.civ + if (civInfo.gameInfo.spaceResources.contains(name)) { civInfo.victoryManager.currentsSpaceshipParts.add(name, 1) return true } - if (cityHealth > 0) { - // city built a building that increases health so add a portion of this added health that is - // proportional to the city's current health - cityConstructions.city.health += (cityHealth.toFloat() * cityConstructions.city.health.toFloat() / cityConstructions.city.getMaxHealth().toFloat()).toInt() - } - cityConstructions.addBuilding(name) - - /** Support for [UniqueType.CreatesOneImprovement] */ - cityConstructions.applyCreateOneImprovement(this) - - // "Provides a free [buildingName] [cityFilter]" - cityConstructions.addFreeBuildings() - - val triggerNotificationText ="due to constructing [$name]" - - for (unique in uniqueObjects) - if (!unique.hasTriggerConditional()) - UniqueTriggerActivation.triggerCivwideUnique(unique, civInfo, cityConstructions.city, triggerNotificationText = triggerNotificationText) - - - for (unique in civInfo.getTriggeredUniques(UniqueType.TriggerUponConstructingBuilding, StateForConditionals(civInfo, city))) - if (unique.conditionals.any {it.type == UniqueType.TriggerUponConstructingBuilding && matchesFilter(it.params[0])}) - UniqueTriggerActivation.triggerCivwideUnique(unique, city.civ, city, triggerNotificationText = triggerNotificationText) - - for (unique in civInfo.getTriggeredUniques(UniqueType.TriggerUponConstructingBuildingCityFilter, StateForConditionals(city.civ, city))) - if (unique.conditionals.any {it.type == UniqueType.TriggerUponConstructingBuildingCityFilter - && matchesFilter(it.params[0]) - && city.matchesFilter(it.params[1])}) - UniqueTriggerActivation.triggerCivwideUnique(unique, city.civ, city, triggerNotificationText = triggerNotificationText) - - if (hasUnique(UniqueType.EnemyUnitsSpendExtraMovement)) - civInfo.cache.updateHasActiveEnemyMovementPenalty() - - // Korean unique - apparently gives the same as the research agreement - if (isStatRelated(Stat.Science) && civInfo.hasUnique(UniqueType.TechBoostWhenScientificBuildingsBuiltInCapital)) - civInfo.tech.addScience(civInfo.tech.scienceOfLast8Turns.sum() / 8) - - // Happiness change _may_ invalidate best worked tiles (#9238), but if the building - // isn't bought (or the AI bought it) then reassignPopulation will run later in startTurn anyway - if (boughtWith != null && isStatRelated(Stat.Happiness)) { - // Happiness is global, so it could affect all cities - Concurrency.runOnNonDaemonThreadPool("reassignPopulationAllCities") { - for (city in civInfo.cities) - city.reassignPopulationDeferred() - } - } - - // Buying a building influencing tile yield may change CityFocus decisions - val uniqueTypesModifyingYields = listOf( - UniqueType.StatsFromTiles, UniqueType.StatsFromTilesWithout, UniqueType.StatsFromObject, - UniqueType.StatPercentFromObject, UniqueType.AllStatsPercentFromObject - ) - if (boughtWith != null && uniqueTypesModifyingYields.any { hasUnique(it) }) { - cityConstructions.city.reassignPopulationDeferred() - } - - cityConstructions.city.cityStats.update() // new building, new stats - civInfo.cache.updateCivResources() // this building/unit could be a resource-requiring one - civInfo.cache.updateCitiesConnectedToCapital(false) // could be a connecting building, like a harbor - return true } diff --git a/core/src/com/unciv/models/ruleset/unique/Unique.kt b/core/src/com/unciv/models/ruleset/unique/Unique.kt index 6354ffa2ed..4e60bbf0a4 100644 --- a/core/src/com/unciv/models/ruleset/unique/Unique.kt +++ b/core/src/com/unciv/models/ruleset/unique/Unique.kt @@ -45,7 +45,7 @@ class Unique(val text: String, val sourceObjectType: UniqueTarget? = null, val s fun hasTriggerConditional(): Boolean { if(conditionals.none()) return false return conditionals.any{ conditional -> conditional.type?.targetTypes - ?.any{ it.canAcceptUniqueTarget(UniqueTarget.TriggerCondition) } + ?.any{ it.canAcceptUniqueTarget(UniqueTarget.TriggerCondition) || it.canAcceptUniqueTarget(UniqueTarget.UnitActionModifier) } ?: false } }