Spruced up Civilopedia - phase 2 - external links (#3981)

* Spruced up Civilopedia - phase 2 - external links

* Spruced up Civilopedia - phase 2 - patch1

* Spruced up Civilopedia - phase 2 - patch2
This commit is contained in:
SomeTroglodyte
2021-05-28 16:41:03 +02:00
committed by GitHub
parent c45ecebb0c
commit 97a36c3772
8 changed files with 223 additions and 44 deletions

View File

@ -5,10 +5,13 @@ import com.unciv.logic.civilization.AlertType
import com.unciv.logic.civilization.NotificationIcon import com.unciv.logic.civilization.NotificationIcon
import com.unciv.logic.civilization.PopupAlert import com.unciv.logic.civilization.PopupAlert
import com.unciv.models.ruleset.Building import com.unciv.models.ruleset.Building
import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.UniqueMap import com.unciv.models.ruleset.UniqueMap
import com.unciv.models.ruleset.unit.BaseUnit import com.unciv.models.ruleset.unit.BaseUnit
import com.unciv.models.stats.Stats import com.unciv.models.stats.Stats
import com.unciv.models.translations.tr import com.unciv.models.translations.tr
import com.unciv.ui.civilopedia.CivilopediaCategories
import com.unciv.ui.civilopedia.FormattedLine
import com.unciv.ui.utils.Fonts import com.unciv.ui.utils.Fonts
import com.unciv.ui.utils.withItem import com.unciv.ui.utils.withItem
import com.unciv.ui.utils.withoutItem import com.unciv.ui.utils.withoutItem
@ -141,6 +144,28 @@ class CityConstructions {
return result return result
} }
fun getProductionMarkup(ruleset: Ruleset): FormattedLine {
val currentConstructionSnapshot = currentConstructionFromQueue
if (currentConstructionSnapshot.isEmpty()) return FormattedLine()
val category = when {
ruleset.buildings[currentConstructionSnapshot]
?.let{ it.isWonder || it.isNationalWonder } == true ->
CivilopediaCategories.Wonder.name
currentConstructionSnapshot in ruleset.buildings ->
CivilopediaCategories.Building.name
currentConstructionSnapshot in ruleset.units ->
CivilopediaCategories.Unit.name
else -> ""
}
var label = currentConstructionSnapshot
if (!PerpetualConstruction.perpetualConstructionsMap.containsKey(currentConstructionSnapshot)) {
val turnsLeft = turnsToConstruction(currentConstructionSnapshot)
label += " - $turnsLeft${Fonts.turn}"
}
return if (category.isEmpty()) FormattedLine(label)
else FormattedLine(label, link="$category/$currentConstructionSnapshot")
}
fun getCurrentConstruction(): IConstruction = getConstruction(currentConstructionFromQueue) fun getCurrentConstruction(): IConstruction = getConstruction(currentConstructionFromQueue)
fun isBuilt(buildingName: String): Boolean = builtBuildings.contains(buildingName) fun isBuilt(buildingName: String): Boolean = builtBuildings.contains(buildingName)

View File

