mirror of
https://github.com/yairm210/Unciv.git
synced 2025-07-11 00:08:58 +07:00
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:
@ -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 =
|
||||||
|
@ -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)
|
||||||
|
@ -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+"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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) {
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
Reference in New Issue
Block a user