2020-04-13 18:53:23 +00:00
package com.unciv.ui
2018-06-26 20:08:21 +00:00
2020-04-08 13:30:10 +00:00
import com.unciv.ui.utils.AutoScrollPane as ScrollPane
2018-12-06 11:33:10 +00:00
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.Actor
import com.badlogic.gdx.scenes.scene2d.Group
2020-03-06 08:31:23 +00:00
import com.badlogic.gdx.scenes.scene2d.Touchable
2019-05-22 19:06:40 +00:00
import com.badlogic.gdx.scenes.scene2d.ui.*
2018-07-01 13:18:25 +00:00
import com.badlogic.gdx.utils.Align
2019-11-23 20:28:23 +00:00
import com.unciv.UncivGame
2018-12-06 11:33:10 +00:00
import com.unciv.logic.HexMath
2020-02-21 09:49:55 +00:00
import com.unciv.logic.city.CityInfo
2018-08-31 12:01:42 +00:00
import com.unciv.logic.civilization.CivilizationInfo
2019-02-10 14:34:46 +00:00
import com.unciv.logic.civilization.diplomacy.DiplomaticStatus
2018-07-30 10:30:13 +00:00
import com.unciv.logic.trade.Trade
2018-08-31 12:01:42 +00:00
import com.unciv.logic.trade.TradeOffersList
2019-12-13 11:58:05 +00:00
import com.unciv.models.ruleset.tile.ResourceType
2019-12-18 21:32:31 +00:00
import com.unciv.models.translations.tr
2019-11-23 20:30:25 +00:00
import com.unciv.ui.cityscreen.CityScreen
2020-03-19 07:57:53 +00:00
import com.unciv.ui.pickerscreens.PromotionPickerScreen
2018-06-26 20:08:21 +00:00
import com.unciv.ui.utils.*
2020-04-13 18:53:23 +00:00
import com.unciv.Constants
2018-12-03 14:00:29 +00:00
import java.text.DecimalFormat
2020-02-08 18:46:42 +00:00
import kotlin.math.*
2018-06-26 20:08:21 +00:00
2020-04-15 20:19:09 +00:00
class EmpireOverviewScreen ( private val viewingPlayer : CivilizationInfo , private val defaultPage : String = " Cities " ) : CameraStageBaseScreen ( ) {
2019-12-21 17:50:01 +00:00
private val topTable = Table ( ) . apply { defaults ( ) . pad ( 10f ) }
private val centerTable = Table ( ) . apply { defaults ( ) . pad ( 20f ) }
2019-06-14 12:03:53 +00:00
2018-06-26 20:08:21 +00:00
init {
2019-11-23 20:28:23 +00:00
onBackButtonClicked { UncivGame . Current . setWorldScreen ( ) }
2020-04-15 20:19:09 +00:00
val clicks = HashMap < String , ( ) -> Unit > ( )
2018-07-01 13:18:25 +00:00
2020-04-15 20:19:09 +00:00
val closeButton = Constants . close . toTextButton ( )
2019-11-23 20:28:23 +00:00
closeButton . onClick { UncivGame . Current . setWorldScreen ( ) }
2018-06-26 20:08:21 +00:00
closeButton . y = stage . height - closeButton . height - 5
2018-07-06 13:28:42 +00:00
topTable . add ( closeButton )
2020-04-15 20:19:09 +00:00
val setCityInfoButton = " Cities " . toTextButton ( )
2018-07-06 13:28:42 +00:00
val setCities = {
centerTable . clear ( )
centerTable . add ( getCityInfoTable ( ) )
centerTable . pack ( )
}
2020-04-15 20:19:09 +00:00
clicks [ " Cities " ] = setCities
2018-09-23 07:39:56 +00:00
setCityInfoButton . onClick ( setCities )
2018-07-06 13:28:42 +00:00
topTable . add ( setCityInfoButton )
2020-04-15 20:19:09 +00:00
val setStatsInfoButton = " Stats " . toTextButton ( )
val setStats = {
2019-12-13 12:31:42 +00:00
game . settings . addCompletedTutorialTask ( " See your stats breakdown " )
2018-07-06 13:28:42 +00:00
centerTable . clear ( )
2019-06-27 09:01:08 +00:00
centerTable . add ( ScrollPane ( Table ( ) . apply {
defaults ( ) . pad ( 40f )
add ( getHappinessTable ( ) ) . top ( )
add ( getGoldTable ( ) ) . top ( )
add ( getScienceTable ( ) ) . top ( )
add ( getGreatPeopleTable ( ) ) . top ( )
2019-05-22 19:06:40 +00:00
} ) )
2018-07-06 13:28:42 +00:00
centerTable . pack ( )
}
2020-04-15 20:19:09 +00:00
clicks [ " Stats " ] = setStats
setStatsInfoButton . onClick ( setStats )
2018-07-06 13:28:42 +00:00
topTable . add ( setStatsInfoButton )
2018-06-26 20:08:21 +00:00
2020-04-15 20:19:09 +00:00
val setCurrentTradesButton = " Trades " . toTextButton ( )
2018-09-23 07:39:56 +00:00
setCurrentTradesButton . onClick {
2018-07-06 13:28:42 +00:00
centerTable . clear ( )
2020-03-03 19:45:39 +00:00
centerTable . add ( ScrollPane ( getTradesTable ( ) ) ) . height ( stage . height * 0.8f ) // so it doesn't cover the navigation buttons
2018-07-06 13:28:42 +00:00
centerTable . pack ( )
}
topTable . add ( setCurrentTradesButton )
2020-03-03 19:45:39 +00:00
if ( viewingPlayer . diplomacy . values . all { it . trades . isEmpty ( ) } )
2019-06-19 17:52:26 +00:00
setCurrentTradesButton . disable ( )
2018-07-01 13:18:25 +00:00
2020-04-15 20:19:09 +00:00
val setUnitsButton = " Units " . toTextButton ( )
2019-02-13 21:53:50 +00:00
setUnitsButton . onClick {
2018-07-19 10:29:52 +00:00
centerTable . clear ( )
2020-03-09 20:13:47 +00:00
centerTable . add ( ScrollPane ( getUnitTable ( ) ) . apply { setOverscroll ( false , false ) } ) . height ( stage . height * 0.8f )
2018-07-19 10:29:52 +00:00
centerTable . pack ( )
}
2020-03-03 19:45:39 +00:00
topTable . add ( setUnitsButton )
2018-07-19 10:29:52 +00:00
2018-12-06 11:33:10 +00:00
2020-04-15 20:19:09 +00:00
val setDiplomacyButton = " Diplomacy " . toTextButton ( )
2018-12-06 11:33:10 +00:00
setDiplomacyButton . onClick {
centerTable . clear ( )
2020-03-03 19:45:39 +00:00
centerTable . add ( getDiplomacyGroup ( ) ) . height ( stage . height * 0.8f )
2018-12-06 11:33:10 +00:00
centerTable . pack ( )
}
2019-06-14 12:03:53 +00:00
topTable . add ( setDiplomacyButton )
2020-04-15 20:19:09 +00:00
val setResourcesButton = " Resources " . toTextButton ( )
val setResources = {
2019-06-14 12:03:53 +00:00
centerTable . clear ( )
2020-03-03 19:45:39 +00:00
centerTable . add ( ScrollPane ( getResourcesTable ( ) ) ) . size ( stage . width * 0.8f , stage . height * 0.8f )
2019-06-14 12:03:53 +00:00
centerTable . pack ( )
}
2020-04-15 20:19:09 +00:00
clicks [ " Resources " ] = setResources
setResourcesButton . onClick ( setResources )
2019-06-14 12:03:53 +00:00
topTable . add ( setResourcesButton )
2020-03-03 19:45:39 +00:00
if ( viewingPlayer . detailedCivResources . isEmpty ( ) )
2019-06-19 17:52:26 +00:00
setResourcesButton . disable ( )
2018-12-06 11:33:10 +00:00
2018-07-06 13:28:42 +00:00
topTable . pack ( )
2020-04-15 20:19:09 +00:00
clicks [ defaultPage ] ?. invoke ( )
2019-05-22 19:06:40 +00:00
val table = Table ( )
table . add ( topTable ) . row ( )
table . add ( centerTable ) . expand ( ) . row ( )
table . setFillParent ( true )
stage . addActor ( table )
2018-07-06 13:28:42 +00:00
}
private fun getTradesTable ( ) : Table {
2018-07-10 06:07:36 +00:00
val tradesTable = Table ( ) . apply { defaults ( ) . pad ( 10f ) }
2020-04-19 13:36:13 +00:00
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 ( )
}
2018-07-06 13:28:42 +00:00
return tradesTable
}
2018-08-31 12:01:42 +00:00
private fun createTradeTable ( trade : Trade , otherCiv : CivilizationInfo ) : Table {
val generalTable = Table ( skin )
2019-12-14 19:04:29 +00:00
generalTable . add ( createOffersTable ( viewingPlayer , trade . ourOffers , trade . theirOffers . size ) ) . fillY ( )
2019-11-17 19:37:27 +00:00
generalTable . add ( createOffersTable ( otherCiv , trade . theirOffers , trade . ourOffers . size ) ) . fillY ( )
2018-08-31 12:01:42 +00:00
return generalTable
}
2019-05-22 20:38:24 +00:00
2018-08-31 12:01:42 +00:00
private fun createOffersTable ( civ : CivilizationInfo , offersList : TradeOffersList , numberOfOtherSidesOffers : Int ) : Table {
val table = Table ( )
2018-07-06 13:28:42 +00:00
table . defaults ( ) . pad ( 10f )
2019-09-14 20:17:52 +00:00
table . background = ImageGetter . getBackground ( civ . nation . getOuterColor ( ) )
2019-10-31 10:01:23 +00:00
table . add ( civ . civName . toLabel ( civ . nation . getInnerColor ( ) ) ) . row ( )
2018-11-23 12:36:22 +00:00
table . addSeparator ( )
2018-08-31 12:01:42 +00:00
for ( offer in offersList ) {
2019-11-17 19:37:27 +00:00
var offerText = offer . getOfferText ( )
if ( ! offerText . contains ( " \n " ) ) offerText += " \n "
2019-10-31 10:01:23 +00:00
table . add ( offerText . toLabel ( civ . nation . getInnerColor ( ) ) ) . row ( )
2018-07-06 13:28:42 +00:00
}
2018-08-31 12:01:42 +00:00
for ( i in 1. . numberOfOtherSidesOffers - offersList . size )
2019-11-17 19:37:27 +00:00
table . add ( " \n " . toLabel ( ) ) . row ( ) // we want both sides of the general table to have the same number of rows
2018-07-06 13:28:42 +00:00
return table
2018-06-26 20:08:21 +00:00
}
2018-08-31 12:01:42 +00:00
2018-07-06 13:28:42 +00:00
private fun getHappinessTable ( ) : Table {
2018-06-26 20:08:21 +00:00
val happinessTable = Table ( skin )
happinessTable . defaults ( ) . pad ( 5f )
2020-04-15 20:17:03 +00:00
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 ( )
2018-11-24 20:48:42 +00:00
happinessTable . addSeparator ( )
2019-07-10 17:05:29 +00:00
2019-12-14 19:04:29 +00:00
val happinessBreakdown = viewingPlayer . stats ( ) . getHappinessBreakdown ( )
2019-07-10 17:05:29 +00:00
2019-10-27 15:30:56 +00:00
for ( entry in happinessBreakdown . filterNot { it . value . roundToInt ( ) == 0 } ) {
2018-08-04 18:36:08 +00:00
happinessTable . add ( entry . key . tr ( ) )
2020-04-15 20:17:03 +00:00
happinessTable . add ( entry . value . roundToInt ( ) . toString ( ) ) . right ( ) . row ( )
2018-06-26 20:08:21 +00:00
}
2018-08-04 18:36:08 +00:00
happinessTable . add ( " Total " . tr ( ) )
2020-04-15 20:17:03 +00:00
happinessTable . add ( happinessBreakdown . values . sum ( ) . roundToInt ( ) . toString ( ) ) . right ( )
2018-06-26 20:08:21 +00:00
happinessTable . pack ( )
return happinessTable
}
2018-07-06 13:28:42 +00:00
private fun getGoldTable ( ) : Table {
2018-06-26 20:08:21 +00:00
val goldTable = Table ( skin )
goldTable . defaults ( ) . pad ( 5f )
2020-04-15 20:17:03 +00:00
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 ( )
2018-11-24 20:48:42 +00:00
goldTable . addSeparator ( )
2018-06-26 20:08:21 +00:00
var total = 0f
2019-12-14 19:04:29 +00:00
for ( entry in viewingPlayer . stats ( ) . getStatMapForNextTurn ( ) ) {
2018-06-26 20:08:21 +00:00
if ( entry . value . gold == 0f ) continue
2018-08-04 18:36:08 +00:00
goldTable . add ( entry . key . tr ( ) )
2020-04-15 20:17:03 +00:00
goldTable . add ( entry . value . gold . roundToInt ( ) . toString ( ) ) . right ( ) . row ( )
2018-06-26 20:08:21 +00:00
total += entry . value . gold
}
2018-08-04 18:36:08 +00:00
goldTable . add ( " Total " . tr ( ) )
2020-04-15 20:17:03 +00:00
goldTable . add ( total . roundToInt ( ) . toString ( ) ) . right ( )
2018-06-26 20:08:21 +00:00
goldTable . pack ( )
return goldTable
}
2018-11-13 19:10:23 +00:00
2019-06-27 09:01:08 +00:00
private fun getScienceTable ( ) : Table {
val scienceTable = Table ( skin )
scienceTable . defaults ( ) . pad ( 5f )
2020-04-15 20:17:03 +00:00
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 ( )
2019-06-27 09:01:08 +00:00
scienceTable . addSeparator ( )
2019-12-14 19:04:29 +00:00
val scienceStats = viewingPlayer . stats ( ) . getStatMapForNextTurn ( )
2019-06-27 09:01:08 +00:00
. filter { it . value . science != 0f }
for ( entry in scienceStats ) {
scienceTable . add ( entry . key . tr ( ) )
2020-04-15 20:17:03 +00:00
scienceTable . add ( entry . value . science . roundToInt ( ) . toString ( ) ) . right ( ) . row ( )
2019-06-27 09:01:08 +00:00
}
scienceTable . add ( " Total " . tr ( ) )
2020-04-15 20:17:03 +00:00
scienceTable . add ( scienceStats . values . map { it . science } . sum ( ) . roundToInt ( ) . toString ( ) ) . right ( )
2019-06-27 09:01:08 +00:00
scienceTable . pack ( )
return scienceTable
}
2018-11-13 19:10:23 +00:00
private fun getGreatPeopleTable ( ) : Table {
val greatPeopleTable = Table ( skin )
2019-12-14 19:04:29 +00:00
val greatPersonPoints = viewingPlayer . greatPeople . greatPersonPoints . toHashMap ( )
val greatPersonPointsPerTurn = viewingPlayer . getGreatPersonPointsForNextTurn ( ) . toHashMap ( )
val pointsToGreatPerson = viewingPlayer . greatPeople . pointsForNextGreatPerson
2018-11-13 19:10:23 +00:00
greatPeopleTable . defaults ( ) . pad ( 5f )
2020-04-15 20:17:03 +00:00
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 ( )
2018-11-24 19:15:22 +00:00
greatPeopleTable . addSeparator ( )
2018-11-13 19:10:23 +00:00
greatPeopleTable . add ( )
2019-05-04 18:17:18 +00:00
greatPeopleTable . add ( " Current points " . tr ( ) )
greatPeopleTable . add ( " Points per turn " . tr ( ) ) . row ( )
2018-11-13 19:10:23 +00:00
2019-12-14 19:04:29 +00:00
val mapping = viewingPlayer . greatPeople . statToGreatPersonMapping
2018-11-13 19:10:23 +00:00
for ( entry in mapping ) {
2018-12-10 16:10:19 +00:00
greatPeopleTable . add ( entry . value . tr ( ) )
2018-11-13 19:10:23 +00:00
greatPeopleTable . add ( greatPersonPoints [ entry . key ] !! . toInt ( ) . toString ( ) + " / " + pointsToGreatPerson )
greatPeopleTable . add ( greatPersonPointsPerTurn [ entry . key ] !! . toInt ( ) . toString ( ) ) . row ( )
}
2019-12-14 19:04:29 +00:00
val pointsForGreatGeneral = viewingPlayer . greatPeople . greatGeneralPoints . toString ( )
val pointsForNextGreatGeneral = viewingPlayer . greatPeople . pointsForNextGreatGeneral . toString ( )
2018-12-26 10:42:22 +00:00
greatPeopleTable . add ( " Great General " . tr ( ) )
2019-02-13 21:53:50 +00:00
greatPeopleTable . add ( " $pointsForGreatGeneral / $pointsForNextGreatGeneral " ) . row ( )
2018-11-13 19:10:23 +00:00
greatPeopleTable . pack ( )
return greatPeopleTable
}
2018-07-06 13:28:42 +00:00
private fun getCityInfoTable ( ) : Table {
2019-09-10 14:41:45 +00:00
val iconSize = 50f //if you set this too low, there is a chance that the tables will be misaligned
2018-07-01 13:18:25 +00:00
val padding = 5f
2020-02-21 09:49:55 +00:00
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 = " "
}
2018-07-01 13:18:25 +00:00
val cityInfoTableIcons = Table ( skin )
cityInfoTableIcons . defaults ( ) . pad ( padding ) . align ( Align . center )
2019-10-31 10:01:23 +00:00
cityInfoTableIcons . add ( " Cities " . toLabel ( fontSize = 24 ) ) . colspan ( 8 ) . align ( Align . center ) . row ( )
2018-07-01 13:18:25 +00:00
2020-02-21 09:49:55 +00:00
val citySortIcon = ImageGetter . getUnitIcon ( " Settler " ) . surroundWithCircle ( iconSize )
citySortIcon . onClick { sortOnClick ( " City " ) }
cityInfoTableIcons . add ( citySortIcon ) . align ( Align . left )
2018-06-26 20:08:21 +00:00
2020-02-21 09:49:55 +00:00
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 )
2018-06-26 20:08:21 +00:00
}
2020-02-21 09:49:55 +00:00
cityInfoTableIcons . pack ( )
fillCitiesTable ( cityInfoTableDetails , " City " , false )
2018-07-01 13:18:25 +00:00
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
2018-08-04 18:36:08 +00:00
cityInfoTableTotal . add ( " Total " . tr ( ) )
2019-12-14 19:04:29 +00:00
cityInfoTableTotal . add ( viewingPlayer . cities . sumBy { it . population . population } . toString ( ) ) . actor !! . setAlignment ( Align . center )
2018-07-01 13:18:25 +00:00
cityInfoTableTotal . add ( ) //an intended empty space
2019-12-14 19:04:29 +00:00
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 )
2018-07-01 13:18:25 +00:00
cityInfoTableTotal . add ( ) //an intended empty space
2019-12-14 19:04:29 +00:00
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 )
2018-07-01 13:18:25 +00:00
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 )
2020-02-21 09:49:55 +00:00
// place the button for sorting by city name on top of the cities names
citySortIcon . width = max ( iconSize , cityInfoTableDetails . width - ( iconSize + padding ) * 8 )
2018-07-01 13:18:25 +00:00
table . add ( cityInfoTableIcons ) . row ( )
2019-05-22 19:06:40 +00:00
table . add ( cityInfoScrollPane ) . width ( cityInfoTableDetails . width ) . row ( )
2018-07-01 13:18:25 +00:00
table . add ( cityInfoTableTotal )
table . pack ( )
return table
2018-06-26 20:08:21 +00:00
}
2018-07-19 10:29:52 +00:00
2020-02-21 09:49:55 +00:00
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 ) {
2020-03-23 22:09:06 +00:00
val button = Button ( city . name . toLabel ( ) , skin )
2020-02-21 09:49:55 +00:00
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 ( )
}
2020-02-08 18:46:42 +00:00
private fun getUnitTable ( ) : Table {
2018-07-19 10:29:52 +00:00
val table = Table ( skin ) . apply { defaults ( ) . pad ( 5f ) }
2018-08-04 18:36:08 +00:00
table . add ( " Name " . tr ( ) )
2019-05-22 20:38:24 +00:00
table . add ( " Action " . tr ( ) )
2018-08-04 18:36:08 +00:00
table . add ( " Strength " . tr ( ) )
table . add ( " Ranged strength " . tr ( ) )
table . add ( " Movement " . tr ( ) )
table . add ( " Closest city " . tr ( ) )
2020-03-19 07:57:53 +00:00
table . add ( " Promotions " . tr ( ) )
table . add ( " Health " . tr ( ) )
2018-07-19 10:29:52 +00:00
table . row ( )
2018-11-24 19:15:22 +00:00
table . addSeparator ( )
2020-03-28 22:51:33 +00:00
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 ) } ) ) ) {
2018-08-16 06:13:34 +00:00
val baseUnit = unit . baseUnit ( )
2019-05-22 19:06:40 +00:00
val button = TextButton ( unit . name . tr ( ) , skin )
button . onClick {
2019-11-23 20:28:23 +00:00
UncivGame . Current . setWorldScreen ( )
2020-01-02 18:02:38 +00:00
UncivGame . Current . worldScreen . mapHolder . setCenterPosition ( unit . currentTile . position )
2019-05-22 19:06:40 +00:00
}
table . add ( button ) . left ( )
2019-05-23 19:21:46 +00:00
val mapUnitAction = unit . mapUnitAction
2019-10-27 15:30:56 +00:00
if ( mapUnitAction != null ) table . add ( if ( mapUnitAction . name ( ) . startsWith ( " Fortify " ) ) " Fortify " . tr ( ) else mapUnitAction . name ( ) . tr ( ) ) else table . add ( )
2018-07-19 10:29:52 +00:00
if ( baseUnit . strength > 0 ) table . add ( baseUnit . strength . toString ( ) ) else table . add ( )
if ( baseUnit . rangedStrength > 0 ) table . add ( baseUnit . rangedStrength . toString ( ) ) else table . add ( )
2018-12-03 14:00:29 +00:00
table . add ( DecimalFormat ( " 0.# " ) . format ( unit . currentMovement ) + " / " + unit . getMaxMovement ( ) )
2018-07-19 10:29:52 +00:00
val closestCity = unit . getTile ( ) . getTilesInDistance ( 3 ) . firstOrNull { it . isCityCenter ( ) }
2020-03-28 22:51:33 +00:00
if ( closestCity != null ) table . add ( closestCity . getCity ( ) !! . name . tr ( ) ) else table . add ( )
2020-03-19 07:57:53 +00:00
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 )
2020-03-22 18:42:22 +00:00
if ( unit . health < 100 ) table . add ( unit . health . toString ( ) ) else table . add ( )
2018-07-19 10:29:52 +00:00
table . row ( )
}
table . pack ( )
return table
}
2018-12-06 11:33:10 +00:00
2018-12-06 14:12:31 +00:00
2020-02-08 18:46:42 +00:00
private fun playerKnows ( civ : CivilizationInfo ) = civ == viewingPlayer ||
2019-12-14 19:04:29 +00:00
viewingPlayer . diplomacy . containsKey ( civ . civName )
2018-12-06 14:12:31 +00:00
2020-02-08 18:46:42 +00:00
private fun getDiplomacyGroup ( ) : Group {
2019-12-14 19:04:29 +00:00
val relevantCivs = viewingPlayer . gameInfo . civilizations . filter { ! it . isBarbarian ( ) && ! it . isCityState ( ) }
2019-12-21 17:50:01 +00:00
val freeWidth = stage . width
val freeHeight = stage . height - topTable . height
2018-12-06 11:33:10 +00:00
val group = Group ( )
2020-02-08 18:46:42 +00:00
group . setSize ( freeWidth , freeHeight )
2019-04-28 21:25:02 +00:00
val civGroups = HashMap < String , Actor > ( )
2020-02-08 18:46:42 +00:00
val civLines = HashMap < String , MutableSet < Actor > > ( )
2019-04-28 21:25:02 +00:00
for ( i in 0. . relevantCivs . lastIndex ) {
2018-12-06 11:33:10 +00:00
val civ = relevantCivs [ i ]
2018-12-06 14:12:31 +00:00
2019-12-14 19:04:29 +00:00
val civGroup = getCivGroup ( civ , " " , viewingPlayer )
2018-12-06 11:33:10 +00:00
2020-01-03 08:33:01 +00:00
val vector = HexMath . getVectorForAngle ( 2 * Math . PI . toFloat ( ) * i / relevantCivs . size )
2018-12-06 11:33:10 +00:00
civGroup . center ( group )
2020-02-08 19:58:03 +00:00
civGroup . moveBy ( vector . x * freeWidth / 2.5f , vector . y * freeHeight / 2.5f )
2020-03-06 08:31:23 +00:00
civGroup . touchable = Touchable . enabled
2020-02-08 18:46:42 +00:00
civGroup . onClick {
onCivClicked ( civLines , civ . civName )
}
2018-12-06 11:33:10 +00:00
2019-04-28 21:25:02 +00:00
civGroups [ civ . civName ] = civGroup
2018-12-06 11:33:10 +00:00
group . addActor ( civGroup )
}
2018-12-21 08:35:03 +00:00
for ( civ in relevantCivs . filter { playerKnows ( it ) && ! it . isDefeated ( ) } )
2019-05-10 10:33:12 +00:00
for ( diplomacy in civ . diplomacy . values .
2019-08-15 07:43:15 +00:00
filter { ! it . otherCiv ( ) . isBarbarian ( ) && ! it . otherCiv ( ) . isCityState ( )
2019-05-10 10:33:12 +00:00
&& playerKnows ( it . otherCiv ( ) ) && ! it . otherCiv ( ) . isDefeated ( ) } ) {
2019-04-28 21:25:02 +00:00
val civGroup = civGroups [ civ . civName ] !!
2019-05-10 10:37:37 +00:00
val otherCivGroup = civGroups [ diplomacy . otherCivName ] !!
2018-12-06 11:33:10 +00:00
2020-02-08 19:58:03 +00:00
if ( ! civLines . containsKey ( civ . civName ) )
civLines [ civ . civName ] = mutableSetOf ( )
2018-12-06 11:33:10 +00:00
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 )
2020-02-08 19:58:03 +00:00
// 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 ( )
2020-02-08 18:46:42 +00:00
}
2020-02-08 19:58:03 +00:00
val diplomacyLevel = diplomacy . diplomaticModifiers . values . sum ( )
statusLine . color = getColorForDiplomacyLevel ( diplomacyLevel )
2020-02-08 18:46:42 +00:00
civLines [ civ . civName ] !! . add ( statusLine )
2018-12-06 11:33:10 +00:00
group . addActor ( statusLine )
statusLine . toBack ( )
}
return group
}
2019-06-14 12:03:53 +00:00
2020-02-08 18:46:42 +00:00
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 )
}
2019-06-14 12:03:53 +00:00
private fun getResourcesTable ( ) : Table {
val resourcesTable = Table ( ) . apply { defaults ( ) . pad ( 10f ) }
2019-12-14 19:04:29 +00:00
val resourceDrilldown = viewingPlayer . detailedCivResources
2019-06-14 12:03:53 +00:00
// First row of table has all the icons
resourcesTable . add ( )
2019-06-15 19:30:07 +00:00
val resources = resourceDrilldown . map { it . resource }
. filter { it . resourceType != ResourceType . Bonus } . distinct ( ) . sortedBy { it . resourceType }
2020-02-01 18:31:12 +00:00
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 )
}
2019-06-14 12:03:53 +00:00
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 ( )
}
2019-06-15 19:30:07 +00:00
2019-06-14 12:03:53 +00:00
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
}
2019-06-19 16:20:25 +00:00
companion object {
fun getCivGroup ( civ : CivilizationInfo , afterCivNameText : String , currentPlayer : CivilizationInfo ) : Table {
val civGroup = Table ( )
2019-10-31 10:01:23 +00:00
var labelText = civ . civName . tr ( ) + afterCivNameText
var labelColor = Color . WHITE
2019-10-31 10:59:19 +00:00
val backgroundColor : Color
2019-06-19 16:20:25 +00:00
if ( civ . isDefeated ( ) ) {
civGroup . add ( ImageGetter . getImage ( " OtherIcons/DisbandUnit " ) ) . size ( 30f )
2019-10-31 10:59:19 +00:00
backgroundColor = Color . LIGHT _GRAY
2019-10-31 10:01:23 +00:00
labelColor = Color . BLACK
2020-04-13 20:21:19 +00:00
} else if ( currentPlayer == civ || UncivGame . Current . viewEntireMapForDebug
|| currentPlayer . knows ( civ ) || currentPlayer . isDefeated ( ) || currentPlayer . victoryManager . hasWon ( ) ) {
2019-08-15 07:43:15 +00:00
civGroup . add ( ImageGetter . getNationIndicator ( civ . nation , 30f ) )
2019-10-31 10:59:19 +00:00
backgroundColor = civ . nation . getOuterColor ( )
2019-10-31 10:01:23 +00:00
labelColor = civ . nation . getInnerColor ( )
2019-06-19 16:20:25 +00:00
} else {
2019-10-31 10:59:19 +00:00
backgroundColor = Color . DARK _GRAY
2019-10-31 10:01:23 +00:00
labelText = " ??? "
2019-06-19 16:20:25 +00:00
}
2019-12-11 20:48:18 +00:00
civGroup . background = ImageGetter . getRoundedEdgeTableBackground ( backgroundColor )
2019-10-31 10:01:23 +00:00
val label = labelText . toLabel ( labelColor )
label . setAlignment ( Align . center )
2019-06-19 16:20:25 +00:00
civGroup . add ( label ) . pad ( 10f )
civGroup . pack ( )
return civGroup
}
}
2018-06-26 20:08:21 +00:00
}