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] =
|
||||
Required tech: [requiredTech] =
|
||||
|
||||
Current construction =
|
||||
Construction queue =
|
||||
Pick a construction =
|
||||
Queue empty =
|
||||
Add to queue =
|
||||
Remove from queue =
|
||||
|
||||
Diplomacy =
|
||||
War =
|
||||
Peace =
|
||||
|
|
|
@ -11,17 +11,25 @@ import com.unciv.models.translations.tr
|
|||
import com.unciv.ui.utils.withItem
|
||||
import com.unciv.ui.utils.withoutItem
|
||||
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 {
|
||||
@Transient lateinit var cityInfo: CityInfo
|
||||
@Transient private var builtBuildingObjects=ArrayList<Building>()
|
||||
@Transient private var builtBuildingObjects = ArrayList<Building>()
|
||||
|
||||
var builtBuildings = HashSet<String>()
|
||||
val inProgressConstructions = HashMap<String, Int>()
|
||||
var currentConstruction: String = "Monument" // default starting building!
|
||||
var currentConstruction: String = "Monument"
|
||||
var currentConstructionIsUserSet = false
|
||||
var constructionQueue = mutableListOf<String>()
|
||||
val queueMaxSize = 10
|
||||
|
||||
//region pure functions
|
||||
fun clone(): CityConstructions {
|
||||
|
@ -30,6 +38,7 @@ class CityConstructions {
|
|||
toReturn.inProgressConstructions.putAll(inProgressConstructions)
|
||||
toReturn.currentConstruction=currentConstruction
|
||||
toReturn.currentConstructionIsUserSet=currentConstructionIsUserSet
|
||||
toReturn.constructionQueue.addAll(constructionQueue)
|
||||
return toReturn
|
||||
}
|
||||
|
||||
|
@ -39,6 +48,9 @@ class CityConstructions {
|
|||
fun getConstructableUnits() = cityInfo.getRuleset().units.values
|
||||
.asSequence().filter { it.isBuildable(this) }
|
||||
|
||||
/**
|
||||
* @return [Stats] provided by all built buildings in city plus the bonus from Library
|
||||
*/
|
||||
fun getStats(): Stats {
|
||||
val stats = Stats()
|
||||
for (building in getBuiltBuildings())
|
||||
|
@ -47,8 +59,14 @@ class CityConstructions {
|
|||
return stats
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Maintenance cost of all built buildings
|
||||
*/
|
||||
fun getMaintenanceCosts(): Int = getBuiltBuildings().sumBy { it.maintenance }
|
||||
|
||||
/**
|
||||
* @return Bonus (%) [Stats] provided by all built buildings in city
|
||||
*/
|
||||
fun getStatPercentBonuses(): Stats {
|
||||
val stats = Stats()
|
||||
for (building in getBuiltBuildings())
|
||||
|
@ -69,7 +87,9 @@ class CityConstructions {
|
|||
}
|
||||
|
||||
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()
|
||||
if (currentConstructionSnapshot!=""
|
||||
&& SpecialConstruction.getSpecialConstructions().none { it.name==currentConstructionSnapshot }) {
|
||||
|
@ -80,17 +100,17 @@ class CityConstructions {
|
|||
}
|
||||
|
||||
fun getCurrentConstruction(): IConstruction = getConstruction(currentConstruction)
|
||||
fun getIConstructionQueue(): List<IConstruction> = constructionQueue.map{ getConstruction(it) }
|
||||
|
||||
fun isBuilt(buildingName: String): Boolean = builtBuildings.contains(buildingName)
|
||||
|
||||
fun isBeingConstructed(constructionName: String): Boolean = currentConstruction == constructionName
|
||||
fun isEnqueued(constructionName: String): Boolean = constructionQueue.contains(constructionName)
|
||||
|
||||
fun isQueueFull(): Boolean = constructionQueue.size == queueMaxSize
|
||||
|
||||
fun isBuildingWonder(): Boolean {
|
||||
val currentConstruction = getCurrentConstruction()
|
||||
if (currentConstruction is Building) {
|
||||
return currentConstruction.isWonder
|
||||
}
|
||||
return false
|
||||
return currentConstruction is Building && currentConstruction.isWonder
|
||||
}
|
||||
|
||||
internal fun getConstruction(constructionName: String): IConstruction {
|
||||
|
@ -179,6 +199,7 @@ class CityConstructions {
|
|||
|
||||
fun endTurn(cityStats: Stats) {
|
||||
stopUnbuildableConstruction()
|
||||
validateConstructionQueue()
|
||||
|
||||
if(getConstruction(currentConstruction) !is SpecialConstruction)
|
||||
addProductionPoints(Math.round(cityStats.production))
|
||||
|
@ -198,7 +219,17 @@ class CityConstructions {
|
|||
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)
|
||||
inProgressConstructions.remove(currentConstruction)
|
||||
|
||||
|
@ -252,16 +283,66 @@ class CityConstructions {
|
|||
cancelCurrentConstruction()
|
||||
}
|
||||
|
||||
fun cancelCurrentConstruction(){
|
||||
currentConstructionIsUserSet=false
|
||||
currentConstruction=""
|
||||
private fun cancelCurrentConstruction() {
|
||||
currentConstructionIsUserSet = false
|
||||
currentConstruction = ""
|
||||
chooseNextConstruction()
|
||||
}
|
||||
|
||||
fun chooseNextConstruction() {
|
||||
if(currentConstructionIsUserSet) return
|
||||
|
||||
if (constructionQueue.isNotEmpty()) {
|
||||
|
||||
currentConstructionIsUserSet = true
|
||||
currentConstruction = constructionQueue.removeAt(0)
|
||||
stopUnbuildableConstruction()
|
||||
|
||||
if (currentConstruction != "") return
|
||||
}
|
||||
|
||||
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
|
|
@ -392,7 +392,10 @@ class CityInfo {
|
|||
isPuppet = true
|
||||
health = getMaxHealth() / 2 // I think that cities recover to half health when conquered?
|
||||
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) {
|
||||
|
|
|
@ -223,6 +223,8 @@ class Building : NamedStats(), IConstruction{
|
|||
|
||||
fun getRejectionReason(construction: CityConstructions):String{
|
||||
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
|
||||
&& !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.Table
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Label
|
||||
import com.badlogic.gdx.utils.Align
|
||||
import com.unciv.Constants
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.logic.city.CityInfo
|
||||
import com.unciv.logic.civilization.GreatPersonManager
|
||||
import com.unciv.models.ruleset.Building
|
||||
import com.unciv.models.translations.tr
|
||||
import com.unciv.models.stats.Stat
|
||||
import com.unciv.models.stats.Stats
|
||||
import com.unciv.ui.utils.*
|
||||
import com.unciv.ui.worldscreen.optionstable.YesNoPopupTable
|
||||
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) {
|
||||
val pad = 5f
|
||||
|
@ -29,10 +34,9 @@ class CityInfoTable(private val cityScreen: CityScreen) : Table(CameraStageBaseS
|
|||
clear()
|
||||
val cityInfo = cityScreen.city
|
||||
|
||||
addCityStats(cityInfo)
|
||||
addBuildingsInfo(cityInfo)
|
||||
|
||||
addStatInfo()
|
||||
|
||||
addGreatPersonPointInfo(cityInfo)
|
||||
|
||||
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) {
|
||||
val wonders = 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.TextButton
|
||||
import com.badlogic.gdx.utils.Align
|
||||
import com.unciv.Constants
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.logic.HexMath
|
||||
import com.unciv.logic.city.CityInfo
|
||||
import com.unciv.logic.city.IConstruction
|
||||
import com.unciv.logic.map.TileInfo
|
||||
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.ui.map.TileGroupMap
|
||||
import com.unciv.ui.tilegroups.TileSetStrings
|
||||
|
@ -21,51 +19,52 @@ import java.util.*
|
|||
import kotlin.math.ceil
|
||||
import kotlin.math.round
|
||||
|
||||
class CityScreen(internal val city: CityInfo) : CameraStageBaseScreen() {
|
||||
private var selectedTile: TileInfo? = null
|
||||
class CityScreen(internal val city: CityInfo): CameraStageBaseScreen() {
|
||||
var selectedTile: TileInfo? = null
|
||||
var selectedConstruction: IConstruction? = null
|
||||
|
||||
// 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 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 */
|
||||
/** Displays current production, production queue and available productions list - sits on LEFT */
|
||||
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>()
|
||||
|
||||
init {
|
||||
onBackButtonClicked { game.setWorldScreen() }
|
||||
addTiles()
|
||||
UncivGame.Current.settings.addCompletedTutorialTask("Enter city screen")
|
||||
|
||||
val tableBackgroundColor = ImageGetter.getBlue().lerp(Color.BLACK,0.5f)
|
||||
addTiles()
|
||||
|
||||
var buildingsTableContainer = Table()
|
||||
buildingsTableContainer.pad(3f)
|
||||
buildingsTableContainer.background = ImageGetter.getBackground(tableBackgroundColor)
|
||||
buildingsTableContainer.background = ImageGetter.getBackground(ImageGetter.getBlue().lerp(Color.BLACK,0.5f))
|
||||
cityInfoTable.update()
|
||||
val buildingsScroll = ScrollPane(cityInfoTable)
|
||||
buildingsTableContainer.add(buildingsScroll)
|
||||
.size(stage.width/4,stage.height / 2)
|
||||
buildingsTableContainer.add(buildingsScroll).size(stage.width/4,stage.height / 2)
|
||||
|
||||
buildingsTableContainer = buildingsTableContainer.addBorder(2f, Color.WHITE)
|
||||
buildingsTableContainer.setPosition(stage.width - buildingsTableContainer.width-5,
|
||||
stage.height - buildingsTableContainer.height-5)
|
||||
buildingsTableContainer.setPosition( stage.width - 5f, stage.height - 5f, Align.topRight)
|
||||
|
||||
//stage.setDebugTableUnderMouse(true)
|
||||
stage.addActor(constructionsTable)
|
||||
stage.addActor(tileTable)
|
||||
|
||||
stage.addActor(selectedConstructionTable)
|
||||
stage.addActor(cityPickerTable)
|
||||
stage.addActor(buildingsTableContainer)
|
||||
|
||||
|
@ -73,87 +72,38 @@ class CityScreen(internal val city: CityInfo) : CameraStageBaseScreen() {
|
|||
}
|
||||
|
||||
internal fun update() {
|
||||
cityInfoTable.update()
|
||||
city.cityStats.update()
|
||||
|
||||
constructionsTable.update(selectedConstruction)
|
||||
constructionsTable.setPosition(5f, stage.height - 5f, Align.topLeft)
|
||||
|
||||
cityPickerTable.update()
|
||||
cityPickerTable.centerX(stage)
|
||||
|
||||
constructionsTable.update()
|
||||
updateAnnexAndRazeCityButton()
|
||||
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()
|
||||
|
||||
topCityStatsTable.remove()
|
||||
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()){
|
||||
if (city.getCenterTile().getTilesAtDistance(4).isNotEmpty())
|
||||
displayTutorial(Tutorial.CityRange)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateTileGroups() {
|
||||
val nextTile = city.expansion.chooseNewTileToOwn()
|
||||
for (tileGroup in tileGroups) {
|
||||
|
||||
tileGroup.update()
|
||||
if(tileGroup.tileInfo == nextTile){
|
||||
tileGroup.showCircle(Color.PURPLE)
|
||||
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() {
|
||||
|
@ -167,15 +117,13 @@ class CityScreen(internal val city: CityInfo) : CameraStageBaseScreen() {
|
|||
update()
|
||||
}
|
||||
razeCityButtonHolder.add(annexCityButton).colspan(cityPickerTable.columns)
|
||||
}
|
||||
else if(!city.isBeingRazed) {
|
||||
} else if(!city.isBeingRazed) {
|
||||
val razeCityButton = TextButton("Raze city".tr(), skin)
|
||||
razeCityButton.labelCell.pad(10f)
|
||||
razeCityButton.onClick { city.isBeingRazed=true; update() }
|
||||
if(!UncivGame.Current.worldScreen.isPlayersTurn) razeCityButton.disable()
|
||||
razeCityButtonHolder.add(razeCityButton).colspan(cityPickerTable.columns)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
val stopRazingCityButton = TextButton("Stop razing city".tr(), skin)
|
||||
stopRazingCityButton.labelCell.pad(10f)
|
||||
stopRazingCityButton.onClick { city.isBeingRazed=false; update() }
|
||||
|
@ -203,6 +151,7 @@ class CityScreen(internal val city: CityInfo) : CameraStageBaseScreen() {
|
|||
tileGroup.onClick {
|
||||
if (!city.isPuppet) {
|
||||
selectedTile = tileInfo
|
||||
selectedConstruction = null
|
||||
if (tileGroup.isWorkable && UncivGame.Current.worldScreen.isPlayersTurn) {
|
||||
if (!tileInfo.isWorked() && city.population.getFreePopulation() > 0) {
|
||||
city.workedTiles.add(tileInfo.position)
|
||||
|
@ -235,5 +184,4 @@ class CityScreen(internal val city: CityInfo) : CameraStageBaseScreen() {
|
|||
scrollPane.scrollPercentY=0.5f
|
||||
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.scenes.scene2d.Touchable
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.*
|
||||
import com.badlogic.gdx.utils.Align
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.logic.city.CityInfo
|
||||
import com.unciv.logic.city.IConstruction
|
||||
import com.unciv.logic.city.SpecialConstruction
|
||||
import com.unciv.models.UncivSound
|
||||
import com.unciv.models.ruleset.Building
|
||||
import com.unciv.models.ruleset.unit.BaseUnit
|
||||
import com.unciv.models.translations.tr
|
||||
import com.unciv.models.stats.Stat
|
||||
import com.unciv.ui.utils.*
|
||||
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
|
||||
var lastConstruction = ""
|
||||
private val constructionsQueueScrollPane: ScrollPane
|
||||
private val availableConstructionsScrollPane: ScrollPane
|
||||
|
||||
private val constructionsQueueTable = Table()
|
||||
private val availableConstructionsTable = Table()
|
||||
private val buttons = Table()
|
||||
|
||||
fun update() {
|
||||
val city = cityScreen.city
|
||||
pad(10f)
|
||||
columnDefaults(0).padRight(10f)
|
||||
clear()
|
||||
private val pad = 10f
|
||||
|
||||
addConstructionPickerScrollpane(city)
|
||||
addCurrentConstructionTable(city)
|
||||
init {
|
||||
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()
|
||||
}
|
||||
|
||||
private fun getProductionButton(construction: String, buttonText: String, rejectionReason: String=""): Table {
|
||||
val pickProductionButton = Table()
|
||||
pickProductionButton.touchable = Touchable.enabled
|
||||
pickProductionButton.align(Align.left)
|
||||
pickProductionButton.pad(5f)
|
||||
private fun clearContent() {
|
||||
constructionsQueueTable.clear()
|
||||
buttons.clear()
|
||||
availableConstructionsTable.clear()
|
||||
}
|
||||
|
||||
if(cityScreen.city.cityConstructions.currentConstruction==construction)
|
||||
pickProductionButton.background = ImageGetter.getBackground(Color.GREEN.cpy().lerp(Color.BLACK,0.5f))
|
||||
else
|
||||
pickProductionButton.background = ImageGetter.getBackground(Color.BLACK)
|
||||
private fun updateButtons(construction: IConstruction?) {
|
||||
buttons.add(getQueueButton(construction)).padRight(5f)
|
||||
buttons.add(getBuyButton(construction))
|
||||
}
|
||||
|
||||
pickProductionButton.add(ImageGetter.getConstructionImage(construction).surroundWithCircle(40f)).padRight(10f)
|
||||
pickProductionButton.add(buttonText.toLabel())
|
||||
private fun updateConstructionQueue() {
|
||||
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!
|
||||
pickProductionButton.onClick {
|
||||
if (!cityScreen.city.isPuppet) {
|
||||
lastConstruction = cityScreen.city.cityConstructions.currentConstruction
|
||||
cityScreen.city.cityConstructions.currentConstruction = construction
|
||||
cityScreen.city.cityConstructions.currentConstructionIsUserSet = true
|
||||
cityScreen.city.cityStats.update()
|
||||
cityScreen.update()
|
||||
cityScreen.game.settings.addCompletedTutorialTask("Pick construction")
|
||||
}
|
||||
constructionsQueueTable.defaults().pad(0f)
|
||||
constructionsQueueTable.add(getHeader("Current construction".tr())).fillX()
|
||||
constructionsQueueTable.addSeparator()
|
||||
|
||||
if (currentConstruction != "")
|
||||
constructionsQueueTable.add(getQueueEntry(-1, currentConstruction, queue.isEmpty(), selectedQueueEntry == -1))
|
||||
.expandX().fillX().row()
|
||||
else
|
||||
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 {
|
||||
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
|
||||
} else
|
||||
constructionsQueueTable.add("Queue empty".toLabel()).pad(2f).row()
|
||||
}
|
||||
|
||||
private fun Table.addCategory(title:String,list:ArrayList<Table>){
|
||||
if(list.isEmpty()) return
|
||||
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) {
|
||||
private fun updateAvailableConstructions() {
|
||||
val city = cityScreen.city
|
||||
val cityConstructions = city.cityConstructions
|
||||
|
||||
val constructionPickerTable = Table()
|
||||
constructionPickerTable.background = ImageGetter.getBackground(Color.BLACK)
|
||||
|
||||
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 buildableNationalWonders = ArrayList<Table>()
|
||||
val buildableBuildings = ArrayList<Table>()
|
||||
val specialConstructions = ArrayList<Table>()
|
||||
|
||||
for (building in city.getRuleset().buildings.values) {
|
||||
if (!building.shouldBeDisplayed(cityConstructions) && building.name != cityConstructions.currentConstruction) continue
|
||||
val turnsToBuilding = cityConstructions.turnsToConstruction(building.name)
|
||||
val productionTextButton = getProductionButton(building.name,
|
||||
building.name.tr() + "\r\n" + turnsToBuilding + (if(turnsToBuilding>1) " {turns}".tr() else " {turn}".tr()),
|
||||
building.getRejectionReason(cityConstructions)
|
||||
)
|
||||
if (building.isWonder)
|
||||
buildableWonders += productionTextButton
|
||||
else if(building.isNationalWonder)
|
||||
buildableNationalWonders += productionTextButton
|
||||
else
|
||||
buildableBuildings += productionTextButton
|
||||
for (unit in city.getRuleset().units.values.filter { it.shouldBeDisplayed(cityConstructions) }) {
|
||||
val turnsToUnit = cityConstructions.turnsToConstruction(unit.name)
|
||||
val productionButton = getProductionButton(unit.name,
|
||||
unit.name.tr() + "\r\n" + turnsToUnit + turnOrTurns(turnsToUnit),
|
||||
unit.getRejectionReason(cityConstructions))
|
||||
units.add(productionButton)
|
||||
}
|
||||
|
||||
constructionPickerTable.addCategory("Wonders",buildableWonders)
|
||||
constructionPickerTable.addCategory("National Wonders",buildableNationalWonders)
|
||||
constructionPickerTable.addCategory("Buildings",buildableBuildings)
|
||||
for (building in city.getRuleset().buildings.values.filter { it.shouldBeDisplayed(cityConstructions)}) {
|
||||
val turnsToBuilding = cityConstructions.turnsToConstruction(building.name)
|
||||
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) }) {
|
||||
specialConstructions += getProductionButton(specialConstruction.name,
|
||||
"Produce [${specialConstruction.name}]".tr())
|
||||
}
|
||||
constructionPickerTable.addCategory("Other",specialConstructions)
|
||||
|
||||
val scrollPane = ScrollPane(constructionPickerTable.addBorder(2f, Color.WHITE))
|
||||
|
||||
// This is to keep the same amount of scrolling on the construction picker scroll between refresh()es
|
||||
if(constructionScrollPane!=null){
|
||||
scrollPane.layout()
|
||||
scrollPane.scrollY = constructionScrollPane!!.scrollY
|
||||
scrollPane.updateVisualScroll()
|
||||
}
|
||||
constructionScrollPane = scrollPane
|
||||
|
||||
add(scrollPane).maxHeight(stage.height / 3 * (stage.height/600)).row()
|
||||
availableConstructionsTable.addCategory("Units", units)
|
||||
availableConstructionsTable.addCategory("Wonders", buildableWonders)
|
||||
availableConstructionsTable.addCategory("National Wonders", buildableNationalWonders)
|
||||
availableConstructionsTable.addCategory("Buildings", buildableBuildings)
|
||||
availableConstructionsTable.addCategory("Other", specialConstructions)
|
||||
}
|
||||
|
||||
private fun addCurrentConstructionTable(city: CityInfo) {
|
||||
val cityConstructions = city.cityConstructions
|
||||
val construction = cityConstructions.getCurrentConstruction()
|
||||
private fun getQueueEntry(idx: Int, name: String, isLast: Boolean, isSelected: Boolean): Table {
|
||||
val city = cityScreen.city
|
||||
val table = Table()
|
||||
table.align(Align.left).pad(5f)
|
||||
table.background = ImageGetter.getBackground(Color.BLACK)
|
||||
|
||||
row()
|
||||
val purchaseConstructionButton: TextButton
|
||||
if (!city.isPuppet && !city.isInResistance() && construction.canBePurchased()) {
|
||||
if (isSelected)
|
||||
table.background = ImageGetter.getBackground(Color.GREEN.cpy().lerp(Color.BLACK, 0.5f))
|
||||
|
||||
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)
|
||||
purchaseConstructionButton = TextButton("Buy for [$constructionGoldCost] gold".tr(), CameraStageBaseScreen.skin)
|
||||
purchaseConstructionButton.onClick(UncivSound.Coin) {
|
||||
YesNoPopupTable("Would you like to purchase [${construction.name}] for [$constructionGoldCost] gold?".tr(), {
|
||||
cityConstructions.purchaseConstruction(construction.name)
|
||||
if(lastConstruction!="" && cityConstructions.getConstruction(lastConstruction).isBuildable(cityConstructions))
|
||||
city.cityConstructions.currentConstruction = lastConstruction
|
||||
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
|
||||
if (isSelectedQueueEntry()) {
|
||||
cityConstructions.removeFromQueue(selectedQueueEntry)
|
||||
selectedQueueEntry = -2
|
||||
cityScreen.selectedConstruction = null
|
||||
}
|
||||
cityScreen.update()
|
||||
}, cityScreen)
|
||||
}
|
||||
if (constructionGoldCost > city.civInfo.gold) {
|
||||
purchaseConstructionButton.disable()
|
||||
}
|
||||
|
||||
if (constructionGoldCost > city.civInfo.gold)
|
||||
button.disable()
|
||||
|
||||
} else {
|
||||
purchaseConstructionButton = TextButton("Buy".tr(), CameraStageBaseScreen.skin)
|
||||
purchaseConstructionButton.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()
|
||||
button.setText("Buy".tr())
|
||||
button.disable()
|
||||
}
|
||||
|
||||
val description: String
|
||||
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
|
||||
button.labelCell.pad(5f)
|
||||
|
||||
val descriptionLabel = description.toLabel()
|
||||
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))
|
||||
return button
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
fun Actor.addBorder(size:Float,color:Color):Table{
|
||||
fun Actor.addBorder(size:Float,color:Color,expandCell:Boolean=false):Table{
|
||||
val table = Table()
|
||||
table.pad(size)
|
||||
table.background = ImageGetter.getBackground(color)
|
||||
table.add(this).fill()
|
||||
val cell = table.add(this)
|
||||
if (expandCell) cell.expand()
|
||||
cell.fill()
|
||||
table.pack()
|
||||
return table
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue