Empire overview resources (#6442)

* Empire Overview Resources: Vertical option

* Empire Overview Resources: Extra Info

* Empire Overview Resources: Tweaks

Co-authored-by: Yair Morgenstern <yairm210@hotmail.com>
This commit is contained in:
SomeTroglodyte
2022-03-28 16:31:19 +02:00
committed by GitHub
parent 870659d142
commit 7526114281
10 changed files with 1097 additions and 914 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

View File

@ -765,7 +765,6 @@ Territory = Territorium
Force = Kampfkraft
GOLDEN AGE = GOLDENES ZEITALTER
Golden Age = Goldenes Zeitalter
We Love The King Day = 'Wir lieben den König'-Tag
Global Effect = Globaler Effekt
[year] BC = [year] v. Chr.
[year] AD = [year] n. Chr.
@ -983,6 +982,15 @@ Far away = Weit entfernt
Status = Status
Location = Standort
Unimproved = Unverbessert
Number of tiles with this resource\nin your territory, without an\nappropriate improvement to use it = Anzahl der Felder mit dieser\nRessource innerhalb Deines Territoriums,\ndenen die entsprechende\nVerbesserung zu ihrer Nutzung fehlt.
We Love The King Day = 'Wir lieben den König'-Tag
WLTK+ = WLDK+
Number of your cities celebrating\n'We Love The King Day' thanks\nto access to this resource = Anzahl Deiner Städte, die den\n'Wir lieben den König'-Tag feiern,\ndank Zugang zu dieser Ressource.
WLTK demand = Bedarf für WLDK-Tag
WLTK- = WLDK-
Number of your cities\ndemanding this resource for\n'We Love The King Day' = Anzahl Deiner Städte, die nach\ndieser Ressource verlangen, um\nden 'Wir lieben den König'-Tag\nfeiern zu können.
# Victory
Science victory = Wissenschaftssieg
@ -5393,8 +5401,8 @@ The Maya measured time in days from what we would call 11th of August, 3114 BCE.
Unciv only displays ය B'ak'tuns, ඹ K'atuns and ම Tuns (from left to right) since that is enough to approximate gregorian calendar years. The Maya numerals are pretty obvious to understand. Have fun deciphering them! = Unciv zeigt nur ය B'ak'tuns, ඹ K'atuns und ම Tuns (von links nach rechts) an, da dies ausreicht, um gregorianische Kalenderjahre anzunähern. Die Maya-Ziffern sind ziemlich einfach zu verstehen. Viel Spaß beim Entschlüsseln!
Your cities will periodically demand different luxury goods to satisfy their desire for new things in life. = Deine Städte werden in regelmäßigen Abständen verschiedene Luxusgüter verlangen, um ihren Wunsch nach neuen Dingen im Leben zu befriedigen.
If you manage to acquire the demanded luxury by trade, expansion, or conquest, the city will celebrate We Love The King Day for 20 turns. = Wenn es dir gelingt, den geforderten Luxus durch Handel, Expansion oder Eroberung zu erwerben, wird die Stadt 20 Runden lang den Wir Lieben Den König Tag feiern.
During the We Love The King Day, the city will grow 25% faster. = Während des Wir Lieben Den König Tags wird die Stadt um 25 % schneller wachsen.
If you manage to acquire the demanded luxury by trade, expansion, or conquest, the city will celebrate We Love The King Day for 20 turns. = Wenn es dir gelingt, den geforderten Luxus durch Handel, Expansion oder Eroberung zu erwerben, wird die Stadt 20 Runden lang den 'Wir Lieben Den König'-Tag feiern.
During the We Love The King Day, the city will grow 25% faster. = Während des 'Wir Lieben Den König'-Tags wird die Stadt um 25 % schneller wachsen.
This means exploration and trade is important to grow your cities! = Das bedeutet, dass Erkundung und Handel wichtig sind, um deine Städte wachsen zu lassen!

View File

@ -770,7 +770,6 @@ Territory =
Force =
GOLDEN AGE =
Golden Age =
We Love The King Day =
Global Effect =
[year] BC =
[year] AD =
@ -988,6 +987,14 @@ Somewhere around [city] =
Far away =
Status =
Location =
Unimproved =
Number of tiles with this resource\nin your territory, without an\nappropriate improvement to use it =
We Love The King Day =
WLTK+ =
Number of your cities celebrating\n'We Love The King Day' thanks\nto access to this resource =
WLTK demand =
WLTK- =
Number of your cities\ndemanding this resource for\n'We Love The King Day' =
# Victory

View File

@ -44,8 +44,8 @@ enum class EmpireOverviewCategories(
= DiplomacyOverviewTab(viewingPlayer, overviewScreen, persistedData),
fun (viewingPlayer: CivilizationInfo) = viewingPlayer.diplomacy.isEmpty().toState()),
Resources("StatIcons/Happiness", 'R', Align.topLeft,
fun (viewingPlayer: CivilizationInfo, overviewScreen: EmpireOverviewScreen, _: EmpireOverviewTabPersistableData?)
= ResourcesOverviewTab(viewingPlayer, overviewScreen),
fun (viewingPlayer: CivilizationInfo, overviewScreen: EmpireOverviewScreen, persistedData: EmpireOverviewTabPersistableData?)
= ResourcesOverviewTab(viewingPlayer, overviewScreen, persistedData),
fun (viewingPlayer: CivilizationInfo) = viewingPlayer.detailedCivResources.isEmpty().toState()),
Religion("StatIcons/Faith", 'F', Align.top,
fun (viewingPlayer: CivilizationInfo, overviewScreen: EmpireOverviewScreen, persistedData: EmpireOverviewTabPersistableData?)

View File

@ -1,75 +1,222 @@
package com.unciv.ui.overviewscreen
import com.badlogic.gdx.scenes.scene2d.Group
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.ui.Label
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.scenes.scene2d.ui.WidgetGroup
import com.badlogic.gdx.utils.Align
import com.unciv.UncivGame
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.models.ruleset.tile.ResourceSupplyList
import com.unciv.models.ruleset.tile.ResourceType
import com.unciv.models.ruleset.tile.TileResource
import com.unciv.models.translations.tr
import com.unciv.ui.utils.ImageGetter
import com.unciv.ui.utils.addSeparator
import com.unciv.ui.utils.onClick
import com.unciv.ui.utils.toLabel
import com.unciv.ui.utils.*
import com.unciv.ui.utils.UncivTooltip.Companion.addTooltip
class ResourcesOverviewTab(
viewingPlayer: CivilizationInfo,
overviewScreen: EmpireOverviewScreen
overviewScreen: EmpireOverviewScreen,
persistedData: EmpireOverviewTabPersistableData? = null
) : EmpireOverviewTab(viewingPlayer, overviewScreen) {
class ResourcesTabPersistableData(
var vertical: Boolean = false
) : EmpireOverviewTabPersistableData() {
override fun isEmpty() = !vertical
}
override val persistableData = (persistedData as? ResourcesTabPersistableData) ?: ResourcesTabPersistableData()
init {
defaults().pad(10f)
companion object {
private const val iconSize = 50f
private const val defaultPad = 10f
private const val tooltipSize = 24f
}
val resourceDrilldown = viewingPlayer.detailedCivResources
private fun getTurnImage(vertical: Boolean) =
ImageGetter.getImage("OtherIcons/Turn right")
.apply {
color = ImageGetter.getBlue()
if (vertical)
rotateBy(90f)
}
.surroundWithCircle(iconSize, color = Color.LIGHT_GRAY)
private val turnImageH = getTurnImage(false)
private val turnImageV = getTurnImage(true)
// First row of table has all the icons
add()
private val resourceDrilldown: ResourceSupplyList = viewingPlayer.detailedCivResources
private val extraDrilldown: ResourceSupplyList = getExtraDrilldown()
private val drilldownSequence = resourceDrilldown.asSequence() + extraDrilldown.asSequence()
// Order of source ResourceSupplyList: by tiles, enumerating the map in that spiral pattern
// UI should not surprise player, thus we need a deterministic and guessable order
val resources = resourceDrilldown.map { it.resource }
.filter { it.resourceType != ResourceType.Bonus }.distinct()
.sortedWith(compareBy({ it.resourceType }, { it.name.tr() }))
private val resources: List<TileResource> = drilldownSequence
.map { it.resource }
.filter { it.resourceType != ResourceType.Bonus }
.distinct()
.sortedWith(
compareBy<TileResource> { it.resourceType }
.thenBy(UncivGame.Current.settings.getCollatorFromLocale()) { it.name.tr() }
)
.toList()
private val origins: List<String> = resourceDrilldown.asSequence()
.map { it.origin }.distinct().toList()
private val extraOrigins: List<ExtraInfoOrigin> = extraDrilldown.asSequence()
.mapNotNull { ExtraInfoOrigin.safeValueOf(it.origin) }.distinct().toList()
for (resource in resources) {
// Create a group of label and icon for each resource.
val resourceImage = ImageGetter.getResourceImage(resource.name, 50f)
val labelPadding = 10f
// Using a table here leads to spacing issues
// due to different label lengths.
val holder = Group()
resourceImage.onClick {
viewingPlayer.gameInfo.notifyExploredResources(viewingPlayer, resource.name, 0, true)
private fun ResourceSupplyList.getLabel(resource: TileResource, origin: String): Label? =
firstOrNull { it.resource == resource && it.origin == origin }?.amount?.toLabel()
private fun ResourceSupplyList.getTotalLabel(resource: TileResource): Label =
filter { it.resource == resource }.sumOf { it.amount }.toLabel()
private fun getResourceImage(name: String) =
ImageGetter.getResourceImage(name, iconSize).apply {
onClick {
viewingPlayer.gameInfo.notifyExploredResources(viewingPlayer, name, 0, true)
overviewScreen.game.setWorldScreen()
}
holder.addActor(resourceImage)
holder.setSize(resourceImage.width, resourceImage.height + 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
}
add(holder)
private enum class ExtraInfoOrigin(
val horizontalCaption: String,
val verticalCaption: String,
val tooltip: String
) {
Unimproved("Unimproved", "Unimproved",
"Number of tiles with this resource\nin your territory, without an\nappropriate improvement to use it"),
CelebratingWLKT("We Love The King Day", "WLTK+",
"Number of your cities celebrating\n'We Love The King Day' thanks\nto access to this resource"),
DemandingWLTK("WLTK demand", "WLTK-",
"Number of your cities\ndemanding this resource for\n'We Love The King Day'"),
;
companion object {
fun safeValueOf(name: String) = values().firstOrNull { it.name == name }
}
}
private val fixedContent = Table()
init {
defaults().pad(defaultPad)
fixedContent.defaults().pad(defaultPad)
turnImageH.onClick {
persistableData.vertical = true
update()
}
turnImageV.onClick {
persistableData.vertical = false
update()
}
update()
}
override fun getFixedContent() = fixedContent
private fun update() {
clear()
fixedContent.clear()
if (persistableData.vertical) updateVertical()
else updateHorizontal()
}
private fun updateHorizontal() {
// First row of table has all the icons
add(turnImageH)
for (resource in resources) {
add(getResourceImage(resource.name).apply {
addTooltip(resource.name, tipAlign = Align.topLeft)
})
}
addSeparator()
val origins = resourceDrilldown.map { it.origin }.distinct()
// One detail row per origin
for (origin in origins) {
add(origin.toLabel()).left()
for (resource in resources) {
add(resourceDrilldown.getLabel(resource, origin))
}
row()
}
addSeparator(Color.GRAY).pad(0f, defaultPad)
// One row for the totals
add("Total".toLabel()).left()
for (resource in resources) {
add(resourceDrilldown.getTotalLabel(resource))
}
addSeparator()
// Separate rows for origins not part of the totals
for (origin in extraOrigins) {
add(origin.horizontalCaption.toLabel().apply {
addTooltip(origin.tooltip, tooltipSize, tipAlign = Align.left)
}).left()
for (resource in resources) {
add(extraDrilldown.getLabel(resource, origin.name))
}
row()
}
}
private fun updateVertical() {
// First row of table has all the origin labels
fixedContent.apply {
add(turnImageV).size(iconSize)
add()
addSeparatorVertical(Color.GRAY).pad(0f)
for (origin in origins) {
add(origin.toLabel())
}
add("Total".toLabel())
addSeparatorVertical(Color.GRAY).pad(0f)
for (origin in extraOrigins) {
add(origin.verticalCaption.toLabel().apply {
addTooltip(origin.tooltip, tooltipSize, targetAlign = Align.bottom, tipAlign = Align.topRight)
})
}
addSeparator().pad(0f, defaultPad)
}
// One detail row per resource
for (resource in resources) {
val resourceSupply = resourceDrilldown.firstOrNull { it.resource == resource && it.origin == origin }
if (resourceSupply == null) add()
else add(resourceSupply.amount.toString().toLabel())
add(getResourceImage(resource.name))
add(resource.name.toLabel())
addSeparatorVertical(Color.GRAY).pad(0f)
for (origin in origins) {
add(resourceDrilldown.getLabel(resource, origin))
}
add(resourceDrilldown.getTotalLabel(resource))
addSeparatorVertical(Color.GRAY).pad(0f)
for (origin in extraOrigins) {
add(extraDrilldown.getLabel(resource, origin.name))
}
row()
}
add("Total".toLabel())
for (resource in resources) {
val sum = resourceDrilldown.filter { it.resource == resource }.sumOf { it.amount }
add(sum.toLabel())
equalizeColumns(fixedContent, this)
overviewScreen.resizePage(this) // Without the height is miscalculated - shouldn't be
}
private fun getExtraDrilldown(): ResourceSupplyList {
val resourceSupplyList = ResourceSupplyList()
for (city in viewingPlayer.cities) {
if (city.demandedResource.isEmpty()) continue
val wltkResource = gameInfo.ruleSet.tileResources[city.demandedResource] ?: continue
if (city.isWeLoveTheKingDayActive()) {
resourceSupplyList.add(wltkResource, 1, ExtraInfoOrigin.CelebratingWLKT.name)
} else {
resourceSupplyList.add(wltkResource, 1, ExtraInfoOrigin.DemandingWLTK.name)
}
for (tile in city.getTiles()) {
if (tile.isCityCenter()) continue
if (!tile.hasViewableResource(viewingPlayer)) continue
val tileResource = tile.tileResource
if (tileResource.resourceType == ResourceType.Bonus) continue
if (tile.improvement == tileResource.improvement) continue
if (tileResource.resourceType == ResourceType.Strategic && tile.getTileImprovement()?.isGreatImprovement() == true) continue
resourceSupplyList.add(tileResource, 1, ExtraInfoOrigin.Unimproved.name)
}
}
return resourceSupplyList
}
}

View File

@ -96,10 +96,10 @@ class WonderOverviewTab(
row()
}
top()
defaults().pad(10f).align(Align.center)
(1..5).forEach { _ -> add() } // dummies so equalizeColumns can work because the first grid cell is colspan(5)
row()
top()
createGrid()

View File

@ -23,6 +23,7 @@ import com.unciv.models.translations.tr
* @param forceContentSize Force virtual [content] width/height for alignment calculation
* - because Gdx auto layout reports wrong dimensions on scaled actors.
*/
// region fields
class UncivTooltip <T: Actor>(
val target: Actor,
val content: T,
@ -33,7 +34,6 @@ class UncivTooltip <T: Actor>(
forceContentSize: Vector2? = null,
) : InputListener() {
// region fields
private val container: Container<T> = Container(content)
enum class TipState { Hidden, Showing, Shown, Hiding }
/** current visibility state of the Tooltip */
@ -49,7 +49,9 @@ class UncivTooltip <T: Actor>(
contentHeight = forceContentSize?.y ?: content.height
}
//endregion
//region show, hide and positioning
/** Show the Tooltip ([immediate]ly or begin the animation). _Can_ be called programmatically. */
fun show(immediate: Boolean = false) {
if (target.stage == null) return
@ -129,9 +131,10 @@ class UncivTooltip <T: Actor>(
}
private fun Actor.getEdgePoint(align: Int) =
Vector2(getOriginX(width,align),getOriginY(height,align))
//endregion
//endregion
//region events
override fun enter(event: InputEvent?, x: Float, y: Float, pointer: Int, fromActor: Actor?) {
// assert(event?.listenerActor == target) - tested - holds true
if (fromActor != null && fromActor.isDescendantOf(target)) return
@ -147,6 +150,7 @@ class UncivTooltip <T: Actor>(
container.toFront() // this is a no-op if it has no parent
return super.touchDown(event, x, y, pointer, button)
}
//endregion
companion object {
@ -158,9 +162,16 @@ class UncivTooltip <T: Actor>(
* @param text Automatically translated tooltip text
* @param size _Vertical_ size of the entire Tooltip including background
* @param always override requirement: presence of physical keyboard
* @param tipAlign Point on the Tooltip to align with the top right of the [target]
* @param targetAlign Point on the [target] widget to align the Tooltip to
* @param tipAlign Point on the Tooltip to align with the given point on the [target]
*/
fun Actor.addTooltip(text: String, size: Float = 26f, always: Boolean = false, tipAlign: Int = Align.top) {
fun Actor.addTooltip(
text: String,
size: Float = 26f,
always: Boolean = false,
targetAlign: Int = Align.topRight,
tipAlign: Int = Align.top
) {
if (!(always || KeyPressDispatcher.keyboardAvailable) || text.isEmpty()) return
val label = text.toLabel(ImageGetter.getBlue(), 38)
@ -175,18 +186,20 @@ class UncivTooltip <T: Actor>(
background.setPadding(4f+skewPadDescenders, horizontalPad, 8f-skewPadDescenders, horizontalPad)
val widthHeightRatio: Float
val multiRowSize = size * (1 + text.count { it == '\n' })
val labelWithBackground = Container(label).apply {
setBackground(background)
pack()
widthHeightRatio = width / height
isTransform = true // otherwise setScale is ignored
setScale(size / height)
setScale(multiRowSize / height)
}
addListener(UncivTooltip(this,
labelWithBackground,
forceContentSize = Vector2(size * widthHeightRatio, size),
offset = Vector2(-size/4, size/4),
forceContentSize = Vector2(multiRowSize * widthHeightRatio, multiRowSize),
offset = Vector2(-multiRowSize/4, size/4),
targetAlign = targetAlign,
tipAlign = tipAlign
))
}

View File

@ -677,6 +677,7 @@ Unless otherwise specified, all the following are from [the Noun Project](https:
* [favor](https://thenounproject.com/icon/favor-1029350/) by MICHAEL G BROWN for WLTK marker on City Overview
* [Party](https://thenounproject.com/icon/party-1784941/) by Adrien Coquet for WLTK header on City Overview
* [Party](https://thenounproject.com/icon/party-2955155/) by Lars Meiertoberens as additional WLKT decoration
* [turn right](https://thenounproject.com/icon/turn-right-1920867/) by Alice Design for Resource Overview
## Main menu