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
This commit is contained in:
SeventhM 2024-12-25 10:38:27 -08:00 committed by GitHub
parent fe5a2acf04
commit c7fb6fb525
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 51 additions and 20 deletions

View File

@ -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()
)
}

View File

@ -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 <reified T : INamed> createHashmap(items: Array<T>): LinkedHashMap<String, T> {
val hashMap = LinkedHashMap<String, T>(items.size)
for (item in items) {

View File

@ -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 {

View File

@ -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

View File

@ -1,4 +1,5 @@
package com.unciv.models.stats
interface GameResource {
val name: String
}

View File

@ -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)