mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-27 13:55:54 -04:00
Reorganize and fix WorldScreenTopBar (#10154)
* Reorganize WorldScreenTopBar and change its update to rebuild the cells instead of tweaking layout * Fix layout error: filler backgrounds looking too small
This commit is contained in:
parent
b6db8df484
commit
4fcbd48662
@ -28,6 +28,7 @@ fun String.getConsumesAmountString(amount: Int, isStockpiled:Boolean): String {
|
|||||||
/** Convert a [resource name][this] into "Need [amount] more $resource" string (untranslated) */
|
/** Convert a [resource name][this] into "Need [amount] more $resource" string (untranslated) */
|
||||||
fun String.getNeedMoreAmountString(amount: Int) = "Need [$amount] more [$this]"
|
fun String.getNeedMoreAmountString(amount: Int) = "Need [$amount] more [$this]"
|
||||||
|
|
||||||
|
// todo: There's a few other `if (>0) "+" else ""` around, and a DecimalFormat solution in DetailedStatsPopup: unify
|
||||||
fun Int.toStringSigned() = if (this > 0) "+$this" else this.toString()
|
fun Int.toStringSigned() = if (this > 0) "+$this" else this.toString()
|
||||||
|
|
||||||
/** Formats the [Duration] into a translated string */
|
/** Formats the [Duration] into a translated string */
|
||||||
|
@ -61,6 +61,7 @@ import com.unciv.ui.screens.worldscreen.status.MultiplayerStatusButton
|
|||||||
import com.unciv.ui.screens.worldscreen.status.NextTurnButton
|
import com.unciv.ui.screens.worldscreen.status.NextTurnButton
|
||||||
import com.unciv.ui.screens.worldscreen.status.NextTurnProgress
|
import com.unciv.ui.screens.worldscreen.status.NextTurnProgress
|
||||||
import com.unciv.ui.screens.worldscreen.status.StatusButtons
|
import com.unciv.ui.screens.worldscreen.status.StatusButtons
|
||||||
|
import com.unciv.ui.screens.worldscreen.topbar.WorldScreenTopBar
|
||||||
import com.unciv.ui.screens.worldscreen.unit.UnitTable
|
import com.unciv.ui.screens.worldscreen.unit.UnitTable
|
||||||
import com.unciv.ui.screens.worldscreen.unit.actions.UnitActionsTable
|
import com.unciv.ui.screens.worldscreen.unit.actions.UnitActionsTable
|
||||||
import com.unciv.utils.Concurrency
|
import com.unciv.utils.Concurrency
|
||||||
|
@ -1,389 +0,0 @@
|
|||||||
package com.unciv.ui.screens.worldscreen
|
|
||||||
|
|
||||||
import com.badlogic.gdx.graphics.Color
|
|
||||||
import com.badlogic.gdx.scenes.scene2d.Actor
|
|
||||||
import com.badlogic.gdx.scenes.scene2d.Group
|
|
||||||
import com.badlogic.gdx.scenes.scene2d.Touchable
|
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.Cell
|
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.Label
|
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
|
||||||
import com.badlogic.gdx.utils.Align
|
|
||||||
import com.unciv.logic.civilization.Civilization
|
|
||||||
import com.unciv.models.ruleset.tile.ResourceType
|
|
||||||
import com.unciv.models.ruleset.tile.TileResource
|
|
||||||
import com.unciv.models.ruleset.unique.UniqueType
|
|
||||||
import com.unciv.models.stats.Stats
|
|
||||||
import com.unciv.models.translations.tr
|
|
||||||
import com.unciv.ui.components.Fonts
|
|
||||||
import com.unciv.ui.components.MayaCalendar
|
|
||||||
import com.unciv.ui.components.YearTextUtil
|
|
||||||
import com.unciv.ui.components.extensions.colorFromRGB
|
|
||||||
import com.unciv.ui.components.extensions.darken
|
|
||||||
import com.unciv.ui.components.extensions.setFontColor
|
|
||||||
import com.unciv.ui.components.extensions.setFontSize
|
|
||||||
import com.unciv.ui.components.extensions.toLabel
|
|
||||||
import com.unciv.ui.components.extensions.toStringSigned
|
|
||||||
import com.unciv.ui.components.extensions.toTextButton
|
|
||||||
import com.unciv.ui.components.input.KeyboardBinding
|
|
||||||
import com.unciv.ui.components.input.onActivation
|
|
||||||
import com.unciv.ui.components.input.onClick
|
|
||||||
import com.unciv.ui.images.ImageGetter
|
|
||||||
import com.unciv.ui.screens.basescreen.BaseScreen
|
|
||||||
import com.unciv.ui.screens.civilopediascreen.CivilopediaCategories
|
|
||||||
import com.unciv.ui.screens.civilopediascreen.CivilopediaScreen
|
|
||||||
import com.unciv.ui.screens.overviewscreen.EmpireOverviewCategories
|
|
||||||
import com.unciv.ui.screens.overviewscreen.EmpireOverviewScreen
|
|
||||||
import com.unciv.ui.screens.pickerscreens.PolicyPickerScreen
|
|
||||||
import com.unciv.ui.screens.pickerscreens.TechPickerScreen
|
|
||||||
import com.unciv.ui.screens.victoryscreen.VictoryScreen
|
|
||||||
import com.unciv.ui.screens.worldscreen.mainmenu.WorldScreenMenuPopup
|
|
||||||
import kotlin.math.ceil
|
|
||||||
import kotlin.math.max
|
|
||||||
import kotlin.math.roundToInt
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Table consisting of the menu button, current civ, some stats and the overview button for the top of [WorldScreen]
|
|
||||||
*/
|
|
||||||
//region Fields
|
|
||||||
class WorldScreenTopBar(val worldScreen: WorldScreen) : Table() {
|
|
||||||
//TODO shouldn't most onClick be addActivationAction instead?
|
|
||||||
private val turnsLabel = "Turns: 0/400".toLabel()
|
|
||||||
private val goldLabel = "0".toLabel(colorFromRGB(225, 217, 71))
|
|
||||||
private val scienceLabel = "0".toLabel(colorFromRGB(78, 140, 151))
|
|
||||||
private val happinessLabel = "0".toLabel()
|
|
||||||
private val cultureLabel = "0".toLabel(colorFromRGB(210, 94, 210))
|
|
||||||
private val faithLabel = "0".toLabel(colorFromRGB(168, 196, 241))
|
|
||||||
private data class ResourceActors(val resource: TileResource, val label: Label, val icon: Group)
|
|
||||||
private val resourceActors = ArrayList<ResourceActors>(12)
|
|
||||||
private val happinessImage = Group()
|
|
||||||
|
|
||||||
// These are all to improve performance IE reduce update time (was 150 ms on my phone, which is a lot!)
|
|
||||||
private val malcontentColor = colorFromRGB(239,83,80) // Color.valueOf("ef5350")
|
|
||||||
private val happinessColor = colorFromRGB(92, 194, 77) // Color.valueOf("8cc24d")
|
|
||||||
private val malcontentGroup = ImageGetter.getStatIcon("Malcontent")
|
|
||||||
private val happinessGroup = ImageGetter.getStatIcon("Happiness")
|
|
||||||
|
|
||||||
private val statsTable = getStatsTable()
|
|
||||||
private val resourcesWrapper = Table()
|
|
||||||
private val resourceTable = getResourceTable()
|
|
||||||
private val selectedCivTable = SelectedCivilizationTable(worldScreen)
|
|
||||||
private val overviewButton = OverviewAndSupplyTable(worldScreen)
|
|
||||||
private val leftFillerCell: Cell<BackgroundActor>
|
|
||||||
private val rightFillerCell: Cell<BackgroundActor>
|
|
||||||
|
|
||||||
//endregion
|
|
||||||
|
|
||||||
init {
|
|
||||||
// Not the Table, the Cells (all except one) have the background. To avoid gaps, _no_
|
|
||||||
// padding except inside the cell actors, and all actors need to _fill_ their cell.
|
|
||||||
val backColor = BaseScreen.skinStrings.skinConfig.baseColor.darken(0.5f)
|
|
||||||
statsTable.background = BaseScreen.skinStrings.getUiBackground("WorldScreen/TopBar/StatsTable", tintColor = backColor)
|
|
||||||
resourceTable.background = BaseScreen.skinStrings.getUiBackground("WorldScreen/TopBar/ResourceTable", tintColor = backColor)
|
|
||||||
add(statsTable).colspan(3).growX().row()
|
|
||||||
add(resourceTable).colspan(3).growX().row()
|
|
||||||
val leftFillerBG = BaseScreen.skinStrings.getUiBackground("WorldScreen/TopBar/LeftAttachment", BaseScreen.skinStrings.roundedEdgeRectangleShape, backColor)
|
|
||||||
leftFillerCell = add(BackgroundActor(leftFillerBG, Align.topLeft))
|
|
||||||
add().growX()
|
|
||||||
val rightFillerBG = BaseScreen.skinStrings.getUiBackground("WorldScreen/TopBar/RightAttachment", BaseScreen.skinStrings.roundedEdgeRectangleShape, backColor)
|
|
||||||
rightFillerCell = add(BackgroundActor(rightFillerBG, Align.topRight))
|
|
||||||
pack()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getStatsTable(): Table {
|
|
||||||
val statsTable = Table()
|
|
||||||
statsTable.defaults().pad(8f, 3f, 3f, 3f)
|
|
||||||
|
|
||||||
fun addStat(label: Label, icon: String, isLast: Boolean = false, screenFactory: ()-> BaseScreen) {
|
|
||||||
val image = ImageGetter.getStatIcon(icon)
|
|
||||||
val action = {
|
|
||||||
worldScreen.game.pushScreen(screenFactory())
|
|
||||||
}
|
|
||||||
label.onClick(action)
|
|
||||||
image.onClick(action)
|
|
||||||
statsTable.add(label)
|
|
||||||
statsTable.add(image).padBottom(6f).size(20f).apply {
|
|
||||||
if (!isLast) padRight(20f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fun addStat(label: Label, icon: String, overviewPage: EmpireOverviewCategories, isLast: Boolean = false) =
|
|
||||||
addStat(label, icon, isLast) { EmpireOverviewScreen(worldScreen.selectedCiv, overviewPage) }
|
|
||||||
|
|
||||||
addStat(goldLabel, "Gold", EmpireOverviewCategories.Stats)
|
|
||||||
addStat(scienceLabel, "Science") { TechPickerScreen(worldScreen.selectedCiv) }
|
|
||||||
|
|
||||||
statsTable.add(happinessImage).padBottom(6f).size(20f)
|
|
||||||
statsTable.add(happinessLabel).padRight(20f)
|
|
||||||
val invokeResourcesPage = {
|
|
||||||
worldScreen.openEmpireOverview(EmpireOverviewCategories.Resources)
|
|
||||||
}
|
|
||||||
happinessImage.onClick(invokeResourcesPage)
|
|
||||||
happinessLabel.onClick(invokeResourcesPage)
|
|
||||||
|
|
||||||
addStat(cultureLabel, "Culture") { PolicyPickerScreen(worldScreen.selectedCiv, worldScreen.canChangeState) }
|
|
||||||
if (worldScreen.gameInfo.isReligionEnabled()) {
|
|
||||||
addStat(faithLabel, "Faith", EmpireOverviewCategories.Religion, isLast = true)
|
|
||||||
} else {
|
|
||||||
statsTable.add("Religion: Off".toLabel())
|
|
||||||
}
|
|
||||||
|
|
||||||
statsTable.pack()
|
|
||||||
return statsTable
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getResourceTable(): Table {
|
|
||||||
// Since cells with invisible actors still occupy the full actor dimensions, we only prepare
|
|
||||||
// the future contents for resourcesWrapper here, they're added to the Table in updateResourcesTable
|
|
||||||
val resourceTable = Table()
|
|
||||||
resourcesWrapper.defaults().pad(5f, 5f, 10f, 5f)
|
|
||||||
resourcesWrapper.touchable = Touchable.enabled
|
|
||||||
|
|
||||||
turnsLabel.onClick {
|
|
||||||
if (worldScreen.selectedCiv.isLongCountDisplay()) {
|
|
||||||
val gameInfo = worldScreen.selectedCiv.gameInfo
|
|
||||||
MayaCalendar.openPopup(worldScreen, worldScreen.selectedCiv, gameInfo.getYear())
|
|
||||||
} else {
|
|
||||||
worldScreen.game.pushScreen(VictoryScreen(worldScreen))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
resourcesWrapper.onClick {
|
|
||||||
worldScreen.openEmpireOverview(EmpireOverviewCategories.Resources)
|
|
||||||
}
|
|
||||||
|
|
||||||
val strategicResources = worldScreen.gameInfo.ruleset.tileResources.values
|
|
||||||
.filter { it.resourceType == ResourceType.Strategic && !it.hasUnique(UniqueType.CityResource) }
|
|
||||||
for (resource in strategicResources) {
|
|
||||||
val resourceImage = ImageGetter.getResourcePortrait(resource.name, 20f)
|
|
||||||
val resourceLabel = "0".toLabel()
|
|
||||||
resourceActors += ResourceActors(resource, resourceLabel, resourceImage)
|
|
||||||
}
|
|
||||||
|
|
||||||
// in case the icons are configured higher than a label, we add a dummy - height will be measured once before it's updated
|
|
||||||
if (resourceActors.isNotEmpty()) {
|
|
||||||
resourcesWrapper.add(resourceActors[0].icon)
|
|
||||||
resourceTable.add(resourcesWrapper)
|
|
||||||
}
|
|
||||||
|
|
||||||
resourceTable.add(turnsLabel).pad(5f, 5f, 10f, 5f)
|
|
||||||
|
|
||||||
return resourceTable
|
|
||||||
}
|
|
||||||
|
|
||||||
private class OverviewAndSupplyTable(worldScreen: WorldScreen) : Table(BaseScreen.skin) {
|
|
||||||
val unitSupplyImage = ImageGetter.getImage("OtherIcons/ExclamationMark")
|
|
||||||
.apply { color = Color.FIREBRICK }
|
|
||||||
val unitSupplyCell: Cell<Actor?>
|
|
||||||
|
|
||||||
init {
|
|
||||||
unitSupplyImage.onClick {
|
|
||||||
worldScreen.openEmpireOverview(EmpireOverviewCategories.Units)
|
|
||||||
}
|
|
||||||
|
|
||||||
val overviewButton = "Overview".toTextButton()
|
|
||||||
overviewButton.onActivation(binding = KeyboardBinding.EmpireOverview) {
|
|
||||||
worldScreen.openEmpireOverview()
|
|
||||||
}
|
|
||||||
|
|
||||||
unitSupplyCell = add()
|
|
||||||
add(overviewButton).pad(10f)
|
|
||||||
pack()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun update(worldScreen: WorldScreen) {
|
|
||||||
val newVisible = worldScreen.selectedCiv.stats.getUnitSupplyDeficit() > 0
|
|
||||||
if (newVisible == unitSupplyCell.hasActor()) return
|
|
||||||
if (newVisible) unitSupplyCell.setActor(unitSupplyImage)
|
|
||||||
.size(50f).padLeft(10f)
|
|
||||||
else unitSupplyCell.setActor(null).size(0f).pad(0f)
|
|
||||||
invalidate()
|
|
||||||
pack()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class SelectedCivilizationTable(worldScreen: WorldScreen) : Table(BaseScreen.skin) {
|
|
||||||
private var selectedCiv = ""
|
|
||||||
private val selectedCivLabel = "".toLabel()
|
|
||||||
private val menuButton = ImageGetter.getImage("OtherIcons/MenuIcon")
|
|
||||||
|
|
||||||
init {
|
|
||||||
left()
|
|
||||||
defaults().pad(10f)
|
|
||||||
|
|
||||||
menuButton.color = Color.WHITE
|
|
||||||
menuButton.onActivation(binding = KeyboardBinding.Menu) {
|
|
||||||
WorldScreenMenuPopup(worldScreen).open(force = true)
|
|
||||||
}
|
|
||||||
|
|
||||||
selectedCivLabel.setFontSize(25)
|
|
||||||
selectedCivLabel.onClick {
|
|
||||||
val civilopediaScreen = CivilopediaScreen(
|
|
||||||
worldScreen.selectedCiv.gameInfo.ruleset,
|
|
||||||
CivilopediaCategories.Nation,
|
|
||||||
worldScreen.selectedCiv.civName
|
|
||||||
)
|
|
||||||
worldScreen.game.pushScreen(civilopediaScreen)
|
|
||||||
}
|
|
||||||
|
|
||||||
add(menuButton).size(50f).padRight(0f)
|
|
||||||
add(selectedCivLabel).padRight(10f)
|
|
||||||
pack()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun update(worldScreen: WorldScreen) {
|
|
||||||
val newCiv = worldScreen.selectedCiv.civName
|
|
||||||
if (this.selectedCiv == newCiv) return
|
|
||||||
this.selectedCiv = newCiv
|
|
||||||
|
|
||||||
selectedCivLabel.setText(newCiv.tr())
|
|
||||||
invalidate()
|
|
||||||
pack()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun layoutButtons() {
|
|
||||||
removeActor(selectedCivTable)
|
|
||||||
removeActor(overviewButton)
|
|
||||||
validate()
|
|
||||||
|
|
||||||
val statsWidth = statsTable.minWidth
|
|
||||||
val resourceWidth = resourceTable.minWidth
|
|
||||||
val overviewWidth = overviewButton.minWidth
|
|
||||||
val selectedCivWidth = selectedCivTable.minWidth
|
|
||||||
val leftRightNeeded = max(selectedCivWidth, overviewWidth)
|
|
||||||
val statsRowHeight = getRowHeight(0)
|
|
||||||
val baseHeight = statsRowHeight + getRowHeight(1)
|
|
||||||
|
|
||||||
// Check whether it gets cramped on narrow aspect ratios
|
|
||||||
val fillerHeight: Float // Height of the background filler cells
|
|
||||||
val buttonY: Float // Vertical center of Civ+Overview buttons relative to this.y
|
|
||||||
when {
|
|
||||||
leftRightNeeded * 2f > stage.width - resourceWidth -> {
|
|
||||||
// Need to shift buttons down to below both stats and resources
|
|
||||||
fillerHeight = baseHeight +1
|
|
||||||
buttonY = overviewButton.minHeight / 2f
|
|
||||||
}
|
|
||||||
leftRightNeeded * 2f > stage.width - statsWidth -> {
|
|
||||||
// Shifting buttons down to below stats row is enough
|
|
||||||
fillerHeight = statsRowHeight +1
|
|
||||||
buttonY = overviewButton.minHeight / 2f
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
// Enough space to keep buttons to the left and right of stats and resources
|
|
||||||
fillerHeight = 0f
|
|
||||||
buttonY = baseHeight / 2f
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val leftFillerWidth = if (fillerHeight > 0f) selectedCivWidth else 0f
|
|
||||||
val rightFillerWidth = if (fillerHeight > 0f) overviewWidth else 0f
|
|
||||||
if (leftFillerCell.minHeight != fillerHeight
|
|
||||||
|| leftFillerCell.minWidth != leftFillerWidth
|
|
||||||
|| rightFillerCell.minWidth != rightFillerWidth) {
|
|
||||||
// Gdx fail: containing Table isn't invalidated when setting Cell size
|
|
||||||
leftFillerCell.width(leftFillerWidth).height(fillerHeight)
|
|
||||||
rightFillerCell.width(rightFillerWidth).height(fillerHeight)
|
|
||||||
invalidate() // Without this all attempts to get a recalculated height are doomed
|
|
||||||
pack() // neither validate nor layout will include the new row height in height
|
|
||||||
}
|
|
||||||
|
|
||||||
width = stage.width
|
|
||||||
setPosition(0f, stage.height, Align.topLeft)
|
|
||||||
|
|
||||||
selectedCivTable.setPosition(1f, buttonY, Align.left)
|
|
||||||
overviewButton.setPosition(stage.width, buttonY, Align.right)
|
|
||||||
addActor(selectedCivTable) // needs to be after pack
|
|
||||||
addActor(overviewButton)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun update(civInfo: Civilization) {
|
|
||||||
updateStatsTable(civInfo)
|
|
||||||
updateResourcesTable(civInfo)
|
|
||||||
selectedCivTable.update(worldScreen)
|
|
||||||
overviewButton.update(worldScreen)
|
|
||||||
layoutButtons()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun rateLabel(value: Float): String {
|
|
||||||
return (if (value > 0) "+" else "") + value.roundToInt()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateStatsTable(civInfo: Civilization) {
|
|
||||||
val nextTurnStats = civInfo.stats.statsForNextTurn
|
|
||||||
val goldPerTurn = " (" + rateLabel(nextTurnStats.gold) + ")"
|
|
||||||
goldLabel.setText(civInfo.gold.toString() + goldPerTurn)
|
|
||||||
|
|
||||||
scienceLabel.setText(rateLabel(nextTurnStats.science))
|
|
||||||
|
|
||||||
happinessLabel.setText(getHappinessText(civInfo))
|
|
||||||
|
|
||||||
if (civInfo.getHappiness() < 0) {
|
|
||||||
happinessLabel.setFontColor(malcontentColor)
|
|
||||||
happinessImage.clearChildren()
|
|
||||||
happinessImage.addActor(malcontentGroup)
|
|
||||||
} else {
|
|
||||||
happinessLabel.setFontColor(happinessColor)
|
|
||||||
happinessImage.clearChildren()
|
|
||||||
happinessImage.addActor(happinessGroup)
|
|
||||||
}
|
|
||||||
|
|
||||||
cultureLabel.setText(getCultureText(civInfo, nextTurnStats))
|
|
||||||
faithLabel.setText(civInfo.religionManager.storedFaith.toString() +
|
|
||||||
" (" + rateLabel(nextTurnStats.faith) + ")")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateResourcesTable(civInfo: Civilization) {
|
|
||||||
val yearText = YearTextUtil.toYearText(
|
|
||||||
civInfo.gameInfo.getYear(), civInfo.isLongCountDisplay()
|
|
||||||
)
|
|
||||||
turnsLabel.setText(Fonts.turn + "" + civInfo.gameInfo.turns + " | " + yearText)
|
|
||||||
resourcesWrapper.clearChildren()
|
|
||||||
var firstPadLeft = 20f // We want a distance from the turns entry to the first resource, but only if any resource is displayed
|
|
||||||
val civResources = civInfo.getCivResourcesByName()
|
|
||||||
val civResourceSupply = civInfo.getCivResourceSupply()
|
|
||||||
for ((resource, label, icon) in resourceActors) {
|
|
||||||
if (resource.hasUnique(UniqueType.NotShownOnWorldScreen)) continue
|
|
||||||
|
|
||||||
val amount = civResources[resource.name] ?: 0
|
|
||||||
|
|
||||||
if (resource.revealedBy != null && !civInfo.tech.isResearched(resource.revealedBy!!)
|
|
||||||
&& amount == 0) // You can trade for resources you cannot process yourself yet
|
|
||||||
continue
|
|
||||||
|
|
||||||
resourcesWrapper.add(icon).padLeft(firstPadLeft).padRight(0f)
|
|
||||||
firstPadLeft = 5f
|
|
||||||
if (!resource.isStockpiled())
|
|
||||||
label.setText(amount)
|
|
||||||
else {
|
|
||||||
val perTurn = civResourceSupply.firstOrNull { it.resource == resource }?.amount ?: 0
|
|
||||||
if (perTurn == 0) label.setText(amount)
|
|
||||||
else label.setText("$amount (${perTurn.toStringSigned()})")
|
|
||||||
}
|
|
||||||
resourcesWrapper.add(label).padTop(8f) // digits don't have descenders, so push them down a little
|
|
||||||
}
|
|
||||||
|
|
||||||
resourceTable.pack()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getCultureText(civInfo: Civilization, nextTurnStats: Stats): String {
|
|
||||||
var cultureString = rateLabel(nextTurnStats.culture)
|
|
||||||
//if (nextTurnStats.culture == 0f) return cultureString // when you start the game, you're not producing any culture
|
|
||||||
|
|
||||||
val turnsToNextPolicy = (civInfo.policies.getCultureNeededForNextPolicy() - civInfo.policies.storedCulture) / nextTurnStats.culture
|
|
||||||
cultureString += if (turnsToNextPolicy <= 0f) " (!)"
|
|
||||||
else if (nextTurnStats.culture <= 0) " (∞)"
|
|
||||||
else " (" + ceil(turnsToNextPolicy).toInt() + ")"
|
|
||||||
return cultureString
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getHappinessText(civInfo: Civilization): String {
|
|
||||||
var happinessText = civInfo.getHappiness().toString()
|
|
||||||
val goldenAges = civInfo.goldenAges
|
|
||||||
happinessText +=
|
|
||||||
if (goldenAges.isGoldenAge())
|
|
||||||
" {GOLDEN AGE}(${goldenAges.turnsLeftForCurrentGoldenAge})".tr()
|
|
||||||
else
|
|
||||||
" (${goldenAges.storedHappiness}/${goldenAges.happinessRequiredForNextGoldenAge()})"
|
|
||||||
return happinessText
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,230 @@
|
|||||||
|
package com.unciv.ui.screens.worldscreen.topbar
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.Color
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.Actor
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.ui.Cell
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||||
|
import com.badlogic.gdx.utils.Align
|
||||||
|
import com.unciv.logic.civilization.Civilization
|
||||||
|
import com.unciv.models.translations.tr
|
||||||
|
import com.unciv.ui.components.extensions.darken
|
||||||
|
import com.unciv.ui.components.extensions.setFontSize
|
||||||
|
import com.unciv.ui.components.extensions.toLabel
|
||||||
|
import com.unciv.ui.components.extensions.toTextButton
|
||||||
|
import com.unciv.ui.components.input.KeyboardBinding
|
||||||
|
import com.unciv.ui.components.input.onActivation
|
||||||
|
import com.unciv.ui.components.input.onClick
|
||||||
|
import com.unciv.ui.images.ImageGetter
|
||||||
|
import com.unciv.ui.screens.basescreen.BaseScreen
|
||||||
|
import com.unciv.ui.screens.civilopediascreen.CivilopediaCategories
|
||||||
|
import com.unciv.ui.screens.civilopediascreen.CivilopediaScreen
|
||||||
|
import com.unciv.ui.screens.overviewscreen.EmpireOverviewCategories
|
||||||
|
import com.unciv.ui.screens.worldscreen.BackgroundActor
|
||||||
|
import com.unciv.ui.screens.worldscreen.WorldScreen
|
||||||
|
import com.unciv.ui.screens.worldscreen.mainmenu.WorldScreenMenuPopup
|
||||||
|
import kotlin.math.max
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Table consisting of the menu button, current civ, some stats and the overview button for the top of [WorldScreen].
|
||||||
|
*
|
||||||
|
* Calling [update] will refresh content and layout, and place the Table on the top edge of the stage, filling its width.
|
||||||
|
*
|
||||||
|
* [update] will also attempt geometry optimization:
|
||||||
|
* * When there's enough room, the top bar has the stats row ([WorldScreenTopBarStats]) and the resources
|
||||||
|
* row ([WorldScreenTopBarResources]), and the selected-civ ([SelectedCivilizationTable]) and overview
|
||||||
|
* ([OverviewAndSupplyTable]) button elements are overlaid (floating, not in a Cell) to the left and right.
|
||||||
|
* * When screen space gets cramped (low resolution or portrait mode) and one of the overlaid elements would
|
||||||
|
* cover parts of the stats and/or resources lines, we move them down accordingly - below the stats line
|
||||||
|
* if the resources still have enough room, below both otherwise.
|
||||||
|
* * But the elements should have a background - this is done with "filler cells". This Table is now 3x3,
|
||||||
|
* with the stats line as colspan(3) in the top row, resources also colspan(3) in the second row,
|
||||||
|
* and the third row is filler - empty - filler. These fillers do a background with just one rounded
|
||||||
|
* corner - bottom and to the screen center. The middle cell of that row has no actor and expands,
|
||||||
|
* and since the entire Table is Touchable.childrenOnly, completely transparent to the map below.
|
||||||
|
*
|
||||||
|
* Table layout in the "cramped" case:
|
||||||
|
* ```
|
||||||
|
* +----------------------------------------+
|
||||||
|
* | WorldScreenTopBarStats colspan(3) |
|
||||||
|
* +----------------------------------------+
|
||||||
|
* | WorldScreenTopBarResources colspan(3) |
|
||||||
|
* +----------------------------------------+
|
||||||
|
* | Filler | transparent!!! | Filler |
|
||||||
|
* +--------╝ ╚--------+
|
||||||
|
* ```
|
||||||
|
* Reminder: Not the `Table`, the `Cell` actors (all except the transparent one) have the background.
|
||||||
|
* To avoid gaps, _no_ padding except inside the cell actors, and all actors need to _fill_ their cell.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//region Fields
|
||||||
|
class WorldScreenTopBar(internal val worldScreen: WorldScreen) : Table() {
|
||||||
|
|
||||||
|
private val statsTable = WorldScreenTopBarStats(this)
|
||||||
|
private val resourceTable = WorldScreenTopBarResources(this)
|
||||||
|
private val selectedCivTable = SelectedCivilizationTable(worldScreen)
|
||||||
|
private val overviewButton = OverviewAndSupplyTable(worldScreen)
|
||||||
|
private val leftFiller: BackgroundActor
|
||||||
|
private val rightFiller: BackgroundActor
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
/** When the "fillers" are used, this is added to the required height, alleviating the "gap" problem a little. */
|
||||||
|
const val gapFillingExtraHeight = 1f
|
||||||
|
}
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
init {
|
||||||
|
// init only prepares, the cells are created by update()
|
||||||
|
|
||||||
|
defaults().center()
|
||||||
|
setRound(false) // Prevent Table from doing internal rounding which would provoke gaps
|
||||||
|
|
||||||
|
val backColor = BaseScreen.skinStrings.skinConfig.baseColor.darken(0.5f)
|
||||||
|
statsTable.background = BaseScreen.skinStrings.getUiBackground("WorldScreen/TopBar/StatsTable", tintColor = backColor)
|
||||||
|
resourceTable.background = BaseScreen.skinStrings.getUiBackground("WorldScreen/TopBar/ResourceTable", tintColor = backColor)
|
||||||
|
|
||||||
|
val leftFillerBG = BaseScreen.skinStrings.getUiBackground("WorldScreen/TopBar/LeftAttachment", BaseScreen.skinStrings.roundedEdgeRectangleShape, backColor)
|
||||||
|
leftFiller = BackgroundActor(leftFillerBG, Align.topLeft)
|
||||||
|
val rightFillerBG = BaseScreen.skinStrings.getUiBackground("WorldScreen/TopBar/RightAttachment", BaseScreen.skinStrings.roundedEdgeRectangleShape, backColor)
|
||||||
|
rightFiller = BackgroundActor(rightFillerBG, Align.topRight)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun update(civInfo: Civilization) {
|
||||||
|
setLayoutEnabled(false)
|
||||||
|
statsTable.update(civInfo)
|
||||||
|
resourceTable.update(civInfo)
|
||||||
|
selectedCivTable.update(worldScreen)
|
||||||
|
overviewButton.update(worldScreen)
|
||||||
|
updateLayout()
|
||||||
|
setLayoutEnabled(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Performs the layout tricks mentioned in the class Kdoc */
|
||||||
|
private fun updateLayout() {
|
||||||
|
val targetWidth = stage.width
|
||||||
|
val resourceWidth = resourceTable.minWidth
|
||||||
|
val overviewWidth = overviewButton.minWidth
|
||||||
|
val overviewHeight = overviewButton.minHeight
|
||||||
|
val selectedCivWidth = selectedCivTable.minWidth
|
||||||
|
val selectedCivHeight = selectedCivTable.minHeight
|
||||||
|
// Since stats/resource lines are centered, the max decides when to snap the overlaid elements down
|
||||||
|
val leftRightNeeded = max(selectedCivWidth, overviewWidth)
|
||||||
|
// Height of the two "overlay" elements should be equal, but just in case:
|
||||||
|
val overlayHeight = max(overviewHeight, selectedCivHeight)
|
||||||
|
|
||||||
|
clear()
|
||||||
|
// Without the explicit cell width, a 'stats' line wider than the stage can force the Table to
|
||||||
|
// misbehave and place the filler actors out of bounds, even if Table.width is correct.
|
||||||
|
add(statsTable).colspan(3).growX().width(targetWidth).row()
|
||||||
|
// Probability of a too-wide resources line is low in Vanilla, but mods may have lots more...
|
||||||
|
add(resourceTable).colspan(3).growX().width(targetWidth).row()
|
||||||
|
layout() // force rowHeight calculation - validate is not enough - Table quirks
|
||||||
|
val statsRowHeight = getRowHeight(0)
|
||||||
|
val baseHeight = statsRowHeight + getRowHeight(1)
|
||||||
|
val statsWidth = statsTable.width
|
||||||
|
|
||||||
|
fun addFillers(fillerHeight: Float) {
|
||||||
|
add(leftFiller).size(selectedCivWidth, fillerHeight + gapFillingExtraHeight)
|
||||||
|
add().growX()
|
||||||
|
add(rightFiller).size(overviewWidth, fillerHeight + gapFillingExtraHeight)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check whether it gets cramped on narrow aspect ratios
|
||||||
|
val centerButtonsToHeight = when {
|
||||||
|
leftRightNeeded * 2f > targetWidth - resourceWidth -> {
|
||||||
|
// Need to shift buttons down to below both stats and resources
|
||||||
|
addFillers(overlayHeight)
|
||||||
|
overlayHeight
|
||||||
|
}
|
||||||
|
leftRightNeeded * 2f > targetWidth - statsWidth -> {
|
||||||
|
// Shifting buttons down to below stats row is enough
|
||||||
|
addFillers(statsRowHeight)
|
||||||
|
overlayHeight
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
// Enough space to keep buttons to the left and right of stats and resources - no fillers
|
||||||
|
baseHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't use align with setPosition as we haven't pack()ed and element dimensions might not be final
|
||||||
|
setSize(targetWidth, prefHeight) // sizing to prefHeight is half a pack()
|
||||||
|
setPosition(0f, stage.height - prefHeight)
|
||||||
|
|
||||||
|
selectedCivTable.setPosition(0f, (centerButtonsToHeight - selectedCivHeight) / 2f)
|
||||||
|
overviewButton.setPosition(targetWidth - overviewWidth, (centerButtonsToHeight - overviewHeight) / 2f)
|
||||||
|
addActor(selectedCivTable) // needs to be after size
|
||||||
|
addActor(overviewButton)
|
||||||
|
}
|
||||||
|
|
||||||
|
private class OverviewAndSupplyTable(worldScreen: WorldScreen) : Table(BaseScreen.skin) {
|
||||||
|
val unitSupplyImage = ImageGetter.getImage("OtherIcons/ExclamationMark")
|
||||||
|
.apply { color = Color.FIREBRICK }
|
||||||
|
val unitSupplyCell: Cell<Actor?>
|
||||||
|
|
||||||
|
init {
|
||||||
|
unitSupplyImage.onClick {
|
||||||
|
worldScreen.openEmpireOverview(EmpireOverviewCategories.Units)
|
||||||
|
}
|
||||||
|
|
||||||
|
val overviewButton = "Overview".toTextButton()
|
||||||
|
overviewButton.onActivation(binding = KeyboardBinding.EmpireOverview) {
|
||||||
|
worldScreen.openEmpireOverview()
|
||||||
|
}
|
||||||
|
|
||||||
|
unitSupplyCell = add()
|
||||||
|
add(overviewButton).pad(10f)
|
||||||
|
pack()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun update(worldScreen: WorldScreen) {
|
||||||
|
val newVisible = worldScreen.selectedCiv.stats.getUnitSupplyDeficit() > 0
|
||||||
|
if (newVisible == unitSupplyCell.hasActor()) return
|
||||||
|
if (newVisible) unitSupplyCell.setActor(unitSupplyImage)
|
||||||
|
.size(50f).padLeft(10f)
|
||||||
|
else unitSupplyCell.setActor(null).size(0f).pad(0f)
|
||||||
|
invalidate()
|
||||||
|
pack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SelectedCivilizationTable(worldScreen: WorldScreen) : Table(BaseScreen.skin) {
|
||||||
|
private var selectedCiv = ""
|
||||||
|
private val selectedCivLabel = "".toLabel()
|
||||||
|
private val menuButton = ImageGetter.getImage("OtherIcons/MenuIcon")
|
||||||
|
|
||||||
|
init {
|
||||||
|
left()
|
||||||
|
defaults().pad(10f)
|
||||||
|
|
||||||
|
menuButton.color = Color.WHITE
|
||||||
|
menuButton.onActivation(binding = KeyboardBinding.Menu) {
|
||||||
|
WorldScreenMenuPopup(worldScreen).open(force = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedCivLabel.setFontSize(25)
|
||||||
|
selectedCivLabel.onClick {
|
||||||
|
val civilopediaScreen = CivilopediaScreen(
|
||||||
|
worldScreen.selectedCiv.gameInfo.ruleset,
|
||||||
|
CivilopediaCategories.Nation,
|
||||||
|
worldScreen.selectedCiv.civName
|
||||||
|
)
|
||||||
|
worldScreen.game.pushScreen(civilopediaScreen)
|
||||||
|
}
|
||||||
|
|
||||||
|
add(menuButton).size(50f).padRight(0f)
|
||||||
|
add(selectedCivLabel)
|
||||||
|
pack()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun update(worldScreen: WorldScreen) {
|
||||||
|
val newCiv = worldScreen.selectedCiv.civName
|
||||||
|
if (this.selectedCiv == newCiv) return
|
||||||
|
this.selectedCiv = newCiv
|
||||||
|
|
||||||
|
selectedCivLabel.setText(newCiv.tr()) // Will include nation icon
|
||||||
|
invalidate()
|
||||||
|
pack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,93 @@
|
|||||||
|
package com.unciv.ui.screens.worldscreen.topbar
|
||||||
|
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.Group
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.Touchable
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.ui.Label
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||||
|
import com.unciv.logic.civilization.Civilization
|
||||||
|
import com.unciv.models.ruleset.tile.ResourceType
|
||||||
|
import com.unciv.models.ruleset.tile.TileResource
|
||||||
|
import com.unciv.models.ruleset.unique.UniqueType
|
||||||
|
import com.unciv.ui.components.Fonts
|
||||||
|
import com.unciv.ui.components.MayaCalendar
|
||||||
|
import com.unciv.ui.components.YearTextUtil
|
||||||
|
import com.unciv.ui.components.extensions.toLabel
|
||||||
|
import com.unciv.ui.components.extensions.toStringSigned
|
||||||
|
import com.unciv.ui.components.input.onClick
|
||||||
|
import com.unciv.ui.images.ImageGetter
|
||||||
|
import com.unciv.ui.screens.overviewscreen.EmpireOverviewCategories
|
||||||
|
import com.unciv.ui.screens.victoryscreen.VictoryScreen
|
||||||
|
|
||||||
|
internal class WorldScreenTopBarResources(topbar: WorldScreenTopBar) : Table() {
|
||||||
|
private val turnsLabel = "Turns: 0/400".toLabel()
|
||||||
|
private data class ResourceActors(val resource: TileResource, val label: Label, val icon: Group)
|
||||||
|
private val resourceActors = ArrayList<ResourceActors>(12)
|
||||||
|
private val resourcesWrapper = Table()
|
||||||
|
|
||||||
|
init {
|
||||||
|
resourcesWrapper.defaults().pad(5f, 5f, 10f, 5f)
|
||||||
|
resourcesWrapper.touchable = Touchable.enabled
|
||||||
|
|
||||||
|
val worldScreen = topbar.worldScreen
|
||||||
|
|
||||||
|
turnsLabel.onClick {
|
||||||
|
if (worldScreen.selectedCiv.isLongCountDisplay()) {
|
||||||
|
val gameInfo = worldScreen.selectedCiv.gameInfo
|
||||||
|
MayaCalendar.openPopup(worldScreen, worldScreen.selectedCiv, gameInfo.getYear())
|
||||||
|
} else {
|
||||||
|
worldScreen.game.pushScreen(VictoryScreen(worldScreen))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resourcesWrapper.onClick {
|
||||||
|
worldScreen.openEmpireOverview(EmpireOverviewCategories.Resources)
|
||||||
|
}
|
||||||
|
|
||||||
|
val strategicResources = worldScreen.gameInfo.ruleset.tileResources.values
|
||||||
|
.filter { it.resourceType == ResourceType.Strategic && !it.hasUnique(UniqueType.CityResource) }
|
||||||
|
for (resource in strategicResources) {
|
||||||
|
val resourceImage = ImageGetter.getResourcePortrait(resource.name, 20f)
|
||||||
|
val resourceLabel = "0".toLabel()
|
||||||
|
resourceActors += ResourceActors(resource, resourceLabel, resourceImage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// in case the icons are configured higher than a label, we add a dummy - height will be measured once before it's updated
|
||||||
|
if (resourceActors.isNotEmpty()) {
|
||||||
|
resourcesWrapper.add(resourceActors[0].icon)
|
||||||
|
add(resourcesWrapper)
|
||||||
|
}
|
||||||
|
|
||||||
|
add(turnsLabel).pad(5f, 5f, 10f, 5f)
|
||||||
|
}
|
||||||
|
fun update(civInfo: Civilization) {
|
||||||
|
val yearText = YearTextUtil.toYearText(
|
||||||
|
civInfo.gameInfo.getYear(), civInfo.isLongCountDisplay()
|
||||||
|
)
|
||||||
|
turnsLabel.setText(Fonts.turn + "" + civInfo.gameInfo.turns + " | " + yearText)
|
||||||
|
resourcesWrapper.clearChildren()
|
||||||
|
var firstPadLeft = 20f // We want a distance from the turns entry to the first resource, but only if any resource is displayed
|
||||||
|
val civResources = civInfo.getCivResourcesByName()
|
||||||
|
val civResourceSupply = civInfo.getCivResourceSupply()
|
||||||
|
for ((resource, label, icon) in resourceActors) {
|
||||||
|
if (resource.hasUnique(UniqueType.NotShownOnWorldScreen)) continue
|
||||||
|
|
||||||
|
val amount = civResources[resource.name] ?: 0
|
||||||
|
|
||||||
|
if (resource.revealedBy != null && !civInfo.tech.isResearched(resource.revealedBy!!)
|
||||||
|
&& amount == 0) // You can trade for resources you cannot process yourself yet
|
||||||
|
continue
|
||||||
|
|
||||||
|
resourcesWrapper.add(icon).padLeft(firstPadLeft).padRight(0f)
|
||||||
|
firstPadLeft = 5f
|
||||||
|
if (!resource.isStockpiled())
|
||||||
|
label.setText(amount)
|
||||||
|
else {
|
||||||
|
val perTurn = civResourceSupply.firstOrNull { it.resource == resource }?.amount ?: 0
|
||||||
|
if (perTurn == 0) label.setText(amount)
|
||||||
|
else label.setText("$amount (${perTurn.toStringSigned()})")
|
||||||
|
}
|
||||||
|
resourcesWrapper.add(label).padTop(8f) // digits don't have descenders, so push them down a little
|
||||||
|
}
|
||||||
|
|
||||||
|
pack()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,141 @@
|
|||||||
|
package com.unciv.ui.screens.worldscreen.topbar
|
||||||
|
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.Group
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.ui.Label
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||||
|
import com.unciv.logic.civilization.Civilization
|
||||||
|
import com.unciv.models.stats.Stats
|
||||||
|
import com.unciv.models.translations.tr
|
||||||
|
import com.unciv.ui.components.extensions.colorFromRGB
|
||||||
|
import com.unciv.ui.components.extensions.setFontColor
|
||||||
|
import com.unciv.ui.components.extensions.toLabel
|
||||||
|
import com.unciv.ui.components.extensions.toStringSigned
|
||||||
|
import com.unciv.ui.components.input.onClick
|
||||||
|
import com.unciv.ui.images.ImageGetter
|
||||||
|
import com.unciv.ui.screens.basescreen.BaseScreen
|
||||||
|
import com.unciv.ui.screens.overviewscreen.EmpireOverviewCategories
|
||||||
|
import com.unciv.ui.screens.overviewscreen.EmpireOverviewScreen
|
||||||
|
import com.unciv.ui.screens.pickerscreens.PolicyPickerScreen
|
||||||
|
import com.unciv.ui.screens.pickerscreens.TechPickerScreen
|
||||||
|
import kotlin.math.ceil
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
internal class WorldScreenTopBarStats(topbar: WorldScreenTopBar) : Table() {
|
||||||
|
private val goldLabel = "0".toLabel(colorFromRGB(225, 217, 71))
|
||||||
|
private val scienceLabel = "0".toLabel(colorFromRGB(78, 140, 151))
|
||||||
|
private val happinessLabel = "0".toLabel()
|
||||||
|
private val cultureLabel = "0".toLabel(colorFromRGB(210, 94, 210))
|
||||||
|
private val faithLabel = "0".toLabel(colorFromRGB(168, 196, 241))
|
||||||
|
|
||||||
|
private val happinessContainer = Group()
|
||||||
|
|
||||||
|
// These are all to improve performance IE reduce update time (was 150 ms on my phone, which is a lot!)
|
||||||
|
private val malcontentColor = colorFromRGB(239,83,80) // Color.valueOf("ef5350")
|
||||||
|
private val happinessColor = colorFromRGB(92, 194, 77) // Color.valueOf("8cc24d")
|
||||||
|
private val malcontentImage = ImageGetter.getStatIcon("Malcontent")
|
||||||
|
private val happinessImage = ImageGetter.getStatIcon("Happiness")
|
||||||
|
|
||||||
|
private val worldScreen = topbar.worldScreen
|
||||||
|
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val defaultImageSize = 20f
|
||||||
|
const val defaultHorizontalPad = 3f
|
||||||
|
const val defaultTopPad = 8f
|
||||||
|
const val defaultBottomPad = 3f
|
||||||
|
const val defaultImageBottomPad = 6f
|
||||||
|
const val padRightBetweenStats = 20f
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
|
||||||
|
fun addStat(label: Label, icon: String, isLast: Boolean = false, screenFactory: ()-> BaseScreen) {
|
||||||
|
val image = ImageGetter.getStatIcon(icon)
|
||||||
|
val action = {
|
||||||
|
worldScreen.game.pushScreen(screenFactory())
|
||||||
|
}
|
||||||
|
label.onClick(action)
|
||||||
|
image.onClick(action)
|
||||||
|
add(label)
|
||||||
|
add(image).padBottom(defaultImageBottomPad).size(defaultImageSize).apply {
|
||||||
|
if (!isLast) padRight(padRightBetweenStats)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addStat(label: Label, icon: String, overviewPage: EmpireOverviewCategories, isLast: Boolean = false) =
|
||||||
|
addStat(label, icon, isLast) { EmpireOverviewScreen(worldScreen.selectedCiv, overviewPage) }
|
||||||
|
|
||||||
|
defaults().pad(defaultTopPad, defaultHorizontalPad, defaultBottomPad, defaultHorizontalPad)
|
||||||
|
addStat(goldLabel, "Gold", EmpireOverviewCategories.Stats)
|
||||||
|
addStat(scienceLabel, "Science") { TechPickerScreen(worldScreen.selectedCiv) }
|
||||||
|
|
||||||
|
add(happinessContainer).padBottom(defaultImageBottomPad).size(defaultImageSize)
|
||||||
|
add(happinessLabel).padRight(padRightBetweenStats)
|
||||||
|
val invokeResourcesPage = {
|
||||||
|
worldScreen.openEmpireOverview(EmpireOverviewCategories.Resources)
|
||||||
|
}
|
||||||
|
happinessContainer.onClick(invokeResourcesPage)
|
||||||
|
happinessLabel.onClick(invokeResourcesPage)
|
||||||
|
|
||||||
|
addStat(cultureLabel, "Culture") { PolicyPickerScreen(worldScreen.selectedCiv, worldScreen.canChangeState) }
|
||||||
|
if (worldScreen.gameInfo.isReligionEnabled()) {
|
||||||
|
addStat(faithLabel, "Faith", EmpireOverviewCategories.Religion, isLast = true)
|
||||||
|
} else {
|
||||||
|
add("Religion: Off".toLabel())
|
||||||
|
}
|
||||||
|
|
||||||
|
//saveDimensions()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun rateLabel(value: Float) = value.roundToInt().toStringSigned()
|
||||||
|
|
||||||
|
fun update(civInfo: Civilization) {
|
||||||
|
//resetChildrenSizes()
|
||||||
|
|
||||||
|
val nextTurnStats = civInfo.stats.statsForNextTurn
|
||||||
|
val goldPerTurn = " (" + rateLabel(nextTurnStats.gold) + ")"
|
||||||
|
goldLabel.setText(civInfo.gold.toString() + goldPerTurn)
|
||||||
|
|
||||||
|
scienceLabel.setText(rateLabel(nextTurnStats.science))
|
||||||
|
|
||||||
|
happinessLabel.setText(getHappinessText(civInfo))
|
||||||
|
|
||||||
|
if (civInfo.getHappiness() < 0) {
|
||||||
|
happinessLabel.setFontColor(malcontentColor)
|
||||||
|
happinessContainer.clearChildren()
|
||||||
|
happinessContainer.addActor(malcontentImage)
|
||||||
|
} else {
|
||||||
|
happinessLabel.setFontColor(happinessColor)
|
||||||
|
happinessContainer.clearChildren()
|
||||||
|
happinessContainer.addActor(happinessImage)
|
||||||
|
}
|
||||||
|
|
||||||
|
cultureLabel.setText(getCultureText(civInfo, nextTurnStats))
|
||||||
|
faithLabel.setText(civInfo.religionManager.storedFaith.toString() +
|
||||||
|
" (" + rateLabel(nextTurnStats.faith) + ")")
|
||||||
|
//scaleToMaxWidth(worldScreen.stage.width)
|
||||||
|
pack()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getCultureText(civInfo: Civilization, nextTurnStats: Stats): String {
|
||||||
|
var cultureString = rateLabel(nextTurnStats.culture)
|
||||||
|
//if (nextTurnStats.culture == 0f) return cultureString // when you start the game, you're not producing any culture
|
||||||
|
|
||||||
|
val turnsToNextPolicy = (civInfo.policies.getCultureNeededForNextPolicy() - civInfo.policies.storedCulture) / nextTurnStats.culture
|
||||||
|
cultureString += if (turnsToNextPolicy <= 0f) " (!)"
|
||||||
|
else if (nextTurnStats.culture <= 0) " (∞)"
|
||||||
|
else " (" + ceil(turnsToNextPolicy).toInt() + ")"
|
||||||
|
return cultureString
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getHappinessText(civInfo: Civilization): String {
|
||||||
|
var happinessText = civInfo.getHappiness().toString()
|
||||||
|
val goldenAges = civInfo.goldenAges
|
||||||
|
happinessText +=
|
||||||
|
if (goldenAges.isGoldenAge())
|
||||||
|
" {GOLDEN AGE}(${goldenAges.turnsLeftForCurrentGoldenAge})".tr()
|
||||||
|
else
|
||||||
|
" (${goldenAges.storedHappiness}/${goldenAges.happinessRequiredForNextGoldenAge()})"
|
||||||
|
return happinessText
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user