World and Natural Wonders Overview (#5297)

* World and Natural Wonders Overview

* World and Natural Wonders Overview - icon

* World and Natural Wonders Overview - groups and tuning

* World and Natural Wonders Overview - atlas

* World and Natural Wonders Overview - lint
This commit is contained in:
SomeTroglodyte 2021-09-24 09:04:30 +02:00 committed by GitHub
parent 8ef84d785e
commit e9e0f2c55f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 628 additions and 365 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 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

@ -872,6 +872,16 @@ Known and defeated ([numberOfCivs]) =
Tiles =
Natural Wonders =
Treasury deficit =
Unknown =
Not built =
Not found =
Known =
Owned =
Near [city] =
Somewhere around [city] =
Far away =
Status =
Location =
# Victory

View File

@ -23,7 +23,7 @@ class EmpireOverviewScreen(private var viewingPlayer:CivilizationInfo, defaultPa
// 50 normal button height + 2*10 topTable padding + 2 Separator + 2*5 centerTable padding
// Since a resize recreates this screen this should be fine as a val
internal val centerAreaHeight = stage.height - 82f
private object ButtonDecorations {
data class IconAndKey (val icon: String, val key: Char = Char.MIN_VALUE)
val keyIconMap: HashMap<String,IconAndKey> = hashMapOf(
@ -33,7 +33,8 @@ class EmpireOverviewScreen(private var viewingPlayer:CivilizationInfo, defaultPa
Pair("Units", IconAndKey("OtherIcons/Shield", 'U')),
Pair("Diplomacy", IconAndKey("OtherIcons/DiplomacyW", 'D')),
Pair("Resources", IconAndKey("StatIcons/Happiness", 'R')),
Pair("Religion", IconAndKey("StatIcons/Faith", 'F'))
Pair("Religion", IconAndKey("StatIcons/Faith", 'F')),
Pair("Wonders", IconAndKey("OtherIcons/Wonders", 'W'))
)
}
@ -79,8 +80,8 @@ class EmpireOverviewScreen(private var viewingPlayer:CivilizationInfo, defaultPa
else game.settings.lastOverviewPage
onBackButtonClicked { game.setWorldScreen() }
addCategory("Cities", CityOverviewTable(viewingPlayer, this), viewingPlayer.cities.none())
addCategory("Cities", CityOverviewTable(viewingPlayer, this), viewingPlayer.cities.isEmpty())
addCategory("Stats", StatsOverviewTable(viewingPlayer, this))
addCategory("Trades", TradesOverviewTable(viewingPlayer, this), viewingPlayer.diplomacy.values.all { it.trades.isEmpty() })
addCategory("Units", UnitOverviewTable(viewingPlayer, this), viewingPlayer.getCivUnits().none())
@ -88,6 +89,7 @@ class EmpireOverviewScreen(private var viewingPlayer:CivilizationInfo, defaultPa
addCategory("Resources", ResourcesOverviewTable(viewingPlayer, this), viewingPlayer.detailedCivResources.isEmpty())
if (viewingPlayer.gameInfo.isReligionEnabled())
addCategory("Religion", ReligionOverviewTable(viewingPlayer, this), viewingPlayer.gameInfo.religions.isEmpty())
addCategory("Wonders", WonderOverviewTable(viewingPlayer, this), viewingPlayer.naturalWonders.isEmpty() && viewingPlayer.cities.isEmpty())
val closeButton = Constants.close.toTextButton().apply {
setColor(0.75f, 0.1f, 0.1f, 1f)

View File

@ -0,0 +1,244 @@
package com.unciv.ui.overviewscreen
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.utils.Align
import com.unciv.Constants
import com.unciv.UncivGame
import com.unciv.logic.city.CityInfo
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.map.TileInfo
import com.unciv.models.ruleset.Building
import com.unciv.models.ruleset.Era
import com.unciv.models.ruleset.QuestName
import com.unciv.models.ruleset.VictoryType
import com.unciv.models.translations.tr
import com.unciv.ui.civilopedia.CivilopediaCategories
import com.unciv.ui.civilopedia.CivilopediaScreen
import com.unciv.ui.utils.ImageGetter
import com.unciv.ui.utils.onClick
import com.unciv.ui.utils.toLabel
class WonderOverviewTable(
private val viewingPlayer: CivilizationInfo,
@Suppress("unused") private val overviewScreen: EmpireOverviewScreen
): Table() {
val gameInfo = viewingPlayer.gameInfo
val ruleSet = gameInfo.ruleSet
private val hideReligionItems = !gameInfo.isReligionEnabled()
private val viewerEra = viewingPlayer.getEraNumber()
private val startingObsolete = ruleSet.eras[gameInfo.gameParameters.startingEra]!!.startingObsoleteWonders
private enum class WonderStatus(val label: String) {
Hidden(""),
Unknown("Unknown"),
Unbuilt("Not built"),
NotFound("Not found"),
Known("Known"),
Owned("Owned")
}
private class WonderInfo (
val name: String,
val category: CivilopediaCategories,
val groupName: String,
val groupColor: Color,
val status: WonderStatus,
val civ: CivilizationInfo?,
val city: CityInfo?,
val location: TileInfo?
) {
val viewEntireMapForDebug = UncivGame.Current.viewEntireMapForDebug
fun getImage() = if (status == WonderStatus.Unknown && !viewEntireMapForDebug) null
else category.getImage?.invoke(name, if (category == CivilopediaCategories.Terrain) 50f else 45f)
fun getNameColumn() = when {
viewEntireMapForDebug -> name
status == WonderStatus.Unknown -> status.label
else -> name
}
fun getStatusColumn() = when {
status != WonderStatus.Known -> status.label
civ == null -> status.label
else -> civ.civName
}
fun getLocationColumn() = when {
status <= WonderStatus.NotFound -> ""
location == null -> ""
location.isCityCenter() -> location.getCity()!!.name
location.getCity() != null -> "Near [${location.getCity()!!}]"
city != null -> "Somewhere around [$city]"
viewEntireMapForDebug -> location.position.toString()
else -> "Far away"
}
}
private val wonders: Array<WonderInfo> = collectInfo()
init {
createGrid()
}
private fun shouldBeDisplayed(wonder: Building, wonderEra: Int) = when {
Constants.hideFromCivilopediaUnique in wonder.uniques -> false
Constants.hiddenWithoutReligionUnique in wonder.uniques && hideReligionItems -> false
wonder.name in startingObsolete -> false
wonder.uniqueObjects.filter { unique ->
unique.placeholderText == "Hidden when [] Victory is disabled"
}.any { unique ->
!gameInfo.gameParameters.victoryTypes.contains(VictoryType.valueOf(unique.params[0]))
} -> false
else -> wonderEra <= viewerEra
}
/** Do we know about a natural wonder despite not having found it yet? */
private fun knownFromQuest(name: String): Boolean {
// No, *your* civInfo's QuestManager has no idea about your quests
for (civ in gameInfo.civilizations) {
for (quest in civ.questManager.assignedQuests) {
if (quest.assignee != viewingPlayer.civName) continue
if (quest.questName == QuestName.FindNaturalWonder.value && quest.data1 == name)
return true
}
}
return false
}
private fun collectInfo(): Array<WonderInfo> {
val collator = UncivGame.Current.settings.getCollatorFromLocale()
// Maps all World Wonders by name to their era for grouping
val wonderEraMap: Map<String, Era> =
ruleSet.buildings.values.asSequence()
.filter { it.isWonder }
.map { it.name to ruleSet.eras[ruleSet.technologies[it.requiredTech]?.era()]!! }
.toMap()
// Maps all World Wonders by their position in sort order to their name
val allWonderMap: Map<Int, String> =
ruleSet.buildings.values.asSequence()
.filter { it.isWonder }
.sortedWith(compareBy<Building> { wonderEraMap[it.name]!!.eraNumber }.thenBy(collator, { it.name.tr() }))
.withIndex()
.map { it.index to it.value.name }
.toMap()
val wonderCount = allWonderMap.size
// Inverse of the above
val wonderIndexMap: Map<String, Int> = allWonderMap.map { it.value to it.key }.toMap()
// Maps all Natural Wonders on the map by name to their tile
val allNaturalsMap: Map<String, TileInfo> =
gameInfo.tileMap.values.asSequence()
.filter { it.isNaturalWonder() }
.map { it.naturalWonder!! to it }
.toMap()
val naturalsCount = allNaturalsMap.size
// Natural Wonders sort order index to name
val naturalsIndexMap: Map<Int, String> = allNaturalsMap.keys
.sortedWith(compareBy(collator, { it.tr() }))
.withIndex()
.map { it.index to it.value }
.toMap()
// Pre-populate result with "Unknown" entries
val wonders = Array(wonderCount + naturalsCount) { index ->
if (index < wonderCount) {
val wonder = ruleSet.buildings[allWonderMap[index]!!]!!
val era = wonderEraMap[wonder.name]!!
val status = if (shouldBeDisplayed(wonder, era.eraNumber)) WonderStatus.Unbuilt else WonderStatus.Hidden
WonderInfo(allWonderMap[index]!!, CivilopediaCategories.Wonder,
era.name, era.getColor(), status, null, null, null)
} else {
WonderInfo(naturalsIndexMap[index - wonderCount]!!, CivilopediaCategories.Terrain,
"Natural Wonders", Color.FOREST, WonderStatus.Unknown, null, null, null)
}
}
for (city in gameInfo.getCities()) {
for (wonderName in city.cityConstructions.builtBuildings.intersect(wonderIndexMap.keys)) {
val index = wonderIndexMap[wonderName]!!
val status = when {
viewingPlayer == city.civInfo -> WonderStatus.Owned
viewingPlayer.knows(city.civInfo) -> WonderStatus.Known
else -> WonderStatus.Unknown
}
wonders[index] = WonderInfo(wonderName, CivilopediaCategories.Wonder,
wonders[index].groupName, wonders[index].groupColor,
status, city.civInfo, city, city.getCenterTile())
}
}
for ((index, name) in naturalsIndexMap) {
val tile = allNaturalsMap[name]!!
val civ = tile.getOwner()
val status = when {
civ == viewingPlayer -> WonderStatus.Owned
name in viewingPlayer.naturalWonders -> WonderStatus.Known
else -> WonderStatus.NotFound
}
if (status == WonderStatus.NotFound && !knownFromQuest(name)) continue
val city = if (status == WonderStatus.NotFound) null
else tile.getTilesInDistance(5)
.filter { it.isCityCenter() }
.filter { viewingPlayer.knows(it.getOwner()!!) }
.filter { it.position in viewingPlayer.exploredTiles }
.sortedBy { it.aerialDistanceTo(tile) }
.firstOrNull()?.getCity()
wonders[index + wonderCount] = WonderInfo(name, CivilopediaCategories.Terrain,
"Natural Wonders", Color.FOREST, status, civ, city, tile)
}
return wonders
}
fun createGrid() {
defaults().pad(10f).align(Align.center)
add()
add("Name".toLabel())
add("Status".toLabel())
add("Location".toLabel())
add().minWidth(30f)
row()
//addSeparator()
var lastGroup = ""
for (wonder in wonders) {
if (wonder.status == WonderStatus.Hidden) continue
if (wonder.groupName != lastGroup) {
lastGroup = wonder.groupName
val groupRow = Table().apply {
add(ImageGetter.getDot(wonder.groupColor)).minHeight(2f).growX()
add(lastGroup.toLabel(wonder.groupColor).apply { setAlignment(Align.right) }).padLeft(1f).right()
}
add(groupRow).fillX().colspan(5).padBottom(0f).row()
}
val image = wonder.getImage()
image?.onClick {
UncivGame.Current.setScreen(CivilopediaScreen(ruleSet, wonder.category, wonder.name))
}
// Terrain image padding is a bit unpredictable, they need ~5f more. Ensure equal line spacing on name, not image:
add(image).pad(0f, 10f, 0f, 10f)
add(wonder.getNameColumn().toLabel()).pad(15f, 10f, 15f, 10f)
add(wonder.getStatusColumn().toLabel())
val locationText = wonder.getLocationColumn()
if (locationText.isNotEmpty()) {
val locationLabel = locationText.toLabel()
if (wonder.location != null)
locationLabel.onClick{
UncivGame.Current.setWorldScreen()
UncivGame.Current.worldScreen.mapHolder.setCenterPosition(wonder.location.position)
}
add(locationLabel).fillY()
}
row()
}
}
}