City construction queue (#1479)

* 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

Rework

* Max queue size, cannot change queue in puppet city or in other player turn

* Queue and current construction reset on puppeting city

Co-authored-by: Yair Morgenstern <yairm210@hotmail.com>
This commit is contained in:
r3versi 2020-01-09 19:58:15 +01:00 committed by Yair Morgenstern
parent 977fcfb97e
commit 12a98aa4bb
13 changed files with 584 additions and 273 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 562 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 B

View file

@ -292,6 +292,13 @@ Requires a [buildingName] in this city =
Requires [resource] = Requires [resource] =
Required tech: [requiredTech] = Required tech: [requiredTech] =
Current construction =
Construction queue =
Pick a construction =
Queue empty =
Add to queue =
Remove from queue =
Diplomacy = Diplomacy =
War = War =
Peace = Peace =

View file

@ -11,17 +11,25 @@ import com.unciv.models.translations.tr
import com.unciv.ui.utils.withItem import com.unciv.ui.utils.withItem
import com.unciv.ui.utils.withoutItem import com.unciv.ui.utils.withoutItem
import java.util.* import java.util.*
import kotlin.collections.ArrayList
/**
* City constructions manager.
*
* @property cityInfo the city it refers to
* @property currentConstruction the name of the construction is currently worked, default = "Monument"
* @property currentConstructionIsUserSet a flag indicating if the [currentConstruction] has been set by the user or by the AI
* @property constructionQueue a list of constructions names enqueued
*/
class CityConstructions { class CityConstructions {
@Transient lateinit var cityInfo: CityInfo @Transient lateinit var cityInfo: CityInfo
@Transient private var builtBuildingObjects=ArrayList<Building>() @Transient private var builtBuildingObjects = ArrayList<Building>()
var builtBuildings = HashSet<String>() var builtBuildings = HashSet<String>()
val inProgressConstructions = HashMap<String, Int>() val inProgressConstructions = HashMap<String, Int>()
var currentConstruction: String = "Monument" // default starting building! var currentConstruction: String = "Monument"
var currentConstructionIsUserSet = false var currentConstructionIsUserSet = false
var constructionQueue = mutableListOf<String>()
val queueMaxSize = 10
//region pure functions //region pure functions
fun clone(): CityConstructions { fun clone(): CityConstructions {
@ -30,6 +38,7 @@ class CityConstructions {
toReturn.inProgressConstructions.putAll(inProgressConstructions) toReturn.inProgressConstructions.putAll(inProgressConstructions)
toReturn.currentConstruction=currentConstruction toReturn.currentConstruction=currentConstruction
toReturn.currentConstructionIsUserSet=currentConstructionIsUserSet toReturn.currentConstructionIsUserSet=currentConstructionIsUserSet
toReturn.constructionQueue.addAll(constructionQueue)
return toReturn return toReturn
} }
@ -39,6 +48,9 @@ class CityConstructions {
fun getConstructableUnits() = cityInfo.getRuleset().units.values fun getConstructableUnits() = cityInfo.getRuleset().units.values
.asSequence().filter { it.isBuildable(this) } .asSequence().filter { it.isBuildable(this) }
/**
* @return [Stats] provided by all built buildings in city plus the bonus from Library
*/
fun getStats(): Stats { fun getStats(): Stats {
val stats = Stats() val stats = Stats()
for (building in getBuiltBuildings()) for (building in getBuiltBuildings())
@ -47,8 +59,14 @@ class CityConstructions {
return stats return stats
} }
/**
* @return Maintenance cost of all built buildings
*/
fun getMaintenanceCosts(): Int = getBuiltBuildings().sumBy { it.maintenance } fun getMaintenanceCosts(): Int = getBuiltBuildings().sumBy { it.maintenance }
/**
* @return Bonus (%) [Stats] provided by all built buildings in city
*/
fun getStatPercentBonuses(): Stats { fun getStatPercentBonuses(): Stats {
val stats = Stats() val stats = Stats()
for (building in getBuiltBuildings()) for (building in getBuiltBuildings())
@ -69,7 +87,9 @@ class CityConstructions {
} }
fun getProductionForTileInfo(): String { fun getProductionForTileInfo(): String {
val currentConstructionSnapshot = currentConstruction // this is because there were rare errors tht I assume were caused because currentContruction changed on another thread /* this is because there were rare errors tht I assume were caused because
currentContruction changed on another thread */
val currentConstructionSnapshot = currentConstruction
var result = currentConstructionSnapshot.tr() var result = currentConstructionSnapshot.tr()
if (currentConstructionSnapshot!="" if (currentConstructionSnapshot!=""
&& SpecialConstruction.getSpecialConstructions().none { it.name==currentConstructionSnapshot }) { && SpecialConstruction.getSpecialConstructions().none { it.name==currentConstructionSnapshot }) {
@ -80,17 +100,17 @@ class CityConstructions {
} }
fun getCurrentConstruction(): IConstruction = getConstruction(currentConstruction) fun getCurrentConstruction(): IConstruction = getConstruction(currentConstruction)
fun getIConstructionQueue(): List<IConstruction> = constructionQueue.map{ getConstruction(it) }
fun isBuilt(buildingName: String): Boolean = builtBuildings.contains(buildingName) fun isBuilt(buildingName: String): Boolean = builtBuildings.contains(buildingName)
fun isBeingConstructed(constructionName: String): Boolean = currentConstruction == constructionName fun isBeingConstructed(constructionName: String): Boolean = currentConstruction == constructionName
fun isEnqueued(constructionName: String): Boolean = constructionQueue.contains(constructionName)
fun isQueueFull(): Boolean = constructionQueue.size == queueMaxSize
fun isBuildingWonder(): Boolean { fun isBuildingWonder(): Boolean {
val currentConstruction = getCurrentConstruction() val currentConstruction = getCurrentConstruction()
if (currentConstruction is Building) { return currentConstruction is Building && currentConstruction.isWonder
return currentConstruction.isWonder
}
return false
} }
internal fun getConstruction(constructionName: String): IConstruction { internal fun getConstruction(constructionName: String): IConstruction {
@ -179,6 +199,7 @@ class CityConstructions {
fun endTurn(cityStats: Stats) { fun endTurn(cityStats: Stats) {
stopUnbuildableConstruction() stopUnbuildableConstruction()
validateConstructionQueue()
if(getConstruction(currentConstruction) !is SpecialConstruction) if(getConstruction(currentConstruction) !is SpecialConstruction)
addProductionPoints(Math.round(cityStats.production)) addProductionPoints(Math.round(cityStats.production))
@ -198,7 +219,17 @@ class CityConstructions {
currentConstruction = saveCurrentConstruction currentConstruction = saveCurrentConstruction
} }
fun constructionComplete(construction: IConstruction) { private fun validateConstructionQueue() {
val queueSnapshot = mutableListOf<String>().apply { addAll(constructionQueue) }
constructionQueue.clear()
for (construction in queueSnapshot) {
if (getConstruction(construction).isBuildable(this))
constructionQueue.add(construction)
}
}
private fun constructionComplete(construction: IConstruction) {
construction.postBuildEvent(this) construction.postBuildEvent(this)
inProgressConstructions.remove(currentConstruction) inProgressConstructions.remove(currentConstruction)
@ -252,16 +283,66 @@ class CityConstructions {
cancelCurrentConstruction() cancelCurrentConstruction()
} }
fun cancelCurrentConstruction(){ private fun cancelCurrentConstruction() {
currentConstructionIsUserSet=false currentConstructionIsUserSet = false
currentConstruction="" currentConstruction = ""
chooseNextConstruction() chooseNextConstruction()
} }
fun chooseNextConstruction() { fun chooseNextConstruction() {
if(currentConstructionIsUserSet) return if(currentConstructionIsUserSet) return
if (constructionQueue.isNotEmpty()) {
currentConstructionIsUserSet = true
currentConstruction = constructionQueue.removeAt(0)
stopUnbuildableConstruction()
if (currentConstruction != "") return
}
ConstructionAutomation(this).chooseNextConstruction() ConstructionAutomation(this).chooseNextConstruction()
} }
//endregion
fun isEnqueuable(constructionName: String): Boolean {
return true
}
fun addToQueue(constructionName: String) {
if (!isQueueFull())
constructionQueue.add(constructionName)
}
fun removeFromQueue(idx: Int) {
// idx -1 is the current construction
if (idx < 0) {
// To prevent Construction Automation
if (constructionQueue.isEmpty()) constructionQueue.add("Nothing")
cancelCurrentConstruction()
} else
constructionQueue.removeAt(idx)
}
fun higherPrio(idx: Int) {
// change current construction
if(idx == 0) {
// Add current construction to queue after the first element
constructionQueue.add(1, currentConstruction)
cancelCurrentConstruction()
}
else
constructionQueue.swap(idx-1, idx)
}
// Lowering == Highering next element in queue
fun lowerPrio(idx: Int) {
higherPrio(idx+1)
}
//endregion
private fun MutableList<String>.swap(idx1: Int, idx2: Int) {
val tmp = this[idx1]
this[idx1] = this[idx2]
this[idx2] = tmp
}
} // for json parsing, we need to have a default constructor } // for json parsing, we need to have a default constructor

View file

@ -392,7 +392,10 @@ class CityInfo {
isPuppet = true isPuppet = true
health = getMaxHealth() / 2 // I think that cities recover to half health when conquered? health = getMaxHealth() / 2 // I think that cities recover to half health when conquered?
cityStats.update() cityStats.update()
cityConstructions.chooseNextConstruction() // The city could be producing something that puppets shouldn't, like units // The city could be producing something that puppets shouldn't, like units
cityConstructions.currentConstructionIsUserSet = false
cityConstructions.constructionQueue.clear()
cityConstructions.chooseNextConstruction()
} }
private fun diplomaticRepercussionsForConqueringCity(oldCiv: CivilizationInfo, conqueringCiv: CivilizationInfo) { private fun diplomaticRepercussionsForConqueringCity(oldCiv: CivilizationInfo, conqueringCiv: CivilizationInfo) {

View file

@ -223,6 +223,8 @@ class Building : NamedStats(), IConstruction{
fun getRejectionReason(construction: CityConstructions):String{ fun getRejectionReason(construction: CityConstructions):String{
if (construction.isBuilt(name)) return "Already built" if (construction.isBuilt(name)) return "Already built"
if (construction.isBeingConstructed(name)) return "Is being built"
if (construction.isEnqueued(name)) return "Already enqueued"
if ("Must be next to desert" in uniques if ("Must be next to desert" in uniques
&& !construction.cityInfo.getCenterTile().getTilesInDistance(1).any { it.baseTerrain == Constants.desert }) && !construction.cityInfo.getCenterTile().getTilesInDistance(1).any { it.baseTerrain == Constants.desert })

View file

@ -6,17 +6,22 @@ import com.badlogic.gdx.scenes.scene2d.ui.Image
import com.badlogic.gdx.scenes.scene2d.ui.Skin import com.badlogic.gdx.scenes.scene2d.ui.Skin
import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.scenes.scene2d.ui.TextButton 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.translations.tr
import com.unciv.models.stats.Stat import com.unciv.models.stats.Stat
import com.unciv.models.stats.Stats
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 val pad = 5f
@ -29,10 +34,9 @@ class CityInfoTable(private val cityScreen: CityScreen) : Table(CameraStageBaseS
clear() clear()
val cityInfo = cityScreen.city val cityInfo = cityScreen.city
addCityStats(cityInfo)
addBuildingsInfo(cityInfo) addBuildingsInfo(cityInfo)
addStatInfo() addStatInfo()
addGreatPersonPointInfo(cityInfo) addGreatPersonPointInfo(cityInfo)
pack() pack()
@ -92,6 +96,65 @@ class CityInfoTable(private val cityScreen: CityScreen) : Table(CameraStageBaseS
} }
} }
private fun addCityStats(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) { private fun addBuildingsInfo(cityInfo: CityInfo) {
val wonders = mutableListOf<Building>() val wonders = mutableListOf<Building>()
val specialistBuildings = mutableListOf<Building>() val specialistBuildings = mutableListOf<Building>()

View file

@ -5,14 +5,12 @@ import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane
import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.scenes.scene2d.ui.TextButton import com.badlogic.gdx.scenes.scene2d.ui.TextButton
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.HexMath import com.unciv.logic.HexMath
import com.unciv.logic.city.CityInfo import com.unciv.logic.city.CityInfo
import com.unciv.logic.city.IConstruction
import com.unciv.logic.map.TileInfo import com.unciv.logic.map.TileInfo
import com.unciv.models.Tutorial import com.unciv.models.Tutorial
import com.unciv.models.stats.Stat
import com.unciv.models.stats.Stats
import com.unciv.models.translations.tr import com.unciv.models.translations.tr
import com.unciv.ui.map.TileGroupMap import com.unciv.ui.map.TileGroupMap
import com.unciv.ui.tilegroups.TileSetStrings import com.unciv.ui.tilegroups.TileSetStrings
@ -21,51 +19,52 @@ import java.util.*
import kotlin.math.ceil import kotlin.math.ceil
import kotlin.math.round import kotlin.math.round
class CityScreen(internal val city: CityInfo) : CameraStageBaseScreen() { class CityScreen(internal val city: CityInfo): CameraStageBaseScreen() {
private var selectedTile: TileInfo? = null var selectedTile: TileInfo? = null
var selectedConstruction: IConstruction? = null
// Clockwise from the top-left // Clockwise from the top-left
/** Displays city stats - sits on the top left side */
var topCityStatsTable=Table()
private var razeCityButtonHolder = Table() // sits on the top /** Displays current production, production queue and available productions list - sits on LEFT */
/** Displays buildings, specialists and stats drilldown - sits on the top right of the city screen */
private var cityInfoTable = CityInfoTable(this)
/** Displays tile info, sits on the bottom right */
private var tileTable = CityScreenTileTable(city)
/** Displays city name, allows switching between cities - sits on the bottom */
private var cityPickerTable = CityScreenCityPickerTable(this)
/** Holds production list and current production - sits on the bottom left */
private var constructionsTable = ConstructionsTable(this) private var constructionsTable = ConstructionsTable(this)
/** Displays raze city button - sits on TOP CENTER */
private var razeCityButtonHolder = Table()
/** Displays stats, buildings, specialists and stats drilldown - sits on TOP RIGHT */
private var cityInfoTable = CityInfoTable(this)
/** Displays tile info, alternate with selectedConstructionTable - sits on BOTTOM RIGHT */
private var tileTable = CityScreenTileTable(city)
/** Displays selected construction info, alternate with tileTable - sits on BOTTOM RIGHT */
private var selectedConstructionTable = ConstructionInfoTable(this.city)
/** Displays city name, allows switching between cities - sits on BOTTOM CENTER */
private var cityPickerTable = CityScreenCityPickerTable(this)
/** Holds City tiles group*/
private var tileGroups = ArrayList<CityTileGroup>() private var tileGroups = ArrayList<CityTileGroup>()
init { init {
onBackButtonClicked { game.setWorldScreen() } onBackButtonClicked { game.setWorldScreen() }
addTiles()
UncivGame.Current.settings.addCompletedTutorialTask("Enter city screen") UncivGame.Current.settings.addCompletedTutorialTask("Enter city screen")
addTiles()
val tableBackgroundColor = ImageGetter.getBlue().lerp(Color.BLACK,0.5f)
var buildingsTableContainer = Table() var buildingsTableContainer = Table()
buildingsTableContainer.pad(3f) buildingsTableContainer.pad(3f)
buildingsTableContainer.background = ImageGetter.getBackground(tableBackgroundColor) buildingsTableContainer.background = ImageGetter.getBackground(ImageGetter.getBlue().lerp(Color.BLACK,0.5f))
cityInfoTable.update() cityInfoTable.update()
val buildingsScroll = ScrollPane(cityInfoTable) val buildingsScroll = ScrollPane(cityInfoTable)
buildingsTableContainer.add(buildingsScroll) buildingsTableContainer.add(buildingsScroll).size(stage.width/4,stage.height / 2)
.size(stage.width/4,stage.height / 2)
buildingsTableContainer = buildingsTableContainer.addBorder(2f, Color.WHITE) buildingsTableContainer = buildingsTableContainer.addBorder(2f, Color.WHITE)
buildingsTableContainer.setPosition(stage.width - buildingsTableContainer.width-5, buildingsTableContainer.setPosition( stage.width - 5f, stage.height - 5f, Align.topRight)
stage.height - buildingsTableContainer.height-5)
//stage.setDebugTableUnderMouse(true)
stage.addActor(constructionsTable) stage.addActor(constructionsTable)
stage.addActor(tileTable) stage.addActor(tileTable)
stage.addActor(selectedConstructionTable)
stage.addActor(cityPickerTable) stage.addActor(cityPickerTable)
stage.addActor(buildingsTableContainer) stage.addActor(buildingsTableContainer)
@ -73,87 +72,38 @@ class CityScreen(internal val city: CityInfo) : CameraStageBaseScreen() {
} }
internal fun update() { internal fun update() {
cityInfoTable.update() city.cityStats.update()
constructionsTable.update(selectedConstruction)
constructionsTable.setPosition(5f, stage.height - 5f, Align.topLeft)
cityPickerTable.update() cityPickerTable.update()
cityPickerTable.centerX(stage) cityPickerTable.centerX(stage)
constructionsTable.update()
updateAnnexAndRazeCityButton()
tileTable.update(selectedTile) tileTable.update(selectedTile)
tileTable.setPosition(stage.width-5, 5f,Align.bottomRight) tileTable.setPosition(stage.width - 5f, 5f, Align.bottomRight)
selectedConstructionTable.update(selectedConstruction)
selectedConstructionTable.setPosition(stage.width - 5f, 5f, Align.bottomRight)
cityInfoTable.update()
updateAnnexAndRazeCityButton()
updateTileGroups() updateTileGroups()
topCityStatsTable.remove() if (city.getCenterTile().getTilesAtDistance(4).isNotEmpty())
topCityStatsTable = getCityStatsTable()
topCityStatsTable.setPosition(5f, stage.height-5, Align.topLeft)
stage.addActor(topCityStatsTable)
constructionsTable.height=stage.height-topCityStatsTable.height
constructionsTable.setPosition(5f, stage.height-5-topCityStatsTable.height, Align.topLeft)
if (city.getCenterTile().getTilesAtDistance(4).isNotEmpty()){
displayTutorial(Tutorial.CityRange) displayTutorial(Tutorial.CityRange)
}
} }
private fun updateTileGroups() { private fun updateTileGroups() {
val nextTile = city.expansion.chooseNewTileToOwn() val nextTile = city.expansion.chooseNewTileToOwn()
for (tileGroup in tileGroups) { for (tileGroup in tileGroups) {
tileGroup.update() tileGroup.update()
if(tileGroup.tileInfo == nextTile){ if(tileGroup.tileInfo == nextTile){
tileGroup.showCircle(Color.PURPLE) tileGroup.showCircle(Color.PURPLE)
tileGroup.setColor(0f,0f,0f,0.7f) tileGroup.setColor(0f,0f,0f,0.7f)
} }
} }
}
fun getCityStatsTable(): Table {
val table=Table().pad(10f)
table.defaults().pad(5f)
table.background=ImageGetter.getBackground(Color.BLACK.cpy().apply { a=0.8f })
val columns = Stats().toHashMap().size
val unassignedPopText = "{Unassigned population}:".tr()+
city.population.getFreePopulation().toString() + "/" + city.population.population
table.add(unassignedPopText.toLabel()).colspan(columns).row()
var turnsToExpansionString = when {
city.cityStats.currentCityStats.culture > 0 -> {
var turnsToExpansion = ceil((city.expansion.getCultureToNextTile() - city.expansion.cultureStored)
/ city.cityStats.currentCityStats.culture).toInt()
if (turnsToExpansion < 1) turnsToExpansion = 1
"[$turnsToExpansion] turns to expansion".tr()
}
else -> "Stopped expansion".tr()
}
turnsToExpansionString += " (" + city.expansion.cultureStored + "/" + city.expansion.getCultureToNextTile() + ")"
table.add(turnsToExpansionString.toLabel()).colspan(columns).row()
var turnsToPopString = when {
city.isGrowing() -> "[${city.getNumTurnsToNewPopulation()}] turns to new population"
city.isStarving() -> "[${city.getNumTurnsToStarvation()}] turns to lose population"
city.cityConstructions.currentConstruction == Constants.settler -> "Food converts to production"
else -> "Stopped population growth"
}.tr()
turnsToPopString += " (" + city.population.foodStored + "/" + city.population.getFoodToNextPopulation() + ")"
table.add(turnsToPopString.toLabel()).colspan(columns).row()
if (city.isInResistance()) {
table.add("In resistance for another [${city.resistanceCounter}] turns".toLabel()).colspan(columns).row()
}
table.addSeparator()
val beige = colorFromRGB(194,180,131)
for(stat in city.cityStats.currentCityStats.toHashMap()) {
if(stat.key==Stat.Happiness) continue
val minitable=Table().padRight(5f).padLeft(5f)
minitable.add(ImageGetter.getStatIcon(stat.key.name)).size(20f).padRight(3f)
minitable.add(round(stat.value).toInt().toString().toLabel())
table.add(minitable)
}
return table.addBorder(2f, beige)
} }
private fun updateAnnexAndRazeCityButton() { private fun updateAnnexAndRazeCityButton() {
@ -167,15 +117,13 @@ class CityScreen(internal val city: CityInfo) : CameraStageBaseScreen() {
update() update()
} }
razeCityButtonHolder.add(annexCityButton).colspan(cityPickerTable.columns) razeCityButtonHolder.add(annexCityButton).colspan(cityPickerTable.columns)
} } else if(!city.isBeingRazed) {
else if(!city.isBeingRazed) {
val razeCityButton = TextButton("Raze city".tr(), skin) val razeCityButton = TextButton("Raze city".tr(), skin)
razeCityButton.labelCell.pad(10f) razeCityButton.labelCell.pad(10f)
razeCityButton.onClick { city.isBeingRazed=true; update() } razeCityButton.onClick { city.isBeingRazed=true; update() }
if(!UncivGame.Current.worldScreen.isPlayersTurn) razeCityButton.disable() if(!UncivGame.Current.worldScreen.isPlayersTurn) razeCityButton.disable()
razeCityButtonHolder.add(razeCityButton).colspan(cityPickerTable.columns) razeCityButtonHolder.add(razeCityButton).colspan(cityPickerTable.columns)
} } else {
else {
val stopRazingCityButton = TextButton("Stop razing city".tr(), skin) val stopRazingCityButton = TextButton("Stop razing city".tr(), skin)
stopRazingCityButton.labelCell.pad(10f) stopRazingCityButton.labelCell.pad(10f)
stopRazingCityButton.onClick { city.isBeingRazed=false; update() } stopRazingCityButton.onClick { city.isBeingRazed=false; update() }
@ -203,6 +151,7 @@ class CityScreen(internal val city: CityInfo) : CameraStageBaseScreen() {
tileGroup.onClick { tileGroup.onClick {
if (!city.isPuppet) { if (!city.isPuppet) {
selectedTile = tileInfo selectedTile = tileInfo
selectedConstruction = null
if (tileGroup.isWorkable && UncivGame.Current.worldScreen.isPlayersTurn) { if (tileGroup.isWorkable && UncivGame.Current.worldScreen.isPlayersTurn) {
if (!tileInfo.isWorked() && city.population.getFreePopulation() > 0) { if (!tileInfo.isWorked() && city.population.getFreePopulation() > 0) {
city.workedTiles.add(tileInfo.position) city.workedTiles.add(tileInfo.position)
@ -235,5 +184,4 @@ class CityScreen(internal val city: CityInfo) : CameraStageBaseScreen() {
scrollPane.scrollPercentY=0.5f scrollPane.scrollPercentY=0.5f
scrollPane.updateVisualScroll() scrollPane.updateVisualScroll()
} }
} }

View file

@ -0,0 +1,78 @@
package com.unciv.ui.cityscreen
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane
import com.unciv.logic.city.CityInfo
import com.unciv.logic.city.IConstruction
import com.unciv.logic.city.SpecialConstruction
import com.unciv.ui.utils.ImageGetter
import com.unciv.models.ruleset.Building
import com.unciv.models.ruleset.unit.BaseUnit
import com.unciv.models.translations.tr
import com.unciv.ui.utils.*
class ConstructionInfoTable(val city: CityInfo): Table() {
val selectedConstructionTable = Table()
init{
selectedConstructionTable.background = ImageGetter.getBackground(ImageGetter.getBlue().lerp(Color.BLACK, 0.5f))
add(selectedConstructionTable).pad(2f).fill()
background = ImageGetter.getBackground(Color.WHITE)
}
fun update(selectedConstruction: IConstruction?) {
selectedConstructionTable.clear()
selectedConstructionTable.pad(20f)
if (selectedConstruction == null) {
isVisible = false
return
}
isVisible = true
addSelectedConstructionTable(selectedConstruction)
pack()
}
private fun addSelectedConstructionTable(construction: IConstruction) {
val cityConstructions = city.cityConstructions
//val selectedConstructionTable = Table()
selectedConstructionTable.background = ImageGetter.getBackground(ImageGetter.getBlue().lerp(Color.BLACK,0.5f))
selectedConstructionTable.pad(10f)
selectedConstructionTable.add(
ImageGetter.getConstructionImage(construction.name).surroundWithCircle(50f))
.pad(5f)
var buildingText = construction.name.tr()
if (SpecialConstruction.getSpecialConstructions().none { it.name == construction.name }) {
val turnsToComplete = cityConstructions.turnsToConstruction(construction.name)
buildingText += ("\r\n" + "Cost".tr() + " " + construction.getProductionCost(city.civInfo).toString()).tr()
buildingText += "\r\n" + turnsToComplete + turnOrTurns(turnsToComplete)
}
selectedConstructionTable.add(buildingText.toLabel()).row()
val description: String
if (construction is BaseUnit)
description = construction.getDescription(true)
else if (construction is Building)
description = construction.getDescription(true, city.civInfo, city.civInfo.gameInfo.ruleSet)
else if(construction is SpecialConstruction)
description = construction.description.tr()
else description="" // Should never happen
val descriptionLabel = description.toLabel()
descriptionLabel.setWrap(true)
descriptionLabel.width = stage.width / 4
val descriptionScroll = ScrollPane(descriptionLabel)
selectedConstructionTable.add(descriptionScroll).colspan(2).width(stage.width / 4).height(stage.height / 8)
}
private fun turnOrTurns(number: Int): String = if(number > 1) " {turns}".tr() else " {turn}".tr()
}

View file

@ -2,217 +2,344 @@ 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.ScrollPane import com.badlogic.gdx.scenes.scene2d.ui.*
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.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.Building
import com.unciv.models.ruleset.unit.BaseUnit import com.unciv.models.ruleset.unit.BaseUnit
import com.unciv.models.translations.tr import com.unciv.models.translations.tr
import com.unciv.models.stats.Stat
import com.unciv.ui.utils.* import com.unciv.ui.utils.*
import com.unciv.ui.worldscreen.optionstable.YesNoPopupTable import com.unciv.ui.worldscreen.optionstable.YesNoPopupTable
class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScreen.skin){ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScreen.skin) {
/* -2 = Nothing, -1 = current construction, >= 0 queue entry */
private var selectedQueueEntry = -2 // None
var constructionScrollPane:ScrollPane?=null private val constructionsQueueScrollPane: ScrollPane
var lastConstruction = "" private val availableConstructionsScrollPane: ScrollPane
private val constructionsQueueTable = Table()
private val availableConstructionsTable = Table()
private val buttons = Table()
fun update() { private val pad = 10f
val city = cityScreen.city
pad(10f)
columnDefaults(0).padRight(10f)
clear()
addConstructionPickerScrollpane(city) init {
addCurrentConstructionTable(city) constructionsQueueScrollPane = ScrollPane(constructionsQueueTable.addBorder(2f, Color.WHITE))
availableConstructionsScrollPane = ScrollPane(availableConstructionsTable.addBorder(2f, Color.WHITE))
constructionsQueueTable.background = ImageGetter.getBackground(Color.BLACK)
availableConstructionsTable.background = ImageGetter.getBackground(Color.BLACK)
add(constructionsQueueScrollPane).left().padBottom(pad).row()
add(buttons).center().bottom().padBottom(pad).row()
add(availableConstructionsScrollPane).left().bottom().row()
}
fun update(selectedConstruction: IConstruction?) {
val queueScrollY = constructionsQueueScrollPane.scrollY
val constrScrollY = availableConstructionsScrollPane.scrollY
clearContent()
updateButtons(selectedConstruction)
updateConstructionQueue()
constructionsQueueScrollPane.layout()
constructionsQueueScrollPane.scrollY = queueScrollY
constructionsQueueScrollPane.updateVisualScroll()
getCell(constructionsQueueScrollPane).maxHeight(stage.height / 3 - 10f)
// Need to pack before computing space left for bottom panel
pack()
val usedHeight = constructionsQueueScrollPane.height + buttons.height + 2f * pad + 10f
updateAvailableConstructions()
availableConstructionsScrollPane.layout()
availableConstructionsScrollPane.scrollY = constrScrollY
availableConstructionsScrollPane.updateVisualScroll()
getCell(availableConstructionsScrollPane).maxHeight(stage.height - usedHeight)
pack() pack()
} }
private fun getProductionButton(construction: String, buttonText: String, rejectionReason: String=""): Table { private fun clearContent() {
val pickProductionButton = Table() constructionsQueueTable.clear()
pickProductionButton.touchable = Touchable.enabled buttons.clear()
pickProductionButton.align(Align.left) availableConstructionsTable.clear()
pickProductionButton.pad(5f) }
if(cityScreen.city.cityConstructions.currentConstruction==construction) private fun updateButtons(construction: IConstruction?) {
pickProductionButton.background = ImageGetter.getBackground(Color.GREEN.cpy().lerp(Color.BLACK,0.5f)) buttons.add(getQueueButton(construction)).padRight(5f)
else buttons.add(getBuyButton(construction))
pickProductionButton.background = ImageGetter.getBackground(Color.BLACK) }
pickProductionButton.add(ImageGetter.getConstructionImage(construction).surroundWithCircle(40f)).padRight(10f) private fun updateConstructionQueue() {
pickProductionButton.add(buttonText.toLabel()) val city = cityScreen.city
val cityConstructions = city.cityConstructions
val currentConstruction = cityConstructions.currentConstruction
val queue = cityConstructions.constructionQueue
if(rejectionReason=="" && UncivGame.Current.worldScreen.isPlayersTurn) { // no rejection reason means we can build it! constructionsQueueTable.defaults().pad(0f)
pickProductionButton.onClick { constructionsQueueTable.add(getHeader("Current construction".tr())).fillX()
if (!cityScreen.city.isPuppet) { constructionsQueueTable.addSeparator()
lastConstruction = cityScreen.city.cityConstructions.currentConstruction
cityScreen.city.cityConstructions.currentConstruction = construction if (currentConstruction != "")
cityScreen.city.cityConstructions.currentConstructionIsUserSet = true constructionsQueueTable.add(getQueueEntry(-1, currentConstruction, queue.isEmpty(), selectedQueueEntry == -1))
cityScreen.city.cityStats.update() .expandX().fillX().row()
cityScreen.update() else
cityScreen.game.settings.addCompletedTutorialTask("Pick construction") constructionsQueueTable.add("Pick a construction".toLabel()).pad(2f).row()
}
constructionsQueueTable.addSeparator()
constructionsQueueTable.add(getHeader("Construction queue".tr())).fillX()
constructionsQueueTable.addSeparator()
if (queue.isNotEmpty()) {
queue.forEachIndexed { i, constructionName ->
constructionsQueueTable.add(getQueueEntry(i, constructionName, i == queue.size - 1, i == selectedQueueEntry))
.expandX().fillX().row()
constructionsQueueTable.addSeparator()
} }
} else
} constructionsQueueTable.add("Queue empty".toLabel()).pad(2f).row()
else {
pickProductionButton.color = Color.GRAY
pickProductionButton.row()
pickProductionButton.add(rejectionReason.toLabel(Color.RED)).colspan(pickProductionButton.columns)
}
if(construction==cityScreen.city.cityConstructions.currentConstruction)
pickProductionButton.color= Color.GREEN
return pickProductionButton
} }
private fun Table.addCategory(title:String,list:ArrayList<Table>){ private fun updateAvailableConstructions() {
if(list.isEmpty()) return val city = cityScreen.city
val titleTable = Table()
titleTable.background = ImageGetter.getBackground(ImageGetter.getBlue())
titleTable.add(title.toLabel(fontSize = 24))
addSeparator()
add(titleTable).fill().row()
addSeparator()
for(table in list) {
add(table).fill().row()
if(table != list.last()) addSeparator()
}
}
private fun addConstructionPickerScrollpane(city: CityInfo) {
val cityConstructions = city.cityConstructions val cityConstructions = city.cityConstructions
val constructionPickerTable = Table()
constructionPickerTable.background = ImageGetter.getBackground(Color.BLACK)
val units = ArrayList<Table>() val units = ArrayList<Table>()
for (unit in city.getRuleset().units.values.filter { it.shouldBeDisplayed(cityConstructions) }) {
val turnsToUnit = cityConstructions.turnsToConstruction(unit.name)
units += getProductionButton(unit.name,
unit.name.tr() + "\r\n" + turnsToUnit + (if(turnsToUnit>1) " {turns}".tr() else " {turn}".tr()),
unit.getRejectionReason(cityConstructions))
}
constructionPickerTable.addCategory("Units",units)
val buildableWonders = ArrayList<Table>() val buildableWonders = ArrayList<Table>()
val buildableNationalWonders = ArrayList<Table>() val buildableNationalWonders = ArrayList<Table>()
val buildableBuildings = ArrayList<Table>() val buildableBuildings = ArrayList<Table>()
val specialConstructions = ArrayList<Table>()
for (building in city.getRuleset().buildings.values) { for (unit in city.getRuleset().units.values.filter { it.shouldBeDisplayed(cityConstructions) }) {
if (!building.shouldBeDisplayed(cityConstructions) && building.name != cityConstructions.currentConstruction) continue val turnsToUnit = cityConstructions.turnsToConstruction(unit.name)
val turnsToBuilding = cityConstructions.turnsToConstruction(building.name) val productionButton = getProductionButton(unit.name,
val productionTextButton = getProductionButton(building.name, unit.name.tr() + "\r\n" + turnsToUnit + turnOrTurns(turnsToUnit),
building.name.tr() + "\r\n" + turnsToBuilding + (if(turnsToBuilding>1) " {turns}".tr() else " {turn}".tr()), unit.getRejectionReason(cityConstructions))
building.getRejectionReason(cityConstructions) units.add(productionButton)
)
if (building.isWonder)
buildableWonders += productionTextButton
else if(building.isNationalWonder)
buildableNationalWonders += productionTextButton
else
buildableBuildings += productionTextButton
} }
constructionPickerTable.addCategory("Wonders",buildableWonders) for (building in city.getRuleset().buildings.values.filter { it.shouldBeDisplayed(cityConstructions)}) {
constructionPickerTable.addCategory("National Wonders",buildableNationalWonders) val turnsToBuilding = cityConstructions.turnsToConstruction(building.name)
constructionPickerTable.addCategory("Buildings",buildableBuildings) val productionTextButton = getProductionButton(building.name,
building.name.tr() + "\r\n" + turnsToBuilding + turnOrTurns(turnsToBuilding),
building.getRejectionReason(cityConstructions)
)
if (building.isWonder) buildableWonders += productionTextButton
else if (building.isNationalWonder) buildableNationalWonders += productionTextButton
else buildableBuildings += productionTextButton
}
val specialConstructions = ArrayList<Table>()
for (specialConstruction in SpecialConstruction.getSpecialConstructions().filter { it.shouldBeDisplayed(cityConstructions) }) { for (specialConstruction in SpecialConstruction.getSpecialConstructions().filter { it.shouldBeDisplayed(cityConstructions) }) {
specialConstructions += getProductionButton(specialConstruction.name, specialConstructions += getProductionButton(specialConstruction.name,
"Produce [${specialConstruction.name}]".tr()) "Produce [${specialConstruction.name}]".tr())
} }
constructionPickerTable.addCategory("Other",specialConstructions)
val scrollPane = ScrollPane(constructionPickerTable.addBorder(2f, Color.WHITE)) availableConstructionsTable.addCategory("Units", units)
availableConstructionsTable.addCategory("Wonders", buildableWonders)
// This is to keep the same amount of scrolling on the construction picker scroll between refresh()es availableConstructionsTable.addCategory("National Wonders", buildableNationalWonders)
if(constructionScrollPane!=null){ availableConstructionsTable.addCategory("Buildings", buildableBuildings)
scrollPane.layout() availableConstructionsTable.addCategory("Other", specialConstructions)
scrollPane.scrollY = constructionScrollPane!!.scrollY
scrollPane.updateVisualScroll()
}
constructionScrollPane = scrollPane
add(scrollPane).maxHeight(stage.height / 3 * (stage.height/600)).row()
} }
private fun addCurrentConstructionTable(city: CityInfo) { private fun getQueueEntry(idx: Int, name: String, isLast: Boolean, isSelected: Boolean): Table {
val cityConstructions = city.cityConstructions val city = cityScreen.city
val construction = cityConstructions.getCurrentConstruction() val table = Table()
table.align(Align.left).pad(5f)
table.background = ImageGetter.getBackground(Color.BLACK)
row() if (isSelected)
val purchaseConstructionButton: TextButton table.background = ImageGetter.getBackground(Color.GREEN.cpy().lerp(Color.BLACK, 0.5f))
if (!city.isPuppet && !city.isInResistance() && construction.canBePurchased()) {
val turnsToComplete = cityScreen.city.cityConstructions.turnsToConstruction(name)
val text = name.tr() + "\r\n" + turnsToComplete + turnOrTurns(turnsToComplete)
table.defaults().pad(2f).minWidth(40f)
table.add(ImageGetter.getConstructionImage(name).surroundWithCircle(40f)).padRight(10f)
table.add(text.toLabel()).expandX().fillX().left()
if (idx >= 0) table.add(getHigherPrioButton(idx, name, city)).right()
else table.add().right()
if (!isLast) table.add(getLowerPrioButton(idx, name, city)).right()
else table.add().right()
table.touchable = Touchable.enabled
table.onClick {
cityScreen.selectedConstruction = cityScreen.city.cityConstructions.getConstruction(name)
cityScreen.selectedTile = null
selectedQueueEntry = idx
cityScreen.update()
}
return table
}
private fun getProductionButton(construction: String, buttonText: String, rejectionReason: String = "", isSelectable: Boolean = true): Table {
val pickProductionButton = Table()
pickProductionButton.align(Align.left).pad(5f)
pickProductionButton.background = ImageGetter.getBackground(Color.BLACK)
pickProductionButton.touchable = Touchable.enabled
if (!isSelectedQueueEntry() && cityScreen.selectedConstruction != null && cityScreen.selectedConstruction!!.name == construction) {
pickProductionButton.background = ImageGetter.getBackground(Color.GREEN.cpy().lerp(Color.BLACK, 0.5f))
}
pickProductionButton.add(ImageGetter.getConstructionImage(construction).surroundWithCircle(40f)).padRight(10f)
pickProductionButton.add(buttonText.toLabel()).expandX().fillX().left()
// no rejection reason means we can build it!
if(rejectionReason == "") {
pickProductionButton.onClick {
cityScreen.selectedConstruction = cityScreen.city.cityConstructions.getConstruction(construction)
cityScreen.selectedTile = null
selectedQueueEntry = -2
cityScreen.update()
}
} else {
pickProductionButton.color = Color.GRAY
pickProductionButton.row()
pickProductionButton.add(rejectionReason.toLabel(Color.RED)).colspan(pickProductionButton.columns).fillX().left().padTop(2f)
}
return pickProductionButton
}
private fun isSelectedQueueEntry(): Boolean = selectedQueueEntry > -2
private fun getQueueButton(construction: IConstruction?): TextButton {
val city = cityScreen.city
val cityConstructions = city.cityConstructions
val button: TextButton
if (isSelectedQueueEntry()) {
button = TextButton("Remove from queue".tr(), CameraStageBaseScreen.skin)
if (UncivGame.Current.worldScreen.isPlayersTurn && !city.isPuppet) {
button.onClick {
cityConstructions.removeFromQueue(selectedQueueEntry)
cityScreen.selectedConstruction = null
selectedQueueEntry = -2
cityScreen.update()
}
} else {
button.disable()
}
} else {
button = TextButton("Add to queue".tr(), CameraStageBaseScreen.skin)
if (construction != null
&& !cityConstructions.isQueueFull()
&& cityConstructions.getConstruction(construction.name).isBuildable(cityConstructions)
&& UncivGame.Current.worldScreen.isPlayersTurn
&& !city.isPuppet) {
button.onClick {
cityConstructions.addToQueue(construction.name)
cityScreen.update()
}
} else {
button.disable()
}
}
button.labelCell.pad(5f)
return button
}
private fun getBuyButton(construction: IConstruction?): TextButton {
val city = cityScreen.city
val cityConstructions = city.cityConstructions
val button = TextButton("", CameraStageBaseScreen.skin)
if (construction != null
&& construction.canBePurchased()
&& UncivGame.Current.worldScreen.isPlayersTurn
&& !city.isPuppet) {
val constructionGoldCost = construction.getGoldCost(city.civInfo) val constructionGoldCost = construction.getGoldCost(city.civInfo)
purchaseConstructionButton = TextButton("Buy for [$constructionGoldCost] gold".tr(), CameraStageBaseScreen.skin) purchaseConstructionButton = TextButton("Buy for [$constructionGoldCost] gold".tr(), CameraStageBaseScreen.skin)
purchaseConstructionButton.onClick(UncivSound.Coin) { purchaseConstructionButton.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(lastConstruction!="" && cityConstructions.getConstruction(lastConstruction).isBuildable(cityConstructions)) if (isSelectedQueueEntry()) {
city.cityConstructions.currentConstruction = lastConstruction cityConstructions.removeFromQueue(selectedQueueEntry)
cityScreen.update() // since the list of available buildings needs to be updated too, so we can "see" that the building we bought now exists in the city selectedQueueEntry = -2
cityScreen.selectedConstruction = null
}
cityScreen.update()
}, cityScreen) }, cityScreen)
} }
if (constructionGoldCost > city.civInfo.gold) {
purchaseConstructionButton.disable() if (constructionGoldCost > city.civInfo.gold)
} button.disable()
} else { } else {
purchaseConstructionButton = TextButton("Buy".tr(), CameraStageBaseScreen.skin) button.setText("Buy".tr())
purchaseConstructionButton.disable() button.disable()
}
purchaseConstructionButton.labelCell.pad(10f)
add(purchaseConstructionButton).pad(10f).row()
val currentConstructionTable = Table()
currentConstructionTable.background = ImageGetter.getBackground(ImageGetter.getBlue().lerp(Color.BLACK,0.5f))
currentConstructionTable.pad(10f)
val userNeedsToSetProduction = city.cityConstructions.currentConstruction==""
if(!userNeedsToSetProduction) {
currentConstructionTable.add(
ImageGetter.getConstructionImage(city.cityConstructions.currentConstruction).surroundWithCircle(50f))
.pad(5f)
val buildingText = city.cityConstructions.getCityProductionTextForCityButton()
currentConstructionTable.add(buildingText.toLabel()).row()
}
else{
currentConstructionTable.add() // no icon
currentConstructionTable.add("Pick construction".toLabel()).row()
} }
val description: String button.labelCell.pad(5f)
if(userNeedsToSetProduction)
description=""
else if (construction is BaseUnit)
description = construction.getDescription(true)
else if (construction is Building)
description = construction.getDescription(true, city.civInfo,
city.civInfo.gameInfo.ruleSet)
else if(construction is SpecialConstruction)
description = construction.description.tr()
else description="" // Should never happen
val descriptionLabel = description.toLabel() return button
descriptionLabel.setWrap(true)
descriptionLabel.width = stage.width / 4
val descriptionScroll = ScrollPane(descriptionLabel)
currentConstructionTable.add(descriptionScroll).colspan(2)
.width(stage.width / 4).height(stage.height / 8)
add(currentConstructionTable.addBorder(2f, Color.WHITE))
} }
private fun getHigherPrioButton(idx: Int, name: String, city: CityInfo): Table {
val tab = Table()
tab.add(ImageGetter.getImage("OtherIcons/Up").surroundWithCircle(40f))
if (UncivGame.Current.worldScreen.isPlayersTurn && !city.isPuppet) {
tab.touchable = Touchable.enabled
tab.onClick {
tab.touchable = Touchable.disabled
city.cityConstructions.higherPrio(idx)
cityScreen.selectedConstruction = cityScreen.city.cityConstructions.getConstruction(name)
cityScreen.selectedTile = null
selectedQueueEntry = idx - 1
cityScreen.update()
}
}
return tab
}
private fun getLowerPrioButton(idx: Int, name: String, city: CityInfo): Table {
val tab = Table()
tab.add(ImageGetter.getImage("OtherIcons/Down").surroundWithCircle(40f))
if (UncivGame.Current.worldScreen.isPlayersTurn && !city.isPuppet) {
tab.touchable = Touchable.enabled
tab.onClick {
tab.touchable = Touchable.disabled
city.cityConstructions.lowerPrio(idx)
cityScreen.selectedConstruction = cityScreen.city.cityConstructions.getConstruction(name)
cityScreen.selectedTile = null
selectedQueueEntry = idx + 1
cityScreen.update()
}
}
return tab
}
private fun turnOrTurns(number: Int): String = if (number > 1) " {turns}".tr() else " {turn}".tr()
private fun getHeader(title: String): Table {
val headerTable = Table()
headerTable.background = ImageGetter.getBackground(ImageGetter.getBlue())
headerTable.add(title.toLabel(fontSize = 24)).fillX()
return headerTable
}
private fun Table.addCategory(title: String, list: ArrayList<Table>) {
if (list.isEmpty()) return
addSeparator()
add(getHeader(title)).fill().row()
addSeparator()
for (table in list) {
add(table).fill().left().row()
if (table != list.last()) addSeparator()
}
}
} }

View file

@ -168,11 +168,13 @@ fun Actor.surroundWithCircle(size:Float,resizeActor:Boolean=true): IconCircleGro
return IconCircleGroup(size,this,resizeActor) return IconCircleGroup(size,this,resizeActor)
} }
fun Actor.addBorder(size:Float,color:Color):Table{ fun Actor.addBorder(size:Float,color:Color,expandCell:Boolean=false):Table{
val table = Table() val table = Table()
table.pad(size) table.pad(size)
table.background = ImageGetter.getBackground(color) table.background = ImageGetter.getBackground(color)
table.add(this).fill() val cell = table.add(this)
if (expandCell) cell.expand()
cell.fill()
table.pack() table.pack()
return table return table
} }