diff --git a/android/assets/jsons/translations/template.properties b/android/assets/jsons/translations/template.properties index 03ea1ed1a4..9b1bc4424c 100644 --- a/android/assets/jsons/translations/template.properties +++ b/android/assets/jsons/translations/template.properties @@ -1159,6 +1159,8 @@ Can be found on = Improved by [improvement] = Bonus stats for improvement = Buildings that consume this resource = +Buildings that provide this resource = +Improvements that provide this resource = Buildings that require this resource worked near the city = Units that consume this resource = Can be built on = diff --git a/core/src/com/unciv/logic/GameInfo.kt b/core/src/com/unciv/logic/GameInfo.kt index fa08051a03..e933afd93e 100644 --- a/core/src/com/unciv/logic/GameInfo.kt +++ b/core/src/com/unciv/logic/GameInfo.kt @@ -320,8 +320,18 @@ class GameInfo { } } - fun notifyExploredResources(civInfo: CivilizationInfo, resourceName: String, maxDistance: Int, showForeign: Boolean) { - // Calling with `maxDistance = 0` removes distance limitation. + /** Generate a notification pointing out resources. + * 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) val exploredRevealTiles: Sequence = @@ -351,7 +361,7 @@ class GameInfo { .sortedWith ( compareBy { it.distance } ) .distinctBy { it.tile } - val chosenCity = exploredRevealInfo.firstOrNull()?.city ?: return + val chosenCity = exploredRevealInfo.firstOrNull()?.city ?: return false val positions = exploredRevealInfo // re-sort to a more pleasant display order .sortedWith(compareBy{ it.tile.aerialDistanceTo(chosenCity.getCenterTile()) }) @@ -368,6 +378,7 @@ class GameInfo { LocationAction(positions), "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) diff --git a/core/src/com/unciv/logic/city/CityInfo.kt b/core/src/com/unciv/logic/city/CityInfo.kt index 2a8491a107..131556d459 100644 --- a/core/src/com/unciv/logic/city/CityInfo.kt +++ b/core/src/com/unciv/logic/city/CityInfo.kt @@ -390,7 +390,7 @@ class CityInfo { cityResources.add( resource, unique.params[0].toInt() * civInfo.getResourceModifier(resource), - "Tiles" + "Buildings+" ) } } diff --git a/core/src/com/unciv/models/ruleset/Building.kt b/core/src/com/unciv/models/ruleset/Building.kt index c78e60a1ae..f71e95df64 100644 --- a/core/src/com/unciv/models/ruleset/Building.kt +++ b/core/src/com/unciv/models/ruleset/Building.kt @@ -247,14 +247,14 @@ class Building : RulesetStatsObject(), INonPerpetualConstruction { if (uniques.isNotEmpty() || !stats.isEmpty() || !percentStats.isEmpty() || this.greatPersonPoints.isNotEmpty() || specialists.isNotEmpty()) textList += FormattedLine() - if (uniques.isNotEmpty()) { - if (replacementTextForUniques.isNotEmpty()) - textList += FormattedLine(replacementTextForUniques) - else - uniqueObjects.forEach { - if (!it.hasFlag(UniqueFlag.HiddenToUsers)) - textList += FormattedLine(it) - } + if (replacementTextForUniques.isNotEmpty()) { + textList += FormattedLine(replacementTextForUniques) + } else if (uniques.isNotEmpty()) { + for (unique in uniqueObjects.sortedBy { it.text }) { + if (unique.hasFlag(UniqueFlag.HiddenToUsers)) continue + if (unique.type == UniqueType.ConsumesResources) continue // already shown from getResourceRequirements + textList += FormattedLine(unique) + } } if (!stats.isEmpty()) { @@ -268,7 +268,7 @@ class Building : RulesetStatsObject(), INonPerpetualConstruction { } } - for((greatPersonName, value) in greatPersonPoints) { + for ((greatPersonName, value) in greatPersonPoints) { textList += FormattedLine( "+$value " + "[$greatPersonName] points".tr(), link = "Unit/$greatPersonName" @@ -296,7 +296,7 @@ class Building : RulesetStatsObject(), INonPerpetualConstruction { val seeAlso = ArrayList() for (building in ruleset.buildings.values) { 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 += Belief.getCivilopediaTextMatching(name, ruleset, false) diff --git a/core/src/com/unciv/models/ruleset/tile/TileResource.kt b/core/src/com/unciv/models/ruleset/tile/TileResource.kt index 681d4aa305..b26eec8cbf 100644 --- a/core/src/com/unciv/models/ruleset/tile/TileResource.kt +++ b/core/src/com/unciv/models/ruleset/tile/TileResource.kt @@ -4,6 +4,7 @@ import com.unciv.models.ruleset.Belief import com.unciv.models.ruleset.Ruleset import com.unciv.models.ruleset.RulesetStatsObject import com.unciv.models.ruleset.unique.UniqueTarget +import com.unciv.models.ruleset.unique.UniqueType import com.unciv.models.stats.Stats import com.unciv.ui.civilopedia.FormattedLine @@ -51,6 +52,34 @@ class TileResource : RulesetStatsObject() { 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) } if (buildingsThatConsumeThis.isNotEmpty()) { textList += FormattedLine() @@ -84,7 +113,7 @@ class TileResource : RulesetStatsObject() { return textList } - + class DepositAmount { var sparse: Int = 1 var default: Int = 2 @@ -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() { fun add(resource: TileResource, amount: Int, origin: String) { diff --git a/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt b/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt index 9e05a65655..67360f4b58 100644 --- a/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt +++ b/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt @@ -127,14 +127,15 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction { textList += FormattedLine(stats.joinToString(", ", "{Cost}: ")) } - if (replacementTextForUniques != "") { + if (replacementTextForUniques.isNotEmpty()) { textList += FormattedLine() textList += FormattedLine(replacementTextForUniques) } else if (uniques.isNotEmpty()) { textList += FormattedLine() - uniqueObjects.sortedBy { it.text }.forEach { - if (!it.hasFlag(UniqueFlag.HiddenToUsers)) - textList += FormattedLine(it) + for (unique in uniqueObjects.sortedBy { it.text }) { + if (unique.hasFlag(UniqueFlag.HiddenToUsers)) continue + if (unique.type == UniqueType.ConsumesResources) continue // already shown from getResourceRequirements + textList += FormattedLine(unique) } } diff --git a/core/src/com/unciv/ui/overviewscreen/ResourcesOverviewTable.kt b/core/src/com/unciv/ui/overviewscreen/ResourcesOverviewTable.kt index e323f5b515..b19386b1f1 100644 --- a/core/src/com/unciv/ui/overviewscreen/ResourcesOverviewTable.kt +++ b/core/src/com/unciv/ui/overviewscreen/ResourcesOverviewTable.kt @@ -10,6 +10,8 @@ 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.civilopedia.CivilopediaCategories +import com.unciv.ui.civilopedia.CivilopediaScreen import com.unciv.ui.images.ImageGetter import com.unciv.ui.utils.* import com.unciv.ui.utils.UncivTooltip.Companion.addTooltip @@ -71,10 +73,15 @@ class ResourcesOverviewTab( private fun getResourceImage(name: String) = ImageGetter.getResourceImage(name, iconSize).apply { onClick { - viewingPlayer.gameInfo.notifyExploredResources(viewingPlayer, name, 0, true) - overviewScreen.game.setWorldScreen() + if (viewingPlayer.gameInfo.notifyExploredResources(viewingPlayer, name, 0, true)) + 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( val horizontalCaption: String, @@ -131,7 +138,7 @@ class ResourcesOverviewTab( // One detail row per origin for (origin in origins) { - add(origin.toLabel()).left() + add(origin.removeSuffix("+").toLabel()).left() for (resource in resources) { add(resourceDrilldown.getLabel(resource, origin)) } @@ -159,13 +166,16 @@ class ResourcesOverviewTab( } private fun updateVertical() { + val groupedOrigins = origins + .groupBy { it.removeSuffix("+") } + // 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()) + for (origin in groupedOrigins) { + add(origin.key.toLabel()) } add("Total".toLabel()) addSeparatorVertical(Color.GRAY).pad(0f) @@ -180,10 +190,17 @@ class ResourcesOverviewTab( // One detail row per resource for (resource in resources) { add(getResourceImage(resource.name)) - add(resource.name.toLabel()) + add(resource.getLabel()) addSeparatorVertical(Color.GRAY).pad(0f) - for (origin in origins) { - add(resourceDrilldown.getLabel(resource, origin)) + for (groupedOrigin in groupedOrigins) { + 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)) addSeparatorVertical(Color.GRAY).pad(0f)