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:
parent
977fcfb97e
commit
12a98aa4bb
13 changed files with 584 additions and 273 deletions
BIN
android/Images/OtherIcons/Down.png
Normal file
BIN
android/Images/OtherIcons/Down.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 441 B |
BIN
android/Images/OtherIcons/Money.png
Normal file
BIN
android/Images/OtherIcons/Money.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.3 KiB |
BIN
android/Images/OtherIcons/Shock.png
Normal file
BIN
android/Images/OtherIcons/Shock.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 562 B |
BIN
android/Images/OtherIcons/Up.png
Normal file
BIN
android/Images/OtherIcons/Up.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 422 B |
|
@ -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 =
|
||||||
|
|
|
@ -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
|
|
@ -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) {
|
||||||
|
|
|
@ -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 })
|
||||||
|
|
|
@ -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>()
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
78
core/src/com/unciv/ui/cityscreen/ConstructionInfoTable.kt
Normal file
78
core/src/com/unciv/ui/cityscreen/ConstructionInfoTable.kt
Normal 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()
|
||||||
|
}
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue