Typed all healing uniques (#6087)

* Typed all healing uniques

* Fixed tests by replacing placeholder texts by types in BeliefAutomation
This commit is contained in:
Xander Lenstra
2022-02-01 08:43:37 +01:00
committed by GitHub
parent 0951e5d6fd
commit 6bc41a627c
7 changed files with 75 additions and 66 deletions

View File

@ -150,7 +150,7 @@
{
"name": "Medic II",
"prerequisites": ["Medic"],
"uniques": ["[+5] HP when healing in [Foreign Land] tiles", "All adjacent units heal [+5] HP when healing"],
"uniques": ["[+5] HP when healing <in [Foreign Land] tiles>", "All adjacent units heal [+5] HP when healing"],
"unitTypes": ["Sword","Gunpowder","Mounted","Scout"]
},
@ -174,13 +174,13 @@
},
{
"name": "Survivalism I",
"uniques": ["[+5] HP when healing in [Foreign Land] tiles", "[+25]% Strength <when defending>"],
"uniques": ["[+5] HP when healing <in [Foreign Land] tiles>", "[+25]% Strength <when defending>"],
"unitTypes": ["Scout"]
},
{
"name": "Survivalism II",
"prerequisites": ["Survivalism I"],
"uniques": ["[+5] HP when healing in [Foreign Land] tiles", "[+25]% Strength <when defending>"],
"uniques": ["[+5] HP when healing <in [Foreign Land] tiles>", "[+25]% Strength <when defending>"],
"unitTypes": ["Scout"]
},
{
@ -306,7 +306,7 @@
{
"name" : "Supply",
"prerequisites": ["Bombardment III", "Targeting III", "Boarding Party III", "Coastal Raider III"],
"uniques": ["May heal outside of friendly territory", "[+15] HP when healing in [Foreign Land] tiles"],
"uniques": ["May heal outside of friendly territory", "[+15] HP when healing <in [Foreign Land] tiles>"],
"unitTypes": ["Melee Water", "Ranged Water"]
},

View File

@ -150,7 +150,7 @@
{
"name": "Medic II",
"prerequisites": ["Medic"],
"uniques": ["[+5] HP when healing in [Foreign Land] tiles", "All adjacent units heal [+5] HP when healing"],
"uniques": ["[+5] HP when healing <in [Foreign Land] tiles>", "All adjacent units heal [+5] HP when healing"],
"unitTypes": ["Sword","Gunpowder","Mounted","Scout"]
},
@ -174,13 +174,13 @@
},
{
"name": "Survivalism I",
"uniques": ["[+5] HP when healing in [Foreign Land] tiles", "[+25]% Strength <when defending>"],
"uniques": ["[+5] HP when healing <in [Foreign Land] tiles>", "[+25]% Strength <when defending>"],
"unitTypes": ["Scout"]
},
{
"name": "Survivalism II",
"prerequisites": ["Survivalism I"],
"uniques": ["[+5] HP when healing in [Foreign Land] tiles", "[+25]% Strength <when defending>"],
"uniques": ["[+5] HP when healing <in [Foreign Land] tiles>", "[+25]% Strength <when defending>"],
"unitTypes": ["Scout"]
},
{
@ -306,7 +306,7 @@
{
"name" : "Supply",
"prerequisites": ["Bombardment III", "Targeting III", "Boarding Party III", "Coastal Raider III"],
"uniques": ["May heal outside of friendly territory", "[+15] HP when healing in [Foreign Land] tiles"],
"uniques": ["May heal outside of friendly territory", "[+15] HP when healing <in [Foreign Land] tiles>"],
"unitTypes": ["Melee Water", "Ranged Water"]
},

View File

@ -9,6 +9,7 @@ import com.unciv.models.ruleset.VictoryType
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.stats.Stat
import kotlin.math.min
import kotlin.math.pow
import kotlin.random.Random
object ChooseBeliefsAutomation {
@ -60,29 +61,23 @@ object ChooseBeliefsAutomation {
var score = 0f
val ruleSet = civInfo.gameInfo.ruleSet
for (unique in belief.uniqueObjects) {
var modifier = 1f
if (unique.conditionals.any { it.isOfType(UniqueType.ConditionalWar)
|| it.isOfType(UniqueType.ConditionalNotWar)
|| it.isOfType(UniqueType.ConditionalAttacking)
|| it.isOfType(UniqueType.ConditionalDefending) }
) {
modifier *= 0.5f
}
val modifier = 0.5f.pow(unique.conditionals.count())
// Multiply by 3/10 if has an obsoleted era
// Multiply by 2 if enough pop/followers (best implemented with conditionals, so left open for now)
// If obsoleted, continue
score += modifier * when (unique.placeholderText) {
UniqueType.GrowthPercentBonus.placeholderText -> unique.params[0].toFloat() / 3f
UniqueType.BorderGrowthPercentage.placeholderText -> -unique.params[0].toFloat() * 2f / 10f
"[]% Strength for cities" -> unique.params[0].toFloat() / 10f // Modified by personality
"[] Units adjacent to this city heal [] HP per turn when healing" -> unique.params[1].toFloat() / 10f
"+[]% Production when constructing []" -> unique.params[0].toFloat() / 3f
UniqueType.StatsFromCitiesOnSpecificTiles.placeholderText ->
score += modifier * when (unique.type) {
UniqueType.GrowthPercentBonus -> unique.params[0].toFloat() / 3f
UniqueType.BorderGrowthPercentage -> -unique.params[0].toFloat() * 2f / 10f
UniqueType.StrengthForCities -> unique.params[0].toFloat() / 10f // Modified by personality
UniqueType.CityHealingUnits -> unique.params[1].toFloat() / 10f
UniqueType.PercentProductionBuildings -> unique.params[0].toFloat() / 3f
UniqueType.PercentProductionWonders -> unique.params[0].toFloat() / 3f
UniqueType.PercentProductionUnits -> unique.params[0].toFloat() / 3f
UniqueType.StatsFromCitiesOnSpecificTiles ->
if (city.getCenterTile().matchesFilter(unique.params[1]))
unique.stats.values.sum() // Modified by personality
else 0f
UniqueType.StatsFromObject.placeholderText,
"[] from every [] in cities where this religion has at least [] followers" ->
UniqueType.StatsFromObject ->
when {
ruleSet.buildings.containsKey(unique.params[1]) -> {
unique.stats.values.sum() /
@ -97,15 +92,15 @@ object ChooseBeliefsAutomation {
}
else -> 0f
}
UniqueType.StatsFromXPopulation.placeholderText ->
UniqueType.StatsFromXPopulation ->
unique.stats.values.sum() // Modified by personality
"[] from each Trade Route" ->
UniqueType.StatsFromTradeRoute ->
unique.stats.values.sum() *
if (city.isConnectedToCapital()) 2f
else 1f
"[]% [] from every follower, up to []%" ->
UniqueType.StatPercentFromReligionFollowers ->
min(unique.params[0].toFloat() * city.population.population, unique.params[2].toFloat())
UniqueType.StatsPerCity.placeholderText ->
UniqueType.StatsPerCity ->
if (city.matchesFilter(unique.params[1]))
unique.stats.values.sum()
else 0f

View File

@ -560,7 +560,7 @@ class MapUnit {
}
private fun adjacentHealingBonus(): Int {
return getMatchingUniques("All adjacent units heal [] HP when healing").sumOf { it.params[0].toInt() }
return getMatchingUniques(UniqueType.HealAdjacentUnits).sumOf { it.params[0].toInt() } + 15 * getMatchingUniques(UniqueType.HealAdjacentUnitsDeprecated).count()
}
// Only military land units can truly "garrison"
@ -688,30 +688,19 @@ class MapUnit {
private fun heal() {
if (isEmbarked()) return // embarked units can't heal
if (civInfo.hasUnique("Can only heal by pillaging")) return
if (health >= 100) return // No need to heal if at max health
if (hasUnique(UniqueType.HealOnlyByPillaging, checkCivInfoUniques = true)) return
var amountToHealBy = rankTileForHealing(getTile())
if (amountToHealBy == 0
&& !(hasUnique(UniqueType.HealsOutsideFriendlyTerritory, checkCivInfoUniques = true)
&& !getTile().isFriendlyTerritory(civInfo)
)
) return
amountToHealBy += getMatchingUniques("[] HP when healing").sumOf { it.params[0].toInt() }
val maxAdjacentHealingBonus = currentTile.neighbors
.flatMap { it.getUnits().asSequence() }.map { it.adjacentHealingBonus() }.maxOrNull()
if (maxAdjacentHealingBonus != null)
amountToHealBy += maxAdjacentHealingBonus
val amountToHealBy = rankTileForHealing(getTile())
if (amountToHealBy == 0) return
healBy(amountToHealBy)
}
fun healBy(amount: Int) {
health += if (hasUnique(UniqueType.HealingEffectsDoubled, checkCivInfoUniques = true))
amount * 2
else
amount
health += amount *
if (hasUnique(UniqueType.HealingEffectsDoubled, checkCivInfoUniques = true)) 2
else 1
if (health > 100) health = 100
}
@ -723,20 +712,22 @@ class MapUnit {
tileInfo.isCityCenter() -> 20
tileInfo.isWater && isFriendlyTerritory && (baseUnit.isWaterUnit() || isTransported) -> 15 // Water unit on friendly water
tileInfo.isWater -> 0 // All other water cases
tileInfo.getOwner() == null -> 10 // Neutral territory
isFriendlyTerritory -> 15 // Allied territory
tileInfo.getOwner() == null -> 10 // Neutral territory
else -> 5 // Enemy territory
}
val mayHeal = healing > 0 || (tileInfo.isWater && hasUnique(UniqueType.HealsOutsideFriendlyTerritory))
val mayHeal = healing > 0 || (tileInfo.isWater && hasUnique(UniqueType.HealsOutsideFriendlyTerritory, checkCivInfoUniques = true))
if (!mayHeal) return healing
for (unique in getMatchingUniques("[] HP when healing in [] tiles")) {
healing += getMatchingUniques(UniqueType.Heal, checkCivInfoUniques = true).sumOf { it.params[0].toInt() }
// Deprecated as of 3.19.4
for (unique in getMatchingUniques(UniqueType.HealInTiles, checkCivInfoUniques = true)) {
if (tileInfo.matchesFilter(unique.params[1], civInfo)) {
healing += unique.params[0].toInt()
}
}
//
val healingCity = tileInfo.getTilesInDistance(1).firstOrNull {
it.isCityCenter() && it.getCity()!!.getMatchingUniques(UniqueType.CityHealingUnits).any()
@ -748,12 +739,17 @@ class MapUnit {
}
}
val maxAdjacentHealingBonus = currentTile.neighbors
.flatMap { it.getUnits().asSequence() }.map { it.adjacentHealingBonus() }.maxOrNull()
if (maxAdjacentHealingBonus != null)
healing += maxAdjacentHealingBonus
return healing
}
fun endTurn() {
if (currentMovement > 0 &&
getTile().improvementInProgress != null
if (currentMovement > 0
&& getTile().improvementInProgress != null
&& canBuildImprovement(getTile().getTileImprovementInProgress()!!)
) workOnImprovement()
if (currentMovement == getMaxMovement().toFloat() && isFortified()) {
@ -765,8 +761,6 @@ class MapUnit {
true
)
}
if (hasUnique("Heal adjacent units for an additional 15 HP per turn"))
currentTile.neighbors.flatMap { it.getUnits() }.forEach { it.healBy(15) }
if (currentMovement == getMaxMovement().toFloat() // didn't move this turn
|| hasUnique(UniqueType.HealsEvenAfterAction)

View File

@ -133,8 +133,8 @@ class Unique(val text: String, val sourceObjectType: UniqueTarget? = null, val s
UniqueType.ConditionalNeighborTilesAnd ->
state.cityInfo != null
&& state.cityInfo.getCenterTile().neighbors.count {
it.matchesFilter(condition.params[2], state.civInfo) &&
it.matchesFilter(condition.params[3], state.civInfo)
it.matchesFilter(condition.params[2], state.civInfo)
&& it.matchesFilter(condition.params[3], state.civInfo)
} in (condition.params[0].toInt())..(condition.params[1].toInt())
UniqueType.ConditionalOnWaterMaps -> state.region?.continentID == -1

View File

@ -356,7 +356,10 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
Movement("[amount] Movement", UniqueTarget.Unit, UniqueTarget.Global),
Sight("[amount] Sight", UniqueTarget.Unit, UniqueTarget.Global, UniqueTarget.Terrain),
Range("[amount] Range", UniqueTarget.Unit, UniqueTarget.Global),
Heal("[amount] HP when healing", UniqueTarget.Unit, UniqueTarget.Global),
SpreadReligionStrength("[amount]% Spread Religion Strength", UniqueTarget.Unit, UniqueTarget.Global),
@Deprecated("As of 3.19.4", ReplaceWith("[amount] HP when healing <in [tileFilter] tiles>"))
HealInTiles("[amount] HP when healing in [tileFilter] tiles", UniqueTarget.Unit, UniqueTarget.Global),
MayFoundReligion("May found a religion", UniqueTarget.Unit),
MayEnhanceReligion("May enhance a religion", UniqueTarget.Unit),
@ -379,11 +382,14 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
CanMoveAfterAttacking("Can move after attacking", UniqueTarget.Unit),
MoveImmediatelyOnceBought("Can move immediately once bought", UniqueTarget.Unit),
HealsOutsideFriendlyTerritory("May heal outside of friendly territory", UniqueTarget.Unit, UniqueTarget.Global),
HealingEffectsDoubled("All healing effects doubled", UniqueTarget.Unit, UniqueTarget.Global),
HealsAfterKilling("Heals [amount] damage if it kills a unit", UniqueTarget.Unit, UniqueTarget.Global),
HealOnlyByPillaging("Can only heal by pillaging", UniqueTarget.Unit, UniqueTarget.Global),
HealsEvenAfterAction("Unit will heal every turn, even if it performs an action", UniqueTarget.Unit),
HealAdjacentUnits("All adjacent units heal [amount] HP when healing", UniqueTarget.Unit),
@Deprecated("As of 3.19.3", ReplaceWith("All adjacent units heal [+15] HP when healing"))
HealAdjacentUnitsDeprecated("Heal adjacent units for an additional 15 HP per turn", UniqueTarget.Unit, UniqueTarget.Global),
NormalVisionWhenEmbarked("Normal vision when embarked", UniqueTarget.Unit, UniqueTarget.Global),
DefenceBonusWhenEmbarked("Defense bonus when embarked", UniqueTarget.Unit, UniqueTarget.Global),

View File

@ -481,6 +481,11 @@ Example: "[20] Range"
Applicable to: Global, Unit
#### [amount] HP when healing
Example: "[20] HP when healing"
Applicable to: Global, Unit
#### [amount]% Spread Religion Strength
Example: "[20]% Spread Religion Strength"
@ -506,6 +511,9 @@ Example: "Heals [20] damage if it kills a unit"
Applicable to: Global, Unit
#### Can only heal by pillaging
Applicable to: Global, Unit
#### Normal vision when embarked
Applicable to: Global, Unit
@ -839,6 +847,11 @@ Applicable to: Unit
#### Unit will heal every turn, even if it performs an action
Applicable to: Unit
#### All adjacent units heal [amount] HP when healing
Example: "All adjacent units heal [20] HP when healing"
Applicable to: Unit
#### 6 tiles in every direction always visible
Applicable to: Unit
@ -1450,6 +1463,7 @@ Applicable to: Conditional
- "+[amount]% attacking strength for cities with garrisoned units" - Deprecated As of 3.19.1, replace with "[+amount]% Strength for cities <with a garrison> <when attacking>"
- "Population loss from nuclear attacks -[amount]%" - Deprecated As of 3.19.2, replace with "Population loss from nuclear attacks [-amount]% [in this city]"
- "[amount]% Natural religion spread [cityFilter] with [tech/policy]" - Deprecated As of 3.19.3, replace with "[amount]% Natural religion spread [cityFilter] <after discovering [tech]> OR [amount]% natural religion spread [cityFilter] <after adopting [policy]>"
- "[amount] HP when healing in [tileFilter] tiles" - Deprecated As of 3.19.4, replace with "[amount] HP when healing <in [tileFilter] tiles>"
- "Melee units pay no movement cost to pillage" - Deprecated As of 3.18.17, replace with "No movement cost to pillage <for [Melee] units>"
- "[mapUnitFilter] units gain [amount]% more Experience from combat" - Deprecated As of 3.18.12, replace with "[amount]% XP gained from combat <for [mapUnitFilter] units>"
- "[amount]% maintenance costs for [mapUnitFilter] units" - Deprecated As of 3.18.14, replace with "[amount]% maintenance costs <for [mapUnitFilter] units>"