Resources UI (#6596)

* More info for Resources in Civilopedia

* Remove duplicates for Resource requirements in Civilopedia

* Resource overview link resource label to Civilopedia

* Resource overview stay if clicking can't notify (resources not existing on map)

* Resource overview display of resources produced by buildings
This commit is contained in:
SomeTroglodyte
2022-04-27 08:15:49 +02:00
committed by GitHub
parent 933e769d8e
commit 8891883998
7 changed files with 88 additions and 28 deletions

View File

@ -1159,6 +1159,8 @@ Can be found on =
Improved by [improvement] = Improved by [improvement] =
Bonus stats for improvement = Bonus stats for improvement =
Buildings that consume this resource = Buildings that consume this resource =
Buildings that provide this resource =
Improvements that provide this resource =
Buildings that require this resource worked near the city = Buildings that require this resource worked near the city =
Units that consume this resource = Units that consume this resource =
Can be built on = Can be built on =

View File

@ -320,8 +320,18 @@ class GameInfo {
} }
} }
fun notifyExploredResources(civInfo: CivilizationInfo, resourceName: String, maxDistance: Int, showForeign: Boolean) { /** Generate a notification pointing out resources.
// Calling with `maxDistance = 0` removes distance limitation. * Used by [addTechnology][TechManager.addTechnology] and [ResourcesOverviewTab][com.unciv.ui.overviewscreen.ResourcesOverviewTab]
* @param maxDistance from next City, 0 removes distance limitation.
* @param showForeign Disables filter to exclude foreign territory.
* @return `false` if no resources were found and no notification was added.
*/
fun notifyExploredResources(
civInfo: CivilizationInfo,
resourceName: String,
maxDistance: Int,
showForeign: Boolean
): Boolean {
data class CityTileAndDistance(val city: CityInfo, val tile: TileInfo, val distance: Int) data class CityTileAndDistance(val city: CityInfo, val tile: TileInfo, val distance: Int)
val exploredRevealTiles: Sequence<TileInfo> = val exploredRevealTiles: Sequence<TileInfo> =
@ -351,7 +361,7 @@ class GameInfo {
.sortedWith ( compareBy { it.distance } ) .sortedWith ( compareBy { it.distance } )
.distinctBy { it.tile } .distinctBy { it.tile }
val chosenCity = exploredRevealInfo.firstOrNull()?.city ?: return val chosenCity = exploredRevealInfo.firstOrNull()?.city ?: return false
val positions = exploredRevealInfo val positions = exploredRevealInfo
// re-sort to a more pleasant display order // re-sort to a more pleasant display order
.sortedWith(compareBy{ it.tile.aerialDistanceTo(chosenCity.getCenterTile()) }) .sortedWith(compareBy{ it.tile.aerialDistanceTo(chosenCity.getCenterTile()) })
@ -368,6 +378,7 @@ class GameInfo {
LocationAction(positions), LocationAction(positions),
"ResourceIcons/$resourceName" "ResourceIcons/$resourceName"
) )
return true
} }
// All cross-game data which needs to be altered (e.g. when removing or changing a name of a building/tech) // All cross-game data which needs to be altered (e.g. when removing or changing a name of a building/tech)

View File

@ -390,7 +390,7 @@ class CityInfo {
cityResources.add( cityResources.add(
resource, resource,
unique.params[0].toInt() * civInfo.getResourceModifier(resource), unique.params[0].toInt() * civInfo.getResourceModifier(resource),
"Tiles" "Buildings+"
) )
} }
} }

View File

