diff --git a/android/Images/OtherIcons/Politics.png b/android/Images/OtherIcons/Politics.png new file mode 100644 index 0000000000..4d0c5ed196 Binary files /dev/null and b/android/Images/OtherIcons/Politics.png differ diff --git a/android/assets/jsons/translations/template.properties b/android/assets/jsons/translations/template.properties index 5eae7fda79..5389493f88 100644 --- a/android/assets/jsons/translations/template.properties +++ b/android/assets/jsons/translations/template.properties @@ -1219,6 +1219,15 @@ Number of your cities celebrating\n'We Love The King Day' thanks\nto access to t WLTK demand = WLTK- = Number of your cities\ndemanding this resource for\n'We Love The King Day' = +Show global politics = +Show diagram = +At war with [enemy] = +Friends with [civName] = +[numberOfTurns] Turns Left = +Denounced [otherCiv] = +Allied with [civName] = +Civilization Info = +Relations = Trade request = # Victory diff --git a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt index e0d226b8e4..6ce2e0437f 100644 --- a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt +++ b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt @@ -44,6 +44,7 @@ import com.unciv.ui.utils.extensions.toPercent import com.unciv.ui.utils.extensions.withItem import com.unciv.ui.victoryscreen.RankingType import java.util.* +import kotlin.collections.HashMap import kotlin.math.max import kotlin.math.min import kotlin.math.roundToInt diff --git a/core/src/com/unciv/logic/civilization/WonderInfo.kt b/core/src/com/unciv/logic/civilization/WonderInfo.kt new file mode 100644 index 0000000000..8ff3c7531a --- /dev/null +++ b/core/src/com/unciv/logic/civilization/WonderInfo.kt @@ -0,0 +1,191 @@ +package com.unciv.logic.civilization + +import com.badlogic.gdx.graphics.Color +import com.unciv.UncivGame +import com.unciv.logic.city.CityInfo +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.unique.UniqueType +import com.unciv.models.translations.tr +import com.unciv.ui.civilopedia.CivilopediaCategories + +class WonderInfo { + val gameInfo = UncivGame.Current.gameInfo!! + val viewingPlayer = gameInfo.getCurrentPlayerCivilization() + val ruleSet = gameInfo.ruleSet + private val hideReligionItems = !gameInfo.isReligionEnabled() + private val viewerEra = viewingPlayer.getEraNumber() + private val startingObsolete = ruleSet.eras[gameInfo.gameParameters.startingEra]!!.startingObsoleteWonders + + enum class WonderStatus(val label: String) { + Hidden(""), + Unknown("Unknown"), + Unbuilt("Not built"), + NotFound("Not found"), + Known("Known"), + Owned("Owned") + } + + 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 fun shouldBeDisplayed(wonder: Building, wonderEra: Int) = when { + wonder.hasUnique(UniqueType.HiddenFromCivilopedia) -> false + wonder.hasUnique(UniqueType.HiddenWithoutReligion) && hideReligionItems -> false + wonder.name in startingObsolete -> false + wonder.getMatchingUniques(UniqueType.HiddenWithoutVictoryType) + .any { unique -> + !gameInfo.gameParameters.victoryTypes.contains(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 + } + + fun collectInfo(): Array { + val collator = UncivGame.Current.settings.getCollatorFromLocale() + + // Maps all World Wonders by name to their era for grouping + val wonderEraMap: Map = + ruleSet.buildings.values.asSequence() + .filter { it.isWonder } + .associate { it.name to (ruleSet.eras[ruleSet.technologies[it.requiredTech]?.era()] ?: viewingPlayer.getEra()) } + + // Maps all World Wonders by their position in sort order to their name + val allWonderMap: Map = + ruleSet.buildings.values.asSequence() + .filter { it.isWonder } + .sortedWith(compareBy { wonderEraMap[it.name]!!.eraNumber }.thenBy(collator) { it.name.tr() }) + .withIndex() + .associate { it.index to it.value.name } + val wonderCount = allWonderMap.size + + // Inverse of the above + val wonderIndexMap: Map = allWonderMap.map { it.value to it.key }.toMap() + + // Maps all Natural Wonders on the map by name to their tile + val allNaturalsMap: Map = + gameInfo.tileMap.values.asSequence() + .filter { it.isNaturalWonder() } + .associateBy { it.naturalWonder!! } + val naturalsCount = allNaturalsMap.size + + // Natural Wonders sort order index to name + val naturalsIndexMap: Map = allNaturalsMap.keys + .sortedWith(compareBy(collator) { it.tr() }) + .withIndex() + .associate { it.index to it.value } + + // 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.exploredTiles.contains(city.location) -> WonderStatus.Known + else -> WonderStatus.NotFound + } + 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 + } +} diff --git a/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt b/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt index d4c2c9c556..47ff038df4 100644 --- a/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt +++ b/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt @@ -823,6 +823,7 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization { otherCivDiplomacy().setModifier(DiplomaticModifiers.DeclarationOfFriendship, 35f) setFlag(DiplomacyFlags.DeclarationOfFriendship, 30) otherCivDiplomacy().setFlag(DiplomacyFlags.DeclarationOfFriendship, 30) + if (otherCiv().playerType == PlayerType.Human) otherCiv().addNotification("[${civInfo.civName}] and [$otherCivName] have signed the Declaration of Friendship!", civInfo.civName, NotificationIcon.Diplomacy, otherCivName) diff --git a/core/src/com/unciv/ui/overviewscreen/EmpireOverviewCategories.kt b/core/src/com/unciv/ui/overviewscreen/EmpireOverviewCategories.kt index 055c853b8f..198b48ad58 100644 --- a/core/src/com/unciv/ui/overviewscreen/EmpireOverviewCategories.kt +++ b/core/src/com/unciv/ui/overviewscreen/EmpireOverviewCategories.kt @@ -40,10 +40,10 @@ enum class EmpireOverviewCategories( fun (viewingPlayer: CivilizationInfo, overviewScreen: EmpireOverviewScreen, persistedData: EmpireOverviewTabPersistableData?) = UnitOverviewTab(viewingPlayer, overviewScreen, persistedData), fun (viewingPlayer: CivilizationInfo) = viewingPlayer.getCivUnits().none().toState()), - Diplomacy("OtherIcons/DiplomacyW", 'D', Align.top, + Politics("OtherIcons/Politics", 'P', Align.top, fun (viewingPlayer: CivilizationInfo, overviewScreen: EmpireOverviewScreen, persistedData: EmpireOverviewTabPersistableData?) - = DiplomacyOverviewTab(viewingPlayer, overviewScreen, persistedData), - fun (viewingPlayer: CivilizationInfo) = viewingPlayer.diplomacy.isEmpty().toState()), + = GlobalPoliticsOverviewTable(viewingPlayer, overviewScreen, persistedData), + fun (_: CivilizationInfo) = EmpireOverviewTabState.Normal), Resources("StatIcons/Happiness", 'R', Align.topLeft, fun (viewingPlayer: CivilizationInfo, overviewScreen: EmpireOverviewScreen, persistedData: EmpireOverviewTabPersistableData?) = ResourcesOverviewTab(viewingPlayer, overviewScreen, persistedData), diff --git a/core/src/com/unciv/ui/overviewscreen/DiplomacyOverviewTable.kt b/core/src/com/unciv/ui/overviewscreen/GlobalPoliticsOverviewTable.kt similarity index 61% rename from core/src/com/unciv/ui/overviewscreen/DiplomacyOverviewTable.kt rename to core/src/com/unciv/ui/overviewscreen/GlobalPoliticsOverviewTable.kt index 561ef952d8..d6ad8f959f 100644 --- a/core/src/com/unciv/ui/overviewscreen/DiplomacyOverviewTable.kt +++ b/core/src/com/unciv/ui/overviewscreen/GlobalPoliticsOverviewTable.kt @@ -6,13 +6,15 @@ import com.badlogic.gdx.scenes.scene2d.Group import com.badlogic.gdx.scenes.scene2d.Touchable import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.scenes.scene2d.ui.TextButton -import com.badlogic.gdx.scenes.scene2d.ui.TextButton.TextButtonStyle import com.badlogic.gdx.utils.Align import com.unciv.Constants import com.unciv.UncivGame import com.unciv.logic.HexMath import com.unciv.logic.civilization.CivilizationInfo +import com.unciv.logic.civilization.WonderInfo +import com.unciv.logic.civilization.diplomacy.DiplomacyFlags import com.unciv.logic.civilization.diplomacy.DiplomaticStatus +import com.unciv.logic.civilization.diplomacy.RelationshipLevel import com.unciv.ui.images.ImageGetter import com.unciv.ui.trade.DiplomacyScreen import com.unciv.ui.utils.AutoScrollPane @@ -20,17 +22,19 @@ import com.unciv.ui.utils.BaseScreen import com.unciv.ui.utils.UncivTooltip.Companion.addTooltip import com.unciv.ui.utils.extensions.addBorder import com.unciv.ui.utils.extensions.addSeparator +import com.unciv.ui.utils.extensions.addSeparatorVertical import com.unciv.ui.utils.extensions.center import com.unciv.ui.utils.extensions.onClick import com.unciv.ui.utils.extensions.toLabel import com.unciv.ui.utils.extensions.toTextButton import kotlin.math.roundToInt -class DiplomacyOverviewTab ( +class GlobalPoliticsOverviewTable ( viewingPlayer: CivilizationInfo, overviewScreen: EmpireOverviewScreen, persistedData: EmpireOverviewTabPersistableData? = null ) : EmpireOverviewTab(viewingPlayer, overviewScreen) { + class DiplomacyTabPersistableData( var includeCityStates: Boolean = false ) : EmpireOverviewTabPersistableData() { @@ -44,19 +48,6 @@ class DiplomacyOverviewTab ( defaults().pad(5f) background = ImageGetter.getBackground(Color.BLACK) } - val toggleCityStatesButton: TextButton = Constants.cityStates.toTextButton().apply { - onClick { - persistableData.includeCityStates = !persistableData.includeCityStates - update() - } - } - private val civTableScroll = AutoScrollPane(civTable).apply { - setOverscroll(false, false) - } - private val floatingTable = Table().apply { - add(toggleCityStatesButton).row() - add(civTableScroll.addBorder(2f, Color.WHITE)).pad(10f) - } // Reusable sequences for the Civilizations to display private var undefeatedCivs = sequenceOf() @@ -66,14 +57,178 @@ class DiplomacyOverviewTab ( private var showDiplomacyGroup = false private var portraitMode = false + init { - update() + updatePoliticsTable() + } + + private fun updatePoliticsTable() { + clear() + getFixedContent().clear() + + val diagramButton = TextButton("Show diagram", skin) + diagramButton.onClick { updateDiagram() } + + add() + addSeparatorVertical(Color.GRAY) + add("Civilization Info".toLabel()) + addSeparatorVertical(Color.GRAY) + add("Social policies".toLabel()) + addSeparatorVertical(Color.GRAY) + add("Wonders".toLabel()) + addSeparatorVertical(Color.GRAY) + add("Relations".toLabel()) + add(diagramButton).pad(10f) + row() + addSeparator(Color.GRAY) + + createGlobalPoliticsTable() + } + + private fun createGlobalPoliticsTable() { + val civilizations = mutableListOf() + civilizations.add(viewingPlayer) + civilizations.addAll(viewingPlayer.getKnownCivs()) + civilizations.removeAll(civilizations.filter { it.isBarbarian() || it.isCityState() || it.isSpectator() }) + for (civ in civilizations) { + // civ image + add(ImageGetter.getNationIndicator(civ.nation, 100f)).pad(20f) + + addSeparatorVertical(Color.GRAY) + + // info about civ + add(getCivInfoTable(civ)).pad(20f) + + addSeparatorVertical(Color.GRAY) + + // policies + add(getPoliciesTable(civ)).pad(20f) + + addSeparatorVertical(Color.GRAY) + + // wonders + add(getWondersOfCivTable(civ)).pad(20f) + + addSeparatorVertical(Color.GRAY) + + //politics + add(getPoliticsOfCivTable(civ)).pad(20f) + + if (civilizations.indexOf(civ) != civilizations.lastIndex) + addSeparator(Color.GRAY) + } + } + + private fun getCivInfoTable(civ: CivilizationInfo): Table { + val civInfoTable = Table(skin) + val leaderName = civ.getLeaderDisplayName().removeSuffix(" of " + civ.civName) + civInfoTable.add(leaderName.toLabel(fontSize = 30)).row() + civInfoTable.add(civ.civName.toLabel()).row() + civInfoTable.add(civ.tech.era.name.toLabel()).row() + return civInfoTable + } + + private fun getPoliciesTable(civ: CivilizationInfo): Table { + val policiesTable = Table(skin) + for (policy in civ.policies.branchCompletionMap) { + if (policy.value != 0) + policiesTable.add("${policy.key.name}: ${policy.value}".toLabel()).row() + } + return policiesTable + } + + private fun getWondersOfCivTable(civ: CivilizationInfo): Table { + val wonderTable = Table(skin) + val wonderInfo = WonderInfo() + val allWorldWonders = wonderInfo.collectInfo() + + for (wonder in allWorldWonders) { + if (wonder.civ?.civName == civ.civName) { + val wonderName = wonder.name.toLabel() + if (wonder.location != null) { + wonderName.onClick { + val worldScreen = UncivGame.Current.resetToWorldScreen() + worldScreen.mapHolder.setCenterPosition(wonder.location.position) + } + } + wonderTable.add(wonderName).row() + } + } + + return wonderTable + } + + private fun getPoliticsOfCivTable(civ: CivilizationInfo): Table { + val politicsTable = Table(skin) + + // wars + for (otherCiv in civ.getKnownCivs()) { + if(civ.diplomacy[otherCiv.civName]?.hasFlag(DiplomacyFlags.DeclaredWar) == true) { + val warText = "At war with ${otherCiv.civName}".toLabel() + warText.color = Color.RED + politicsTable.add(warText).row() + } + } + politicsTable.row() + + // declaration of friendships + for (otherCiv in civ.getKnownCivs()) { + if(civ.diplomacy[otherCiv.civName]?.hasFlag(DiplomacyFlags.DeclarationOfFriendship) == true) { + val friendtext = "Friends with ${otherCiv.civName} ".toLabel() + friendtext.color = Color.GREEN + val turnsLeftText = "({${civ.diplomacy[otherCiv.civName]?.getFlag(DiplomacyFlags.DeclarationOfFriendship)} Turns Left})".toLabel() + politicsTable.add(friendtext) + politicsTable.add(turnsLeftText).row() + } + } + politicsTable.row() + + // denounced civs + for (otherCiv in civ.getKnownCivs()) { + if(civ.diplomacy[otherCiv.civName]?.hasFlag(DiplomacyFlags.Denunciation) == true) { + val denouncedText = "Denounced ${otherCiv.civName} ".toLabel() + denouncedText.color = Color.RED + val turnsLeftText = "({${civ.diplomacy[otherCiv.civName]?.getFlag(DiplomacyFlags.Denunciation)} Turns Left})".toLabel() + politicsTable.add(denouncedText) + politicsTable.add(turnsLeftText).row() + } + } + politicsTable.row() + + //allied CS + for (cityState in gameInfo.getAliveCityStates()) { + if (cityState.diplomacy[civ.civName]?.relationshipLevel() == RelationshipLevel.Ally) { + val alliedText = "Allied with ${cityState.civName}".toLabel() + alliedText.color = Color.GREEN + politicsTable.add(alliedText).row() + } + } + + return politicsTable } override fun getFixedContent() = fixedContent // Refresh content and determine landscape/portrait layout - private fun update() { + private fun updateDiagram() { + val politicsButton = TextButton("Show global politics", skin).apply { onClick { updatePoliticsTable() } } + + val toggleCityStatesButton: TextButton = Constants.cityStates.toTextButton().apply { + onClick { + persistableData.includeCityStates = !persistableData.includeCityStates + updateDiagram() + } + } + + val civTableScroll = AutoScrollPane(civTable).apply { + setOverscroll(false, false) + } + val floatingTable = Table().apply { + add(toggleCityStatesButton).pad(10f).row() + add(politicsButton).row() + add(civTableScroll.addBorder(2f, Color.WHITE)).pad(10f) + } + relevantCivsCount = gameInfo.civilizations.count { !it.isSpectator() && !it.isBarbarian() && (persistableData.includeCityStates || !it.isCityState()) } @@ -111,9 +266,9 @@ class DiplomacyOverviewTab ( table.add(floatingTable) toggleCityStatesButton.style = if (persistableData.includeCityStates) { - BaseScreen.skin.get("negative", TextButtonStyle::class.java) + BaseScreen.skin.get("negative", TextButton.TextButtonStyle::class.java) } else { - BaseScreen.skin.get("positive", TextButtonStyle::class.java) + BaseScreen.skin.get("positive", TextButton.TextButtonStyle::class.java) } civTableScroll.setScrollingDisabled(portraitMode, portraitMode) } @@ -252,7 +407,7 @@ class DiplomacyOverviewTab ( width = 2f) statusLine.color = if (diplomacy.diplomaticStatus == DiplomaticStatus.War) Color.RED - else diplomacy.relationshipLevel().color + else diplomacy.relationshipLevel().color if (!civLines.containsKey(civ.civName)) civLines[civ.civName] = mutableSetOf() civLines[civ.civName]!!.add(statusLine) diff --git a/core/src/com/unciv/ui/overviewscreen/WonderOverviewTable.kt b/core/src/com/unciv/ui/overviewscreen/WonderOverviewTable.kt index 1eb7988c51..a4ec0cca79 100644 --- a/core/src/com/unciv/ui/overviewscreen/WonderOverviewTable.kt +++ b/core/src/com/unciv/ui/overviewscreen/WonderOverviewTable.kt @@ -1,18 +1,10 @@ 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.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.unique.UniqueType -import com.unciv.models.translations.tr -import com.unciv.ui.civilopedia.CivilopediaCategories +import com.unciv.logic.civilization.WonderInfo import com.unciv.ui.civilopedia.CivilopediaScreen import com.unciv.ui.images.ImageGetter import com.unciv.ui.utils.extensions.onClick @@ -24,58 +16,8 @@ class WonderOverviewTab( ) : EmpireOverviewTab(viewingPlayer, overviewScreen) { 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 = collectInfo() + val wonderInfo = WonderInfo() + private val wonders: Array = wonderInfo.collectInfo() private val fixedContent = Table() override fun getFixedContent() = fixedContent @@ -101,120 +43,11 @@ class WonderOverviewTab( equalizeColumns(fixedContent, this) } - private fun shouldBeDisplayed(wonder: Building, wonderEra: Int) = when { - wonder.hasUnique(UniqueType.HiddenFromCivilopedia) -> false - wonder.hasUnique(UniqueType.HiddenWithoutReligion) && hideReligionItems -> false - wonder.name in startingObsolete -> false - wonder.getMatchingUniques(UniqueType.HiddenWithoutVictoryType) - .any { unique -> - !gameInfo.gameParameters.victoryTypes.contains(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 { - val collator = UncivGame.Current.settings.getCollatorFromLocale() - - // Maps all World Wonders by name to their era for grouping - val wonderEraMap: Map = - ruleSet.buildings.values.asSequence() - .filter { it.isWonder } - .associate { it.name to (ruleSet.eras[ruleSet.technologies[it.requiredTech]?.era()] ?: viewingPlayer.getEra()) } - - // Maps all World Wonders by their position in sort order to their name - val allWonderMap: Map = - ruleSet.buildings.values.asSequence() - .filter { it.isWonder } - .sortedWith(compareBy { wonderEraMap[it.name]!!.eraNumber }.thenBy(collator) { it.name.tr() }) - .withIndex() - .associate { it.index to it.value.name } - val wonderCount = allWonderMap.size - - // Inverse of the above - val wonderIndexMap: Map = allWonderMap.map { it.value to it.key }.toMap() - - // Maps all Natural Wonders on the map by name to their tile - val allNaturalsMap: Map = - gameInfo.tileMap.values.asSequence() - .filter { it.isNaturalWonder() } - .associateBy { it.naturalWonder!! } - val naturalsCount = allNaturalsMap.size - - // Natural Wonders sort order index to name - val naturalsIndexMap: Map = allNaturalsMap.keys - .sortedWith(compareBy(collator) { it.tr() }) - .withIndex() - .associate { it.index to it.value } - - // 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.exploredTiles.contains(city.location) -> WonderStatus.Known - else -> WonderStatus.NotFound - } - 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() { var lastGroup = "" for (wonder in wonders) { - if (wonder.status == WonderStatus.Hidden) continue + if (wonder.status == WonderInfo.WonderStatus.Hidden) continue if (wonder.groupName != lastGroup) { lastGroup = wonder.groupName val groupRow = Table().apply { diff --git a/docs/Credits.md b/docs/Credits.md index a7b91a9018..8441f8f8e5 100644 --- a/docs/Credits.md +++ b/docs/Credits.md @@ -746,6 +746,7 @@ Unless otherwise specified, all the following are from [the Noun Project](https: - [turn right](https://thenounproject.com/icon/turn-right-1920867/) by Alice Design for Resource Overview - [Tyrannosaurus Rex](https://thenounproject.com/icon/tyrannosaurus-rex-4130976/) by Amethyst Studio for Civilopedia Eras header - [Timer](https://www.flaticon.com/free-icons/timer) created by Gregor Cresnar Premium - Flaticon +- [Political Science](https://www.flaticon.com/premium-icon/political-science_5403775) created by Hilmy Abiyyu A. - Flaticon - [Question](https://thenounproject.com/icon/question-1157126/) created by Aneeque Ahmed for Question Icon ### Main menu