mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-24 03:53:12 -04:00
Added a table in city screen, to show a breakdown of the ciy stats
This commit is contained in:
parent
39cc236fae
commit
f662cd910d
@ -21,8 +21,8 @@ android {
|
||||
applicationId "com.unciv.game"
|
||||
minSdkVersion 14
|
||||
targetSdkVersion 26
|
||||
versionCode 36
|
||||
versionName "1.4.3"
|
||||
versionCode 37
|
||||
versionName "1.4.4"
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
|
@ -4,12 +4,15 @@ import com.unciv.logic.map.RoadStatus
|
||||
import com.unciv.logic.map.TileInfo
|
||||
import com.unciv.models.gamebasics.Building
|
||||
import com.unciv.models.gamebasics.GameBasics
|
||||
import com.unciv.models.stats.Stat
|
||||
import com.unciv.models.stats.Stats
|
||||
|
||||
|
||||
class CityStats {
|
||||
|
||||
@Transient @JvmField var currentCityStats: Stats = Stats() // This is so we won't have to calculate this multiple times - takes a lot of time, especially on phones
|
||||
@Transient var baseStatList = LinkedHashMap<String,Stats>()
|
||||
@Transient var statModifiers = LinkedHashMap<String,Stats>()
|
||||
@Transient var currentCityStats: Stats = Stats() // This is so we won't have to calculate this multiple times - takes a lot of time, especially on phones
|
||||
@Transient lateinit var cityInfo: CityInfo
|
||||
|
||||
private fun getStatsFromTiles(): Stats {
|
||||
@ -182,19 +185,17 @@ class CityStats {
|
||||
return stats
|
||||
}
|
||||
|
||||
|
||||
fun update() {
|
||||
baseStatList = LinkedHashMap<String, Stats>()
|
||||
val civInfo = cityInfo.civInfo
|
||||
|
||||
val stats = Stats()
|
||||
stats.science += cityInfo.population.population.toFloat()
|
||||
stats.production += cityInfo.population.freePopulation.toFloat()
|
||||
|
||||
stats.add(getStatsFromTiles())
|
||||
stats.add(getStatsFromSpecialists(cityInfo.population.specialists, civInfo.policies.adoptedPolicies))
|
||||
stats.add(getStatsFromTradeRoute())
|
||||
stats.add(cityInfo.cityConstructions.getStats())
|
||||
stats.add(getStatsFromPolicies(civInfo.policies.adoptedPolicies))
|
||||
baseStatList["Population"] = Stats().add(Stat.Science,cityInfo.population.population.toFloat())
|
||||
.add(Stat.Production,cityInfo.population.freePopulation.toFloat())
|
||||
baseStatList["Tile yields"] = getStatsFromTiles()
|
||||
baseStatList["Specialists"] = getStatsFromSpecialists(cityInfo.population.specialists, civInfo.policies.adoptedPolicies)
|
||||
baseStatList["Trade route"] = getStatsFromTradeRoute()
|
||||
baseStatList["Buildings"] = cityInfo.cityConstructions.getStats()
|
||||
baseStatList["Policies"] = getStatsFromPolicies(civInfo.policies.adoptedPolicies)
|
||||
|
||||
val statPercentBonuses = cityInfo.cityConstructions.getStatPercentBonuses()
|
||||
statPercentBonuses.add(getStatPercentBonusesFromGoldenAge(cityInfo.civInfo.goldenAges.isGoldenAge()))
|
||||
@ -203,6 +204,8 @@ class CityStats {
|
||||
statPercentBonuses.add(getStatPercentBonusesFromMarble())
|
||||
statPercentBonuses.add(getStatPercentBonusesFromComputers())
|
||||
|
||||
val stats = Stats()
|
||||
for (stat in baseStatList.values) stats.add(stat)
|
||||
stats.production *= 1 + statPercentBonuses.production / 100 // So they get bonuses for production and gold/science
|
||||
|
||||
stats.add(getStatsFromProduction())
|
||||
@ -214,18 +217,21 @@ class CityStats {
|
||||
|
||||
val isUnhappy = civInfo.happiness < 0
|
||||
if (!isUnhappy) stats.food *= 1 + statPercentBonuses.food / 100 // Regular food bonus revoked when unhappy per https://forums.civfanatics.com/resources/complete-guide-to-happiness-vanilla.25584/
|
||||
stats.food -= (cityInfo.population.population * 2).toFloat() // Food reduced after the bonus
|
||||
val foodEaten = (cityInfo.population.population * 2).toFloat()
|
||||
baseStatList["Population"]!!.food -= foodEaten // to display it to the user
|
||||
stats.food -= foodEaten // Food reduced after the bonus
|
||||
if (civInfo.policies.isAdopted("Civil Society"))
|
||||
stats.food += cityInfo.population.numberOfSpecialists.toFloat()
|
||||
|
||||
if (isUnhappy) stats.food /= 4f // Reduce excess food to 1/4 per the same
|
||||
stats.food *= 1 + getGrowthBonusFromPolicies()
|
||||
|
||||
stats.gold -= cityInfo.cityConstructions.getMaintenanceCosts().toFloat() // this is AFTER the bonus calculation!
|
||||
val buildingsMaintainance = cityInfo.cityConstructions.getMaintenanceCosts().toFloat() // this is AFTER the bonus calculation!
|
||||
baseStatList["Buildings"]!!.gold -= buildingsMaintainance
|
||||
stats.gold -= buildingsMaintainance
|
||||
this.currentCityStats = stats
|
||||
}
|
||||
|
||||
|
||||
private fun isConnectedToCapital(roadType: RoadStatus): Boolean {
|
||||
if(cityInfo.civInfo.cities.count()<2) return false// first city!
|
||||
val capitalTile = cityInfo.civInfo.capital.tile
|
||||
|
@ -29,10 +29,11 @@ open class Stats() {
|
||||
setStats(hashMap)
|
||||
}
|
||||
|
||||
fun add(stat:Stat, value:Float) {
|
||||
fun add(stat:Stat, value:Float): Stats {
|
||||
val hashMap = toHashMap()
|
||||
hashMap[stat] = hashMap[stat]!!+value
|
||||
setStats(hashMap)
|
||||
return this
|
||||
}
|
||||
|
||||
fun clone(): Stats {
|
||||
|
@ -8,21 +8,19 @@ import com.badlogic.gdx.scenes.scene2d.utils.ActorGestureListener
|
||||
import com.badlogic.gdx.utils.Align
|
||||
import com.unciv.logic.city.CityInfo
|
||||
import com.unciv.logic.map.TileInfo
|
||||
import com.unciv.models.gamebasics.Building
|
||||
import com.unciv.ui.tilegroups.TileGroup
|
||||
import com.unciv.ui.utils.CameraStageBaseScreen
|
||||
import com.unciv.ui.utils.HexMath
|
||||
import com.unciv.ui.utils.ImageGetter
|
||||
import com.unciv.ui.utils.disable
|
||||
import java.util.*
|
||||
|
||||
class CityScreen(internal val city: CityInfo) : CameraStageBaseScreen() {
|
||||
private var selectedTile: TileInfo? = null
|
||||
|
||||
private var buttonScale = game.settings.buttonScale
|
||||
private var tileTable = Table()
|
||||
private var buildingsTable = BuildingsTable(this)
|
||||
private var cityStatsTable = Table()
|
||||
private var cityStatsTable = CityStatsTable(this)
|
||||
private var statExplainer = Table(skin)
|
||||
private var cityPickerTable = Table()
|
||||
private var goToWorldButton = TextButton("Exit city", CameraStageBaseScreen.skin)
|
||||
private var tileGroups = ArrayList<TileGroup>()
|
||||
@ -42,7 +40,6 @@ class CityScreen(internal val city: CityInfo) : CameraStageBaseScreen() {
|
||||
val buildingsTableContainer = Table()
|
||||
buildingsTableContainer.pad(20f)
|
||||
buildingsTableContainer.background = tileTableBackground
|
||||
//BuildingsTableContainer.add(new Label("Buildings",skin)).row();
|
||||
buildingsTable.update()
|
||||
val buildingsScroll = ScrollPane(buildingsTable)
|
||||
buildingsTableContainer.add(buildingsScroll).height(stage.height / 2)
|
||||
@ -55,6 +52,7 @@ class CityScreen(internal val city: CityInfo) : CameraStageBaseScreen() {
|
||||
stage.addActor(cityStatsTable)
|
||||
stage.addActor(goToWorldButton)
|
||||
stage.addActor(cityPickerTable)
|
||||
stage.addActor(statExplainer)
|
||||
stage.addActor(buildingsTableContainer)
|
||||
update()
|
||||
displayTutorials("CityEntered")
|
||||
@ -63,12 +61,39 @@ class CityScreen(internal val city: CityInfo) : CameraStageBaseScreen() {
|
||||
internal fun update() {
|
||||
buildingsTable.update()
|
||||
updateCityPickerTable()
|
||||
updateCityTable()
|
||||
cityStatsTable.update()
|
||||
updateStatExplainer()
|
||||
updateGoToWorldButton()
|
||||
updateTileTable()
|
||||
updateTileGroups()
|
||||
}
|
||||
|
||||
private fun updateStatExplainer() {
|
||||
statExplainer.defaults().pad(5f)
|
||||
statExplainer.clear()
|
||||
statExplainer.add()
|
||||
statExplainer.add("Production")
|
||||
statExplainer.add("Food")
|
||||
statExplainer.add("Science")
|
||||
statExplainer.add("Gold")
|
||||
statExplainer.add("Culture")
|
||||
|
||||
for (entry in city.cityStats.baseStatList){
|
||||
if(entry.value.toHashMap().values.all { it==0f }) continue //irrelevant!
|
||||
statExplainer.row()
|
||||
statExplainer.add(entry.key)
|
||||
statExplainer.add(entry.value.production.toInt().toString())
|
||||
statExplainer.add(entry.value.food.toInt().toString())
|
||||
statExplainer.add(entry.value.science.toInt().toString())
|
||||
statExplainer.add(entry.value.gold.toInt().toString())
|
||||
statExplainer.add(entry.value.culture.toInt().toString())
|
||||
}
|
||||
statExplainer.pack()
|
||||
statExplainer.isTransform=true
|
||||
statExplainer.setScale(0.8f)
|
||||
statExplainer.setPosition(5f,cityStatsTable.top + 10)
|
||||
}
|
||||
|
||||
|
||||
private fun updateTileGroups() {
|
||||
for (HG in tileGroups) {
|
||||
@ -184,68 +209,6 @@ class CityScreen(internal val city: CityInfo) : CameraStageBaseScreen() {
|
||||
stage.addActor(scrollPane)
|
||||
}
|
||||
|
||||
private fun updateCityTable() {
|
||||
val stats = city.cityStats.currentCityStats
|
||||
cityStatsTable.pad(20f)
|
||||
cityStatsTable.columnDefaults(0).padRight(10f)
|
||||
cityStatsTable.clear()
|
||||
|
||||
val cityStatsHeader = Label("City Stats", CameraStageBaseScreen.skin)
|
||||
|
||||
cityStatsHeader.setFontScale(2f)
|
||||
cityStatsTable.add(cityStatsHeader).colspan(2).pad(10f)
|
||||
cityStatsTable.row()
|
||||
|
||||
val cityStatsValues = LinkedHashMap<String, String>()
|
||||
cityStatsValues["Production"] = Math.round(stats.production).toString() + city.cityConstructions.getAmountConstructedText()
|
||||
cityStatsValues["Food"] = (Math.round(stats.food).toString()
|
||||
+ " (" + city.population.foodStored + "/" + city.population.foodToNextPopulation + ")")
|
||||
cityStatsValues["Gold"] = Math.round(stats.gold).toString() + ""
|
||||
cityStatsValues["Science"] = Math.round(stats.science).toString() + ""
|
||||
cityStatsValues["Culture"] = (Math.round(stats.culture).toString()
|
||||
+ " (" + city.expansion.cultureStored + "/" + city.expansion.cultureToNextTile + ")")
|
||||
cityStatsValues["Population"] = city.population.freePopulation.toString() + "/" + city.population.population
|
||||
|
||||
for (key in cityStatsValues.keys) {
|
||||
cityStatsTable.add<Image>(com.unciv.ui.utils.ImageGetter.getStatIcon(key)).align(Align.right)
|
||||
cityStatsTable.add(Label(cityStatsValues[key], CameraStageBaseScreen.skin)).align(Align.left)
|
||||
cityStatsTable.row()
|
||||
}
|
||||
|
||||
val buildingText = city.cityConstructions.getCityProductionTextForCityButton()
|
||||
val buildingPickButton = TextButton(buildingText, CameraStageBaseScreen.skin)
|
||||
buildingPickButton.addClickListener {
|
||||
game.screen = com.unciv.ui.pickerscreens.ConstructionPickerScreen(city)
|
||||
dispose()
|
||||
}
|
||||
|
||||
buildingPickButton.label.setFontScale(buttonScale)
|
||||
cityStatsTable.add(buildingPickButton).colspan(2).pad(10f)
|
||||
.size(buildingPickButton.width * buttonScale, buildingPickButton.height * buttonScale)
|
||||
|
||||
|
||||
// https://forums.civfanatics.com/threads/rush-buying-formula.393892/
|
||||
val construction = city.cityConstructions.getCurrentConstruction()
|
||||
if (!(construction is Building && construction.isWonder)) {
|
||||
cityStatsTable.row()
|
||||
val buildingGoldCost = construction.getGoldCost(city.civInfo.policies.getAdoptedPolicies())
|
||||
val buildingBuyButton = TextButton("Buy for \r\n$buildingGoldCost gold", CameraStageBaseScreen.skin)
|
||||
buildingBuyButton.addClickListener {
|
||||
city.cityConstructions.purchaseBuilding(city.cityConstructions.currentConstruction)
|
||||
update()
|
||||
}
|
||||
if (buildingGoldCost > city.civInfo.gold) {
|
||||
buildingBuyButton.disable()
|
||||
}
|
||||
buildingBuyButton.label.setFontScale(buttonScale)
|
||||
cityStatsTable.add(buildingBuyButton).colspan(2).pad(10f)
|
||||
.size(buildingBuyButton.width * buttonScale, buildingBuyButton.height * buttonScale)
|
||||
}
|
||||
|
||||
cityStatsTable.setPosition(10f, 10f)
|
||||
cityStatsTable.pack()
|
||||
}
|
||||
|
||||
private fun updateTileTable() {
|
||||
if (selectedTile == null) return
|
||||
tileTable.clearChildren()
|
||||
@ -268,9 +231,7 @@ class CityScreen(internal val city: CityInfo) : CameraStageBaseScreen() {
|
||||
tileTable.row()
|
||||
}
|
||||
|
||||
|
||||
tileTable.pack()
|
||||
|
||||
tileTable.setPosition(stage.width - 10f - tileTable.width, 10f)
|
||||
}
|
||||
|
||||
|
79
core/src/com/unciv/ui/cityscreen/CityStatsTable.kt
Normal file
79
core/src/com/unciv/ui/cityscreen/CityStatsTable.kt
Normal file
@ -0,0 +1,79 @@
|
||||
package com.unciv.ui.cityscreen
|
||||
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Label
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
|
||||
import com.badlogic.gdx.utils.Align
|
||||
import com.unciv.models.gamebasics.Building
|
||||
import com.unciv.ui.UnCivGame
|
||||
import com.unciv.ui.pickerscreens.ConstructionPickerScreen
|
||||
import com.unciv.ui.utils.CameraStageBaseScreen
|
||||
import com.unciv.ui.utils.ImageGetter
|
||||
import com.unciv.ui.utils.disable
|
||||
import java.util.*
|
||||
|
||||
class CityStatsTable(val cityScreen: CityScreen) : Table(){
|
||||
fun update() {
|
||||
val city = cityScreen.city
|
||||
val buttonScale = cityScreen.game.settings.buttonScale
|
||||
val stats = city.cityStats.currentCityStats
|
||||
pad(20f)
|
||||
columnDefaults(0).padRight(10f)
|
||||
clear()
|
||||
|
||||
val cityStatsHeader = Label("City Stats", CameraStageBaseScreen.skin)
|
||||
|
||||
cityStatsHeader.setFontScale(2f)
|
||||
add(cityStatsHeader).colspan(2).pad(10f)
|
||||
row()
|
||||
|
||||
val cityStatsValues = LinkedHashMap<String, String>()
|
||||
cityStatsValues["Production"] = Math.round(stats.production).toString() + city.cityConstructions.getAmountConstructedText()
|
||||
cityStatsValues["Food"] = (Math.round(stats.food).toString()
|
||||
+ " (" + city.population.foodStored + "/" + city.population.foodToNextPopulation + ")")
|
||||
cityStatsValues["Gold"] = Math.round(stats.gold).toString() + ""
|
||||
cityStatsValues["Science"] = Math.round(stats.science).toString() + ""
|
||||
cityStatsValues["Culture"] = (Math.round(stats.culture).toString()
|
||||
+ " (" + city.expansion.cultureStored + "/" + city.expansion.cultureToNextTile + ")")
|
||||
cityStatsValues["Population"] = city.population.freePopulation.toString() + "/" + city.population.population
|
||||
|
||||
for (key in cityStatsValues.keys) {
|
||||
add(ImageGetter.getStatIcon(key)).align(Align.right)
|
||||
add(Label(cityStatsValues[key], CameraStageBaseScreen.skin)).align(Align.left)
|
||||
row()
|
||||
}
|
||||
|
||||
val buildingText = city.cityConstructions.getCityProductionTextForCityButton()
|
||||
val buildingPickButton = TextButton(buildingText, CameraStageBaseScreen.skin)
|
||||
buildingPickButton.addClickListener {
|
||||
UnCivGame.Current.screen = ConstructionPickerScreen(city)
|
||||
cityScreen.dispose()
|
||||
}
|
||||
|
||||
buildingPickButton.label.setFontScale(buttonScale)
|
||||
add(buildingPickButton).colspan(2).pad(10f)
|
||||
.size(buildingPickButton.width * buttonScale, buildingPickButton.height * buttonScale)
|
||||
|
||||
|
||||
// https://forums.civfanatics.com/threads/rush-buying-formula.393892/
|
||||
val construction = city.cityConstructions.getCurrentConstruction()
|
||||
if (!(construction is Building && construction.isWonder)) {
|
||||
row()
|
||||
val buildingGoldCost = construction.getGoldCost(city.civInfo.policies.getAdoptedPolicies())
|
||||
val buildingBuyButton = TextButton("Buy for \r\n$buildingGoldCost gold", CameraStageBaseScreen.skin)
|
||||
buildingBuyButton.addClickListener {
|
||||
city.cityConstructions.purchaseBuilding(city.cityConstructions.currentConstruction)
|
||||
update()
|
||||
}
|
||||
if (buildingGoldCost > city.civInfo.gold) {
|
||||
buildingBuyButton.disable()
|
||||
}
|
||||
buildingBuyButton.label.setFontScale(buttonScale)
|
||||
add(buildingBuyButton).colspan(2).pad(10f)
|
||||
.size(buildingBuyButton.width * buttonScale, buildingBuyButton.height * buttonScale)
|
||||
}
|
||||
|
||||
setPosition(10f, 10f)
|
||||
pack()
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user