@ -247,13 +247,13 @@ class Building : RulesetStatsObject(), INonPerpetualConstruction {
if (uniques.isNotEmpty() || !stats.isEmpty() || !percentStats.isEmpty() || this.greatPersonPoints.isNotEmpty() || specialists.isNotEmpty()) if (uniques.isNotEmpty() || !stats.isEmpty() || !percentStats.isEmpty() || this.greatPersonPoints.isNotEmpty() || specialists.isNotEmpty())
textList += FormattedLine() textList += FormattedLine()
if (uniques.isNotEmpty()) { if (replacementTextForUniques.isNotEmpty()) {
if (replacementTextForUniques.isNotEmpty())
textList += FormattedLine(replacementTextForUniques) textList += FormattedLine(replacementTextForUniques)
else } else if (uniques.isNotEmpty()) {
uniqueObjects.forEach { for (unique in uniqueObjects.sortedBy { it.text }) {
if (!it.hasFlag(UniqueFlag.HiddenToUsers)) if (unique.hasFlag(UniqueFlag.HiddenToUsers)) continue
textList += FormattedLine(it) if (unique.type == UniqueType.ConsumesResources) continue // already shown from getResourceRequirements
textList += FormattedLine(unique)
} }
} }
@ -268,7 +268,7 @@ class Building : RulesetStatsObject(), INonPerpetualConstruction {
} }
} }
for((greatPersonName, value) in greatPersonPoints) { for ((greatPersonName, value) in greatPersonPoints) {
textList += FormattedLine( textList += FormattedLine(
"+$value " + "[$greatPersonName] points".tr(), "+$value " + "[$greatPersonName] points".tr(),
link = "Unit/$greatPersonName" link = "Unit/$greatPersonName"
@ -296,7 +296,7 @@ class Building : RulesetStatsObject(), INonPerpetualConstruction {
val seeAlso = ArrayList<FormattedLine>() val seeAlso = ArrayList<FormattedLine>()
for (building in ruleset.buildings.values) { for (building in ruleset.buildings.values) {
if (building.replaces == name if (building.replaces == name
|| building.uniqueObjects.any { unique -> unique.params.any { it ==name } }) || building.uniqueObjects.any { unique -> unique.params.any { it == name } })
seeAlso += FormattedLine(building.name, link=building.makeLink(), indent=1) seeAlso += FormattedLine(building.name, link=building.makeLink(), indent=1)
} }
seeAlso += Belief.getCivilopediaTextMatching(name, ruleset, false) seeAlso += Belief.getCivilopediaTextMatching(name, ruleset, false)

View File

@ -4,6 +4,7 @@ import com.unciv.models.ruleset.Belief
import com.unciv.models.ruleset.Ruleset import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.RulesetStatsObject import com.unciv.models.ruleset.RulesetStatsObject
import com.unciv.models.ruleset.unique.UniqueTarget import com.unciv.models.ruleset.unique.UniqueTarget
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.stats.Stats import com.unciv.models.stats.Stats
import com.unciv.ui.civilopedia.FormattedLine import com.unciv.ui.civilopedia.FormattedLine
@ -51,6 +52,34 @@ class TileResource : RulesetStatsObject() {
textList += FormattedLine("{Bonus stats for improvement}: " + improvementStats.toString()) textList += FormattedLine("{Bonus stats for improvement}: " + improvementStats.toString())
} }
val improvementsThatProvideThis = ruleset.tileImprovements.values
.filter { improvement ->
improvement.uniqueObjects.any { unique ->
unique.type == UniqueType.ProvidesResources && unique.params[1] == name
}
}
if (improvementsThatProvideThis.isNotEmpty()) {
textList += FormattedLine()
textList += FormattedLine("{Improvements that provide this resource}:")
improvementsThatProvideThis.forEach {
textList += FormattedLine(it.name, link = it.makeLink(), indent = 1)
}
}
val buildingsThatProvideThis = ruleset.buildings.values
.filter { building ->
building.uniqueObjects.any { unique ->
unique.type == UniqueType.ProvidesResources && unique.params[1] == name
}
}
if (buildingsThatProvideThis.isNotEmpty()) {
textList += FormattedLine()
textList += FormattedLine("{Buildings that provide this resource}:")
buildingsThatProvideThis.forEach {
textList += FormattedLine(it.name, link = it.makeLink(), indent = 1)
}
}
val buildingsThatConsumeThis = ruleset.buildings.values.filter { it.getResourceRequirements().containsKey(name) } val buildingsThatConsumeThis = ruleset.buildings.values.filter { it.getResourceRequirements().containsKey(name) }
if (buildingsThatConsumeThis.isNotEmpty()) { if (buildingsThatConsumeThis.isNotEmpty()) {
textList += FormattedLine() textList += FormattedLine()
@ -94,7 +123,7 @@ class TileResource : RulesetStatsObject() {
} }
data class ResourceSupply(val resource:TileResource,var amount:Int, val origin:String) data class ResourceSupply(val resource:TileResource, var amount:Int, val origin:String)
class ResourceSupplyList:ArrayList<ResourceSupply>() { class ResourceSupplyList:ArrayList<ResourceSupply>() {
fun add(resource: TileResource, amount: Int, origin: String) { fun add(resource: TileResource, amount: Int, origin: String) {

View File

@ -127,14 +127,15 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction {
textList += FormattedLine(stats.joinToString(", ", "{Cost}: ")) textList += FormattedLine(stats.joinToString(", ", "{Cost}: "))
} }
if (replacementTextForUniques != "") { if (replacementTextForUniques.isNotEmpty()) {
textList += FormattedLine() textList += FormattedLine()
textList += FormattedLine(replacementTextForUniques) textList += FormattedLine(replacementTextForUniques)
} else if (uniques.isNotEmpty()) { } else if (uniques.isNotEmpty()) {
textList += FormattedLine() textList += FormattedLine()
uniqueObjects.sortedBy { it.text }.forEach { for (unique in uniqueObjects.sortedBy { it.text }) {
if (!it.hasFlag(UniqueFlag.HiddenToUsers)) if (unique.hasFlag(UniqueFlag.HiddenToUsers)) continue
textList += FormattedLine(it) if (unique.type == UniqueType.ConsumesResources) continue // already shown from getResourceRequirements
textList += FormattedLine(unique)
} }
} }

View File

@ -10,6 +10,8 @@ import com.unciv.models.ruleset.tile.ResourceSupplyList
import com.unciv.models.ruleset.tile.ResourceType import com.unciv.models.ruleset.tile.ResourceType
import com.unciv.models.ruleset.tile.TileResource import com.unciv.models.ruleset.tile.TileResource
import com.unciv.models.translations.tr import com.unciv.models.translations.tr
import com.unciv.ui.civilopedia.CivilopediaCategories
import com.unciv.ui.civilopedia.CivilopediaScreen
import com.unciv.ui.images.ImageGetter import com.unciv.ui.images.ImageGetter
import com.unciv.ui.utils.* import com.unciv.ui.utils.*
import com.unciv.ui.utils.UncivTooltip.Companion.addTooltip import com.unciv.ui.utils.UncivTooltip.Companion.addTooltip
@ -71,10 +73,15 @@ class ResourcesOverviewTab(
private fun getResourceImage(name: String) = private fun getResourceImage(name: String) =
ImageGetter.getResourceImage(name, iconSize).apply { ImageGetter.getResourceImage(name, iconSize).apply {
onClick { onClick {
viewingPlayer.gameInfo.notifyExploredResources(viewingPlayer, name, 0, true) if (viewingPlayer.gameInfo.notifyExploredResources(viewingPlayer, name, 0, true))
overviewScreen.game.setWorldScreen() overviewScreen.game.setWorldScreen()
} }
} }
private fun TileResource.getLabel() = name.toLabel().apply {
onClick {
overviewScreen.game.setScreen(CivilopediaScreen(gameInfo.ruleSet, overviewScreen, CivilopediaCategories.Resource, this@getLabel.name))
}
}
private enum class ExtraInfoOrigin( private enum class ExtraInfoOrigin(
val horizontalCaption: String, val horizontalCaption: String,
@ -131,7 +138,7 @@ class ResourcesOverviewTab(
// One detail row per origin // One detail row per origin
for (origin in origins) { for (origin in origins) {
add(origin.toLabel()).left() add(origin.removeSuffix("+").toLabel()).left()
for (resource in resources) { for (resource in resources) {
add(resourceDrilldown.getLabel(resource, origin)) add(resourceDrilldown.getLabel(resource, origin))
} }
@ -159,13 +166,16 @@ class ResourcesOverviewTab(
} }
private fun updateVertical() { private fun updateVertical() {
val groupedOrigins = origins
.groupBy { it.removeSuffix("+") }
// First row of table has all the origin labels // First row of table has all the origin labels
fixedContent.apply { fixedContent.apply {
add(turnImageV).size(iconSize) add(turnImageV).size(iconSize)
add() add()
addSeparatorVertical(Color.GRAY).pad(0f) addSeparatorVertical(Color.GRAY).pad(0f)
for (origin in origins) { for (origin in groupedOrigins) {
add(origin.toLabel()) add(origin.key.toLabel())
} }
add("Total".toLabel()) add("Total".toLabel())
addSeparatorVertical(Color.GRAY).pad(0f) addSeparatorVertical(Color.GRAY).pad(0f)
@ -180,10 +190,17 @@ class ResourcesOverviewTab(
// One detail row per resource // One detail row per resource
for (resource in resources) { for (resource in resources) {
add(getResourceImage(resource.name)) add(getResourceImage(resource.name))
add(resource.name.toLabel()) add(resource.getLabel())
addSeparatorVertical(Color.GRAY).pad(0f) addSeparatorVertical(Color.GRAY).pad(0f)
for (origin in origins) { for (groupedOrigin in groupedOrigins) {
add(resourceDrilldown.getLabel(resource, origin)) if (groupedOrigin.value.size == 1)
add(resourceDrilldown.getLabel(resource, groupedOrigin.key))
else
add(Table().apply {
for (origin in groupedOrigin.value.withIndex())
add(resourceDrilldown.getLabel(resource, origin.value))
.padLeft(if (origin.index == 0) 0f else defaultPad)
})
} }
add(resourceDrilldown.getTotalLabel(resource)) add(resourceDrilldown.getTotalLabel(resource))
addSeparatorVertical(Color.GRAY).pad(0f) addSeparatorVertical(Color.GRAY).pad(0f)