From c7fb6fb5259dfbb7d7d54dfbccad8f16c661e319 Mon Sep 17 00:00:00 2001 From: SeventhM <127357473+SeventhM@users.noreply.github.com> Date: Wed, 25 Dec 2024 10:38:27 -0800 Subject: [PATCH] Allow stat from battle uniques to also give stockpiles (#12689) * Allow stat from battle uniques to also give stockpiles * Add helper for finding a gameResource * Cleanup the formating of function --- core/src/com/unciv/logic/battle/Battle.kt | 40 +++++++++++++++---- core/src/com/unciv/models/ruleset/Ruleset.kt | 7 ++++ .../ruleset/unique/UniqueTriggerActivation.kt | 5 +-- .../unciv/models/ruleset/unique/UniqueType.kt | 8 ++-- .../com/unciv/models/stats/GameResource.kt | 1 + core/src/com/unciv/models/stats/SubStat.kt | 10 +++-- 6 files changed, 51 insertions(+), 20 deletions(-) diff --git a/core/src/com/unciv/logic/battle/Battle.kt b/core/src/com/unciv/logic/battle/Battle.kt index f7bd8c2e3e..8abc09dba0 100644 --- a/core/src/com/unciv/logic/battle/Battle.kt +++ b/core/src/com/unciv/logic/battle/Battle.kt @@ -21,11 +21,13 @@ import com.unciv.models.ruleset.unique.UniqueTriggerActivation import com.unciv.models.ruleset.unique.UniqueType import com.unciv.models.stats.Stat import com.unciv.models.stats.Stats +import com.unciv.models.stats.SubStat import com.unciv.ui.components.UnitMovementMemoryType import com.unciv.ui.screens.worldscreen.unit.actions.UnitActionsPillage import com.unciv.utils.debug import kotlin.math.max import kotlin.math.min +import kotlin.math.roundToInt import kotlin.random.Random /** @@ -257,8 +259,9 @@ object Battle { if (defeatedUnitYieldSourceType == "Cost") unitCost else unitStr val yieldAmount = (yieldTypeSourceAmount * yieldPercent).toInt() - val stat = Stat.valueOf(unique.params[3]) - civUnit.getCivInfo().addStat(stat, yieldAmount) + val resource = civUnit.getCivInfo().gameInfo.ruleset.getGameResource(unique.params[3]) + ?: continue + civUnit.getCivInfo().addGameResource(resource, yieldAmount) } // CS friendship from killing barbarians @@ -362,16 +365,35 @@ object Battle { ) { // implementation based on the description of the original civilopedia, see issue #4374 if (plunderingUnit !is MapUnitCombatant) return + val civ = plunderingUnit.getCivInfo() val plunderedGoods = Stats() for (unique in plunderingUnit.unit.getMatchingUniques(UniqueType.DamageUnitsPlunder, checkCivInfoUniques = true)) { - if (plunderedUnit.matchesFilter(unique.params[1])) { - val percentage = unique.params[0].toFloat() - plunderedGoods.add(Stat.valueOf(unique.params[2]), percentage / 100f * damageDealt) + if (!plunderedUnit.matchesFilter(unique.params[1])) continue + + val percentage = unique.params[0].toFloat() + val amount = percentage / 100f * damageDealt + val resourceName = unique.params[2] + val resource = plunderedUnit.getCivInfo().gameInfo.ruleset.getGameResource(resourceName) + ?: continue + + if (resource is Stat) { + plunderedGoods.add(resource, amount) + continue // Notification and adding to the civ happens all at once for stats further down } + + val plunderedAmount = amount.roundToInt() + civ.addGameResource(resource, plunderedAmount) + val icon = if (resource is SubStat) resource.icon else "ResourceIcons/$resourceName" + civ.addNotification( + "Your [${plunderingUnit.getName()}] plundered [${plunderedAmount}] [${resourceName}] from [${plunderedUnit.getName()}]", + plunderedUnit.getTile().position, + NotificationCategory.War, + plunderingUnit.getName(), NotificationIcon.War, icon, + if (plunderedUnit is CityCombatant) NotificationIcon.City else plunderedUnit.getName() + ) } - val civ = plunderingUnit.getCivInfo() for ((key, value) in plunderedGoods) { val plunderedAmount = value.toInt() if (plunderedAmount == 0) continue @@ -564,8 +586,10 @@ object Battle { val stateForConditionals = StateForConditionals(civInfo = attackerCiv, city=city, unit = attacker.unit, ourCombatant = attacker, attackedTile = city.getCenterTile()) for (unique in attacker.getMatchingUniques(UniqueType.CaptureCityPlunder, stateForConditionals, true)) { - attackerCiv.addStat( - Stat.valueOf(unique.params[2]), + val resource = attacker.getCivInfo().gameInfo.ruleset.getGameResource(unique.params[2]) + ?: continue + attackerCiv.addGameResource( + resource, unique.params[0].toInt() * city.cityStats.currentCityStats[Stat.valueOf(unique.params[1])].toInt() ) } diff --git a/core/src/com/unciv/models/ruleset/Ruleset.kt b/core/src/com/unciv/models/ruleset/Ruleset.kt index 3b41499915..6788d1e7f3 100644 --- a/core/src/com/unciv/models/ruleset/Ruleset.kt +++ b/core/src/com/unciv/models/ruleset/Ruleset.kt @@ -25,7 +25,10 @@ import com.unciv.models.ruleset.unit.Promotion import com.unciv.models.ruleset.unit.UnitType import com.unciv.models.ruleset.validation.RulesetValidator import com.unciv.models.ruleset.validation.UniqueValidator +import com.unciv.models.stats.GameResource import com.unciv.models.stats.INamed +import com.unciv.models.stats.Stat +import com.unciv.models.stats.SubStat import com.unciv.models.translations.tr import com.unciv.ui.screens.civilopediascreen.ICivilopediaText import com.unciv.utils.Log @@ -148,6 +151,10 @@ class Ruleset { return newRuleset } + fun getGameResource(resourceName: String): GameResource? = Stat.safeValueOf(resourceName) + ?: SubStat.safeValueOf(resourceName) + ?: tileResources[resourceName] + private inline fun createHashmap(items: Array): LinkedHashMap { val hashMap = LinkedHashMap(items.size) for (item in items) { diff --git a/core/src/com/unciv/models/ruleset/unique/UniqueTriggerActivation.kt b/core/src/com/unciv/models/ruleset/unique/UniqueTriggerActivation.kt index 73e8a5b1a3..22f86e8fe1 100644 --- a/core/src/com/unciv/models/ruleset/unique/UniqueTriggerActivation.kt +++ b/core/src/com/unciv/models/ruleset/unique/UniqueTriggerActivation.kt @@ -30,7 +30,6 @@ import com.unciv.models.ruleset.tile.TerrainType import com.unciv.models.ruleset.tile.TileResource import com.unciv.models.stats.Stat import com.unciv.models.stats.Stats -import com.unciv.models.stats.SubStat import com.unciv.models.translations.fillPlaceholders import com.unciv.models.translations.hasPlaceholderParameters import com.unciv.models.translations.tr @@ -561,9 +560,7 @@ object UniqueTriggerActivation { UniqueType.OneTimeGainResource -> { val resourceName = unique.params[1] - val resource = Stat.safeValueOf(resourceName) ?: - SubStat.safeValueOf(resourceName) ?: - ruleset.tileResources[resourceName] ?: return null + val resource = ruleset.getGameResource(resourceName) ?: return null if (resource is TileResource && !resource.isStockpiled) return null return { diff --git a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt index b87fa7c550..e6af145cd3 100644 --- a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt +++ b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt @@ -449,10 +449,10 @@ enum class UniqueType( UnitUpgradeCost("[relativeAmount]% Gold cost of upgrading", UniqueTarget.Unit, UniqueTarget.Global), // Gains from battle - DamageUnitsPlunder("Earn [amount]% of the damage done to [combatantFilter] units as [civWideStat]", UniqueTarget.Unit, UniqueTarget.Global), - CaptureCityPlunder("Upon capturing a city, receive [amount] times its [stat] production as [civWideStat] immediately", UniqueTarget.Unit, UniqueTarget.Global), - KillUnitPlunder("Earn [amount]% of killed [mapUnitFilter] unit's [costOrStrength] as [civWideStat]", UniqueTarget.Unit, UniqueTarget.Global), - KillUnitPlunderNearCity("Earn [amount]% of [mapUnitFilter] unit's [costOrStrength] as [civWideStat] when killed within 4 tiles of a city following this religion", UniqueTarget.FollowerBelief), + DamageUnitsPlunder("Earn [amount]% of the damage done to [combatantFilter] units as [stockpile]", UniqueTarget.Unit, UniqueTarget.Global), + CaptureCityPlunder("Upon capturing a city, receive [amount] times its [stat] production as [stockpile] immediately", UniqueTarget.Unit, UniqueTarget.Global), + KillUnitPlunder("Earn [amount]% of killed [mapUnitFilter] unit's [costOrStrength] as [stockpile]", UniqueTarget.Unit, UniqueTarget.Global), + KillUnitPlunderNearCity("Earn [amount]% of [mapUnitFilter] unit's [costOrStrength] as [stockpile] when killed within 4 tiles of a city following this religion", UniqueTarget.FollowerBelief), KillUnitCapture("May capture killed [mapUnitFilter] units", UniqueTarget.Unit), // XP diff --git a/core/src/com/unciv/models/stats/GameResource.kt b/core/src/com/unciv/models/stats/GameResource.kt index e3c0f679d3..424cb03cd1 100644 --- a/core/src/com/unciv/models/stats/GameResource.kt +++ b/core/src/com/unciv/models/stats/GameResource.kt @@ -1,4 +1,5 @@ package com.unciv.models.stats interface GameResource { + val name: String } diff --git a/core/src/com/unciv/models/stats/SubStat.kt b/core/src/com/unciv/models/stats/SubStat.kt index fd957733b9..1d3d6b7ba3 100644 --- a/core/src/com/unciv/models/stats/SubStat.kt +++ b/core/src/com/unciv/models/stats/SubStat.kt @@ -1,9 +1,11 @@ package com.unciv.models.stats -enum class SubStat : GameResource { - GoldenAgePoints, - TotalCulture, - StoredFood, +import com.unciv.logic.civilization.NotificationIcon + +enum class SubStat(val icon: String) : GameResource { + GoldenAgePoints(NotificationIcon.Happiness), + TotalCulture(NotificationIcon.Culture), + StoredFood(NotificationIcon.Food), ; companion object { val useableToBuy = setOf(GoldenAgePoints, StoredFood)