mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-22 10:54:19 -04:00
optimized city screen for smart phone (#12315)
* optimized city screen for smart phone - moved "buy" button to city info table - removed "add to queue" button - expand icon changed to android defaults - CityStatsTable: big scrollable area, expandable * made CityStatsTable collapsible * Extracted BuyButtonFactory and re-added buy button close to construction queue --------- Co-authored-by: M. Rittweger <m.rittweger@mvolution.de> Co-authored-by: Yair Morgenstern <yairm210@hotmail.com>
This commit is contained in:
parent
32247fe437
commit
835ca58b4e
@ -74,7 +74,7 @@ class ExpanderTab(
|
||||
header.defaults().pad(headerPad)
|
||||
headerIcon.setSize(arrowSize, arrowSize)
|
||||
headerIcon.setOrigin(Align.center)
|
||||
headerIcon.rotation = 180f
|
||||
headerIcon.rotation = 0f
|
||||
headerIcon.color = arrowColor
|
||||
header.background(
|
||||
BaseScreen.skinStrings.getUiBackground(
|
||||
@ -83,7 +83,7 @@ class ExpanderTab(
|
||||
)
|
||||
)
|
||||
if (icon != null) header.add(icon)
|
||||
header.add(headerLabel)
|
||||
header.add(headerLabel).expandX()
|
||||
header.add(headerIcon).size(arrowSize).align(Align.center)
|
||||
header.touchable= Touchable.enabled
|
||||
header.onActivation { toggle() }
|
||||
@ -111,11 +111,11 @@ class ExpanderTab(
|
||||
if (noAnimation || !UncivGame.Current.settings.continuousRendering) {
|
||||
contentWrapper.clear()
|
||||
if (isOpen) contentWrapper.add(innerTable)
|
||||
headerIcon.rotation = if (isOpen) 90f else 180f
|
||||
headerIcon.rotation = if (isOpen) 90f else 0f
|
||||
if (!noAnimation) onChange?.invoke()
|
||||
return
|
||||
}
|
||||
val action = object: FloatAction ( 90f, 180f, animationDuration, Interpolation.linear) {
|
||||
val action = object: FloatAction ( 90f, 0f, animationDuration, Interpolation.linear) {
|
||||
override fun update(percent: Float) {
|
||||
super.update(percent)
|
||||
headerIcon.rotation = this.value
|
||||
|
200
core/src/com/unciv/ui/screens/cityscreen/BuyButtonFactory.kt
Normal file
200
core/src/com/unciv/ui/screens/cityscreen/BuyButtonFactory.kt
Normal file
@ -0,0 +1,200 @@
|
||||
package com.unciv.ui.screens.cityscreen
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Cell
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
|
||||
import com.unciv.Constants
|
||||
import com.unciv.logic.city.CityConstructions
|
||||
import com.unciv.logic.map.tile.Tile
|
||||
import com.unciv.models.Religion
|
||||
import com.unciv.models.ruleset.Building
|
||||
import com.unciv.models.ruleset.IConstruction
|
||||
import com.unciv.models.ruleset.INonPerpetualConstruction
|
||||
import com.unciv.models.ruleset.PerpetualConstruction
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
import com.unciv.models.stats.Stat
|
||||
import com.unciv.models.translations.tr
|
||||
import com.unciv.ui.audio.SoundPlayer
|
||||
import com.unciv.ui.components.extensions.disable
|
||||
import com.unciv.ui.components.extensions.isEnabled
|
||||
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.popups.Popup
|
||||
import com.unciv.ui.popups.closeAllPopups
|
||||
import com.unciv.ui.screens.basescreen.BaseScreen
|
||||
|
||||
/**
|
||||
* Use [addBuyButtons] to add buy buttons to a table.
|
||||
* This class handles everything related to buying constructions. This includes
|
||||
* showing and handling [ConfirmBuyPopup] and the actual purchase in [purchaseConstruction].
|
||||
*/
|
||||
class BuyButtonFactory(val cityScreen: CityScreen) {
|
||||
|
||||
private var preferredBuyStat = Stat.Gold // Used for keyboard buy
|
||||
|
||||
fun addBuyButtons(table: Table, construction: IConstruction?, onButtonAdded: (Cell<TextButton>) -> Unit) {
|
||||
for (button in getBuyButtons(construction)) {
|
||||
onButtonAdded(table.add(button))
|
||||
}
|
||||
}
|
||||
|
||||
fun hasBuyButtons(construction: IConstruction?): Boolean {
|
||||
return getBuyButtons(construction).isNotEmpty()
|
||||
}
|
||||
|
||||
private fun getBuyButtons(construction: IConstruction?): List<TextButton> {
|
||||
val selection = cityScreen.selectedConstruction!=null || cityScreen.selectedQueueEntry >= 0
|
||||
if (selection && construction != null && construction !is PerpetualConstruction)
|
||||
return Stat.statsUsableToBuy.mapNotNull {
|
||||
getBuyButton(construction as INonPerpetualConstruction, it)
|
||||
}
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
private fun getBuyButton(construction: INonPerpetualConstruction?, stat: Stat = Stat.Gold): TextButton? {
|
||||
if (stat !in Stat.statsUsableToBuy || construction == null)
|
||||
return null
|
||||
|
||||
val city = cityScreen.city
|
||||
val button = "".toTextButton()
|
||||
|
||||
if (!isConstructionPurchaseShown(construction, stat)) {
|
||||
// This can't ever be bought with the given currency.
|
||||
// We want one disabled "buy" button without a price for "priceless" buildings such as wonders
|
||||
// We don't want such a button when the construction can be bought using a different currency
|
||||
if (stat != Stat.Gold || construction.canBePurchasedWithAnyStat(city))
|
||||
return null
|
||||
button.setText("Buy".tr())
|
||||
button.disable()
|
||||
} else {
|
||||
val constructionBuyCost = construction.getStatBuyCost(city, stat)!!
|
||||
button.setText("Buy".tr() + " " + constructionBuyCost.tr() + stat.character)
|
||||
|
||||
button.onActivation(binding = KeyboardBinding.BuyConstruction) {
|
||||
button.disable()
|
||||
buyButtonOnClick(construction, stat)
|
||||
}
|
||||
button.isEnabled = cityScreen.canCityBeChanged() &&
|
||||
city.cityConstructions.isConstructionPurchaseAllowed(construction, stat, constructionBuyCost)
|
||||
preferredBuyStat = stat // Not very intelligent, but the least common currency "wins"
|
||||
}
|
||||
|
||||
button.labelCell.pad(5f)
|
||||
|
||||
return button
|
||||
}
|
||||
|
||||
private fun buyButtonOnClick(construction: INonPerpetualConstruction, stat: Stat = preferredBuyStat) {
|
||||
if (construction !is Building || !construction.hasCreateOneImprovementUnique())
|
||||
return askToBuyConstruction(construction, stat)
|
||||
if (cityScreen.selectedQueueEntry < 0)
|
||||
return cityScreen.startPickTileForCreatesOneImprovement(construction, stat, true)
|
||||
// Buying a UniqueType.CreatesOneImprovement building from queue must pass down
|
||||
// the already selected tile, otherwise a new one is chosen from Automation code.
|
||||
val improvement = construction.getImprovementToCreate(
|
||||
cityScreen.city.getRuleset(), cityScreen.city.civ)!!
|
||||
val tileForImprovement = cityScreen.city.cityConstructions.getTileForImprovement(improvement.name)
|
||||
askToBuyConstruction(construction, stat, tileForImprovement)
|
||||
}
|
||||
|
||||
/** Ask whether user wants to buy [construction] for [stat].
|
||||
*
|
||||
* Used from onClick and keyboard dispatch, thus only minimal parameters are passed,
|
||||
* and it needs to do all checks and the sound as appropriate.
|
||||
*/
|
||||
fun askToBuyConstruction(
|
||||
construction: INonPerpetualConstruction,
|
||||
stat: Stat = preferredBuyStat,
|
||||
tile: Tile? = null
|
||||
) {
|
||||
if (!isConstructionPurchaseShown(construction, stat)) return
|
||||
val city = cityScreen.city
|
||||
val constructionStatBuyCost = construction.getStatBuyCost(city, stat)!!
|
||||
if (!city.cityConstructions.isConstructionPurchaseAllowed(construction, stat, constructionStatBuyCost)) return
|
||||
|
||||
cityScreen.closeAllPopups()
|
||||
ConfirmBuyPopup(construction, stat,constructionStatBuyCost, tile)
|
||||
}
|
||||
|
||||
private inner class ConfirmBuyPopup(
|
||||
construction: INonPerpetualConstruction,
|
||||
stat: Stat,
|
||||
constructionStatBuyCost: Int,
|
||||
tile: Tile?
|
||||
) : Popup(cityScreen.stage) {
|
||||
init {
|
||||
val city = cityScreen.city
|
||||
val balance = city.getStatReserve(stat)
|
||||
val majorityReligion = city.religion.getMajorityReligion()
|
||||
val yourReligion = city.civ.religionManager.religion
|
||||
val isBuyingWithFaithForForeignReligion = construction.hasUnique(UniqueType.ReligiousUnit)
|
||||
&& !construction.hasUnique(UniqueType.TakeReligionOverBirthCity)
|
||||
&& majorityReligion != yourReligion
|
||||
|
||||
addGoodSizedLabel("Currently you have [$balance] [${stat.name}].").padBottom(10f).row()
|
||||
if (isBuyingWithFaithForForeignReligion) {
|
||||
// Earlier tests should forbid this Popup unless both religions are non-null, but to be safe:
|
||||
fun Religion?.getName() = this?.getReligionDisplayName() ?: Constants.unknownCityName
|
||||
addGoodSizedLabel("You are buying a religious unit in a city that doesn't follow the religion you founded ([${yourReligion.getName()}]). " +
|
||||
"This means that the unit is tied to that foreign religion ([${majorityReligion.getName()}]) and will be less useful.").row()
|
||||
addGoodSizedLabel("Are you really sure you want to purchase this unit?", Constants.headingFontSize).run {
|
||||
actor.color = Color.FIREBRICK
|
||||
padBottom(10f)
|
||||
row()
|
||||
}
|
||||
}
|
||||
addGoodSizedLabel("Would you like to purchase [${construction.name}] for [$constructionStatBuyCost] [${stat.character}]?").row()
|
||||
|
||||
addCloseButton(Constants.cancel, KeyboardBinding.Cancel) { cityScreen.update() }
|
||||
val confirmStyle = BaseScreen.skin.get("positive", TextButton.TextButtonStyle::class.java)
|
||||
addOKButton("Purchase", KeyboardBinding.Confirm, confirmStyle) {
|
||||
purchaseConstruction(construction, stat, tile)
|
||||
}
|
||||
equalizeLastTwoButtonWidths()
|
||||
open(true)
|
||||
}
|
||||
}
|
||||
|
||||
/** This tests whether the buy button should be _shown_ */
|
||||
private fun isConstructionPurchaseShown(construction: INonPerpetualConstruction, stat: Stat): Boolean {
|
||||
val city = cityScreen.city
|
||||
return construction.canBePurchasedWithStat(city, stat)
|
||||
}
|
||||
|
||||
/** Called only by askToBuyConstruction's Yes answer - not to be confused with [CityConstructions.purchaseConstruction]
|
||||
* @param tile supports [UniqueType.CreatesOneImprovement]
|
||||
*/
|
||||
private fun purchaseConstruction(
|
||||
construction: INonPerpetualConstruction,
|
||||
stat: Stat = Stat.Gold,
|
||||
tile: Tile? = null
|
||||
) {
|
||||
SoundPlayer.play(stat.purchaseSound)
|
||||
val city = cityScreen.city
|
||||
if (!city.cityConstructions.purchaseConstruction(construction, cityScreen.selectedQueueEntry, false, stat, tile)) {
|
||||
Popup(cityScreen).apply {
|
||||
add("No space available to place [${construction.name}] near [${city.name}]".tr()).row()
|
||||
addCloseButton()
|
||||
open()
|
||||
}
|
||||
return
|
||||
}
|
||||
if (cityScreen.selectedQueueEntry>=0 || cityScreen.selectedConstruction?.isBuildable(city.cityConstructions) != true) {
|
||||
cityScreen.selectedQueueEntry = -1
|
||||
cityScreen.clearSelection()
|
||||
|
||||
// Allow buying next queued or auto-assigned construction right away
|
||||
city.cityConstructions.chooseNextConstruction()
|
||||
if (city.cityConstructions.currentConstructionFromQueue.isNotEmpty()) {
|
||||
val newConstruction = city.cityConstructions.getCurrentConstruction()
|
||||
if (newConstruction is INonPerpetualConstruction)
|
||||
cityScreen.selectConstruction(newConstruction)
|
||||
}
|
||||
}
|
||||
cityScreen.city.reassignPopulation()
|
||||
cityScreen.update()
|
||||
}
|
||||
|
||||
}
|
@ -5,14 +5,11 @@ 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.Table
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
|
||||
import com.badlogic.gdx.utils.Align
|
||||
import com.unciv.Constants
|
||||
import com.unciv.GUI
|
||||
import com.unciv.logic.city.City
|
||||
import com.unciv.logic.city.CityConstructions
|
||||
import com.unciv.logic.map.tile.Tile
|
||||
import com.unciv.models.Religion
|
||||
import com.unciv.models.UncivSound
|
||||
import com.unciv.models.ruleset.Building
|
||||
import com.unciv.models.ruleset.IConstruction
|
||||
@ -32,13 +29,10 @@ import com.unciv.ui.components.extensions.addCell
|
||||
import com.unciv.ui.components.extensions.addSeparator
|
||||
import com.unciv.ui.components.extensions.brighten
|
||||
import com.unciv.ui.components.extensions.darken
|
||||
import com.unciv.ui.components.extensions.disable
|
||||
import com.unciv.ui.components.extensions.getConsumesAmountString
|
||||
import com.unciv.ui.components.extensions.isEnabled
|
||||
import com.unciv.ui.components.extensions.packIfNeeded
|
||||
import com.unciv.ui.components.extensions.surroundWithCircle
|
||||
import com.unciv.ui.components.extensions.toLabel
|
||||
import com.unciv.ui.components.extensions.toTextButton
|
||||
import com.unciv.ui.components.fonts.Fonts
|
||||
import com.unciv.ui.components.input.KeyboardBinding
|
||||
import com.unciv.ui.components.input.keyShortcuts
|
||||
@ -49,8 +43,6 @@ import com.unciv.ui.components.widgets.ColorMarkupLabel
|
||||
import com.unciv.ui.components.widgets.ExpanderTab
|
||||
import com.unciv.ui.images.ImageGetter
|
||||
import com.unciv.ui.popups.CityScreenConstructionMenu
|
||||
import com.unciv.ui.popups.Popup
|
||||
import com.unciv.ui.popups.closeAllPopups
|
||||
import com.unciv.ui.screens.basescreen.BaseScreen
|
||||
import com.unciv.utils.Concurrency
|
||||
import com.unciv.utils.launchOnGLThread
|
||||
@ -66,19 +58,19 @@ private class ConstructionButtonDTO(
|
||||
|
||||
/**
|
||||
* Manager to hold and coordinate two widgets for the city screen left side:
|
||||
* - Construction queue with the enqueue / buy buttons.
|
||||
* - Construction queue with the buy button.
|
||||
* The queue is scrollable, limited to one third of the stage height.
|
||||
* - Available constructions display, scrolling, grouped with expanders and therefore of dynamic height.
|
||||
*/
|
||||
class CityConstructionsTable(private val cityScreen: CityScreen) {
|
||||
/* -1 = Nothing, >= 0 queue entry (0 = current construction) */
|
||||
private var selectedQueueEntry = -1 // None
|
||||
private var preferredBuyStat = Stat.Gold // Used for keyboard buy
|
||||
var selectedQueueEntry = -1 // None
|
||||
|
||||
private val upperTable = Table(BaseScreen.skin)
|
||||
private val constructionsQueueScrollPane: ScrollPane
|
||||
private val constructionsQueueTable = Table()
|
||||
private val buyButtonsTable = Table()
|
||||
private val buttonsTable = Table()
|
||||
private val buyButtonFactory = BuyButtonFactory(cityScreen)
|
||||
|
||||
private val lowerTable = Table()
|
||||
private val availableConstructionsScrollPane: ScrollPane
|
||||
@ -109,7 +101,7 @@ class CityConstructionsTable(private val cityScreen: CityScreen) {
|
||||
upperTable.add(constructionsQueueScrollPane)
|
||||
.maxHeight(stageHeight / 3 - 10f)
|
||||
.padBottom(pad).row()
|
||||
upperTable.add(buyButtonsTable).padBottom(pad).row()
|
||||
upperTable.add(buttonsTable).padBottom(pad).row()
|
||||
|
||||
availableConstructionsScrollPane = ScrollPane(availableConstructionsTable.addBorder(2f, Color.WHITE))
|
||||
availableConstructionsScrollPane.setOverscroll(false, false)
|
||||
@ -149,14 +141,13 @@ class CityConstructionsTable(private val cityScreen: CityScreen) {
|
||||
}
|
||||
|
||||
private fun updateButtons(construction: IConstruction?) {
|
||||
buyButtonsTable.clear()
|
||||
if (!cityScreen.canChangeState) return
|
||||
/** [UniqueType.MayBuyConstructionsInPuppets] support - we need a buy button for civs that could buy items in puppets */
|
||||
if (cityScreen.city.isPuppet && !cityScreen.city.getMatchingUniques(UniqueType.MayBuyConstructionsInPuppets).any()) return
|
||||
buyButtonsTable.add(getQueueButton(construction)).padRight(5f)
|
||||
if (construction != null && construction !is PerpetualConstruction)
|
||||
for (button in getBuyButtons(construction as INonPerpetualConstruction))
|
||||
buyButtonsTable.add(button).padRight(5f)
|
||||
buttonsTable.clear()
|
||||
buyButtonFactory.addBuyButtons(buttonsTable, construction) {
|
||||
it.padRight(5f)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateConstructionQueue() {
|
||||
@ -553,38 +544,6 @@ class CityConstructionsTable(private val cityScreen: CityScreen) {
|
||||
|| city.isPuppet
|
||||
}
|
||||
|
||||
private fun getQueueButton(construction: IConstruction?): TextButton {
|
||||
val city = cityScreen.city
|
||||
val cityConstructions = city.cityConstructions
|
||||
val button: TextButton
|
||||
|
||||
if (isSelectedQueueEntry()) {
|
||||
button = "Remove from queue".toTextButton()
|
||||
button.onActivation(binding = KeyboardBinding.AddConstruction) {
|
||||
cityConstructions.removeFromQueue(selectedQueueEntry, false)
|
||||
cityScreen.clearSelection()
|
||||
selectedQueueEntry = -1
|
||||
cityScreen.city.reassignPopulation()
|
||||
cityScreen.update()
|
||||
}
|
||||
if (city.isPuppet)
|
||||
button.disable()
|
||||
} else {
|
||||
button = "Add to queue".toTextButton()
|
||||
if (construction == null
|
||||
|| cannotAddConstructionToQueue(construction, city, cityConstructions)) {
|
||||
button.disable()
|
||||
} else {
|
||||
button.onActivation(binding = KeyboardBinding.AddConstruction, sound = UncivSound.Silent) {
|
||||
addConstructionToQueue(construction, cityConstructions)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
button.labelCell.pad(5f)
|
||||
return button
|
||||
}
|
||||
|
||||
private fun addConstructionToQueue(construction: IConstruction, cityConstructions: CityConstructions) {
|
||||
// Some evil person decided to double tap real fast - #4977
|
||||
if (cannotAddConstructionToQueue(construction, cityScreen.city, cityConstructions))
|
||||
@ -618,155 +577,7 @@ class CityConstructionsTable(private val cityScreen: CityScreen) {
|
||||
else -> UncivSound.Click
|
||||
}
|
||||
}
|
||||
|
||||
private fun getBuyButtons(construction: INonPerpetualConstruction?): List<TextButton> {
|
||||
return Stat.statsUsableToBuy.mapNotNull { getBuyButton(construction, it) }
|
||||
}
|
||||
|
||||
private fun getBuyButton(construction: INonPerpetualConstruction?, stat: Stat = Stat.Gold): TextButton? {
|
||||
if (stat !in Stat.statsUsableToBuy || construction == null)
|
||||
return null
|
||||
|
||||
val city = cityScreen.city
|
||||
val button = "".toTextButton()
|
||||
|
||||
if (!isConstructionPurchaseShown(construction, stat)) {
|
||||
// This can't ever be bought with the given currency.
|
||||
// We want one disabled "buy" button without a price for "priceless" buildings such as wonders
|
||||
// We don't want such a button when the construction can be bought using a different currency
|
||||
if (stat != Stat.Gold || construction.canBePurchasedWithAnyStat(city))
|
||||
return null
|
||||
button.setText("Buy".tr())
|
||||
button.disable()
|
||||
} else {
|
||||
val constructionBuyCost = construction.getStatBuyCost(city, stat)!!
|
||||
button.setText("Buy".tr() + " " + constructionBuyCost.tr() + stat.character)
|
||||
|
||||
button.onActivation(binding = KeyboardBinding.BuyConstruction) {
|
||||
button.disable()
|
||||
buyButtonOnClick(construction, stat)
|
||||
}
|
||||
button.isEnabled = cityScreen.canCityBeChanged() &&
|
||||
city.cityConstructions.isConstructionPurchaseAllowed(construction, stat, constructionBuyCost)
|
||||
preferredBuyStat = stat // Not very intelligent, but the least common currency "wins"
|
||||
}
|
||||
|
||||
button.labelCell.pad(5f)
|
||||
|
||||
return button
|
||||
}
|
||||
|
||||
private fun buyButtonOnClick(construction: INonPerpetualConstruction, stat: Stat = preferredBuyStat) {
|
||||
if (construction !is Building || !construction.hasCreateOneImprovementUnique())
|
||||
return askToBuyConstruction(construction, stat)
|
||||
if (selectedQueueEntry < 0)
|
||||
return cityScreen.startPickTileForCreatesOneImprovement(construction, stat, true)
|
||||
// Buying a UniqueType.CreatesOneImprovement building from queue must pass down
|
||||
// the already selected tile, otherwise a new one is chosen from Automation code.
|
||||
val improvement = construction.getImprovementToCreate(
|
||||
cityScreen.city.getRuleset(), cityScreen.city.civ)!!
|
||||
val tileForImprovement = cityScreen.city.cityConstructions.getTileForImprovement(improvement.name)
|
||||
askToBuyConstruction(construction, stat, tileForImprovement)
|
||||
}
|
||||
|
||||
/** Ask whether user wants to buy [construction] for [stat].
|
||||
*
|
||||
* Used from onClick and keyboard dispatch, thus only minimal parameters are passed,
|
||||
* and it needs to do all checks and the sound as appropriate.
|
||||
*/
|
||||
fun askToBuyConstruction(
|
||||
construction: INonPerpetualConstruction,
|
||||
stat: Stat = preferredBuyStat,
|
||||
tile: Tile? = null
|
||||
) {
|
||||
if (!isConstructionPurchaseShown(construction, stat)) return
|
||||
val city = cityScreen.city
|
||||
val constructionStatBuyCost = construction.getStatBuyCost(city, stat)!!
|
||||
if (!city.cityConstructions.isConstructionPurchaseAllowed(construction, stat, constructionStatBuyCost)) return
|
||||
|
||||
cityScreen.closeAllPopups()
|
||||
ConfirmBuyPopup(construction, stat,constructionStatBuyCost, tile)
|
||||
}
|
||||
|
||||
private inner class ConfirmBuyPopup(
|
||||
construction: INonPerpetualConstruction,
|
||||
stat: Stat,
|
||||
constructionStatBuyCost: Int,
|
||||
tile: Tile?
|
||||
) : Popup(cityScreen.stage) {
|
||||
init {
|
||||
val city = cityScreen.city
|
||||
val balance = city.getStatReserve(stat)
|
||||
val majorityReligion = city.religion.getMajorityReligion()
|
||||
val yourReligion = city.civ.religionManager.religion
|
||||
val isBuyingWithFaithForForeignReligion = construction.hasUnique(UniqueType.ReligiousUnit)
|
||||
&& !construction.hasUnique(UniqueType.TakeReligionOverBirthCity)
|
||||
&& majorityReligion != yourReligion
|
||||
|
||||
addGoodSizedLabel("Currently you have [$balance] [${stat.name}].").padBottom(10f).row()
|
||||
if (isBuyingWithFaithForForeignReligion) {
|
||||
// Earlier tests should forbid this Popup unless both religions are non-null, but to be safe:
|
||||
fun Religion?.getName() = this?.getReligionDisplayName() ?: Constants.unknownCityName
|
||||
addGoodSizedLabel("You are buying a religious unit in a city that doesn't follow the religion you founded ([${yourReligion.getName()}]). " +
|
||||
"This means that the unit is tied to that foreign religion ([${majorityReligion.getName()}]) and will be less useful.").row()
|
||||
addGoodSizedLabel("Are you really sure you want to purchase this unit?", Constants.headingFontSize).run {
|
||||
actor.color = Color.FIREBRICK
|
||||
padBottom(10f)
|
||||
row()
|
||||
}
|
||||
}
|
||||
addGoodSizedLabel("Would you like to purchase [${construction.name}] for [$constructionStatBuyCost] [${stat.character}]?").row()
|
||||
|
||||
addCloseButton(Constants.cancel, KeyboardBinding.Cancel) { cityScreen.update() }
|
||||
val confirmStyle = BaseScreen.skin.get("positive", TextButton.TextButtonStyle::class.java)
|
||||
addOKButton("Purchase", KeyboardBinding.Confirm, confirmStyle) {
|
||||
purchaseConstruction(construction, stat, tile)
|
||||
}
|
||||
equalizeLastTwoButtonWidths()
|
||||
open(true)
|
||||
}
|
||||
}
|
||||
|
||||
/** This tests whether the buy button should be _shown_ */
|
||||
private fun isConstructionPurchaseShown(construction: INonPerpetualConstruction, stat: Stat): Boolean {
|
||||
val city = cityScreen.city
|
||||
return construction.canBePurchasedWithStat(city, stat)
|
||||
}
|
||||
|
||||
/** Called only by askToBuyConstruction's Yes answer - not to be confused with [CityConstructions.purchaseConstruction]
|
||||
* @param tile supports [UniqueType.CreatesOneImprovement]
|
||||
*/
|
||||
private fun purchaseConstruction(
|
||||
construction: INonPerpetualConstruction,
|
||||
stat: Stat = Stat.Gold,
|
||||
tile: Tile? = null
|
||||
) {
|
||||
SoundPlayer.play(stat.purchaseSound)
|
||||
val city = cityScreen.city
|
||||
if (!city.cityConstructions.purchaseConstruction(construction, selectedQueueEntry, false, stat, tile)) {
|
||||
Popup(cityScreen).apply {
|
||||
add("No space available to place [${construction.name}] near [${city.name}]".tr()).row()
|
||||
addCloseButton()
|
||||
open()
|
||||
}
|
||||
return
|
||||
}
|
||||
if (isSelectedQueueEntry() || cityScreen.selectedConstruction?.isBuildable(city.cityConstructions) != true) {
|
||||
selectedQueueEntry = -1
|
||||
cityScreen.clearSelection()
|
||||
|
||||
// Allow buying next queued or auto-assigned construction right away
|
||||
city.cityConstructions.chooseNextConstruction()
|
||||
if (city.cityConstructions.currentConstructionFromQueue.isNotEmpty()) {
|
||||
val newConstruction = city.cityConstructions.getCurrentConstruction()
|
||||
if (newConstruction is INonPerpetualConstruction)
|
||||
cityScreen.selectConstruction(newConstruction)
|
||||
}
|
||||
}
|
||||
cityScreen.city.reassignPopulation()
|
||||
cityScreen.update()
|
||||
}
|
||||
|
||||
|
||||
private fun getMovePriorityButton(
|
||||
arrowDirection: Int,
|
||||
binding: KeyboardBinding,
|
||||
|
@ -133,6 +133,9 @@ class CityScreen(
|
||||
var pickTileData: PickTileForImprovementData? = null
|
||||
/** A [Building] with [UniqueType.CreatesOneImprovement] has been selected _in the queue_: show the tile it will place the improvement on */
|
||||
private var selectedQueueEntryTargetTile: Tile? = null
|
||||
var selectedQueueEntry
|
||||
get() = constructionsTable.selectedQueueEntry
|
||||
set(value) { constructionsTable.selectedQueueEntry = value }
|
||||
/** Cached city.expansion.chooseNewTileToOwn() */
|
||||
// val should be OK as buying tiles is what changes this, and that would re-create the whole CityScreen
|
||||
private val nextTileToOwn = city.expansion.chooseNewTileToOwn()
|
||||
@ -452,7 +455,7 @@ class CityScreen(
|
||||
val improvement = pickTileData.improvement
|
||||
if (tileInfo.improvementFunctions.canBuildImprovement(improvement, city.civ)) {
|
||||
if (pickTileData.isBuying) {
|
||||
constructionsTable.askToBuyConstruction(pickTileData.building, pickTileData.buyStat, tileInfo)
|
||||
BuyButtonFactory(this).askToBuyConstruction(pickTileData.building, pickTileData.buyStat, tileInfo)
|
||||
} else {
|
||||
// This way to store where the improvement a CreatesOneImprovement Building will create goes
|
||||
// might get a bit fragile if several buildings constructing the same improvement type
|
||||
|
@ -2,7 +2,7 @@ package com.unciv.ui.screens.cityscreen
|
||||
|
||||
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.Touchable
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Label
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||
import com.badlogic.gdx.utils.Align
|
||||
@ -32,8 +32,14 @@ class CityStatsTable(private val cityScreen: CityScreen) : Table() {
|
||||
private val lowerTable = Table() // table that will be in the ScrollPane
|
||||
private val lowerPane: ScrollPane
|
||||
private val city = cityScreen.city
|
||||
private val lowerCell: Cell<ScrollPane>
|
||||
|
||||
private val headerIcon = ImageGetter.getImage("OtherIcons/BackArrow").apply {
|
||||
setSize(18f, 18f)
|
||||
setOrigin(Align.center)
|
||||
rotation = 90f
|
||||
}
|
||||
private var headerIconClickArea = Table()
|
||||
private var isOpen = true
|
||||
|
||||
private val detailedStatsButton = "Stats".toTextButton().apply {
|
||||
labelCell.pad(10f)
|
||||
onActivation(binding = KeyboardBinding.ShowStats) {
|
||||
@ -53,16 +59,22 @@ class CityStatsTable(private val cityScreen: CityScreen) : Table() {
|
||||
"CityScreen/CityStatsTable/InnerTable",
|
||||
tintColor = Color.BLACK.cpy().apply { a = 0.8f }
|
||||
)
|
||||
innerTable.add(upperTable).row()
|
||||
|
||||
upperTable.defaults().pad(2f)
|
||||
lowerTable.defaults().pad(2f)
|
||||
lowerPane = ScrollPane(lowerTable)
|
||||
lowerPane.setOverscroll(false, false)
|
||||
lowerPane.setScrollingDisabled(true, false)
|
||||
lowerCell = innerTable.add(lowerPane)
|
||||
|
||||
add(innerTable)
|
||||
add(innerTable).growX()
|
||||
|
||||
// collapse icon with larger click area
|
||||
headerIconClickArea.add(headerIcon).size(headerIcon.width).pad(6f+2f, 12f, 6f, 2f )
|
||||
headerIconClickArea.touchable = Touchable.enabled
|
||||
headerIconClickArea.onClick {
|
||||
isOpen = !isOpen
|
||||
cityScreen.updateWithoutConstructionAndMap()
|
||||
}
|
||||
}
|
||||
|
||||
fun update(height: Float) {
|
||||
@ -93,10 +105,10 @@ class CityStatsTable(private val cityScreen: CityScreen) : Table() {
|
||||
val valueToDisplay = if (stat == Stat.Happiness) city.cityStats.happinessList.values.sum() else amount
|
||||
miniStatsTable.add(round(valueToDisplay).toInt().toLabel()).padRight(5f)
|
||||
}
|
||||
upperTable.add(miniStatsTable)
|
||||
|
||||
upperTable.add(miniStatsTable).expandX()
|
||||
upperTable.addSeparator()
|
||||
upperTable.add(detailedStatsButton).row()
|
||||
|
||||
lowerTable.add(detailedStatsButton).row()
|
||||
addText()
|
||||
|
||||
// begin lowerTable
|
||||
@ -110,11 +122,20 @@ class CityStatsTable(private val cityScreen: CityScreen) : Table() {
|
||||
|
||||
addBuildingsInfo()
|
||||
|
||||
headerIcon.rotation = if(isOpen) 90f else 0f
|
||||
|
||||
innerTable.clear()
|
||||
innerTable.add(upperTable).expandX()
|
||||
innerTable.add(headerIconClickArea).row()
|
||||
val lowerCell = if (isOpen) {
|
||||
innerTable.add(lowerPane).colspan(2)
|
||||
} else null
|
||||
|
||||
upperTable.pack()
|
||||
lowerTable.pack()
|
||||
lowerPane.layout()
|
||||
lowerPane.updateVisualScroll()
|
||||
lowerCell.maxHeight(height - upperTable.height - 8f) // 2 on each side of each cell in innerTable
|
||||
lowerCell?.maxHeight(height - upperTable.height - 8f) // 2 on each side of each cell in innerTable
|
||||
|
||||
innerTable.pack() // update innerTable
|
||||
pack() // update self last
|
||||
@ -158,9 +179,9 @@ class CityStatsTable(private val cityScreen: CityScreen) : Table() {
|
||||
}.tr()
|
||||
turnsToPopString += " (${city.population.foodStored}${Fonts.food}/${city.population.getFoodToNextPopulation()}${Fonts.food})"
|
||||
|
||||
upperTable.add(unassignedPopLabel).row()
|
||||
upperTable.add(turnsToExpansionString.toLabel()).row()
|
||||
upperTable.add(turnsToPopString.toLabel()).row()
|
||||
lowerTable.add(unassignedPopLabel).row()
|
||||
lowerTable.add(turnsToExpansionString.toLabel()).row()
|
||||
lowerTable.add(turnsToPopString.toLabel()).row()
|
||||
|
||||
val tableWithIcons = Table()
|
||||
tableWithIcons.defaults().pad(2f)
|
||||
@ -200,7 +221,7 @@ class CityStatsTable(private val cityScreen: CityScreen) : Table() {
|
||||
tableWithIcons.add(wltkLabel).row()
|
||||
}
|
||||
|
||||
upperTable.add(tableWithIcons).row()
|
||||
lowerTable.add(tableWithIcons).row()
|
||||
}
|
||||
|
||||
private fun addCitizenManagement() {
|
||||
|
@ -25,6 +25,7 @@ import com.unciv.ui.screens.basescreen.BaseScreen
|
||||
|
||||
class ConstructionInfoTable(val cityScreen: CityScreen) : Table() {
|
||||
private val selectedConstructionTable = Table()
|
||||
private val buyButtonFactory = BuyButtonFactory(cityScreen)
|
||||
|
||||
init {
|
||||
selectedConstructionTable.background = BaseScreen.skinStrings.getUiBackground(
|
||||
@ -89,9 +90,23 @@ class ConstructionInfoTable(val cityScreen: CityScreen) : Table() {
|
||||
descriptionLabel.wrap = true
|
||||
add(descriptionLabel).colspan(2).width(stage.width / 4)
|
||||
|
||||
// Show sell button if construction is a currently sellable building
|
||||
if (construction is Building && cityConstructions.isBuilt(construction.name)
|
||||
&& construction.isSellable()) {
|
||||
if (cityConstructions.isBuilt(construction.name)) {
|
||||
showSellButton(construction)
|
||||
} else if (buyButtonFactory.hasBuyButtons(construction)) {
|
||||
row()
|
||||
buyButtonFactory.addBuyButtons(selectedConstructionTable, construction) {
|
||||
it.padTop(5f).colspan(2).center()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Show sell button if construction is a currently sellable building
|
||||
private fun showSellButton(
|
||||
construction: IConstruction
|
||||
) {
|
||||
if (construction is Building && construction.isSellable()) {
|
||||
selectedConstructionTable.run {
|
||||
val sellAmount = cityScreen.city.getGoldForSellingBuilding(construction.name)
|
||||
val sellText = "{Sell} $sellAmount " + Fonts.gold
|
||||
val sellBuildingButton = sellText.toTextButton()
|
||||
@ -138,4 +153,5 @@ class ConstructionInfoTable(val cityScreen: CityScreen) : Table() {
|
||||
cityScreen.clearSelection()
|
||||
cityScreen.update()
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user