mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-26 21:35:14 -04:00
Stat bonus drilldown (#6053)
* Step 1 - converted stat bonus list to tree. No visual difference yet, since the stat bonus list is still generated in the same way. * Step 2 - updateStatPercentBonusList converted to tree form * Step 3 - buildings converted to tree form - now user visible! * Step 4 - Bonuses from uniques are now drilldownable * Removed unneeded todo * Welp, turns out I forgot to apply conditionals
This commit is contained in:
parent
824efcb1a9
commit
84ef8944d0
@ -253,9 +253,7 @@ object SpecificUnitAutomation {
|
|||||||
val relatedStat = improvement.maxByOrNull { it.value }?.key ?: Stat.Culture
|
val relatedStat = improvement.maxByOrNull { it.value }?.key ?: Stat.Culture
|
||||||
|
|
||||||
val citiesByStatBoost = unit.civInfo.cities.sortedByDescending {
|
val citiesByStatBoost = unit.civInfo.cities.sortedByDescending {
|
||||||
val stats = Stats()
|
it.cityStats.statPercentBonusTree.totalStats[relatedStat]
|
||||||
for (bonus in it.cityStats.statPercentBonusList.values) stats.add(bonus)
|
|
||||||
stats[relatedStat]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -107,16 +107,6 @@ class CityConstructions {
|
|||||||
return maintenanceCost
|
return maintenanceCost
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Bonus (%) [Stats] provided by all built buildings in city
|
|
||||||
*/
|
|
||||||
fun getStatPercentBonuses(): Stats {
|
|
||||||
val stats = Stats()
|
|
||||||
for (building in getBuiltBuildings())
|
|
||||||
stats.add(building.getStatPercentageBonuses(cityInfo))
|
|
||||||
return stats
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getCityProductionTextForCityButton(): String {
|
fun getCityProductionTextForCityButton(): String {
|
||||||
val currentConstructionSnapshot = currentConstructionFromQueue // See below
|
val currentConstructionSnapshot = currentConstructionFromQueue // See below
|
||||||
var result = currentConstructionSnapshot.tr()
|
var result = currentConstructionSnapshot.tr()
|
||||||
|
@ -45,12 +45,13 @@ class StatTreeNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val totalStats: Stats by lazy {
|
val totalStats: Stats
|
||||||
val toReturn = Stats()
|
get() {
|
||||||
if (innerStats != null) toReturn.add(innerStats!!)
|
val toReturn = Stats()
|
||||||
for (child in children.values) toReturn.add(child.totalStats)
|
if (innerStats != null) toReturn.add(innerStats!!)
|
||||||
toReturn
|
for (child in children.values) toReturn.add(child.totalStats)
|
||||||
}
|
return toReturn
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds and calculates [Stats] for a city.
|
/** Holds and calculates [Stats] for a city.
|
||||||
@ -63,10 +64,10 @@ class CityStats(val cityInfo: CityInfo) {
|
|||||||
|
|
||||||
var baseStatTree = StatTreeNode()
|
var baseStatTree = StatTreeNode()
|
||||||
|
|
||||||
var baseStatList = LinkedHashMap<String, Stats>()
|
|
||||||
|
|
||||||
var statPercentBonusList = LinkedHashMap<String, Stats>()
|
var statPercentBonusList = LinkedHashMap<String, Stats>()
|
||||||
|
|
||||||
|
var statPercentBonusTree = StatTreeNode()
|
||||||
|
|
||||||
// Computed from baseStatList and statPercentBonusList - this is so the players can see a breakdown
|
// Computed from baseStatList and statPercentBonusList - this is so the players can see a breakdown
|
||||||
var finalStatList = LinkedHashMap<String, Stats>()
|
var finalStatList = LinkedHashMap<String, Stats>()
|
||||||
|
|
||||||
@ -124,6 +125,12 @@ class CityStats(val cityInfo: CityInfo) {
|
|||||||
return stats
|
return stats
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun addStatPercentBonusesFromBuildings(statPercentBonusTree: StatTreeNode) {
|
||||||
|
for (building in cityInfo.cityConstructions.getBuiltBuildings())
|
||||||
|
statPercentBonusTree.addStats(building.getStatPercentageBonuses(cityInfo), "Buildings", building.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private fun getStatsFromCityStates(): Stats {
|
private fun getStatsFromCityStates(): Stats {
|
||||||
val stats = Stats()
|
val stats = Stats()
|
||||||
@ -265,10 +272,11 @@ class CityStats(val cityInfo: CityInfo) {
|
|||||||
return stats
|
return stats
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getStatsPercentBonusesFromUniquesBySource(currentConstruction: IConstruction):StatMap {
|
private fun getStatsPercentBonusesFromUniquesBySource(currentConstruction: IConstruction): StatTreeNode {
|
||||||
val sourceToStats = StatMap()
|
val sourceToStats = StatTreeNode()
|
||||||
fun addUniqueStats(unique: Unique, stat:Stat, amount:Float) {
|
|
||||||
sourceToStats.add(getSourceNameForUnique(unique), Stats().add(stat, amount))
|
fun addUniqueStats(unique:Unique, stat:Stat, amount:Float) {
|
||||||
|
sourceToStats.addStats(Stats().add(stat, amount), getSourceNameForUnique(unique), unique.sourceObjectName ?: "")
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unique in cityInfo.getMatchingUniques(UniqueType.StatPercentBonus)) {
|
for (unique in cityInfo.getMatchingUniques(UniqueType.StatPercentBonus)) {
|
||||||
@ -472,25 +480,24 @@ class CityStats(val cityInfo: CityInfo) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun updateStatPercentBonusList(currentConstruction: IConstruction, localBuildingUniques: Sequence<Unique>) {
|
private fun updateStatPercentBonusList(currentConstruction: IConstruction) {
|
||||||
val newStatPercentBonusList = StatMap()
|
val newStatsBonusTree = StatTreeNode()
|
||||||
|
|
||||||
newStatPercentBonusList["Golden Age"] = getStatPercentBonusesFromGoldenAge(cityInfo.civInfo.goldenAges.isGoldenAge())
|
newStatsBonusTree.addStats(getStatPercentBonusesFromGoldenAge(cityInfo.civInfo.goldenAges.isGoldenAge()),"Golden Age")
|
||||||
.plus(cityInfo.cityConstructions.getStatPercentBonuses()) // This function is to be deprecated but it'll take a while.
|
addStatPercentBonusesFromBuildings(newStatsBonusTree)
|
||||||
newStatPercentBonusList["Railroads"] = getStatPercentBonusesFromRailroad() // Name chosen same as tech, for translation, but theoretically independent
|
newStatsBonusTree.addStats(getStatPercentBonusesFromRailroad(), "Railroad")
|
||||||
newStatPercentBonusList["Puppet City"] = getStatPercentBonusesFromPuppetCity()
|
newStatsBonusTree.addStats(getStatPercentBonusesFromPuppetCity(), "Puppet City")
|
||||||
newStatPercentBonusList["Unit Supply"] = getStatPercentBonusesFromUnitSupply()
|
newStatsBonusTree.addStats(getStatPercentBonusesFromUnitSupply(), "Unit Supply")
|
||||||
|
|
||||||
for ((source, stats) in getStatsPercentBonusesFromUniquesBySource(currentConstruction))
|
newStatsBonusTree.add(getStatsPercentBonusesFromUniquesBySource(currentConstruction))
|
||||||
newStatPercentBonusList.add(source, stats)
|
|
||||||
|
|
||||||
if (UncivGame.Current.superchargedForDebug) {
|
if (UncivGame.Current.superchargedForDebug) {
|
||||||
val stats = Stats()
|
val stats = Stats()
|
||||||
for (stat in Stat.values()) stats[stat] = 10000f
|
for (stat in Stat.values()) stats[stat] = 10000f
|
||||||
newStatPercentBonusList["Supercharged"] = stats
|
newStatsBonusTree.addStats(stats, "Supercharged")
|
||||||
}
|
}
|
||||||
|
|
||||||
statPercentBonusList = newStatPercentBonusList
|
statPercentBonusTree = newStatsBonusTree
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Does not update tile stats - instead, updating tile stats updates this */
|
/** Does not update tile stats - instead, updating tile stats updates this */
|
||||||
@ -498,17 +505,12 @@ class CityStats(val cityInfo: CityInfo) {
|
|||||||
updateTileStats:Boolean = true) {
|
updateTileStats:Boolean = true) {
|
||||||
if (updateTileStats) updateTileStats()
|
if (updateTileStats) updateTileStats()
|
||||||
|
|
||||||
// We calculate this here for concurrency reasons
|
|
||||||
// If something needs this, we pass this through as a parameter
|
|
||||||
val localBuildingUniques = cityInfo.cityConstructions.builtBuildingUniqueMap.getAllUniques()
|
|
||||||
|
|
||||||
|
|
||||||
// We need to compute Tile yields before happiness
|
// We need to compute Tile yields before happiness
|
||||||
|
|
||||||
val statsFromBuildings = cityInfo.cityConstructions.getStats() // this is performance heavy, so calculate once
|
val statsFromBuildings = cityInfo.cityConstructions.getStats() // this is performance heavy, so calculate once
|
||||||
updateBaseStatList(statsFromBuildings)
|
updateBaseStatList(statsFromBuildings)
|
||||||
updateCityHappiness(statsFromBuildings)
|
updateCityHappiness(statsFromBuildings)
|
||||||
updateStatPercentBonusList(currentConstruction, localBuildingUniques)
|
updateStatPercentBonusList(currentConstruction)
|
||||||
|
|
||||||
updateFinalStatList(currentConstruction) // again, we don't edit the existing currentCityStats directly, in order to avoid concurrency exceptions
|
updateFinalStatList(currentConstruction) // again, we don't edit the existing currentCityStats directly, in order to avoid concurrency exceptions
|
||||||
|
|
||||||
@ -525,8 +527,7 @@ class CityStats(val cityInfo: CityInfo) {
|
|||||||
for ((key, value) in baseStatTree.children)
|
for ((key, value) in baseStatTree.children)
|
||||||
newFinalStatList[key] = value.totalStats.clone()
|
newFinalStatList[key] = value.totalStats.clone()
|
||||||
|
|
||||||
val statPercentBonusesSum = Stats()
|
val statPercentBonusesSum = statPercentBonusTree.totalStats
|
||||||
for (bonus in statPercentBonusList.values) statPercentBonusesSum.add(bonus)
|
|
||||||
|
|
||||||
for (entry in newFinalStatList.values)
|
for (entry in newFinalStatList.values)
|
||||||
entry.production *= statPercentBonusesSum.production.toPercent()
|
entry.production *= statPercentBonusesSum.production.toPercent()
|
||||||
|
@ -168,7 +168,8 @@ class TechManager {
|
|||||||
var allCitiesScience = 0f
|
var allCitiesScience = 0f
|
||||||
civInfo.cities.forEach { it ->
|
civInfo.cities.forEach { it ->
|
||||||
val totalBaseScience = it.cityStats.baseStatTree.totalStats.science
|
val totalBaseScience = it.cityStats.baseStatTree.totalStats.science
|
||||||
val totalBonusPercents = it.cityStats.statPercentBonusList.filter { it.key != "Policies" }.values.map { it.science }.sum()
|
val totalBonusPercents = it.cityStats.statPercentBonusTree.children.asSequence()
|
||||||
|
.filter { it.key != "Policies" }.map { it.value.totalStats.science }.sum()
|
||||||
allCitiesScience += totalBaseScience * totalBonusPercents.toPercent()
|
allCitiesScience += totalBaseScience * totalBonusPercents.toPercent()
|
||||||
}
|
}
|
||||||
scienceOfLast8Turns[civInfo.gameInfo.turns % 8] = allCitiesScience.toInt()
|
scienceOfLast8Turns[civInfo.gameInfo.turns % 8] = allCitiesScience.toInt()
|
||||||
|
@ -19,7 +19,7 @@ interface IHasUniques {
|
|||||||
* But making this a function is relevant for future "unify Unciv object" plans ;)
|
* But making this a function is relevant for future "unify Unciv object" plans ;)
|
||||||
* */
|
* */
|
||||||
fun getUniqueTarget(): UniqueTarget
|
fun getUniqueTarget(): UniqueTarget
|
||||||
|
|
||||||
fun getMatchingUniques(uniqueTemplate: String, stateForConditionals: StateForConditionals? = null): Sequence<Unique> {
|
fun getMatchingUniques(uniqueTemplate: String, stateForConditionals: StateForConditionals? = null): Sequence<Unique> {
|
||||||
val matchingUniques = uniqueMap[uniqueTemplate] ?: return sequenceOf()
|
val matchingUniques = uniqueMap[uniqueTemplate] ?: return sequenceOf()
|
||||||
return matchingUniques.asSequence().filter { it.conditionalsApply(stateForConditionals) }
|
return matchingUniques.asSequence().filter { it.conditionalsApply(stateForConditionals) }
|
||||||
|
@ -149,7 +149,9 @@ class CityInfoTable(private val cityScreen: CityScreen) : Table(BaseScreen.skin)
|
|||||||
private fun addStatsToHashmap(statTreeNode: StatTreeNode, hashMap: HashMap<String, Float>, stat:Stat,
|
private fun addStatsToHashmap(statTreeNode: StatTreeNode, hashMap: HashMap<String, Float>, stat:Stat,
|
||||||
showDetails:Boolean, indentation:Int=0) {
|
showDetails:Boolean, indentation:Int=0) {
|
||||||
for ((name, child) in statTreeNode.children) {
|
for ((name, child) in statTreeNode.children) {
|
||||||
hashMap["- ".repeat(indentation) + name] = child.totalStats[stat]
|
val statAmount = child.totalStats[stat]
|
||||||
|
if (statAmount == 0f) continue
|
||||||
|
hashMap["- ".repeat(indentation) + name] = statAmount
|
||||||
if (showDetails) addStatsToHashmap(child, hashMap, stat, showDetails, indentation + 1)
|
if (showDetails) addStatsToHashmap(child, hashMap, stat, showDetails, indentation + 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -207,23 +209,22 @@ class CityInfoTable(private val cityScreen: CityScreen) : Table(BaseScreen.skin)
|
|||||||
statValuesTable.add("Total".toLabel())
|
statValuesTable.add("Total".toLabel())
|
||||||
statValuesTable.add(sumOfAllBaseValues.toOneDecimalLabel()).row()
|
statValuesTable.add(sumOfAllBaseValues.toOneDecimalLabel()).row()
|
||||||
|
|
||||||
val relevantBonuses = cityStats.statPercentBonusList.filter { it.value[stat] != 0f }
|
val relevantBonuses = LinkedHashMap<String, Float>()
|
||||||
if (relevantBonuses.isNotEmpty()) {
|
addStatsToHashmap(cityStats.statPercentBonusTree, relevantBonuses, stat, showDetails)
|
||||||
|
|
||||||
|
val totalBonusStats = cityStats.statPercentBonusTree.totalStats
|
||||||
|
if (totalBonusStats[stat] != 0f) {
|
||||||
statValuesTable.add("Bonuses".toLabel(fontSize = FONT_SIZE_STAT_INFO_HEADER)).colspan(2)
|
statValuesTable.add("Bonuses".toLabel(fontSize = FONT_SIZE_STAT_INFO_HEADER)).colspan(2)
|
||||||
.padTop(20f).row()
|
.padTop(20f).row()
|
||||||
var sumOfBonuses = 0f
|
for ((source, bonusAmount) in relevantBonuses) {
|
||||||
for (entry in relevantBonuses) {
|
statValuesTable.add(source.toLabel()).left()
|
||||||
val specificStatValue = entry.value[stat]
|
statValuesTable.add(bonusAmount.toPercentLabel()).row() // negative bonus
|
||||||
sumOfBonuses += specificStatValue
|
|
||||||
statValuesTable.add(entry.key.toLabel())
|
|
||||||
statValuesTable.add(specificStatValue.toPercentLabel()).row() // negative bonus
|
|
||||||
}
|
}
|
||||||
statValuesTable.addSeparator()
|
statValuesTable.addSeparator()
|
||||||
statValuesTable.add("Total".toLabel())
|
statValuesTable.add("Total".toLabel())
|
||||||
statValuesTable.add(sumOfBonuses.toPercentLabel()).row() // negative bonus
|
statValuesTable.add(totalBonusStats[stat].toPercentLabel()).row() // negative bonus
|
||||||
}
|
|
||||||
|
|
||||||
if (stat != Stat.Happiness) {
|
|
||||||
statValuesTable.add("Final".toLabel(fontSize = FONT_SIZE_STAT_INFO_HEADER)).colspan(2)
|
statValuesTable.add("Final".toLabel(fontSize = FONT_SIZE_STAT_INFO_HEADER)).colspan(2)
|
||||||
.padTop(20f).row()
|
.padTop(20f).row()
|
||||||
var finalTotal = 0f
|
var finalTotal = 0f
|
||||||
|
Loading…
x
Reference in New Issue
Block a user