mirror of
https://github.com/yairm210/Unciv.git
synced 2025-07-16 02:40:41 +07:00
chore: improvement stat functions are more related to 'stat' than to 'improvement'
This commit is contained in:
@ -1,7 +1,7 @@
|
|||||||
package com.unciv.logic.automation
|
package com.unciv.logic.automation
|
||||||
|
|
||||||
import com.unciv.logic.city.CityFocus
|
|
||||||
import com.unciv.logic.city.City
|
import com.unciv.logic.city.City
|
||||||
|
import com.unciv.logic.city.CityFocus
|
||||||
import com.unciv.logic.city.INonPerpetualConstruction
|
import com.unciv.logic.city.INonPerpetualConstruction
|
||||||
import com.unciv.logic.civilization.Civilization
|
import com.unciv.logic.civilization.Civilization
|
||||||
import com.unciv.logic.map.BFS
|
import com.unciv.logic.map.BFS
|
||||||
@ -389,7 +389,7 @@ object Automation {
|
|||||||
|
|
||||||
// Improvements are good: less points
|
// Improvements are good: less points
|
||||||
if (tile.improvement != null &&
|
if (tile.improvement != null &&
|
||||||
tile.improvementFunctions.getImprovementStats(
|
tile.stats.getImprovementStats(
|
||||||
tile.getTileImprovement()!!,
|
tile.getTileImprovement()!!,
|
||||||
city.civ,
|
city.civ,
|
||||||
city,
|
city,
|
||||||
|
@ -169,142 +169,6 @@ class TileInfoImprovementFunctions(val tile: Tile) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Also multiplies the stats by the percentage bonus for improvements (but not for tiles)
|
|
||||||
fun getImprovementStats(
|
|
||||||
improvement: TileImprovement,
|
|
||||||
observingCiv: Civilization,
|
|
||||||
city: City?,
|
|
||||||
cityUniqueCache: LocalUniqueCache = LocalUniqueCache(false)
|
|
||||||
): Stats {
|
|
||||||
val stats = improvement.cloneStats()
|
|
||||||
if (tile.hasViewableResource(observingCiv) && tile.tileResource.isImprovedBy(improvement.name)
|
|
||||||
&& tile.tileResource.improvementStats != null
|
|
||||||
)
|
|
||||||
stats.add(tile.tileResource.improvementStats!!.clone()) // resource-specific improvement
|
|
||||||
|
|
||||||
val conditionalState = StateForConditionals(civInfo = observingCiv, city = city, tile = tile)
|
|
||||||
for (unique in improvement.getMatchingUniques(UniqueType.Stats, conditionalState)) {
|
|
||||||
stats.add(unique.stats)
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unique in improvement.getMatchingUniques(UniqueType.ImprovementStatsForAdjacencies, conditionalState)) {
|
|
||||||
val adjacent = unique.params[1]
|
|
||||||
val numberOfBonuses = tile.neighbors.count {
|
|
||||||
it.matchesFilter(adjacent, observingCiv)
|
|
||||||
|| it.getUnpillagedRoad().name == adjacent
|
|
||||||
}
|
|
||||||
stats.add(unique.stats.times(numberOfBonuses.toFloat()))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (city != null) stats.add(getImprovementStatsForCity(improvement, city, conditionalState, cityUniqueCache))
|
|
||||||
|
|
||||||
for ((stat, value) in getImprovementPercentageStats(improvement, observingCiv, city, cityUniqueCache)) {
|
|
||||||
stats[stat] *= value.toPercent()
|
|
||||||
}
|
|
||||||
|
|
||||||
return stats
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getImprovementStatsForCity(
|
|
||||||
improvement: TileImprovement,
|
|
||||||
city: City,
|
|
||||||
conditionalState: StateForConditionals,
|
|
||||||
cityUniqueCache: LocalUniqueCache
|
|
||||||
): Stats {
|
|
||||||
val stats = Stats()
|
|
||||||
|
|
||||||
fun statsFromTiles(){
|
|
||||||
// Since the conditionalState contains the current tile, it is different for each tile,
|
|
||||||
// therefore if we want the cache to be useful it needs to hold the pre-filtered uniques,
|
|
||||||
// and then for each improvement we'll filter the uniques locally.
|
|
||||||
// This is still a MASSIVE save of RAM!
|
|
||||||
val tileUniques = cityUniqueCache.get(UniqueType.StatsFromTiles.name,
|
|
||||||
city.getMatchingUniques(UniqueType.StatsFromTiles, StateForConditionals.IgnoreConditionals)
|
|
||||||
.filter { city.matchesFilter(it.params[2]) }) // These are the uniques for all improvements for this city,
|
|
||||||
.filter { it.conditionalsApply(conditionalState) } // ...and this is those with applicable conditions
|
|
||||||
val improvementUniques =
|
|
||||||
improvement.getMatchingUniques(UniqueType.ImprovementStatsOnTile, conditionalState)
|
|
||||||
|
|
||||||
for (unique in tileUniques + improvementUniques) {
|
|
||||||
if (improvement.matchesFilter(unique.params[1])
|
|
||||||
|| unique.params[1] == Constants.freshWater && tile.isAdjacentTo(Constants.freshWater)
|
|
||||||
|| unique.params[1] == "non-fresh water" && !tile.isAdjacentTo(Constants.freshWater)
|
|
||||||
)
|
|
||||||
stats.add(unique.stats)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
statsFromTiles()
|
|
||||||
|
|
||||||
fun statsFromObject() {
|
|
||||||
// Same as above - cache holds unfiltered uniques for the city, while we use only the filtered ones
|
|
||||||
val uniques = cityUniqueCache.get(UniqueType.StatsFromObject.name,
|
|
||||||
city.getMatchingUniques(UniqueType.StatsFromObject, StateForConditionals.IgnoreConditionals))
|
|
||||||
.filter { it.conditionalsApply(conditionalState) }
|
|
||||||
for (unique in uniques) {
|
|
||||||
if (improvement.matchesFilter(unique.params[1])) {
|
|
||||||
stats.add(unique.stats)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
statsFromObject()
|
|
||||||
return stats
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("MemberVisibilityCanBePrivate")
|
|
||||||
fun getImprovementPercentageStats(
|
|
||||||
improvement: TileImprovement,
|
|
||||||
observingCiv: Civilization,
|
|
||||||
city: City?,
|
|
||||||
cityUniqueCache: LocalUniqueCache
|
|
||||||
): Stats {
|
|
||||||
val stats = Stats()
|
|
||||||
val conditionalState = StateForConditionals(civInfo = observingCiv, city = city, tile = tile)
|
|
||||||
|
|
||||||
// I would love to make an interface 'canCallMatchingUniques'
|
|
||||||
// from which both cityInfo and CivilizationInfo derive, so I don't have to duplicate all this code
|
|
||||||
// But something something too much for this PR.
|
|
||||||
|
|
||||||
if (city != null) {
|
|
||||||
// As above, since the conditional is tile-dependant,
|
|
||||||
// we save uniques in the cache without conditional filtering, and use only filtered ones
|
|
||||||
val allStatPercentUniques = cityUniqueCache.get(UniqueType.AllStatsPercentFromObject.name,
|
|
||||||
city.getMatchingUniques(UniqueType.AllStatsPercentFromObject, StateForConditionals.IgnoreConditionals))
|
|
||||||
.filter { it.conditionalsApply(conditionalState) }
|
|
||||||
for (unique in allStatPercentUniques) {
|
|
||||||
if (!improvement.matchesFilter(unique.params[1])) continue
|
|
||||||
for (stat in Stat.values()) {
|
|
||||||
stats[stat] += unique.params[0].toFloat()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Same trick different unique - not sure if worth generalizing this 'late apply' of conditions?
|
|
||||||
val statPercentUniques = cityUniqueCache.get(UniqueType.StatPercentFromObject.name,
|
|
||||||
city.getMatchingUniques(UniqueType.StatPercentFromObject, StateForConditionals.IgnoreConditionals))
|
|
||||||
.filter { it.conditionalsApply(conditionalState) }
|
|
||||||
|
|
||||||
for (unique in statPercentUniques) {
|
|
||||||
if (!improvement.matchesFilter(unique.params[2])) continue
|
|
||||||
val stat = Stat.valueOf(unique.params[1])
|
|
||||||
stats[stat] += unique.params[0].toFloat()
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
for (unique in observingCiv.getMatchingUniques(UniqueType.AllStatsPercentFromObject, conditionalState)) {
|
|
||||||
if (!improvement.matchesFilter(unique.params[1])) continue
|
|
||||||
for (stat in Stat.values()) {
|
|
||||||
stats[stat] += unique.params[0].toFloat()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (unique in observingCiv.getMatchingUniques(UniqueType.StatPercentFromObject, conditionalState)) {
|
|
||||||
if (!improvement.matchesFilter(unique.params[2])) continue
|
|
||||||
val stat = Stat.valueOf(unique.params[1])
|
|
||||||
stats[stat] += unique.params[0].toFloat()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return stats
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Marks tile as target tile for a building with a [UniqueType.CreatesOneImprovement] unique */
|
/** Marks tile as target tile for a building with a [UniqueType.CreatesOneImprovement] unique */
|
||||||
fun markForCreatesOneImprovement(improvement: String) {
|
fun markForCreatesOneImprovement(improvement: String) {
|
||||||
|
@ -3,6 +3,7 @@ package com.unciv.logic.map.tile
|
|||||||
import com.unciv.Constants
|
import com.unciv.Constants
|
||||||
import com.unciv.logic.city.City
|
import com.unciv.logic.city.City
|
||||||
import com.unciv.logic.civilization.Civilization
|
import com.unciv.logic.civilization.Civilization
|
||||||
|
import com.unciv.models.ruleset.tile.TileImprovement
|
||||||
import com.unciv.models.ruleset.unique.LocalUniqueCache
|
import com.unciv.models.ruleset.unique.LocalUniqueCache
|
||||||
import com.unciv.models.ruleset.unique.StateForConditionals
|
import com.unciv.models.ruleset.unique.StateForConditionals
|
||||||
import com.unciv.models.ruleset.unique.UniqueType
|
import com.unciv.models.ruleset.unique.UniqueType
|
||||||
@ -71,7 +72,7 @@ class TileStatFunctions(val tile: Tile) {
|
|||||||
|
|
||||||
val improvement = tile.getUnpillagedTileImprovement()
|
val improvement = tile.getUnpillagedTileImprovement()
|
||||||
if (improvement != null)
|
if (improvement != null)
|
||||||
stats.add(tile.improvementFunctions.getImprovementStats(improvement, observingCiv, city, localUniqueCache))
|
stats.add(getImprovementStats(improvement, observingCiv, city, localUniqueCache))
|
||||||
|
|
||||||
if (stats.gold != 0f && observingCiv.goldenAges.isGoldenAge())
|
if (stats.gold != 0f && observingCiv.goldenAges.isGoldenAge())
|
||||||
stats.gold++
|
stats.gold++
|
||||||
@ -174,4 +175,141 @@ class TileStatFunctions(val tile: Tile) {
|
|||||||
return stats.food + stats.production + stats.gold
|
return stats.food + stats.production + stats.gold
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Also multiplies the stats by the percentage bonus for improvements (but not for tiles)
|
||||||
|
fun getImprovementStats(
|
||||||
|
improvement: TileImprovement,
|
||||||
|
observingCiv: Civilization,
|
||||||
|
city: City?,
|
||||||
|
cityUniqueCache: LocalUniqueCache = LocalUniqueCache(false)
|
||||||
|
): Stats {
|
||||||
|
val stats = improvement.cloneStats()
|
||||||
|
if (tile.hasViewableResource(observingCiv) && tile.tileResource.isImprovedBy(improvement.name)
|
||||||
|
&& tile.tileResource.improvementStats != null
|
||||||
|
)
|
||||||
|
stats.add(tile.tileResource.improvementStats!!.clone()) // resource-specific improvement
|
||||||
|
|
||||||
|
val conditionalState = StateForConditionals(civInfo = observingCiv, city = city, tile = tile)
|
||||||
|
for (unique in improvement.getMatchingUniques(UniqueType.Stats, conditionalState)) {
|
||||||
|
stats.add(unique.stats)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unique in improvement.getMatchingUniques(UniqueType.ImprovementStatsForAdjacencies, conditionalState)) {
|
||||||
|
val adjacent = unique.params[1]
|
||||||
|
val numberOfBonuses = tile.neighbors.count {
|
||||||
|
it.matchesFilter(adjacent, observingCiv)
|
||||||
|
|| it.getUnpillagedRoad().name == adjacent
|
||||||
|
}
|
||||||
|
stats.add(unique.stats.times(numberOfBonuses.toFloat()))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (city != null) stats.add(getImprovementStatsForCity(improvement, city, conditionalState, cityUniqueCache))
|
||||||
|
|
||||||
|
for ((stat, value) in getImprovementPercentageStats(improvement, observingCiv, city, cityUniqueCache)) {
|
||||||
|
stats[stat] *= value.toPercent()
|
||||||
|
}
|
||||||
|
|
||||||
|
return stats
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getImprovementStatsForCity(
|
||||||
|
improvement: TileImprovement,
|
||||||
|
city: City,
|
||||||
|
conditionalState: StateForConditionals,
|
||||||
|
cityUniqueCache: LocalUniqueCache
|
||||||
|
): Stats {
|
||||||
|
val stats = Stats()
|
||||||
|
|
||||||
|
fun statsFromTiles(){
|
||||||
|
// Since the conditionalState contains the current tile, it is different for each tile,
|
||||||
|
// therefore if we want the cache to be useful it needs to hold the pre-filtered uniques,
|
||||||
|
// and then for each improvement we'll filter the uniques locally.
|
||||||
|
// This is still a MASSIVE save of RAM!
|
||||||
|
val tileUniques = cityUniqueCache.get(UniqueType.StatsFromTiles.name,
|
||||||
|
city.getMatchingUniques(UniqueType.StatsFromTiles, StateForConditionals.IgnoreConditionals)
|
||||||
|
.filter { city.matchesFilter(it.params[2]) }) // These are the uniques for all improvements for this city,
|
||||||
|
.filter { it.conditionalsApply(conditionalState) } // ...and this is those with applicable conditions
|
||||||
|
val improvementUniques =
|
||||||
|
improvement.getMatchingUniques(UniqueType.ImprovementStatsOnTile, conditionalState)
|
||||||
|
|
||||||
|
for (unique in tileUniques + improvementUniques) {
|
||||||
|
if (improvement.matchesFilter(unique.params[1])
|
||||||
|
|| unique.params[1] == Constants.freshWater && tile.isAdjacentTo(Constants.freshWater)
|
||||||
|
|| unique.params[1] == "non-fresh water" && !tile.isAdjacentTo(Constants.freshWater)
|
||||||
|
)
|
||||||
|
stats.add(unique.stats)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
statsFromTiles()
|
||||||
|
|
||||||
|
fun statsFromObject() {
|
||||||
|
// Same as above - cache holds unfiltered uniques for the city, while we use only the filtered ones
|
||||||
|
val uniques = cityUniqueCache.get(UniqueType.StatsFromObject.name,
|
||||||
|
city.getMatchingUniques(UniqueType.StatsFromObject, StateForConditionals.IgnoreConditionals))
|
||||||
|
.filter { it.conditionalsApply(conditionalState) }
|
||||||
|
for (unique in uniques) {
|
||||||
|
if (improvement.matchesFilter(unique.params[1])) {
|
||||||
|
stats.add(unique.stats)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
statsFromObject()
|
||||||
|
return stats
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("MemberVisibilityCanBePrivate")
|
||||||
|
fun getImprovementPercentageStats(
|
||||||
|
improvement: TileImprovement,
|
||||||
|
observingCiv: Civilization,
|
||||||
|
city: City?,
|
||||||
|
cityUniqueCache: LocalUniqueCache
|
||||||
|
): Stats {
|
||||||
|
val stats = Stats()
|
||||||
|
val conditionalState = StateForConditionals(civInfo = observingCiv, city = city, tile = tile)
|
||||||
|
|
||||||
|
// I would love to make an interface 'canCallMatchingUniques'
|
||||||
|
// from which both cityInfo and CivilizationInfo derive, so I don't have to duplicate all this code
|
||||||
|
// But something something too much for this PR.
|
||||||
|
|
||||||
|
if (city != null) {
|
||||||
|
// As above, since the conditional is tile-dependant,
|
||||||
|
// we save uniques in the cache without conditional filtering, and use only filtered ones
|
||||||
|
val allStatPercentUniques = cityUniqueCache.get(UniqueType.AllStatsPercentFromObject.name,
|
||||||
|
city.getMatchingUniques(UniqueType.AllStatsPercentFromObject, StateForConditionals.IgnoreConditionals))
|
||||||
|
.filter { it.conditionalsApply(conditionalState) }
|
||||||
|
for (unique in allStatPercentUniques) {
|
||||||
|
if (!improvement.matchesFilter(unique.params[1])) continue
|
||||||
|
for (stat in Stat.values()) {
|
||||||
|
stats[stat] += unique.params[0].toFloat()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same trick different unique - not sure if worth generalizing this 'late apply' of conditions?
|
||||||
|
val statPercentUniques = cityUniqueCache.get(UniqueType.StatPercentFromObject.name,
|
||||||
|
city.getMatchingUniques(UniqueType.StatPercentFromObject, StateForConditionals.IgnoreConditionals))
|
||||||
|
.filter { it.conditionalsApply(conditionalState) }
|
||||||
|
|
||||||
|
for (unique in statPercentUniques) {
|
||||||
|
if (!improvement.matchesFilter(unique.params[2])) continue
|
||||||
|
val stat = Stat.valueOf(unique.params[1])
|
||||||
|
stats[stat] += unique.params[0].toFloat()
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
for (unique in observingCiv.getMatchingUniques(UniqueType.AllStatsPercentFromObject, conditionalState)) {
|
||||||
|
if (!improvement.matchesFilter(unique.params[1])) continue
|
||||||
|
for (stat in Stat.values()) {
|
||||||
|
stats[stat] += unique.params[0].toFloat()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (unique in observingCiv.getMatchingUniques(UniqueType.StatPercentFromObject, conditionalState)) {
|
||||||
|
if (!improvement.matchesFilter(unique.params[2])) continue
|
||||||
|
val stat = Stat.valueOf(unique.params[1])
|
||||||
|
stats[stat] += unique.params[0].toFloat()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return stats
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -197,13 +197,13 @@ class CityScreen(
|
|||||||
fun isExistingImprovementValuable(tile: Tile, improvementToPlace: TileImprovement): Boolean {
|
fun isExistingImprovementValuable(tile: Tile, improvementToPlace: TileImprovement): Boolean {
|
||||||
if (tile.improvement == null) return false
|
if (tile.improvement == null) return false
|
||||||
val civInfo = city.civ
|
val civInfo = city.civ
|
||||||
val existingStats = tile.improvementFunctions.getImprovementStats(
|
val existingStats = tile.stats.getImprovementStats(
|
||||||
tile.getTileImprovement()!!,
|
tile.getTileImprovement()!!,
|
||||||
civInfo,
|
civInfo,
|
||||||
city,
|
city,
|
||||||
cityUniqueCache
|
cityUniqueCache
|
||||||
)
|
)
|
||||||
val replacingStats = tile.improvementFunctions.getImprovementStats(
|
val replacingStats = tile.stats.getImprovementStats(
|
||||||
improvementToPlace,
|
improvementToPlace,
|
||||||
civInfo,
|
civInfo,
|
||||||
city,
|
city,
|
||||||
|
@ -155,7 +155,7 @@ class ImprovementPickerScreen(
|
|||||||
val statIcons = getStatIconsTable(provideResource, removeImprovement)
|
val statIcons = getStatIconsTable(provideResource, removeImprovement)
|
||||||
|
|
||||||
// get benefits of the new improvement
|
// get benefits of the new improvement
|
||||||
val stats = tile.improvementFunctions.getImprovementStats(
|
val stats = tile.stats.getImprovementStats(
|
||||||
improvement,
|
improvement,
|
||||||
currentPlayerCiv,
|
currentPlayerCiv,
|
||||||
tile.getCity(),
|
tile.getCity(),
|
||||||
@ -164,7 +164,7 @@ class ImprovementPickerScreen(
|
|||||||
// subtract the benefits of the replaced improvement, if any
|
// subtract the benefits of the replaced improvement, if any
|
||||||
val existingImprovement = tile.getTileImprovement()
|
val existingImprovement = tile.getTileImprovement()
|
||||||
if (existingImprovement != null && removeImprovement) {
|
if (existingImprovement != null && removeImprovement) {
|
||||||
val existingStats = tile.improvementFunctions.getImprovementStats(
|
val existingStats = tile.stats.getImprovementStats(
|
||||||
existingImprovement,
|
existingImprovement,
|
||||||
currentPlayerCiv,
|
currentPlayerCiv,
|
||||||
tile.getCity(),
|
tile.getCity(),
|
||||||
|
Reference in New Issue
Block a user