@ -10,6 +10,7 @@ import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.tile.* import com.unciv.models.ruleset.tile.*
import com.unciv.models.stats.Stats import com.unciv.models.stats.Stats
import com.unciv.models.translations.tr import com.unciv.models.translations.tr
import com.unciv.ui.civilopedia.FormattedLine
import com.unciv.ui.utils.Fonts import com.unciv.ui.utils.Fonts
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.min import kotlin.math.min
@ -144,7 +145,7 @@ open class TileInfo {
else if (!ruleset.tileResources.containsKey(resource!!)) throw Exception("Resource $resource does not exist in this ruleset!") else if (!ruleset.tileResources.containsKey(resource!!)) throw Exception("Resource $resource does not exist in this ruleset!")
else ruleset.tileResources[resource!!]!! else ruleset.tileResources[resource!!]!!
fun getNaturalWonder(): Terrain = private fun getNaturalWonder(): Terrain =
if (naturalWonder == null) throw Exception("No natural wonder exists for this tile!") if (naturalWonder == null) throw Exception("No natural wonder exists for this tile!")
else ruleset.terrains[naturalWonder!!]!! else ruleset.terrains[naturalWonder!!]!!
@ -179,8 +180,7 @@ open class TileInfo {
fun getBaseTerrain(): Terrain = baseTerrainObject fun getBaseTerrain(): Terrain = baseTerrainObject
fun getOwner(): CivilizationInfo? { fun getOwner(): CivilizationInfo? {
val containingCity = getCity() val containingCity = getCity() ?: return null
if (containingCity == null) return null
return containingCity.civInfo return containingCity.civInfo
} }
@ -204,8 +204,7 @@ open class TileInfo {
fun hasUnique(unique: String) = getAllTerrains().any { it.uniques.contains(unique) } fun hasUnique(unique: String) = getAllTerrains().any { it.uniques.contains(unique) }
fun getWorkingCity(): CityInfo? { fun getWorkingCity(): CityInfo? {
val civInfo = getOwner() val civInfo = getOwner() ?: return null
if (civInfo == null) return null
return civInfo.cities.firstOrNull { it.isWorked(this) } return civInfo.cities.firstOrNull { it.isWorked(this) }
} }
@ -260,7 +259,7 @@ open class TileInfo {
stats.add(getTileResource()) // resource base stats.add(getTileResource()) // resource base
if (resource.building != null && city != null && city.cityConstructions.isBuilt(resource.building!!)) { if (resource.building != null && city != null && city.cityConstructions.isBuilt(resource.building!!)) {
val resourceBuilding = tileMap.gameInfo.ruleSet.buildings[resource.building!!] val resourceBuilding = tileMap.gameInfo.ruleSet.buildings[resource.building!!]
if (resourceBuilding != null && resourceBuilding.resourceBonusStats != null) if (resourceBuilding?.resourceBonusStats != null)
stats.add(resourceBuilding.resourceBonusStats!!) // resource-specific building (eg forge, stable) bonus stats.add(resourceBuilding.resourceBonusStats!!) // resource-specific building (eg forge, stable) bonus
} }
} }
@ -337,7 +336,7 @@ open class TileInfo {
improvement.hasUnique("Can be built outside your borders") improvement.hasUnique("Can be built outside your borders")
// citadel can be built only next to or within own borders // citadel can be built only next to or within own borders
|| improvement.hasUnique("Can be built just outside your borders") || improvement.hasUnique("Can be built just outside your borders")
&& neighbors.any { it.getOwner() == civInfo } && !civInfo.cities.isEmpty() && neighbors.any { it.getOwner() == civInfo } && civInfo.cities.isNotEmpty()
) -> false ) -> false
improvement.uniqueObjects.any { improvement.uniqueObjects.any {
it.placeholderText == "Obsolete with []" && civInfo.tech.isResearched(it.params[0]) it.placeholderText == "Obsolete with []" && civInfo.tech.isResearched(it.params[0])
@ -346,10 +345,10 @@ open class TileInfo {
} }
} }
/** Without regards to what civinfo it is, a lot of the checks are just for the improvement on the tile. /** Without regards to what CivInfo it is, a lot of the checks are just for the improvement on the tile.
* Doubles as a check for the map editor. * Doubles as a check for the map editor.
*/ */
fun canImprovementBeBuiltHere(improvement: TileImprovement, resourceIsVisible: Boolean = resource != null): Boolean { private fun canImprovementBeBuiltHere(improvement: TileImprovement, resourceIsVisible: Boolean = resource != null): Boolean {
val topTerrain = getLastTerrain() val topTerrain = getLastTerrain()
return when { return when {
@ -358,7 +357,7 @@ open class TileInfo {
"Cannot be built on bonus resource" in improvement.uniques && resource != null "Cannot be built on bonus resource" in improvement.uniques && resource != null
&& getTileResource().resourceType == ResourceType.Bonus -> false && getTileResource().resourceType == ResourceType.Bonus -> false
// Road improvements can change on tiles withh irremovable improvements - nothing else can, though. // Road improvements can change on tiles with irremovable improvements - nothing else can, though.
improvement.name != RoadStatus.Railroad.name && improvement.name != RoadStatus.Railroad.name improvement.name != RoadStatus.Railroad.name && improvement.name != RoadStatus.Railroad.name
&& improvement.name != "Remove Road" && improvement.name != "Remove Railroad" && improvement.name != "Remove Road" && improvement.name != "Remove Railroad"
&& getTileImprovement().let { it != null && it.hasUnique("Irremovable") } -> false && getTileImprovement().let { it != null && it.hasUnique("Irremovable") } -> false
@ -371,7 +370,7 @@ open class TileInfo {
improvement.uniqueObjects.filter { it.placeholderText == "Must be next to []" }.any { improvement.uniqueObjects.filter { it.placeholderText == "Must be next to []" }.any {
val filter = it.params[0] val filter = it.params[0]
if (filter == "River") return@any !isAdjacentToRiver() if (filter == "River") return@any !isAdjacentToRiver()
else return@any !neighbors.any { it.matchesUniqueFilter(filter) } else return@any !neighbors.any { neighbor -> neighbor.matchesUniqueFilter(filter) }
} -> false } -> false
improvement.name == "Road" && roadStatus == RoadStatus.None && !isWater -> true improvement.name == "Road" && roadStatus == RoadStatus.None && !isWater -> true
improvement.name == "Railroad" && this.roadStatus != RoadStatus.Railroad && !isWater -> true improvement.name == "Railroad" && this.roadStatus != RoadStatus.Railroad && !isWater -> true
@ -448,8 +447,20 @@ open class TileInfo {
return min(distance, wrappedDistance).toInt() return min(distance, wrappedDistance).toInt()
} }
override fun toString(): String { // for debugging, it helps to see what you're doing /** Shows important properties of this tile for debugging _only_, it helps to see what you're doing */
return toString(null) override fun toString(): String {
val lineList = arrayListOf("TileInfo @($position)")
if (isCityCenter()) lineList += getCity()!!.name
lineList += baseTerrain
for (terrainFeature in terrainFeatures) lineList += terrainFeature
if (resource != null ) lineList += resource!!
if (naturalWonder != null) lineList += naturalWonder!!
if (roadStatus !== RoadStatus.None && !isCityCenter()) lineList += roadStatus.name
if (improvement != null) lineList += improvement!!
if (civilianUnit != null) lineList += civilianUnit!!.name + " - " + civilianUnit!!.civInfo.civName
if (militaryUnit != null) lineList += militaryUnit!!.name + " - " + militaryUnit!!.civInfo.civName
if (isImpassible()) lineList += Constants.impassable
return lineList.joinToString()
} }
/** The two tiles have a river between them */ /** The two tiles have a river between them */
@ -481,8 +492,8 @@ open class TileInfo {
return true return true
} }
fun toString(viewingCiv: CivilizationInfo?): String { fun toMarkup(viewingCiv: CivilizationInfo?): ArrayList<FormattedLine> {
val lineList = ArrayList<String>() // more readable than StringBuilder, with same performance for our use-case val lineList = ArrayList<FormattedLine>() // more readable than StringBuilder, with same performance for our use-case
val isViewableToPlayer = viewingCiv == null || UncivGame.Current.viewEntireMapForDebug val isViewableToPlayer = viewingCiv == null || UncivGame.Current.viewEntireMapForDebug
|| viewingCiv.viewableTiles.contains(this) || viewingCiv.viewableTiles.contains(this)
@ -490,42 +501,46 @@ open class TileInfo {
val city = getCity()!! val city = getCity()!!
var cityString = city.name.tr() var cityString = city.name.tr()
if (isViewableToPlayer) cityString += " (" + city.health + ")" if (isViewableToPlayer) cityString += " (" + city.health + ")"
lineList += cityString lineList += FormattedLine(cityString)
if (UncivGame.Current.viewEntireMapForDebug || city.civInfo == viewingCiv) if (UncivGame.Current.viewEntireMapForDebug || city.civInfo == viewingCiv)
lineList += city.cityConstructions.getProductionForTileInfo() lineList += city.cityConstructions.getProductionMarkup(ruleset)
} }
lineList += baseTerrain.tr() lineList += FormattedLine(baseTerrain, link="Terrain/$baseTerrain")
for (terrainFeature in terrainFeatures) lineList += terrainFeature.tr() for (terrainFeature in terrainFeatures)
if (resource != null && (viewingCiv == null || hasViewableResource(viewingCiv))) lineList += resource!!.tr() lineList += FormattedLine(terrainFeature, link="Terrain/$terrainFeature")
if (naturalWonder != null) lineList += naturalWonder!!.tr() if (resource != null && (viewingCiv == null || hasViewableResource(viewingCiv)))
if (roadStatus !== RoadStatus.None && !isCityCenter()) lineList += roadStatus.name.tr() lineList += FormattedLine(resource!!, link="Resource/$resource")
if (improvement != null) lineList += improvement!!.tr() if (naturalWonder != null)
lineList += FormattedLine(naturalWonder!!, link="Terrain/$naturalWonder")
if (roadStatus !== RoadStatus.None && !isCityCenter())
lineList += FormattedLine(roadStatus.name, link="Improvement/${roadStatus.name}")
if (improvement != null)
lineList += FormattedLine(improvement!!, link="Improvement/$improvement")
if (improvementInProgress != null && isViewableToPlayer) { if (improvementInProgress != null && isViewableToPlayer) {
var line = "{$improvementInProgress}" val line = "{$improvementInProgress}" +
if (turnsToImprovement > 0) line += " - $turnsToImprovement${Fonts.turn}" if (turnsToImprovement > 0) " - $turnsToImprovement${Fonts.turn}" else " ({Under construction})"
else line += " ({Under construction})" lineList += FormattedLine(line, link="Improvement/$improvementInProgress")
lineList += line.tr()
} }
if (civilianUnit != null && isViewableToPlayer) if (civilianUnit != null && isViewableToPlayer)
lineList += civilianUnit!!.name.tr() + " - " + civilianUnit!!.civInfo.civName.tr() lineList += FormattedLine(civilianUnit!!.name.tr() + " - " + civilianUnit!!.civInfo.civName.tr(),
link="Unit/${civilianUnit!!.name}")
if (militaryUnit != null && isViewableToPlayer) { if (militaryUnit != null && isViewableToPlayer) {
var milUnitString = militaryUnit!!.name.tr() val milUnitString = militaryUnit!!.name.tr() +
if (militaryUnit!!.health < 100) milUnitString += "(" + militaryUnit!!.health + ")" (if (militaryUnit!!.health < 100) "(" + militaryUnit!!.health + ")" else "") +
milUnitString += " - " + militaryUnit!!.civInfo.civName.tr() " - " + militaryUnit!!.civInfo.civName.tr()
lineList += milUnitString lineList += FormattedLine(milUnitString, link="Unit/${militaryUnit!!.name}")
} }
val defenceBonus = getDefensiveBonus() val defenceBonus = getDefensiveBonus()
if (defenceBonus != 0f) { if (defenceBonus != 0f) {
var defencePercentString = (defenceBonus * 100).toInt().toString() + "%" var defencePercentString = (defenceBonus * 100).toInt().toString() + "%"
if (!defencePercentString.startsWith("-")) defencePercentString = "+$defencePercentString" if (!defencePercentString.startsWith("-")) defencePercentString = "+$defencePercentString"
lineList += "[$defencePercentString] to unit defence".tr() lineList += FormattedLine("[$defencePercentString] to unit defence")
} }
if (isImpassible()) lineList += Constants.impassable.tr() if (isImpassible()) lineList += FormattedLine(Constants.impassable)
return lineList.joinToString("\n") return lineList
} }
fun hasEnemyInvisibleUnit(viewingCiv: CivilizationInfo): Boolean { fun hasEnemyInvisibleUnit(viewingCiv: CivilizationInfo): Boolean {
val unitsInTile = getUnits() val unitsInTile = getUnits()
if (unitsInTile.none()) return false if (unitsInTile.none()) return false
@ -649,7 +664,7 @@ open class TileInfo {
private fun normalizeTileImprovement(ruleset: Ruleset) { private fun normalizeTileImprovement(ruleset: Ruleset) {
if (improvement!!.startsWith("StartingLocation") == true) { if (improvement!!.startsWith("StartingLocation")) {
if (!isLand || getLastTerrain().impassable) improvement = null if (!isLand || getLastTerrain().impassable) improvement = null
return return
} }

View File

@ -7,6 +7,8 @@ import com.unciv.logic.map.TileInfo
import com.unciv.models.UncivSound import com.unciv.models.UncivSound
import com.unciv.models.stats.Stats import com.unciv.models.stats.Stats
import com.unciv.models.translations.tr import com.unciv.models.translations.tr
import com.unciv.ui.civilopedia.CivilopediaScreen
import com.unciv.ui.civilopedia.MarkupRenderer
import com.unciv.ui.utils.* import com.unciv.ui.utils.*
import kotlin.math.roundToInt import kotlin.math.roundToInt
@ -32,7 +34,10 @@ class CityScreenTileTable(private val cityScreen: CityScreen): Table() {
val stats = selectedTile.getTileStats(city, city.civInfo) val stats = selectedTile.getTileStats(city, city.civInfo)
innerTable.pad(5f) innerTable.pad(5f)
innerTable.add(selectedTile.toString(city.civInfo).toLabel()).colspan(2) innerTable.add( MarkupRenderer.render(selectedTile.toMarkup(city.civInfo)) {
// Sorry, this will leave the city screen
UncivGame.Current.setScreen(CivilopediaScreen(city.civInfo.gameInfo.ruleSet, link = it))
} ).colspan(2)
innerTable.row() innerTable.row()
innerTable.add(getTileStatsTable(stats)).row() innerTable.add(getTileStatsTable(stats)).row()

View File

@ -28,7 +28,11 @@ object CivilopediaImageGetters {
} }
TerrainType.TerrainFeature -> { TerrainType.TerrainFeature -> {
tileInfo.terrainFeatures.add(terrain.name) tileInfo.terrainFeatures.add(terrain.name)
tileInfo.baseTerrain = terrain.occursOn.lastOrNull() ?: Constants.grassland tileInfo.baseTerrain =
if (terrain.occursOn.isEmpty() || terrain.occursOn.contains(Constants.grassland))
Constants.grassland
else
terrain.occursOn.lastOrNull()!!
} }
else -> else ->
tileInfo.baseTerrain = terrain.name tileInfo.baseTerrain = terrain.name

View File

@ -0,0 +1,112 @@
package com.unciv.ui.civilopedia
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.scenes.scene2d.Actor
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.utils.Align
import com.unciv.ui.utils.*
/** Represents a text line with optional linking capability.
* Special cases:
* - Automatic external links (no [text] but [link] begins with a URL protocol)
*
* @param text Text to display.
* @param link Create link: Line gets a 'Link' icon and is linked to either
* an Unciv object (format `category/entryname`) or an external URL.
*/
class FormattedLine (
val text: String = "",
val link: String = "",
) {
// Note: This gets directly deserialized by Json - please keep all attributes meant to be read
// from json in the primary constructor parameters above. Everything else should be a fun(),
// have no backing field, be `by lazy` or use @Transient, Thank you.
/** Link types that can be used for [FormattedLine.link] */
enum class LinkType {
None,
/** Link points to a Civilopedia entry in the form `category/item` **/
Internal,
/** Link opens as URL in external App - begins with `https://`, `http://` or `mailto:` **/
External
}
/** The type of the [link]'s destination */
val linkType: LinkType by lazy {
when {
link.hasProtocol() -> LinkType.External
link.isNotEmpty() -> LinkType.Internal
else -> LinkType.None
}
}
private val textToDisplay: String by lazy {
if (text.isEmpty() && linkType == LinkType.External) link else text
}
/** Returns true if this formatted line will not display anything */
fun isEmpty(): Boolean = text.isEmpty() && link.isEmpty()
/** Extension: determines if a [String] looks like a link understood by the OS */
private fun String.hasProtocol() = startsWith("http://") || startsWith("https://") || startsWith("mailto:")
/**
* Renders the formatted line as a scene2d [Actor] (currently always a [Table])
* @param labelWidth Total width to render into, needed to support wrap on Labels.
*/
fun render(labelWidth: Float): Actor {
val table = Table(CameraStageBaseScreen.skin)
if (textToDisplay.isNotEmpty()) {
val label = textToDisplay.toLabel()
label.wrap = labelWidth > 0f
if (labelWidth == 0f)
table.add(label)
else
table.add(label).width(labelWidth)
}
return table
}
}
/** Makes [renderer][render] available outside [ICivilopediaText] */
object MarkupRenderer {
private const val emptyLineHeight = 10f
private const val defaultPadding = 2.5f
/**
* Build a Gdx [Table] showing [formatted][FormattedLine] [content][lines].
*
* @param lines The formatted content to render.
* @param labelWidth Available width needed for wrapping labels and [centered][FormattedLine.centered] attribute.
* @param linkAction Delegate to call for internal links. Leave null to suppress linking.
*/
fun render(
lines: Collection<FormattedLine>,
labelWidth: Float = 0f,
linkAction: ((id: String) -> Unit)? = null
): Table {
val skin = CameraStageBaseScreen.skin
val table = Table(skin).apply { defaults().pad(defaultPadding).align(Align.left) }
for (line in lines) {
if (line.isEmpty()) {
table.add().padTop(emptyLineHeight).row()
continue
}
val actor = line.render(labelWidth)
if (line.linkType == FormattedLine.LinkType.Internal && linkAction != null)
actor.onClick {
linkAction(line.link)
}
else if (line.linkType == FormattedLine.LinkType.External)
actor.onClick {
Gdx.net.openURI(line.link)
}
if (labelWidth == 0f)
table.add(actor).row()
else
table.add(actor).width(labelWidth).row()
}
return table.apply { pack() }
}
}

View File

@ -471,8 +471,15 @@ class WorldMapHolder(internal val worldScreen: WorldScreen, internal val tileMap
} }
var blinkAction: Action? = null var blinkAction: Action? = null
fun setCenterPosition(vector: Vector2, immediately: Boolean = false, selectUnit: Boolean = true) {
val tileGroup = allWorldTileGroups.firstOrNull { it.tileInfo.position == vector } ?: return /** Scrolls the world map to specified coordinates.
* @param vector Position to center on
* @param immediately Do so without animation
* @param selectUnit Select a unit at the destination
* @return `true` if scroll position was changed, `false` otherwise
*/
fun setCenterPosition(vector: Vector2, immediately: Boolean = false, selectUnit: Boolean = true): Boolean {
val tileGroup = allWorldTileGroups.firstOrNull { it.tileInfo.position == vector } ?: return false
selectedTile = tileGroup.tileInfo selectedTile = tileGroup.tileInfo
if (selectUnit) if (selectUnit)
worldScreen.bottomUnitTable.tileSelected(selectedTile!!) worldScreen.bottomUnitTable.tileSelected(selectedTile!!)
@ -487,6 +494,8 @@ class WorldMapHolder(internal val worldScreen: WorldScreen, internal val tileMap
// Here it's the same, only the Y axis is inverted - when at 0 we're at the top, not bottom - so we invert it back. // Here it's the same, only the Y axis is inverted - when at 0 we're at the top, not bottom - so we invert it back.
val finalScrollY = maxY - (tileGroup.y + tileGroup.width / 2 - height / 2) val finalScrollY = maxY - (tileGroup.y + tileGroup.width / 2 - height / 2)
if (finalScrollX == originalScrollX && finalScrollY == originalScrollY) return false
if (immediately) { if (immediately) {
scrollX = finalScrollX scrollX = finalScrollX
scrollY = finalScrollY scrollY = finalScrollY
@ -513,6 +522,7 @@ class WorldMapHolder(internal val worldScreen: WorldScreen, internal val tileMap
addAction(blinkAction) // Don't set it on the group because it's an actionlss group addAction(blinkAction) // Don't set it on the group because it's an actionlss group
worldScreen.shouldUpdate = true worldScreen.shouldUpdate = true
return true
} }
override fun zoom(zoomScale: Float) { override fun zoom(zoomScale: Float) {

View File

@ -6,6 +6,8 @@ import com.badlogic.gdx.utils.Align
import com.unciv.UncivGame import com.unciv.UncivGame
import com.unciv.logic.civilization.CivilizationInfo import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.map.TileInfo import com.unciv.logic.map.TileInfo
import com.unciv.ui.civilopedia.CivilopediaScreen
import com.unciv.ui.civilopedia.MarkupRenderer
import com.unciv.ui.utils.CameraStageBaseScreen import com.unciv.ui.utils.CameraStageBaseScreen
import com.unciv.ui.utils.ImageGetter import com.unciv.ui.utils.ImageGetter
import com.unciv.ui.utils.toLabel import com.unciv.ui.utils.toLabel
@ -20,7 +22,9 @@ class TileInfoTable(private val viewingCiv :CivilizationInfo) : Table(CameraStag
if (tile != null && (UncivGame.Current.viewEntireMapForDebug || viewingCiv.exploredTiles.contains(tile.position)) ) { if (tile != null && (UncivGame.Current.viewEntireMapForDebug || viewingCiv.exploredTiles.contains(tile.position)) ) {
add(getStatsTable(tile)) add(getStatsTable(tile))
add(tile.toString(viewingCiv).toLabel()).colspan(2).pad(10f) add( MarkupRenderer.render(tile.toMarkup(viewingCiv) ) {
UncivGame.Current.setScreen(CivilopediaScreen(viewingCiv.gameInfo.ruleSet, link = it))
} ).pad(10f)
// For debug only! // For debug only!
// add(tile.position.toString().toLabel()).colspan(2).pad(10f) // add(tile.position.toString().toLabel()).colspan(2).pad(10f)
} }
@ -40,4 +44,4 @@ class TileInfoTable(private val viewingCiv :CivilizationInfo) : Table(CameraStag
} }
return table return table
} }
} }

View File

@ -13,6 +13,8 @@ import com.unciv.logic.city.CityInfo
import com.unciv.logic.map.MapUnit import com.unciv.logic.map.MapUnit
import com.unciv.logic.map.TileInfo import com.unciv.logic.map.TileInfo
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.pickerscreens.PromotionPickerScreen import com.unciv.ui.pickerscreens.PromotionPickerScreen
import com.unciv.ui.utils.* import com.unciv.ui.utils.*
import com.unciv.ui.worldscreen.WorldScreen import com.unciv.ui.worldscreen.WorldScreen
@ -78,7 +80,9 @@ class UnitTable(val worldScreen: WorldScreen) : Table(){
touchable = Touchable.enabled touchable = Touchable.enabled
onClick { onClick {
selectedUnit?.currentTile?.position?.let { selectedUnit?.currentTile?.position?.let {
worldScreen.mapHolder.setCenterPosition(it, false, false) if ( !worldScreen.mapHolder.setCenterPosition(it, false, false) && selectedUnit != null ) {
worldScreen.game.setScreen(CivilopediaScreen(worldScreen.gameInfo.ruleSet, CivilopediaCategories.Unit, selectedUnit!!.name))
}
} }
} }
}).expand() }).expand()