mirror of
https://github.com/yairm210/Unciv.git
synced 2025-01-09 23:07:35 +07:00
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:
parent
8ef84d785e
commit
e9e0f2c55f
BIN
android/Images/OtherIcons/Wonders.png
Normal file
BIN
android/Images/OtherIcons/Wonders.png
Normal file
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 |
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
244
core/src/com/unciv/ui/overviewscreen/WonderOverviewTable.kt
Normal file
244
core/src/com/unciv/ui/overviewscreen/WonderOverviewTable.kt
Normal 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()
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user