mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-29 06:51:30 -04:00
Converted stat list to stat tree (#6022)
* Converted stat list to stat tree - current changes do not affect UI at all, since we're still going by the shallow mapping that existed beforehand * Display details of both buildings and uniques * Unique stats now add correctly to building base stats, good thing we have tests :) * Stat details are now click-to-expand, and calculate correctly :) * Added small +/- button to show it's expandable
This commit is contained in:
parent
39ed8bd269
commit
a8dbd4784c
@ -84,10 +84,10 @@ class CityConstructions {
|
|||||||
/**
|
/**
|
||||||
* @return [Stats] provided by all built buildings in city plus the bonus from Library
|
* @return [Stats] provided by all built buildings in city plus the bonus from Library
|
||||||
*/
|
*/
|
||||||
fun getStats(): Stats {
|
fun getStats(): StatTreeNode {
|
||||||
val stats = Stats()
|
val stats = StatTreeNode()
|
||||||
for (building in getBuiltBuildings())
|
for (building in getBuiltBuildings())
|
||||||
stats.add(building.getStats(cityInfo))
|
stats.addStats(building.getStats(cityInfo), building.name)
|
||||||
return stats
|
return stats
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,9 +7,7 @@ import com.unciv.logic.map.RoadStatus
|
|||||||
import com.unciv.models.Counter
|
import com.unciv.models.Counter
|
||||||
import com.unciv.models.ruleset.Building
|
import com.unciv.models.ruleset.Building
|
||||||
import com.unciv.models.ruleset.ModOptionsConstants
|
import com.unciv.models.ruleset.ModOptionsConstants
|
||||||
import com.unciv.models.ruleset.unique.StateForConditionals
|
|
||||||
import com.unciv.models.ruleset.unique.Unique
|
import com.unciv.models.ruleset.unique.Unique
|
||||||
import com.unciv.models.ruleset.unique.UniqueMapTyped
|
|
||||||
import com.unciv.models.ruleset.unique.UniqueType
|
import com.unciv.models.ruleset.unique.UniqueType
|
||||||
import com.unciv.models.ruleset.unit.BaseUnit
|
import com.unciv.models.ruleset.unit.BaseUnit
|
||||||
import com.unciv.models.stats.Stat
|
import com.unciv.models.stats.Stat
|
||||||
@ -19,6 +17,42 @@ import com.unciv.ui.utils.toPercent
|
|||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
|
|
||||||
|
class StatTreeNode {
|
||||||
|
val children = LinkedHashMap<String, StatTreeNode>()
|
||||||
|
private var innerStats: Stats? = null
|
||||||
|
|
||||||
|
private fun addInnerStats(stats: Stats) {
|
||||||
|
if (innerStats == null) innerStats = stats
|
||||||
|
else innerStats!!.add(stats) // What happens if we add 2 stats to the same leaf?
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addStats(newStats: Stats, vararg hierarchyList: String) {
|
||||||
|
if (hierarchyList.isEmpty()) {
|
||||||
|
addInnerStats(newStats)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val childName = hierarchyList.first()
|
||||||
|
if (!children.containsKey(childName))
|
||||||
|
children[childName] = StatTreeNode()
|
||||||
|
children[childName]!!.addStats(newStats, *hierarchyList.drop(1).toTypedArray())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun add(otherTree: StatTreeNode) {
|
||||||
|
if (otherTree.innerStats != null) addInnerStats(otherTree.innerStats!!)
|
||||||
|
for ((key, value) in otherTree.children) {
|
||||||
|
if (!children.containsKey(key)) children[key] = value
|
||||||
|
else children[key]!!.add(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val totalStats: Stats by lazy {
|
||||||
|
val toReturn = Stats()
|
||||||
|
if (innerStats != null) toReturn.add(innerStats!!)
|
||||||
|
for (child in children.values) toReturn.add(child.totalStats)
|
||||||
|
toReturn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Holds and calculates [Stats] for a city.
|
/** Holds and calculates [Stats] for a city.
|
||||||
*
|
*
|
||||||
* No field needs to be saved, all are calculated on the fly,
|
* No field needs to be saved, all are calculated on the fly,
|
||||||
@ -27,6 +61,8 @@ import kotlin.math.min
|
|||||||
class CityStats(val cityInfo: CityInfo) {
|
class CityStats(val cityInfo: CityInfo) {
|
||||||
//region Fields, Transient
|
//region Fields, Transient
|
||||||
|
|
||||||
|
var baseStatTree = StatTreeNode()
|
||||||
|
|
||||||
var baseStatList = LinkedHashMap<String, Stats>()
|
var baseStatList = LinkedHashMap<String, Stats>()
|
||||||
|
|
||||||
var statPercentBonusList = LinkedHashMap<String, Stats>()
|
var statPercentBonusList = LinkedHashMap<String, Stats>()
|
||||||
@ -168,10 +204,10 @@ class CityStats(val cityInfo: CityInfo) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun getStatsFromUniquesBySource():StatMap {
|
private fun getStatsFromUniquesBySource(): StatTreeNode {
|
||||||
val sourceToStats = StatMap()
|
val sourceToStats = StatTreeNode()
|
||||||
fun addUniqueStats(unique:Unique) =
|
fun addUniqueStats(unique:Unique) =
|
||||||
sourceToStats.add(unique.sourceObjectType?.name ?: "", unique.stats)
|
sourceToStats.addStats(unique.stats, unique.sourceObjectType?.name ?: "", unique.sourceObjectName ?: "")
|
||||||
|
|
||||||
for (unique in cityInfo.getMatchingUniques(UniqueType.Stats))
|
for (unique in cityInfo.getMatchingUniques(UniqueType.Stats))
|
||||||
addUniqueStats(unique)
|
addUniqueStats(unique)
|
||||||
@ -184,7 +220,7 @@ class CityStats(val cityInfo: CityInfo) {
|
|||||||
for (unique in cityInfo.getMatchingUniques(UniqueType.StatsPerPopulation))
|
for (unique in cityInfo.getMatchingUniques(UniqueType.StatsPerPopulation))
|
||||||
if (cityInfo.matchesFilter(unique.params[2])) {
|
if (cityInfo.matchesFilter(unique.params[2])) {
|
||||||
val amountOfEffects = (cityInfo.population.population / unique.params[1].toInt()).toFloat()
|
val amountOfEffects = (cityInfo.population.population / unique.params[1].toInt()).toFloat()
|
||||||
sourceToStats.add(unique.sourceObjectType?.name ?: "", unique.stats.times(amountOfEffects))
|
sourceToStats.addStats(unique.stats.times(amountOfEffects), unique.sourceObjectType?.name ?: "", unique.sourceObjectName ?: "")
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unique in cityInfo.getMatchingUniques(UniqueType.StatsFromXPopulation))
|
for (unique in cityInfo.getMatchingUniques(UniqueType.StatsFromXPopulation))
|
||||||
@ -201,7 +237,7 @@ class CityStats(val cityInfo: CityInfo) {
|
|||||||
addUniqueStats(unique)
|
addUniqueStats(unique)
|
||||||
//
|
//
|
||||||
|
|
||||||
renameStatmapKeys(sourceToStats)
|
renameStatmapKeys(sourceToStats.children)
|
||||||
|
|
||||||
return sourceToStats
|
return sourceToStats
|
||||||
}
|
}
|
||||||
@ -218,6 +254,18 @@ class CityStats(val cityInfo: CityInfo) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun<T> renameStatmapKeys(statMap: LinkedHashMap<String, T>){
|
||||||
|
fun rename(source: String, displayedSource: String) {
|
||||||
|
if (!statMap.containsKey(source)) return
|
||||||
|
statMap.put(displayedSource, statMap[source]!!)
|
||||||
|
statMap.remove(source)
|
||||||
|
}
|
||||||
|
rename("Wonder", "Wonders")
|
||||||
|
rename("Building", "Buildings")
|
||||||
|
rename("Policy", "Policies")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun getStatPercentBonusesFromGoldenAge(isGoldenAge: Boolean): Stats {
|
private fun getStatPercentBonusesFromGoldenAge(isGoldenAge: Boolean): Stats {
|
||||||
val stats = Stats()
|
val stats = Stats()
|
||||||
if (isGoldenAge) {
|
if (isGoldenAge) {
|
||||||
@ -348,7 +396,7 @@ class CityStats(val cityInfo: CityInfo) {
|
|||||||
|
|
||||||
// needs to be a separate function because we need to know the global happiness state
|
// needs to be a separate function because we need to know the global happiness state
|
||||||
// in order to determine how much food is produced in a city!
|
// in order to determine how much food is produced in a city!
|
||||||
fun updateCityHappiness(statsFromBuildings: Stats) {
|
fun updateCityHappiness(statsFromBuildings: StatTreeNode) {
|
||||||
val civInfo = cityInfo.civInfo
|
val civInfo = cityInfo.civInfo
|
||||||
val newHappinessList = LinkedHashMap<String, Float>()
|
val newHappinessList = LinkedHashMap<String, Float>()
|
||||||
var unhappinessModifier = civInfo.getDifficulty().unhappinessModifier
|
var unhappinessModifier = civInfo.getDifficulty().unhappinessModifier
|
||||||
@ -395,15 +443,15 @@ class CityStats(val cityInfo: CityInfo) {
|
|||||||
.toFloat()
|
.toFloat()
|
||||||
if (happinessFromSpecialists > 0) newHappinessList["Specialists"] = happinessFromSpecialists
|
if (happinessFromSpecialists > 0) newHappinessList["Specialists"] = happinessFromSpecialists
|
||||||
|
|
||||||
newHappinessList["Buildings"] = statsFromBuildings.happiness.toInt().toFloat()
|
newHappinessList["Buildings"] = statsFromBuildings.totalStats.happiness.toInt().toFloat()
|
||||||
|
|
||||||
newHappinessList["Tile yields"] = statsFromTiles.happiness
|
newHappinessList["Tile yields"] = statsFromTiles.happiness
|
||||||
|
|
||||||
val happinessBySource = getStatsFromUniquesBySource()
|
val happinessBySource = getStatsFromUniquesBySource()
|
||||||
for ((source, stats) in happinessBySource)
|
for ((source, stats) in happinessBySource.children)
|
||||||
if (stats.happiness != 0f) {
|
if (stats.totalStats.happiness != 0f) {
|
||||||
if (!newHappinessList.containsKey(source)) newHappinessList[source] = 0f
|
if (!newHappinessList.containsKey(source)) newHappinessList[source] = 0f
|
||||||
newHappinessList[source] = newHappinessList[source]!! + stats.happiness
|
newHappinessList[source] = newHappinessList[source]!! + stats.totalStats.happiness
|
||||||
}
|
}
|
||||||
|
|
||||||
// we don't want to modify the existing happiness list because that leads
|
// we don't want to modify the existing happiness list because that leads
|
||||||
@ -411,26 +459,28 @@ class CityStats(val cityInfo: CityInfo) {
|
|||||||
happinessList = newHappinessList
|
happinessList = newHappinessList
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateBaseStatList(statsFromBuildings: Stats) {
|
private fun updateBaseStatList(statsFromBuildings: StatTreeNode) {
|
||||||
|
val newBaseStatTree = StatTreeNode()
|
||||||
|
|
||||||
val newBaseStatList =
|
val newBaseStatList =
|
||||||
StatMap() // we don't edit the existing baseStatList directly, in order to avoid concurrency exceptions
|
StatMap() // we don't edit the existing baseStatList directly, in order to avoid concurrency exceptions
|
||||||
|
|
||||||
newBaseStatList["Population"] = Stats(
|
newBaseStatTree.addStats(Stats(
|
||||||
science = cityInfo.population.population.toFloat(),
|
science = cityInfo.population.population.toFloat(),
|
||||||
production = cityInfo.population.getFreePopulation().toFloat()
|
production = cityInfo.population.getFreePopulation().toFloat()
|
||||||
)
|
), "Population")
|
||||||
newBaseStatList["Tile yields"] = statsFromTiles
|
newBaseStatList["Tile yields"] = statsFromTiles
|
||||||
newBaseStatList["Specialists"] =
|
newBaseStatList["Specialists"] =
|
||||||
getStatsFromSpecialists(cityInfo.population.getNewSpecialists())
|
getStatsFromSpecialists(cityInfo.population.getNewSpecialists())
|
||||||
newBaseStatList["Trade routes"] = getStatsFromTradeRoute()
|
newBaseStatList["Trade routes"] = getStatsFromTradeRoute()
|
||||||
newBaseStatList["Buildings"] = statsFromBuildings
|
newBaseStatTree.children["Buildings"] = statsFromBuildings
|
||||||
newBaseStatList["City-States"] = getStatsFromCityStates()
|
newBaseStatList["City-States"] = getStatsFromCityStates()
|
||||||
|
|
||||||
val statMap = getStatsFromUniquesBySource()
|
for ((source, stats) in newBaseStatList)
|
||||||
for ((source, stats) in statMap)
|
newBaseStatTree.addStats(stats, source)
|
||||||
newBaseStatList.add(source, stats)
|
|
||||||
|
|
||||||
baseStatList = newBaseStatList
|
newBaseStatTree.add(getStatsFromUniquesBySource())
|
||||||
|
baseStatTree = newBaseStatTree
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -490,8 +540,8 @@ class CityStats(val cityInfo: CityInfo) {
|
|||||||
private fun updateFinalStatList(currentConstruction: IConstruction, citySpecificUniques: Sequence<Unique>) {
|
private fun updateFinalStatList(currentConstruction: IConstruction, citySpecificUniques: Sequence<Unique>) {
|
||||||
val newFinalStatList = StatMap() // again, we don't edit the existing currentCityStats directly, in order to avoid concurrency exceptions
|
val newFinalStatList = StatMap() // again, we don't edit the existing currentCityStats directly, in order to avoid concurrency exceptions
|
||||||
|
|
||||||
for (entry in baseStatList)
|
for ((key, value) in baseStatTree.children)
|
||||||
newFinalStatList[entry.key] = entry.value.clone()
|
newFinalStatList[key] = value.totalStats.clone()
|
||||||
|
|
||||||
val statPercentBonusesSum = Stats()
|
val statPercentBonusesSum = Stats()
|
||||||
for (bonus in statPercentBonusList.values) statPercentBonusesSum.add(bonus)
|
for (bonus in statPercentBonusList.values) statPercentBonusesSum.add(bonus)
|
||||||
@ -499,9 +549,15 @@ class CityStats(val cityInfo: CityInfo) {
|
|||||||
for (entry in newFinalStatList.values)
|
for (entry in newFinalStatList.values)
|
||||||
entry.production *= statPercentBonusesSum.production.toPercent()
|
entry.production *= statPercentBonusesSum.production.toPercent()
|
||||||
|
|
||||||
|
// We only add the 'extra stats from production' AFTER we calculate the production INCLUDING BONUSES
|
||||||
val statsFromProduction = getStatsFromProduction(newFinalStatList.values.map { it.production }.sum())
|
val statsFromProduction = getStatsFromProduction(newFinalStatList.values.map { it.production }.sum())
|
||||||
baseStatList = LinkedHashMap(baseStatList).apply { put("Construction", statsFromProduction) } // concurrency-safe addition
|
if (!statsFromProduction.isEmpty()) {
|
||||||
newFinalStatList["Construction"] = statsFromProduction
|
baseStatTree = StatTreeNode().apply {
|
||||||
|
children.putAll(baseStatTree.children)
|
||||||
|
addStats(statsFromProduction, "Production")
|
||||||
|
} // concurrency-safe addition
|
||||||
|
newFinalStatList["Construction"] = statsFromProduction
|
||||||
|
}
|
||||||
|
|
||||||
for (entry in newFinalStatList.values) {
|
for (entry in newFinalStatList.values) {
|
||||||
entry.gold *= statPercentBonusesSum.gold.toPercent()
|
entry.gold *= statPercentBonusesSum.gold.toPercent()
|
||||||
|
@ -167,7 +167,7 @@ class TechManager {
|
|||||||
// The Science the Great Scientist generates does not include Science from Policies, Trade routes and City-States.
|
// The Science the Great Scientist generates does not include Science from Policies, Trade routes and City-States.
|
||||||
var allCitiesScience = 0f
|
var allCitiesScience = 0f
|
||||||
civInfo.cities.forEach { it ->
|
civInfo.cities.forEach { it ->
|
||||||
val totalBaseScience = it.cityStats.baseStatList.values.map { it.science }.sum()
|
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.statPercentBonusList.filter { it.key != "Policies" }.values.map { it.science }.sum()
|
||||||
allCitiesScience += totalBaseScience * totalBonusPercents.toPercent()
|
allCitiesScience += totalBaseScience * totalBonusPercents.toPercent()
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
package com.unciv.ui.cityscreen
|
package com.unciv.ui.cityscreen
|
||||||
|
|
||||||
import com.badlogic.gdx.graphics.Color
|
import com.badlogic.gdx.graphics.Color
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.Touchable
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||||
import com.badlogic.gdx.utils.Align
|
import com.badlogic.gdx.utils.Align
|
||||||
import com.unciv.Constants
|
import com.unciv.Constants
|
||||||
import com.unciv.UncivGame
|
import com.unciv.UncivGame
|
||||||
import com.unciv.logic.city.CityInfo
|
import com.unciv.logic.city.CityInfo
|
||||||
|
import com.unciv.logic.city.CityStats
|
||||||
|
import com.unciv.logic.city.StatTreeNode
|
||||||
import com.unciv.models.UncivSound
|
import com.unciv.models.UncivSound
|
||||||
import com.unciv.models.ruleset.Building
|
import com.unciv.models.ruleset.Building
|
||||||
import com.unciv.models.stats.Stat
|
import com.unciv.models.stats.Stat
|
||||||
@ -143,69 +146,108 @@ class CityInfoTable(private val cityScreen: CityScreen) : Table(BaseScreen.skin)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun addStatsToHashmap(statTreeNode: StatTreeNode, hashMap: HashMap<String, Float>, stat:Stat,
|
||||||
|
showDetails:Boolean, indentation:Int=0) {
|
||||||
|
for ((name, child) in statTreeNode.children) {
|
||||||
|
hashMap["- ".repeat(indentation) + name] = child.totalStats[stat]
|
||||||
|
if (showDetails) addStatsToHashmap(child, hashMap, stat, showDetails, indentation + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun Table.addStatInfo() {
|
private fun Table.addStatInfo() {
|
||||||
val cityStats = cityScreen.city.cityStats
|
val cityStats = cityScreen.city.cityStats
|
||||||
|
|
||||||
|
|
||||||
for (stat in Stat.values()) {
|
for (stat in Stat.values()) {
|
||||||
val relevantBaseStats = LinkedHashMap<String, Float>()
|
val statValuesTable = Table()
|
||||||
|
statValuesTable.touchable = Touchable.enabled
|
||||||
if (stat != Stat.Happiness)
|
|
||||||
for ((key, value) in cityStats.baseStatList)
|
|
||||||
relevantBaseStats[key] = value[stat]
|
|
||||||
else relevantBaseStats.putAll(cityStats.happinessList)
|
|
||||||
for (key in relevantBaseStats.keys.toList())
|
|
||||||
if (relevantBaseStats[key] == 0f) relevantBaseStats.remove(key)
|
|
||||||
|
|
||||||
if (relevantBaseStats.isEmpty()) continue
|
|
||||||
|
|
||||||
val statValuesTable = Table().apply { defaults().pad(2f) }
|
|
||||||
addCategory(stat.name, statValuesTable)
|
addCategory(stat.name, statValuesTable)
|
||||||
|
|
||||||
statValuesTable.add("Base values".toLabel(fontSize = FONT_SIZE_STAT_INFO_HEADER)).pad(4f).colspan(2).row()
|
updateStatValuesTable(stat, cityStats, statValuesTable)
|
||||||
var sumOfAllBaseValues = 0f
|
}
|
||||||
for (entry in relevantBaseStats) {
|
}
|
||||||
val specificStatValue = entry.value
|
|
||||||
|
private fun updateStatValuesTable(
|
||||||
|
stat: Stat,
|
||||||
|
cityStats: CityStats,
|
||||||
|
statValuesTable: Table,
|
||||||
|
showDetails:Boolean = false
|
||||||
|
) {
|
||||||
|
statValuesTable.clear()
|
||||||
|
statValuesTable.defaults().pad(2f)
|
||||||
|
statValuesTable.onClick {
|
||||||
|
updateStatValuesTable(
|
||||||
|
stat,
|
||||||
|
cityStats,
|
||||||
|
statValuesTable,
|
||||||
|
!showDetails
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val relevantBaseStats = LinkedHashMap<String, Float>()
|
||||||
|
|
||||||
|
if (stat != Stat.Happiness)
|
||||||
|
addStatsToHashmap(cityStats.baseStatTree, relevantBaseStats, stat, showDetails)
|
||||||
|
else relevantBaseStats.putAll(cityStats.happinessList)
|
||||||
|
for (key in relevantBaseStats.keys.toList())
|
||||||
|
if (relevantBaseStats[key] == 0f) relevantBaseStats.remove(key)
|
||||||
|
|
||||||
|
if (relevantBaseStats.isEmpty()) return
|
||||||
|
|
||||||
|
statValuesTable.add("Base values".toLabel(fontSize = FONT_SIZE_STAT_INFO_HEADER)).pad(4f)
|
||||||
|
.colspan(2).row()
|
||||||
|
var sumOfAllBaseValues = 0f
|
||||||
|
for (entry in relevantBaseStats) {
|
||||||
|
val specificStatValue = entry.value
|
||||||
|
if (!entry.key.startsWith('-'))
|
||||||
sumOfAllBaseValues += specificStatValue
|
sumOfAllBaseValues += specificStatValue
|
||||||
|
statValuesTable.add(entry.key.toLabel()).left()
|
||||||
|
statValuesTable.add(specificStatValue.toOneDecimalLabel()).row()
|
||||||
|
}
|
||||||
|
statValuesTable.addSeparator()
|
||||||
|
statValuesTable.add("Total".toLabel())
|
||||||
|
statValuesTable.add(sumOfAllBaseValues.toOneDecimalLabel()).row()
|
||||||
|
|
||||||
|
val relevantBonuses = cityStats.statPercentBonusList.filter { it.value[stat] != 0f }
|
||||||
|
if (relevantBonuses.isNotEmpty()) {
|
||||||
|
statValuesTable.add("Bonuses".toLabel(fontSize = FONT_SIZE_STAT_INFO_HEADER)).colspan(2)
|
||||||
|
.padTop(20f).row()
|
||||||
|
var sumOfBonuses = 0f
|
||||||
|
for (entry in relevantBonuses) {
|
||||||
|
val specificStatValue = entry.value[stat]
|
||||||
|
sumOfBonuses += specificStatValue
|
||||||
|
statValuesTable.add(entry.key.toLabel())
|
||||||
|
statValuesTable.add(specificStatValue.toPercentLabel()).row() // negative bonus
|
||||||
|
}
|
||||||
|
statValuesTable.addSeparator()
|
||||||
|
statValuesTable.add("Total".toLabel())
|
||||||
|
statValuesTable.add(sumOfBonuses.toPercentLabel()).row() // negative bonus
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stat != Stat.Happiness) {
|
||||||
|
statValuesTable.add("Final".toLabel(fontSize = FONT_SIZE_STAT_INFO_HEADER)).colspan(2)
|
||||||
|
.padTop(20f).row()
|
||||||
|
var finalTotal = 0f
|
||||||
|
for (entry in cityStats.finalStatList) {
|
||||||
|
val specificStatValue = entry.value[stat]
|
||||||
|
finalTotal += specificStatValue
|
||||||
|
if (specificStatValue == 0f) continue
|
||||||
statValuesTable.add(entry.key.toLabel())
|
statValuesTable.add(entry.key.toLabel())
|
||||||
statValuesTable.add(specificStatValue.toOneDecimalLabel()).row()
|
statValuesTable.add(specificStatValue.toOneDecimalLabel()).row()
|
||||||
}
|
}
|
||||||
statValuesTable.addSeparator()
|
statValuesTable.addSeparator()
|
||||||
statValuesTable.add("Total".toLabel())
|
statValuesTable.add("Total".toLabel())
|
||||||
statValuesTable.add(sumOfAllBaseValues.toOneDecimalLabel()).row()
|
statValuesTable.add(finalTotal.toOneDecimalLabel()).row()
|
||||||
|
|
||||||
val relevantBonuses = cityStats.statPercentBonusList.filter { it.value[stat] != 0f }
|
|
||||||
if (relevantBonuses.isNotEmpty()) {
|
|
||||||
statValuesTable.add("Bonuses".toLabel(fontSize = FONT_SIZE_STAT_INFO_HEADER)).colspan(2).padTop(20f).row()
|
|
||||||
var sumOfBonuses = 0f
|
|
||||||
for (entry in relevantBonuses) {
|
|
||||||
val specificStatValue = entry.value[stat]
|
|
||||||
sumOfBonuses += specificStatValue
|
|
||||||
statValuesTable.add(entry.key.toLabel())
|
|
||||||
statValuesTable.add(specificStatValue.toPercentLabel()).row() // negative bonus
|
|
||||||
}
|
|
||||||
statValuesTable.addSeparator()
|
|
||||||
statValuesTable.add("Total".toLabel())
|
|
||||||
statValuesTable.add(sumOfBonuses.toPercentLabel()).row() // negative bonus
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stat != Stat.Happiness) {
|
|
||||||
statValuesTable.add("Final".toLabel(fontSize = FONT_SIZE_STAT_INFO_HEADER)).colspan(2).padTop(20f).row()
|
|
||||||
var finalTotal = 0f
|
|
||||||
for (entry in cityStats.finalStatList) {
|
|
||||||
val specificStatValue = entry.value[stat]
|
|
||||||
finalTotal += specificStatValue
|
|
||||||
if (specificStatValue == 0f) continue
|
|
||||||
statValuesTable.add(entry.key.toLabel())
|
|
||||||
statValuesTable.add(specificStatValue.toOneDecimalLabel()).row()
|
|
||||||
}
|
|
||||||
statValuesTable.addSeparator()
|
|
||||||
statValuesTable.add("Total".toLabel())
|
|
||||||
statValuesTable.add(finalTotal.toOneDecimalLabel()).row()
|
|
||||||
}
|
|
||||||
|
|
||||||
statValuesTable.padBottom(4f)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
statValuesTable.pack()
|
||||||
|
val toggleButtonChar = if (showDetails) "-" else "+"
|
||||||
|
val toggleButton = toggleButtonChar.toLabel().apply { setAlignment(Align.center) }
|
||||||
|
.surroundWithCircle(25f, color = ImageGetter.getBlue())
|
||||||
|
.surroundWithCircle(27f, false)
|
||||||
|
statValuesTable.addActor(toggleButton)
|
||||||
|
toggleButton.setPosition(0f, statValuesTable.height, Align.topLeft)
|
||||||
|
|
||||||
|
statValuesTable.padBottom(4f)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Table.addGreatPersonPointInfo(cityInfo: CityInfo) {
|
private fun Table.addGreatPersonPointInfo(cityInfo: CityInfo) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user