Unciv/core/src/com/unciv/ui/EmpireOverviewScreen.kt
2020-04-19 16:36:13 +03:00

633 lines
No EOL
29 KiB
Kotlin

package com.unciv.ui
import com.unciv.ui.utils.AutoScrollPane as ScrollPane
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.Actor
import com.badlogic.gdx.scenes.scene2d.Group
import com.badlogic.gdx.scenes.scene2d.Touchable
import com.badlogic.gdx.scenes.scene2d.ui.*
import com.badlogic.gdx.utils.Align
import com.unciv.UncivGame
import com.unciv.logic.HexMath
import com.unciv.logic.city.CityInfo
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.civilization.diplomacy.DiplomaticStatus
import com.unciv.logic.trade.Trade
import com.unciv.logic.trade.TradeOffersList
import com.unciv.models.ruleset.tile.ResourceType
import com.unciv.models.translations.tr
import com.unciv.ui.cityscreen.CityScreen
import com.unciv.ui.pickerscreens.PromotionPickerScreen
import com.unciv.ui.utils.*
import com.unciv.Constants
import java.text.DecimalFormat
import kotlin.math.*
class EmpireOverviewScreen(private val viewingPlayer:CivilizationInfo, private val defaultPage: String = "Cities") : CameraStageBaseScreen(){
private val topTable = Table().apply { defaults().pad(10f) }
private val centerTable = Table().apply { defaults().pad(20f) }
init {
onBackButtonClicked { UncivGame.Current.setWorldScreen() }
val clicks = HashMap<String,() -> Unit>()
val closeButton = Constants.close.toTextButton()
closeButton.onClick { UncivGame.Current.setWorldScreen() }
closeButton.y = stage.height - closeButton.height - 5
topTable.add(closeButton)
val setCityInfoButton = "Cities".toTextButton()
val setCities = {
centerTable.clear()
centerTable.add(getCityInfoTable())
centerTable.pack()
}
clicks["Cities"] = setCities
setCityInfoButton.onClick(setCities)
topTable.add(setCityInfoButton)
val setStatsInfoButton = "Stats".toTextButton()
val setStats = {
game.settings.addCompletedTutorialTask("See your stats breakdown")
centerTable.clear()
centerTable.add(ScrollPane(Table().apply {
defaults().pad(40f)
add(getHappinessTable()).top()
add(getGoldTable()).top()
add(getScienceTable()).top()
add(getGreatPeopleTable()).top()
}))
centerTable.pack()
}
clicks["Stats"] = setStats
setStatsInfoButton.onClick(setStats)
topTable.add(setStatsInfoButton)
val setCurrentTradesButton = "Trades".toTextButton()
setCurrentTradesButton.onClick {
centerTable.clear()
centerTable.add(ScrollPane(getTradesTable())).height(stage.height * 0.8f) // so it doesn't cover the navigation buttons
centerTable.pack()
}
topTable.add(setCurrentTradesButton)
if (viewingPlayer.diplomacy.values.all { it.trades.isEmpty() })
setCurrentTradesButton.disable()
val setUnitsButton = "Units".toTextButton()
setUnitsButton.onClick {
centerTable.clear()
centerTable.add(ScrollPane(getUnitTable()).apply { setOverscroll(false,false) }).height(stage.height * 0.8f)
centerTable.pack()
}
topTable.add(setUnitsButton)
val setDiplomacyButton = "Diplomacy".toTextButton()
setDiplomacyButton.onClick {
centerTable.clear()
centerTable.add(getDiplomacyGroup()).height(stage.height * 0.8f)
centerTable.pack()
}
topTable.add(setDiplomacyButton)
val setResourcesButton = "Resources".toTextButton()
val setResources = {
centerTable.clear()
centerTable.add(ScrollPane(getResourcesTable())).size(stage.width * 0.8f, stage.height * 0.8f)
centerTable.pack()
}
clicks["Resources"] = setResources
setResourcesButton.onClick(setResources)
topTable.add(setResourcesButton)
if (viewingPlayer.detailedCivResources.isEmpty())
setResourcesButton.disable()
topTable.pack()
clicks[defaultPage]?.invoke()
val table = Table()
table.add(topTable).row()
table.add(centerTable).expand().row()
table.setFillParent(true)
stage.addActor(table)
}
private fun getTradesTable(): Table {
val tradesTable = Table().apply { defaults().pad(10f) }
val diplomacies = viewingPlayer.diplomacy.values.filter { it.trades.isNotEmpty() }
.sortedWith(Comparator { d0, d1 ->
val d0offers = d0.trades.first().ourOffers
val d1offers = d1.trades.first().ourOffers
val d0max = if (d0offers.isEmpty()) 0 else d0offers.maxBy { it.duration }!!.duration
val d1max = if (d1offers.isEmpty()) 0 else d1offers.maxBy { it.duration }!!.duration
when {
d0max > d1max -> 1
d0max == d1max -> 0
else -> -1
}
})
for(diplomacy in diplomacies) {
for (trade in diplomacy.trades)
tradesTable.add(createTradeTable(trade, diplomacy.otherCiv())).row()
}
return tradesTable
}
private fun createTradeTable(trade: Trade, otherCiv:CivilizationInfo): Table {
val generalTable = Table(skin)
generalTable.add(createOffersTable(viewingPlayer,trade.ourOffers, trade.theirOffers.size)).fillY()
generalTable.add(createOffersTable(otherCiv, trade.theirOffers, trade.ourOffers.size)).fillY()
return generalTable
}
private fun createOffersTable(civ: CivilizationInfo, offersList: TradeOffersList, numberOfOtherSidesOffers: Int): Table {
val table = Table()
table.defaults().pad(10f)
table.background = ImageGetter.getBackground(civ.nation.getOuterColor())
table.add(civ.civName.toLabel(civ.nation.getInnerColor())).row()
table.addSeparator()
for(offer in offersList){
var offerText = offer.getOfferText()
if(!offerText.contains("\n")) offerText+="\n"
table.add(offerText.toLabel(civ.nation.getInnerColor())).row()
}
for(i in 1..numberOfOtherSidesOffers - offersList.size)
table.add("\n".toLabel()).row() // we want both sides of the general table to have the same number of rows
return table
}
private fun getHappinessTable(): Table {
val happinessTable = Table(skin)
happinessTable.defaults().pad(5f)
val happinessHeader = Table(skin)
happinessHeader.add(ImageGetter.getStatIcon("Happiness")).pad(5f,0f,5f,12f).size(20f)
happinessHeader.add("Happiness".toLabel(fontSize = 24)).padTop(5f)
happinessTable.add(happinessHeader).colspan(2).row()
happinessTable.addSeparator()
val happinessBreakdown = viewingPlayer.stats().getHappinessBreakdown()
for (entry in happinessBreakdown.filterNot { it.value.roundToInt()==0 }) {
happinessTable.add(entry.key.tr())
happinessTable.add(entry.value.roundToInt().toString()).right().row()
}
happinessTable.add("Total".tr())
happinessTable.add(happinessBreakdown.values.sum().roundToInt().toString()).right()
happinessTable.pack()
return happinessTable
}
private fun getGoldTable(): Table {
val goldTable = Table(skin)
goldTable.defaults().pad(5f)
val goldHeader = Table(skin)
goldHeader.add(ImageGetter.getStatIcon("Gold")).pad(5f,0f,5f,12f).size(20f)
goldHeader.add("Gold".toLabel(fontSize = 24)).padTop(5f)
goldTable.add(goldHeader).colspan(2).row()
goldTable.addSeparator()
var total=0f
for (entry in viewingPlayer.stats().getStatMapForNextTurn()) {
if(entry.value.gold==0f) continue
goldTable.add(entry.key.tr())
goldTable.add(entry.value.gold.roundToInt().toString()).right().row()
total += entry.value.gold
}
goldTable.add("Total".tr())
goldTable.add(total.roundToInt().toString()).right()
goldTable.pack()
return goldTable
}
private fun getScienceTable(): Table {
val scienceTable = Table(skin)
scienceTable.defaults().pad(5f)
val scienceHeader = Table(skin)
scienceHeader.add(ImageGetter.getStatIcon("Science")).pad(5f,0f,5f,12f).size(20f)
scienceHeader.add("Science".toLabel(fontSize = 24)).padTop(5f)
scienceTable.add(scienceHeader).colspan(2).row()
scienceTable.addSeparator()
val scienceStats = viewingPlayer.stats().getStatMapForNextTurn()
.filter { it.value.science!=0f }
for (entry in scienceStats) {
scienceTable.add(entry.key.tr())
scienceTable.add(entry.value.science.roundToInt().toString()).right().row()
}
scienceTable.add("Total".tr())
scienceTable.add(scienceStats.values.map { it.science }.sum().roundToInt().toString()).right()
scienceTable.pack()
return scienceTable
}
private fun getGreatPeopleTable(): Table {
val greatPeopleTable = Table(skin)
val greatPersonPoints = viewingPlayer.greatPeople.greatPersonPoints.toHashMap()
val greatPersonPointsPerTurn = viewingPlayer.getGreatPersonPointsForNextTurn().toHashMap()
val pointsToGreatPerson = viewingPlayer.greatPeople.pointsForNextGreatPerson
greatPeopleTable.defaults().pad(5f)
val greatPeopleHeader = Table(skin)
val greatPeopleIcon = ImageGetter.getStatIcon("Specialist")
greatPeopleIcon.color = Color.ROYAL
greatPeopleHeader.add(greatPeopleIcon).padRight(12f).size(30f)
greatPeopleHeader.add("Great person points".toLabel(fontSize = 24)).padTop(5f)
greatPeopleTable.add(greatPeopleHeader).colspan(3).row()
greatPeopleTable.addSeparator()
greatPeopleTable.add()
greatPeopleTable.add("Current points".tr())
greatPeopleTable.add("Points per turn".tr()).row()
val mapping = viewingPlayer.greatPeople.statToGreatPersonMapping
for(entry in mapping){
greatPeopleTable.add(entry.value.tr())
greatPeopleTable.add(greatPersonPoints[entry.key]!!.toInt().toString()+"/"+pointsToGreatPerson)
greatPeopleTable.add(greatPersonPointsPerTurn[entry.key]!!.toInt().toString()).row()
}
val pointsForGreatGeneral = viewingPlayer.greatPeople.greatGeneralPoints.toString()
val pointsForNextGreatGeneral = viewingPlayer.greatPeople.pointsForNextGreatGeneral.toString()
greatPeopleTable.add("Great General".tr())
greatPeopleTable.add("$pointsForGreatGeneral/$pointsForNextGreatGeneral").row()
greatPeopleTable.pack()
return greatPeopleTable
}
private fun getCityInfoTable(): Table {
val iconSize = 50f//if you set this too low, there is a chance that the tables will be misaligned
val padding = 5f
var sortedBy = "City"
val cityInfoTableDetails = Table(skin)
cityInfoTableDetails.defaults().pad(padding).minWidth(iconSize).align(Align.left)//we need the min width so we can align the different tables
fun sortOnClick(iconName: String) {
val descending = sortedBy == iconName
sortedBy = iconName
// sort the table: clear and fill with sorted data
cityInfoTableDetails.clear()
fillCitiesTable(cityInfoTableDetails, iconName, descending)
// reset to return back for ascending next time
if (descending) sortedBy = ""
}
val cityInfoTableIcons = Table(skin)
cityInfoTableIcons.defaults().pad(padding).align(Align.center)
cityInfoTableIcons.add("Cities".toLabel(fontSize = 24)).colspan(8).align(Align.center).row()
val citySortIcon = ImageGetter.getUnitIcon("Settler").surroundWithCircle(iconSize)
citySortIcon.onClick { sortOnClick("City") }
cityInfoTableIcons.add(citySortIcon).align(Align.left)
val columnsNames = arrayListOf("Population", "Food", "Gold", "Science", "Production", "Culture", "Happiness")
for (name in columnsNames) {
val icon = ImageGetter.getStatIcon(name)
icon.onClick { sortOnClick(name) }
cityInfoTableIcons.add(icon).size(iconSize)
}
cityInfoTableIcons.pack()
fillCitiesTable(cityInfoTableDetails, "City", false)
val cityInfoScrollPane = ScrollPane(cityInfoTableDetails)
cityInfoScrollPane.pack()
cityInfoScrollPane.setOverscroll(false, false)//I think it feels better with no overscroll
val cityInfoTableTotal = Table(skin)
cityInfoTableTotal.defaults().pad(padding).minWidth(iconSize)//we need the min width so we can align the different tables
cityInfoTableTotal.add("Total".tr())
cityInfoTableTotal.add(viewingPlayer.cities.sumBy { it.population.population }.toString()).actor!!.setAlignment(Align.center)
cityInfoTableTotal.add()//an intended empty space
cityInfoTableTotal.add(viewingPlayer.cities.sumBy { it.cityStats.currentCityStats.gold.toInt() }.toString()).actor!!.setAlignment(Align.center)
cityInfoTableTotal.add(viewingPlayer.cities.sumBy { it.cityStats.currentCityStats.science.toInt() }.toString()).actor!!.setAlignment(Align.center)
cityInfoTableTotal.add()//an intended empty space
cityInfoTableTotal.add(viewingPlayer.cities.sumBy { it.cityStats.currentCityStats.culture.toInt() }.toString()).actor!!.setAlignment(Align.center)
cityInfoTableTotal.add(viewingPlayer.cities.sumBy { it.cityStats.currentCityStats.happiness.toInt() }.toString()).actor!!.setAlignment(Align.center)
cityInfoTableTotal.pack()
val table = Table(skin)
//since the names of the cities are on the left, and the length of the names varies
//we align every row to the right, coz we set the size of the other(number) cells to the image size
//and thus, we can guarantee that the tables will be aligned
table.defaults().pad(padding).align(Align.right)
// place the button for sorting by city name on top of the cities names
citySortIcon.width = max(iconSize, cityInfoTableDetails.width - (iconSize+padding) * 8)
table.add(cityInfoTableIcons).row()
table.add(cityInfoScrollPane).width(cityInfoTableDetails.width).row()
table.add(cityInfoTableTotal)
table.pack()
return table
}
private fun fillCitiesTable(citiesTable: Table, sortType: String, descending: Boolean) {
val sorter = Comparator {city2, city1 : CityInfo -> when (sortType) {
"Population" -> city1.population.population - city2.population.population
"Food" -> (city1.cityStats.currentCityStats.food - city2.cityStats.currentCityStats.food).toInt()
"Gold" -> (city1.cityStats.currentCityStats.gold - city2.cityStats.currentCityStats.gold).toInt()
"Science" -> (city1.cityStats.currentCityStats.science - city2.cityStats.currentCityStats.science).toInt()
"Production" -> (city1.cityStats.currentCityStats.production - city2.cityStats.currentCityStats.production).toInt()
"Culture" -> (city1.cityStats.currentCityStats.culture - city2.cityStats.currentCityStats.culture).toInt()
"Happiness" -> (city1.cityStats.currentCityStats.happiness - city2.cityStats.currentCityStats.happiness).toInt()
else -> city2.name.compareTo(city1.name)
} }
var cityList = viewingPlayer.cities.sortedWith(sorter)
if (descending)
cityList = cityList.reversed()
for (city in cityList) {
val button = Button(city.name.toLabel(), skin)
button.onClick {
UncivGame.Current.setScreen(CityScreen(city))
}
citiesTable.add(button)
citiesTable.add(city.cityConstructions.getCityProductionTextForCityButton()).actor!!.setAlignment(Align.left)
citiesTable.add(city.population.population.toString()).actor!!.setAlignment(Align.center)
citiesTable.add(city.cityStats.currentCityStats.food.roundToInt().toString()).actor!!.setAlignment(Align.center)
citiesTable.add(city.cityStats.currentCityStats.gold.roundToInt().toString()).actor!!.setAlignment(Align.center)
citiesTable.add(city.cityStats.currentCityStats.science.roundToInt().toString()).actor!!.setAlignment(Align.center)
citiesTable.add(city.cityStats.currentCityStats.production.roundToInt().toString()).actor!!.setAlignment(Align.center)
citiesTable.add(city.cityStats.currentCityStats.culture.roundToInt().toString()).actor!!.setAlignment(Align.center)
citiesTable.add(city.cityStats.currentCityStats.happiness.roundToInt().toString()).actor!!.setAlignment(Align.center)
citiesTable.row()
}
citiesTable.pack()
}
private fun getUnitTable(): Table {
val table=Table(skin).apply { defaults().pad(5f) }
table.add("Name".tr())
table.add("Action".tr())
table.add("Strength".tr())
table.add("Ranged strength".tr())
table.add("Movement".tr())
table.add("Closest city".tr())
table.add("Promotions".tr())
table.add("Health".tr())
table.row()
table.addSeparator()
for(unit in viewingPlayer.getCivUnits().sortedWith(compareBy({it.name},{!it.due},
{it.currentMovement<0.1f},{abs(it.currentTile.position.x)+abs(it.currentTile.position.y)}))) {
val baseUnit = unit.baseUnit()
val button = TextButton(unit.name.tr(), skin)
button.onClick {
UncivGame.Current.setWorldScreen()
UncivGame.Current.worldScreen.mapHolder.setCenterPosition(unit.currentTile.position)
}
table.add(button).left()
val mapUnitAction = unit.mapUnitAction
if (mapUnitAction != null) table.add(if(mapUnitAction.name().startsWith("Fortify")) "Fortify".tr() else mapUnitAction.name().tr()) else table.add()
if(baseUnit.strength>0) table.add(baseUnit.strength.toString()) else table.add()
if(baseUnit.rangedStrength>0) table.add(baseUnit.rangedStrength.toString()) else table.add()
table.add(DecimalFormat("0.#").format(unit.currentMovement)+"/"+unit.getMaxMovement())
val closestCity = unit.getTile().getTilesInDistance(3).firstOrNull{it.isCityCenter()}
if (closestCity!=null) table.add(closestCity.getCity()!!.name.tr()) else table.add()
val promotionsTable = Table()
val promotionsForUnit = unit.civInfo.gameInfo.ruleSet.unitPromotions.values.filter { unit.promotions.promotions.contains(it.name) } // force same sorting as on picker (.sorted() would be simpler code, but...)
for(promotion in promotionsForUnit)
promotionsTable.add(ImageGetter.getPromotionIcon(promotion.name))
if (unit.promotions.canBePromoted()) promotionsTable.add(ImageGetter.getImage("OtherIcons/Star").apply { color= Color.GOLDENROD }).size(24f).padLeft(8f)
if (unit.canUpgrade()) promotionsTable.add(ImageGetter.getUnitIcon(baseUnit.upgradesTo!!, Color.GREEN)).size(28f).padLeft(8f)
promotionsTable.onClick {
if (unit.promotions.canBePromoted() || unit.promotions.promotions.isNotEmpty()) {
UncivGame.Current.setScreen(PromotionPickerScreen(unit))
}
}
table.add(promotionsTable)
if (unit.health < 100) table.add(unit.health.toString()) else table.add()
table.row()
}
table.pack()
return table
}
private fun playerKnows(civ:CivilizationInfo) = civ==viewingPlayer ||
viewingPlayer.diplomacy.containsKey(civ.civName)
private fun getDiplomacyGroup(): Group {
val relevantCivs = viewingPlayer.gameInfo.civilizations.filter { !it.isBarbarian() && !it.isCityState() }
val freeWidth = stage.width
val freeHeight = stage.height - topTable.height
val group = Group()
group.setSize(freeWidth,freeHeight)
val civGroups = HashMap<String, Actor>()
val civLines = HashMap<String, MutableSet<Actor>>()
for(i in 0..relevantCivs.lastIndex){
val civ = relevantCivs[i]
val civGroup = getCivGroup(civ, "", viewingPlayer)
val vector = HexMath.getVectorForAngle(2 * Math.PI.toFloat() *i / relevantCivs.size)
civGroup.center(group)
civGroup.moveBy(vector.x*freeWidth/2.5f, vector.y*freeHeight/2.5f)
civGroup.touchable = Touchable.enabled
civGroup.onClick {
onCivClicked(civLines, civ.civName)
}
civGroups[civ.civName]=civGroup
group.addActor(civGroup)
}
for(civ in relevantCivs.filter { playerKnows(it) && !it.isDefeated() })
for(diplomacy in civ.diplomacy.values.
filter { !it.otherCiv().isBarbarian() && !it.otherCiv().isCityState()
&& playerKnows(it.otherCiv()) && !it.otherCiv().isDefeated()}){
val civGroup = civGroups[civ.civName]!!
val otherCivGroup = civGroups[diplomacy.otherCivName]!!
if (!civLines.containsKey(civ.civName))
civLines[civ.civName] = mutableSetOf()
val statusLine = ImageGetter.getLine(civGroup.x+civGroup.width/2,civGroup.y+civGroup.height/2,
otherCivGroup.x+otherCivGroup.width/2,otherCivGroup.y+otherCivGroup.height/2,3f)
// draw a parallel line for additional relationships
if (diplomacy.hasOpenBorders ||
diplomacy.diplomaticStatus == DiplomaticStatus.War ||
diplomacy.totalOfScienceDuringRA > 0) {
val lineAngle = (statusLine.rotation-90) * Math.PI / 180
val shiftX = 4f*cos(lineAngle).toFloat()
val shiftY = 4f*sin(lineAngle).toFloat()
val secondaryLine = ImageGetter.getLine(civGroup.x+civGroup.width/2+shiftX,civGroup.y+civGroup.height/2+shiftY,
otherCivGroup.x+otherCivGroup.width/2+shiftX,otherCivGroup.y+otherCivGroup.height/2+shiftY,2f)
secondaryLine.color = when {
diplomacy.diplomaticStatus == DiplomaticStatus.War -> Color.RED
diplomacy.hasOpenBorders -> Color.CYAN
diplomacy.totalOfScienceDuringRA > 0 -> Color.BLUE
else -> Color.WHITE
}
civLines[civ.civName]!!.add(secondaryLine)
group.addActor(secondaryLine)
secondaryLine.toBack()
}
val diplomacyLevel = diplomacy.diplomaticModifiers.values.sum()
statusLine.color = getColorForDiplomacyLevel(diplomacyLevel)
civLines[civ.civName]!!.add(statusLine)
group.addActor(statusLine)
statusLine.toBack()
}
return group
}
private fun onCivClicked(civLines: HashMap<String, MutableSet<Actor>>, name: String) {
// ignore the clicks on "dead" civilizations, and remember the selected one
val selectedLines = civLines[name] ?: return
// let's check whether lines of all civs are visible (except selected one)
var atLeastOneLineVisible = false
var allAreLinesInvisible = true
for (lines in civLines.values) {
// skip the civilization selected by user, and civilizations with no lines
if (lines == selectedLines || lines.isEmpty()) continue
val visibility = lines.first().isVisible
atLeastOneLineVisible = atLeastOneLineVisible || visibility
allAreLinesInvisible = allAreLinesInvisible && visibility
// check whether both visible and invisible lines are present
if (atLeastOneLineVisible && !allAreLinesInvisible) {
// invert visibility of the selected civ's lines
selectedLines.forEach{ it.isVisible = !it.isVisible }
return
}
}
if (selectedLines.first().isVisible)
// invert visibility of all lines except selected one
civLines.filter{ it.key != name }.forEach{ it.value.forEach{line -> line.isVisible = !line.isVisible} }
else
// it happens only when all are visible except selected one
// invert visibility of the selected civ's lines
selectedLines.forEach{ it.isVisible = !it.isVisible }
}
private fun getColorForDiplomacyLevel(value: Float): Color {
var amplitude = min(1.0f,abs(value)/80) // 80 = RelationshipLevel.Ally
val shade = max(0.5f - amplitude, 0.0f)
amplitude = max(amplitude, 0.5f)
return Color( if (sign(value) < 0) amplitude else shade,
if (sign(value) > 0) amplitude else shade,
shade,1.0f)
}
private fun getResourcesTable(): Table {
val resourcesTable=Table().apply { defaults().pad(10f) }
val resourceDrilldown = viewingPlayer.detailedCivResources
// First row of table has all the icons
resourcesTable.add()
val resources = resourceDrilldown.map { it.resource }
.filter { it.resourceType!=ResourceType.Bonus }.distinct().sortedBy { it.resourceType }
var visibleLabel: Label? = null
for(resource in resources) {
// Create a group of label and icon for each resource.
val resourceImage = ImageGetter.getResourceImage(resource.name,50f)
val resourceLabel = resource.name.toLabel()
val labelPadding = 10f
// Using a table here leads to spacing issues
// due to different label lengths.
val holder = Group()
resourceImage.onClick {
if (visibleLabel != null)
visibleLabel!!.setVisible(false)
resourceLabel.setVisible(true)
visibleLabel = resourceLabel
}
holder.addActor(resourceImage)
holder.addActor(resourceLabel)
holder.setSize(resourceImage.getWidth(),
resourceImage.getHeight() + resourceLabel.getHeight() + labelPadding)
// Center-align all labels, but right-align the last couple resources' labels
// because they may get clipped otherwise. The leftmost label should be fine
// center-aligned (if there are more than 2 resources), because the left side
// has more padding.
val alignFactor = when {
(resources.indexOf(resource) + 2 >= resources.count()) -> 1
else -> 2
}
resourceLabel.moveBy((resourceImage.getWidth() - resourceLabel.getWidth()) / alignFactor,
resourceImage.getHeight() + labelPadding)
resourceLabel.setVisible(false)
resourcesTable.add(holder)
}
resourcesTable.addSeparator()
val origins = resourceDrilldown.map { it.origin }.distinct()
for(origin in origins){
resourcesTable.add(origin.toLabel())
for(resource in resources){
val resourceSupply = resourceDrilldown.firstOrNull { it.resource==resource && it.origin==origin }
if(resourceSupply==null) resourcesTable.add()
else resourcesTable.add(resourceSupply.amount.toString().toLabel())
}
resourcesTable.row()
}
resourcesTable.add("Total".toLabel())
for(resource in resources){
val sum = resourceDrilldown.filter { it.resource==resource }.sumBy { it.amount }
resourcesTable.add(sum.toString().toLabel())
}
return resourcesTable
}
companion object {
fun getCivGroup(civ: CivilizationInfo, afterCivNameText:String,currentPlayer:CivilizationInfo): Table {
val civGroup = Table()
var labelText = civ.civName.tr()+afterCivNameText
var labelColor=Color.WHITE
val backgroundColor:Color
if (civ.isDefeated()) {
civGroup.add(ImageGetter.getImage("OtherIcons/DisbandUnit")).size(30f)
backgroundColor = Color.LIGHT_GRAY
labelColor = Color.BLACK
} else if (currentPlayer==civ || UncivGame.Current.viewEntireMapForDebug
|| currentPlayer.knows(civ) || currentPlayer.isDefeated() || currentPlayer.victoryManager.hasWon()) {
civGroup.add(ImageGetter.getNationIndicator(civ.nation, 30f))
backgroundColor = civ.nation.getOuterColor()
labelColor = civ.nation.getInnerColor()
} else {
backgroundColor = Color.DARK_GRAY
labelText = "???"
}
civGroup.background = ImageGetter.getRoundedEdgeTableBackground(backgroundColor)
val label = labelText.toLabel(labelColor)
label.setAlignment(Align.center)
civGroup.add(label).pad(10f)
civGroup.pack()
return civGroup
}
}
}