mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-27 13:55:54 -04:00
WIP Construction Queue (#1648)
* Construction Queue * Added constructionQueue in addition to currentConstruction: if currentConstruction is done, next construction from Queue is started; if Queue is empty invoke ConstructionAutomation * Queue utility methods: add, remove, higher prio, lower prio * Icons to move constructions in queue * Top left city stats moved to top right panel * Added current construction and queue construction to top left * Extended selected construction (containing description) moved to bottom right, it is now displayed alternatively to selected tile * Max queue size, cannot change queue in puppet city or in other player turn * Queue and current construction reset on puppeting city * Cleanup again * CityStatsTable is a separate class so we can play around with where it's located with minimal code changes * Rejection reason wrap & removing nothing on enqueue a construction * Crude UI proposal * Tutorial updates for queues Co-authored-by: Yair Morgenstern <yairm210@hotmail.com>
This commit is contained in:
parent
12a98aa4bb
commit
2daf27278d
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Before Width: | Height: | Size: 884 KiB After Width: | Height: | Size: 885 KiB |
Binary file not shown.
Before Width: | Height: | Size: 309 KiB After Width: | Height: | Size: 317 KiB |
@ -5,7 +5,7 @@ Move a unit!\nClick on a unit > Click on a destination > Click the arrow popup =
|
|||||||
Found a city!\nSelect the Settler (flag unit) > Click on 'Found city' (bottom-left corner) =
|
Found a city!\nSelect the Settler (flag unit) > Click on 'Found city' (bottom-left corner) =
|
||||||
Enter the city screen!\nClick the city button twice =
|
Enter the city screen!\nClick the city button twice =
|
||||||
Pick a technology to research!\nClick on the tech button (greenish, top left) > \n select technology > click 'Research' (bottom right) =
|
Pick a technology to research!\nClick on the tech button (greenish, top left) > \n select technology > click 'Research' (bottom right) =
|
||||||
Pick a construction!\nEnter city screen > Click on a unit or building (left side) =
|
Pick a construction!\nEnter city screen > Click on a unit or building (bottom left side) > \n click 'add to queue' =
|
||||||
Pass a turn!\nCycle through units with 'Next unit' > Click 'Next turn' =
|
Pass a turn!\nCycle through units with 'Next unit' > Click 'Next turn' =
|
||||||
Reassign worked tiles!\nEnter city screen > click the assigned (green) tile to unassign > \n click an unassigned tile to assign population =
|
Reassign worked tiles!\nEnter city screen > click the assigned (green) tile to unassign > \n click an unassigned tile to assign population =
|
||||||
Meet another civilization!\nExplore the map until you encounter another civilization! =
|
Meet another civilization!\nExplore the map until you encounter another civilization! =
|
||||||
|
@ -37,7 +37,7 @@ class UncivGame(
|
|||||||
/** For when you need to test something in an advanced game and don't have time to faff around */
|
/** For when you need to test something in an advanced game and don't have time to faff around */
|
||||||
val superchargedForDebug = false
|
val superchargedForDebug = false
|
||||||
|
|
||||||
var rewriteTranslationFiles = true
|
var rewriteTranslationFiles = false
|
||||||
|
|
||||||
|
|
||||||
lateinit var worldScreen: WorldScreen
|
lateinit var worldScreen: WorldScreen
|
||||||
|
@ -107,6 +107,7 @@ class CityConstructions {
|
|||||||
fun isEnqueued(constructionName: String): Boolean = constructionQueue.contains(constructionName)
|
fun isEnqueued(constructionName: String): Boolean = constructionQueue.contains(constructionName)
|
||||||
|
|
||||||
fun isQueueFull(): Boolean = constructionQueue.size == queueMaxSize
|
fun isQueueFull(): Boolean = constructionQueue.size == queueMaxSize
|
||||||
|
fun isQueueEmpty(): Boolean = constructionQueue.isEmpty()
|
||||||
|
|
||||||
fun isBuildingWonder(): Boolean {
|
fun isBuildingWonder(): Boolean {
|
||||||
val currentConstruction = getCurrentConstruction()
|
val currentConstruction = getCurrentConstruction()
|
||||||
@ -309,8 +310,13 @@ class CityConstructions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun addToQueue(constructionName: String) {
|
fun addToQueue(constructionName: String) {
|
||||||
if (!isQueueFull())
|
if (!isQueueFull()) {
|
||||||
constructionQueue.add(constructionName)
|
if (isQueueEmpty() && currentConstruction == "Nothing") {
|
||||||
|
currentConstruction = constructionName
|
||||||
|
currentConstructionIsUserSet = true
|
||||||
|
} else
|
||||||
|
constructionQueue.add(constructionName)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeFromQueue(idx: Int) {
|
fun removeFromQueue(idx: Int) {
|
||||||
|
@ -2,47 +2,57 @@ package com.unciv.ui.cityscreen
|
|||||||
|
|
||||||
import com.badlogic.gdx.graphics.Color
|
import com.badlogic.gdx.graphics.Color
|
||||||
import com.badlogic.gdx.scenes.scene2d.Touchable
|
import com.badlogic.gdx.scenes.scene2d.Touchable
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.Image
|
import com.badlogic.gdx.scenes.scene2d.ui.*
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.Skin
|
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
|
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.Label
|
|
||||||
import com.badlogic.gdx.utils.Align
|
import com.badlogic.gdx.utils.Align
|
||||||
import com.unciv.Constants
|
|
||||||
import com.unciv.UncivGame
|
import com.unciv.UncivGame
|
||||||
import com.unciv.logic.city.CityInfo
|
import com.unciv.logic.city.CityInfo
|
||||||
import com.unciv.logic.civilization.GreatPersonManager
|
import com.unciv.logic.civilization.GreatPersonManager
|
||||||
import com.unciv.models.ruleset.Building
|
import com.unciv.models.ruleset.Building
|
||||||
import com.unciv.models.translations.tr
|
|
||||||
import com.unciv.models.stats.Stat
|
import com.unciv.models.stats.Stat
|
||||||
import com.unciv.models.stats.Stats
|
import com.unciv.models.translations.tr
|
||||||
import com.unciv.ui.utils.*
|
import com.unciv.ui.utils.*
|
||||||
import com.unciv.ui.worldscreen.optionstable.YesNoPopupTable
|
import com.unciv.ui.worldscreen.optionstable.YesNoPopupTable
|
||||||
import java.text.DecimalFormat
|
import java.text.DecimalFormat
|
||||||
import kotlin.math.ceil
|
|
||||||
import kotlin.math.floor
|
|
||||||
import kotlin.math.round
|
|
||||||
|
|
||||||
class CityInfoTable(private val cityScreen: CityScreen) : Table(CameraStageBaseScreen.skin) {
|
class CityInfoTable(private val cityScreen: CityScreen) : Table(CameraStageBaseScreen.skin) {
|
||||||
val pad = 5f
|
private val pad = 10f
|
||||||
|
|
||||||
|
private val showConstructionsTableButton = TextButton("Show construction queue", skin)
|
||||||
|
private val cityInfoScrollPane: ScrollPane
|
||||||
|
private val cityInfoTable = Table(skin)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
defaults().pad(pad)
|
showConstructionsTableButton.onClick {
|
||||||
width = cityScreen.stage.width/4
|
cityScreen.showConstructionsTable = true
|
||||||
|
cityScreen.update()
|
||||||
|
}
|
||||||
|
|
||||||
|
cityInfoTable.width = cityScreen.stage.width/4
|
||||||
|
cityInfoTable.background = ImageGetter.getBackground(ImageGetter.getBlue().lerp(Color.BLACK,0.5f))
|
||||||
|
cityInfoScrollPane = ScrollPane(cityInfoTable.addBorder(2f, Color.WHITE))
|
||||||
|
cityInfoScrollPane.setOverscroll(false, false)
|
||||||
|
|
||||||
|
add(showConstructionsTableButton).left().padLeft(pad).padBottom(pad).row()
|
||||||
|
add(cityInfoScrollPane).left().row()
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun update() {
|
internal fun update() {
|
||||||
clear()
|
|
||||||
val cityInfo = cityScreen.city
|
val cityInfo = cityScreen.city
|
||||||
|
|
||||||
addCityStats(cityInfo)
|
cityInfoTable.clear()
|
||||||
addBuildingsInfo(cityInfo)
|
|
||||||
addStatInfo()
|
|
||||||
addGreatPersonPointInfo(cityInfo)
|
|
||||||
|
|
||||||
|
//TODO: Sorry, this is a hack, i'm getting tired and needed some content to test the idea
|
||||||
|
cityInfoTable.apply {
|
||||||
|
addBuildingsInfo(cityInfo)
|
||||||
|
addStatInfo()
|
||||||
|
addGreatPersonPointInfo(cityInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
getCell(cityInfoScrollPane).maxHeight(stage.height - showConstructionsTableButton.height - pad - 10f)
|
||||||
pack()
|
pack()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addCategory(str: String, showHideTable: Table) {
|
private fun Table.addCategory(str: String, showHideTable: Table) {
|
||||||
val titleTable = Table().background(ImageGetter.getBackground(ImageGetter.getBlue()))
|
val titleTable = Table().background(ImageGetter.getBackground(ImageGetter.getBlue()))
|
||||||
val width = cityScreen.stage.width/4 - 2*pad
|
val width = cityScreen.stage.width/4 - 2*pad
|
||||||
val showHideTableWrapper = Table()
|
val showHideTableWrapper = Table()
|
||||||
@ -56,7 +66,7 @@ class CityInfoTable(private val cityScreen: CityScreen) : Table(CameraStageBaseS
|
|||||||
add(showHideTableWrapper).row()
|
add(showHideTableWrapper).row()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addBuildingInfo(building: Building, wondersTable: Table){
|
private fun Table.addBuildingInfo(building: Building, wondersTable: Table){
|
||||||
val wonderNameAndIconTable = Table()
|
val wonderNameAndIconTable = Table()
|
||||||
wonderNameAndIconTable.touchable = Touchable.enabled
|
wonderNameAndIconTable.touchable = Touchable.enabled
|
||||||
wonderNameAndIconTable.add(ImageGetter.getConstructionImage(building.name).surroundWithCircle(30f))
|
wonderNameAndIconTable.add(ImageGetter.getConstructionImage(building.name).surroundWithCircle(30f))
|
||||||
@ -96,66 +106,7 @@ class CityInfoTable(private val cityScreen: CityScreen) : Table(CameraStageBaseS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addCityStats(cityInfo: CityInfo) {
|
private fun Table.addBuildingsInfo(cityInfo: CityInfo) {
|
||||||
val statsTable = Table().align(Align.center)
|
|
||||||
addCategory("Stats", statsTable)
|
|
||||||
|
|
||||||
|
|
||||||
val columns = Stats().toHashMap().size
|
|
||||||
statsTable.add(Label("{Unassigned population}:".tr()
|
|
||||||
+" "+cityInfo.population.getFreePopulation().toString() + "/" + cityInfo.population.population, skin))
|
|
||||||
.pad(5f).row()
|
|
||||||
|
|
||||||
val turnsToExpansionString : String
|
|
||||||
if (cityInfo.cityStats.currentCityStats.culture > 0) {
|
|
||||||
var turnsToExpansion = ceil((cityInfo.expansion.getCultureToNextTile() - cityInfo.expansion.cultureStored)
|
|
||||||
/ cityInfo.cityStats.currentCityStats.culture).toInt()
|
|
||||||
if (turnsToExpansion < 1) turnsToExpansion = 1
|
|
||||||
turnsToExpansionString = "[$turnsToExpansion] turns to expansion".tr()
|
|
||||||
} else {
|
|
||||||
turnsToExpansionString = "Stopped expansion".tr()
|
|
||||||
}
|
|
||||||
|
|
||||||
statsTable.add(Label(turnsToExpansionString + " (" + cityInfo.expansion.cultureStored + "/" + cityInfo.expansion.getCultureToNextTile() + ")",
|
|
||||||
skin)).pad(5f).row()
|
|
||||||
|
|
||||||
val turnsToPopString : String
|
|
||||||
if (cityInfo.cityStats.currentCityStats.food > 0) {
|
|
||||||
if (cityInfo.cityConstructions.currentConstruction == Constants.settler) {
|
|
||||||
turnsToPopString = "Food converts to production".tr()
|
|
||||||
} else {
|
|
||||||
var turnsToPopulation = ceil((cityInfo.population.getFoodToNextPopulation()-cityInfo.population.foodStored)
|
|
||||||
/ cityInfo.cityStats.currentCityStats.food).toInt()
|
|
||||||
if (turnsToPopulation < 1) turnsToPopulation = 1
|
|
||||||
turnsToPopString = "[$turnsToPopulation] turns to new population".tr()
|
|
||||||
}
|
|
||||||
} else if (cityInfo.cityStats.currentCityStats.food < 0) {
|
|
||||||
val turnsToStarvation = floor(cityInfo.population.foodStored / -cityInfo.cityStats.currentCityStats.food).toInt() + 1
|
|
||||||
turnsToPopString = "[$turnsToStarvation] turns to lose population".tr()
|
|
||||||
} else {
|
|
||||||
turnsToPopString = "Stopped population growth".tr()
|
|
||||||
}
|
|
||||||
statsTable.add(Label(turnsToPopString + " (" + cityInfo.population.foodStored + "/" + cityInfo.population.getFoodToNextPopulation() + ")"
|
|
||||||
,skin)).pad(5f).row()
|
|
||||||
|
|
||||||
if (cityInfo.resistanceCounter > 0) {
|
|
||||||
statsTable.add(Label("In resistance for another [${cityInfo.resistanceCounter}] turns".tr(),skin)).pad(5f).row()
|
|
||||||
}
|
|
||||||
|
|
||||||
statsTable.addSeparator()
|
|
||||||
|
|
||||||
val ministatsTable = Table().pad(5f)
|
|
||||||
ministatsTable.defaults()
|
|
||||||
statsTable.add(ministatsTable)
|
|
||||||
|
|
||||||
for(stat in cityInfo.cityStats.currentCityStats.toHashMap()) {
|
|
||||||
if(stat.key == Stat.Happiness) continue
|
|
||||||
ministatsTable.add(ImageGetter.getStatIcon(stat.key.name)).size(20f).padRight(3f)
|
|
||||||
ministatsTable.add(round(stat.value).toInt().toString().toLabel()).padRight(13f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun addBuildingsInfo(cityInfo: CityInfo) {
|
|
||||||
val wonders = mutableListOf<Building>()
|
val wonders = mutableListOf<Building>()
|
||||||
val specialistBuildings = mutableListOf<Building>()
|
val specialistBuildings = mutableListOf<Building>()
|
||||||
val otherBuildings = mutableListOf<Building>()
|
val otherBuildings = mutableListOf<Building>()
|
||||||
@ -200,7 +151,7 @@ class CityInfoTable(private val cityScreen: CityScreen) : Table(CameraStageBaseS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addStatInfo() {
|
private fun Table.addStatInfo() {
|
||||||
val cityStats = cityScreen.city.cityStats
|
val cityStats = cityScreen.city.cityStats
|
||||||
|
|
||||||
for(stat in Stat.values().filter { it!=Stat.Happiness }){
|
for(stat in Stat.values().filter { it!=Stat.Happiness }){
|
||||||
@ -257,7 +208,7 @@ class CityInfoTable(private val cityScreen: CityScreen) : Table(CameraStageBaseS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addGreatPersonPointInfo(cityInfo: CityInfo) {
|
private fun Table.addGreatPersonPointInfo(cityInfo: CityInfo) {
|
||||||
val greatPersonPoints = cityInfo.getGreatPersonMap()
|
val greatPersonPoints = cityInfo.getGreatPersonMap()
|
||||||
val statToGreatPerson = GreatPersonManager().statToGreatPersonMapping
|
val statToGreatPerson = GreatPersonManager().statToGreatPersonMapping
|
||||||
for (stat in Stat.values()) {
|
for (stat in Stat.values()) {
|
||||||
@ -276,7 +227,7 @@ class CityInfoTable(private val cityScreen: CityScreen) : Table(CameraStageBaseS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addSpecialistAllocation(skin: Skin, cityInfo: CityInfo) {
|
private fun Table.addSpecialistAllocation(skin: Skin, cityInfo: CityInfo) {
|
||||||
val specialistAllocationTable = Table()
|
val specialistAllocationTable = Table()
|
||||||
addCategory("Specialist Allocation", specialistAllocationTable) // todo WRONG, BAD - table should contain all the below specialist stuff
|
addCategory("Specialist Allocation", specialistAllocationTable) // todo WRONG, BAD - table should contain all the below specialist stuff
|
||||||
|
|
||||||
@ -346,5 +297,4 @@ class CityInfoTable(private val cityScreen: CityScreen) : Table(CameraStageBaseS
|
|||||||
|
|
||||||
return specialist
|
return specialist
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -16,23 +16,26 @@ import com.unciv.ui.map.TileGroupMap
|
|||||||
import com.unciv.ui.tilegroups.TileSetStrings
|
import com.unciv.ui.tilegroups.TileSetStrings
|
||||||
import com.unciv.ui.utils.*
|
import com.unciv.ui.utils.*
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.math.ceil
|
|
||||||
import kotlin.math.round
|
|
||||||
|
|
||||||
class CityScreen(internal val city: CityInfo): CameraStageBaseScreen() {
|
class CityScreen(internal val city: CityInfo): CameraStageBaseScreen() {
|
||||||
var selectedTile: TileInfo? = null
|
var selectedTile: TileInfo? = null
|
||||||
var selectedConstruction: IConstruction? = null
|
var selectedConstruction: IConstruction? = null
|
||||||
|
|
||||||
|
/** Toggle between Constructions and cityInfo (buildings, specialists etc. */
|
||||||
|
var showConstructionsTable = true
|
||||||
|
|
||||||
// Clockwise from the top-left
|
// Clockwise from the top-left
|
||||||
|
|
||||||
/** Displays current production, production queue and available productions list - sits on LEFT */
|
/** Displays current production, production queue and available productions list - sits on LEFT */
|
||||||
private var constructionsTable = ConstructionsTable(this)
|
private var constructionsTable = ConstructionsTable(this)
|
||||||
|
/** Displays stats, buildings, specialists and stats drilldown - sits on TOP RIGHT */
|
||||||
|
private var cityInfoTable = CityInfoTable(this)
|
||||||
|
|
||||||
/** Displays raze city button - sits on TOP CENTER */
|
/** Displays raze city button - sits on TOP CENTER */
|
||||||
private var razeCityButtonHolder = Table()
|
private var razeCityButtonHolder = Table()
|
||||||
|
|
||||||
/** Displays stats, buildings, specialists and stats drilldown - sits on TOP RIGHT */
|
/** Displays city stats info */
|
||||||
private var cityInfoTable = CityInfoTable(this)
|
private var cityStatsTable = CityStatsTable(this.city)
|
||||||
|
|
||||||
/** Displays tile info, alternate with selectedConstructionTable - sits on BOTTOM RIGHT */
|
/** Displays tile info, alternate with selectedConstructionTable - sits on BOTTOM RIGHT */
|
||||||
private var tileTable = CityScreenTileTable(city)
|
private var tileTable = CityScreenTileTable(city)
|
||||||
@ -49,34 +52,36 @@ class CityScreen(internal val city: CityInfo): CameraStageBaseScreen() {
|
|||||||
init {
|
init {
|
||||||
onBackButtonClicked { game.setWorldScreen() }
|
onBackButtonClicked { game.setWorldScreen() }
|
||||||
UncivGame.Current.settings.addCompletedTutorialTask("Enter city screen")
|
UncivGame.Current.settings.addCompletedTutorialTask("Enter city screen")
|
||||||
|
|
||||||
addTiles()
|
addTiles()
|
||||||
|
|
||||||
var buildingsTableContainer = Table()
|
|
||||||
buildingsTableContainer.pad(3f)
|
|
||||||
buildingsTableContainer.background = ImageGetter.getBackground(ImageGetter.getBlue().lerp(Color.BLACK,0.5f))
|
|
||||||
cityInfoTable.update()
|
|
||||||
val buildingsScroll = ScrollPane(cityInfoTable)
|
|
||||||
buildingsTableContainer.add(buildingsScroll).size(stage.width/4,stage.height / 2)
|
|
||||||
|
|
||||||
buildingsTableContainer = buildingsTableContainer.addBorder(2f, Color.WHITE)
|
|
||||||
buildingsTableContainer.setPosition( stage.width - 5f, stage.height - 5f, Align.topRight)
|
|
||||||
|
|
||||||
//stage.setDebugTableUnderMouse(true)
|
//stage.setDebugTableUnderMouse(true)
|
||||||
|
stage.addActor(cityStatsTable)
|
||||||
stage.addActor(constructionsTable)
|
stage.addActor(constructionsTable)
|
||||||
stage.addActor(tileTable)
|
stage.addActor(tileTable)
|
||||||
stage.addActor(selectedConstructionTable)
|
stage.addActor(selectedConstructionTable)
|
||||||
stage.addActor(cityPickerTable)
|
stage.addActor(cityPickerTable)
|
||||||
stage.addActor(buildingsTableContainer)
|
stage.addActor(cityInfoTable)
|
||||||
|
|
||||||
update()
|
update()
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun update() {
|
internal fun update() {
|
||||||
|
if (showConstructionsTable) {
|
||||||
|
constructionsTable.isVisible = true
|
||||||
|
cityInfoTable.isVisible = false
|
||||||
|
} else {
|
||||||
|
constructionsTable.isVisible = false
|
||||||
|
cityInfoTable.isVisible = true
|
||||||
|
}
|
||||||
|
|
||||||
city.cityStats.update()
|
city.cityStats.update()
|
||||||
|
|
||||||
constructionsTable.update(selectedConstruction)
|
constructionsTable.update(selectedConstruction)
|
||||||
constructionsTable.setPosition(5f, stage.height - 5f, Align.topLeft)
|
constructionsTable.setPosition(5f, stage.height - 5f, Align.topLeft)
|
||||||
|
|
||||||
|
cityInfoTable.update()
|
||||||
|
cityInfoTable.setPosition(5f, stage.height - 5f, Align.topLeft)
|
||||||
|
|
||||||
cityPickerTable.update()
|
cityPickerTable.update()
|
||||||
cityPickerTable.centerX(stage)
|
cityPickerTable.centerX(stage)
|
||||||
|
|
||||||
@ -86,7 +91,8 @@ class CityScreen(internal val city: CityInfo): CameraStageBaseScreen() {
|
|||||||
selectedConstructionTable.update(selectedConstruction)
|
selectedConstructionTable.update(selectedConstruction)
|
||||||
selectedConstructionTable.setPosition(stage.width - 5f, 5f, Align.bottomRight)
|
selectedConstructionTable.setPosition(stage.width - 5f, 5f, Align.bottomRight)
|
||||||
|
|
||||||
cityInfoTable.update()
|
cityStatsTable.update()
|
||||||
|
cityStatsTable.setPosition( stage.width - 5f, stage.height - 5f, Align.topRight)
|
||||||
|
|
||||||
updateAnnexAndRazeCityButton()
|
updateAnnexAndRazeCityButton()
|
||||||
updateTileGroups()
|
updateTileGroups()
|
||||||
|
76
core/src/com/unciv/ui/cityscreen/CityStatsTable.kt
Normal file
76
core/src/com/unciv/ui/cityscreen/CityStatsTable.kt
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
package com.unciv.ui.cityscreen
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.Color
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||||
|
import com.unciv.Constants
|
||||||
|
import com.unciv.logic.city.CityInfo
|
||||||
|
import com.unciv.models.stats.Stat
|
||||||
|
import com.unciv.models.translations.tr
|
||||||
|
import com.unciv.ui.utils.ImageGetter
|
||||||
|
import com.unciv.ui.utils.addSeparator
|
||||||
|
import com.unciv.ui.utils.colorFromRGB
|
||||||
|
import com.unciv.ui.utils.toLabel
|
||||||
|
import kotlin.math.ceil
|
||||||
|
import kotlin.math.round
|
||||||
|
|
||||||
|
class CityStatsTable(val cityInfo: CityInfo): Table() {
|
||||||
|
private val innerTable = Table()
|
||||||
|
|
||||||
|
init {
|
||||||
|
pad(2f)
|
||||||
|
background = ImageGetter.getBackground(colorFromRGB(194,180,131))
|
||||||
|
|
||||||
|
innerTable.pad(5f)
|
||||||
|
innerTable.defaults().pad(5f)
|
||||||
|
innerTable.background = ImageGetter.getBackground(Color.BLACK.cpy().apply { a=0.8f })
|
||||||
|
|
||||||
|
add(innerTable).fill()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun update() {
|
||||||
|
innerTable.clear()
|
||||||
|
|
||||||
|
val unassignedPopString = "{Unassigned population}:".tr()+
|
||||||
|
" "+cityInfo.population.getFreePopulation().toString() + "/" + cityInfo.population.population
|
||||||
|
|
||||||
|
var turnsToExpansionString =
|
||||||
|
if (cityInfo.cityStats.currentCityStats.culture > 0) {
|
||||||
|
val remainingCulture = cityInfo.expansion.getCultureToNextTile() - cityInfo.expansion.cultureStored
|
||||||
|
var turnsToExpansion = ceil(remainingCulture / cityInfo.cityStats.currentCityStats.culture).toInt()
|
||||||
|
if (turnsToExpansion < 1) turnsToExpansion = 1
|
||||||
|
"[$turnsToExpansion] turns to expansion".tr()
|
||||||
|
} else {
|
||||||
|
"Stopped expansion".tr()
|
||||||
|
}
|
||||||
|
turnsToExpansionString += " (" + cityInfo.expansion.cultureStored + "/" +
|
||||||
|
cityInfo.expansion.getCultureToNextTile() + ")"
|
||||||
|
|
||||||
|
var turnsToPopString =
|
||||||
|
when {
|
||||||
|
cityInfo.isGrowing() -> "[${cityInfo.getNumTurnsToNewPopulation()}] turns to new population".tr()
|
||||||
|
cityInfo.isStarving() -> "[${cityInfo.getNumTurnsToStarvation()}] turns to lose population".tr()
|
||||||
|
cityInfo.cityConstructions.currentConstruction == Constants.settler -> "Food converts to production".tr()
|
||||||
|
else -> "Stopped population growth".tr()
|
||||||
|
}
|
||||||
|
turnsToPopString += " (" + cityInfo.population.foodStored + "/" + cityInfo.population.getFoodToNextPopulation() + ")"
|
||||||
|
|
||||||
|
val ministatsTable = Table().pad(5f)
|
||||||
|
ministatsTable.defaults()
|
||||||
|
|
||||||
|
for(stat in cityInfo.cityStats.currentCityStats.toHashMap()) {
|
||||||
|
if(stat.key == Stat.Happiness) continue
|
||||||
|
ministatsTable.add(ImageGetter.getStatIcon(stat.key.name)).size(20f).padRight(3f)
|
||||||
|
ministatsTable.add(round(stat.value).toInt().toString().toLabel()).padRight(13f)
|
||||||
|
}
|
||||||
|
|
||||||
|
innerTable.add(unassignedPopString.toLabel()).row()
|
||||||
|
innerTable.add(turnsToExpansionString.toLabel()).row()
|
||||||
|
innerTable.add(turnsToPopString.toLabel()).row()
|
||||||
|
if (cityInfo.isInResistance())
|
||||||
|
innerTable.add("In resistance for another [${cityInfo.resistanceCounter}] turns".toLabel()).row()
|
||||||
|
innerTable.addSeparator()
|
||||||
|
innerTable.add(ministatsTable)
|
||||||
|
|
||||||
|
pack()
|
||||||
|
}
|
||||||
|
}
|
@ -2,17 +2,17 @@ package com.unciv.ui.cityscreen
|
|||||||
|
|
||||||
import com.badlogic.gdx.graphics.Color
|
import com.badlogic.gdx.graphics.Color
|
||||||
import com.badlogic.gdx.scenes.scene2d.Touchable
|
import com.badlogic.gdx.scenes.scene2d.Touchable
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.*
|
import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
|
||||||
import com.badlogic.gdx.utils.Align
|
import com.badlogic.gdx.utils.Align
|
||||||
import com.unciv.UncivGame
|
import com.unciv.UncivGame
|
||||||
import com.unciv.logic.city.CityInfo
|
import com.unciv.logic.city.CityInfo
|
||||||
import com.unciv.logic.city.IConstruction
|
import com.unciv.logic.city.IConstruction
|
||||||
import com.unciv.logic.city.SpecialConstruction
|
import com.unciv.logic.city.SpecialConstruction
|
||||||
import com.unciv.models.UncivSound
|
import com.unciv.models.UncivSound
|
||||||
import com.unciv.models.ruleset.Building
|
|
||||||
import com.unciv.models.ruleset.unit.BaseUnit
|
|
||||||
import com.unciv.models.translations.tr
|
|
||||||
import com.unciv.models.stats.Stat
|
import com.unciv.models.stats.Stat
|
||||||
|
import com.unciv.models.translations.tr
|
||||||
import com.unciv.ui.utils.*
|
import com.unciv.ui.utils.*
|
||||||
import com.unciv.ui.worldscreen.optionstable.YesNoPopupTable
|
import com.unciv.ui.worldscreen.optionstable.YesNoPopupTable
|
||||||
|
|
||||||
@ -20,6 +20,7 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre
|
|||||||
/* -2 = Nothing, -1 = current construction, >= 0 queue entry */
|
/* -2 = Nothing, -1 = current construction, >= 0 queue entry */
|
||||||
private var selectedQueueEntry = -2 // None
|
private var selectedQueueEntry = -2 // None
|
||||||
|
|
||||||
|
private val showCityInfoTableButton: TextButton
|
||||||
private val constructionsQueueScrollPane: ScrollPane
|
private val constructionsQueueScrollPane: ScrollPane
|
||||||
private val availableConstructionsScrollPane: ScrollPane
|
private val availableConstructionsScrollPane: ScrollPane
|
||||||
|
|
||||||
@ -30,12 +31,21 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre
|
|||||||
private val pad = 10f
|
private val pad = 10f
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
showCityInfoTableButton = TextButton("Show stats drilldown", skin)
|
||||||
|
showCityInfoTableButton.onClick {
|
||||||
|
cityScreen.showConstructionsTable = false
|
||||||
|
cityScreen.update()
|
||||||
|
}
|
||||||
|
|
||||||
constructionsQueueScrollPane = ScrollPane(constructionsQueueTable.addBorder(2f, Color.WHITE))
|
constructionsQueueScrollPane = ScrollPane(constructionsQueueTable.addBorder(2f, Color.WHITE))
|
||||||
|
constructionsQueueScrollPane.setOverscroll(false,false)
|
||||||
availableConstructionsScrollPane = ScrollPane(availableConstructionsTable.addBorder(2f, Color.WHITE))
|
availableConstructionsScrollPane = ScrollPane(availableConstructionsTable.addBorder(2f, Color.WHITE))
|
||||||
|
availableConstructionsScrollPane.setOverscroll(false,false)
|
||||||
|
|
||||||
constructionsQueueTable.background = ImageGetter.getBackground(Color.BLACK)
|
constructionsQueueTable.background = ImageGetter.getBackground(Color.BLACK)
|
||||||
availableConstructionsTable.background = ImageGetter.getBackground(Color.BLACK)
|
availableConstructionsTable.background = ImageGetter.getBackground(Color.BLACK)
|
||||||
|
|
||||||
|
add(showCityInfoTableButton).left().padLeft(pad).padBottom(pad).row()
|
||||||
add(constructionsQueueScrollPane).left().padBottom(pad).row()
|
add(constructionsQueueScrollPane).left().padBottom(pad).row()
|
||||||
add(buttons).center().bottom().padBottom(pad).row()
|
add(buttons).center().bottom().padBottom(pad).row()
|
||||||
add(availableConstructionsScrollPane).left().bottom().row()
|
add(availableConstructionsScrollPane).left().bottom().row()
|
||||||
@ -57,7 +67,7 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre
|
|||||||
|
|
||||||
// Need to pack before computing space left for bottom panel
|
// Need to pack before computing space left for bottom panel
|
||||||
pack()
|
pack()
|
||||||
val usedHeight = constructionsQueueScrollPane.height + buttons.height + 2f * pad + 10f
|
val usedHeight = showCityInfoTableButton.height + constructionsQueueScrollPane.height + buttons.height + 3f * pad + 10f
|
||||||
|
|
||||||
updateAvailableConstructions()
|
updateAvailableConstructions()
|
||||||
availableConstructionsScrollPane.layout()
|
availableConstructionsScrollPane.layout()
|
||||||
@ -103,7 +113,8 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre
|
|||||||
queue.forEachIndexed { i, constructionName ->
|
queue.forEachIndexed { i, constructionName ->
|
||||||
constructionsQueueTable.add(getQueueEntry(i, constructionName, i == queue.size - 1, i == selectedQueueEntry))
|
constructionsQueueTable.add(getQueueEntry(i, constructionName, i == queue.size - 1, i == selectedQueueEntry))
|
||||||
.expandX().fillX().row()
|
.expandX().fillX().row()
|
||||||
constructionsQueueTable.addSeparator()
|
if (i != queue.size - 1)
|
||||||
|
constructionsQueueTable.addSeparator()
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
constructionsQueueTable.add("Queue empty".toLabel()).pad(2f).row()
|
constructionsQueueTable.add("Queue empty".toLabel()).pad(2f).row()
|
||||||
@ -206,7 +217,8 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre
|
|||||||
} else {
|
} else {
|
||||||
pickProductionButton.color = Color.GRAY
|
pickProductionButton.color = Color.GRAY
|
||||||
pickProductionButton.row()
|
pickProductionButton.row()
|
||||||
pickProductionButton.add(rejectionReason.toLabel(Color.RED)).colspan(pickProductionButton.columns).fillX().left().padTop(2f)
|
pickProductionButton.add(rejectionReason.toLabel(Color.RED).apply{ setWrap(true)} )
|
||||||
|
.colspan(pickProductionButton.columns).fillX().left().padTop(2f)
|
||||||
}
|
}
|
||||||
|
|
||||||
return pickProductionButton
|
return pickProductionButton
|
||||||
@ -259,10 +271,14 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre
|
|||||||
if (construction != null
|
if (construction != null
|
||||||
&& construction.canBePurchased()
|
&& construction.canBePurchased()
|
||||||
&& UncivGame.Current.worldScreen.isPlayersTurn
|
&& UncivGame.Current.worldScreen.isPlayersTurn
|
||||||
&& !city.isPuppet) {
|
&& !city.isPuppet
|
||||||
|
&& !city.isInResistance()) {
|
||||||
|
|
||||||
val constructionGoldCost = construction.getGoldCost(city.civInfo)
|
val constructionGoldCost = construction.getGoldCost(city.civInfo)
|
||||||
purchaseConstructionButton = TextButton("Buy for [$constructionGoldCost] gold".tr(), CameraStageBaseScreen.skin)
|
button.setText("Buy".tr() + " " + constructionGoldCost)
|
||||||
purchaseConstructionButton.onClick(UncivSound.Coin) {
|
button.add(ImageGetter.getStatIcon(Stat.Gold.name)).size(20f).padBottom(2f)
|
||||||
|
|
||||||
|
button.onClick(UncivSound.Coin) {
|
||||||
YesNoPopupTable("Would you like to purchase [${construction.name}] for [$constructionGoldCost] gold?".tr(), {
|
YesNoPopupTable("Would you like to purchase [${construction.name}] for [$constructionGoldCost] gold?".tr(), {
|
||||||
cityConstructions.purchaseConstruction(construction.name)
|
cityConstructions.purchaseConstruction(construction.name)
|
||||||
if (isSelectedQueueEntry()) {
|
if (isSelectedQueueEntry()) {
|
||||||
|
@ -26,15 +26,7 @@ import com.unciv.ui.pickerscreens.PolicyPickerScreen
|
|||||||
import com.unciv.ui.pickerscreens.TechButton
|
import com.unciv.ui.pickerscreens.TechButton
|
||||||
import com.unciv.ui.pickerscreens.TechPickerScreen
|
import com.unciv.ui.pickerscreens.TechPickerScreen
|
||||||
import com.unciv.ui.trade.DiplomacyScreen
|
import com.unciv.ui.trade.DiplomacyScreen
|
||||||
import com.unciv.ui.utils.CameraStageBaseScreen
|
import com.unciv.ui.utils.*
|
||||||
import com.unciv.ui.utils.ImageGetter
|
|
||||||
import com.unciv.ui.utils.centerX
|
|
||||||
import com.unciv.ui.utils.colorFromRGB
|
|
||||||
import com.unciv.ui.utils.disable
|
|
||||||
import com.unciv.ui.utils.enable
|
|
||||||
import com.unciv.ui.utils.onClick
|
|
||||||
import com.unciv.ui.utils.setFontSize
|
|
||||||
import com.unciv.ui.utils.toLabel
|
|
||||||
import com.unciv.ui.worldscreen.bottombar.BattleTable
|
import com.unciv.ui.worldscreen.bottombar.BattleTable
|
||||||
import com.unciv.ui.worldscreen.bottombar.TileInfoTable
|
import com.unciv.ui.worldscreen.bottombar.TileInfoTable
|
||||||
import com.unciv.ui.worldscreen.optionstable.OnlineMultiplayer
|
import com.unciv.ui.worldscreen.optionstable.OnlineMultiplayer
|
||||||
@ -234,7 +226,8 @@ class WorldScreen(val viewingCiv:CivilizationInfo) : CameraStageBaseScreen() {
|
|||||||
return "Pick a technology to research!\nClick on the tech button (greenish, top left) > " +
|
return "Pick a technology to research!\nClick on the tech button (greenish, top left) > " +
|
||||||
"\n select technology > click 'Research' (bottom right)"
|
"\n select technology > click 'Research' (bottom right)"
|
||||||
if(!completedTasks.contains("Pick construction"))
|
if(!completedTasks.contains("Pick construction"))
|
||||||
return "Pick a construction!\nEnter city screen > Click on a unit or building (left side)"
|
return "Pick a construction!\nEnter city screen > Click on a unit or building (bottom left side) >" +
|
||||||
|
" \n click 'add to queue'"
|
||||||
if(!completedTasks.contains("Pass a turn"))
|
if(!completedTasks.contains("Pass a turn"))
|
||||||
return "Pass a turn!\nCycle through units with 'Next unit' > Click 'Next turn'"
|
return "Pass a turn!\nCycle through units with 'Next unit' > Click 'Next turn'"
|
||||||
if(!completedTasks.contains("Reassign worked tiles"))
|
if(!completedTasks.contains("Reassign worked tiles"))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user