From bf2ee91b672bc195a98336c6a67a12f7f5a3d8f7 Mon Sep 17 00:00:00 2001 From: SomeTroglodyte <63000004+SomeTroglodyte@users.noreply.github.com> Date: Fri, 27 Aug 2021 15:24:23 +0200 Subject: [PATCH] Civilopedia Phase X (#5003) * Civilopedia Phase X - Show Policies * Civilopedia Phase X - Show City States * Civilopedia - Loop-driven init and Cleanup * Civilopedia - City States * Civilopedia Phase X - Remove spurious comments --- .../jsons/translations/template.properties | 15 +- .../unciv/logic/civilization/CityStateType.kt | 10 +- .../unciv/logic/civilization/CivInfoStats.kt | 3 +- .../logic/civilization/CivilizationInfo.kt | 6 +- .../unciv/logic/civilization/PolicyManager.kt | 3 +- core/src/com/unciv/models/ruleset/Belief.kt | 20 +- core/src/com/unciv/models/ruleset/Era.kt | 20 +- core/src/com/unciv/models/ruleset/Nation.kt | 64 +++++- core/src/com/unciv/models/ruleset/Policy.kt | 93 +++++++- .../com/unciv/models/ruleset/RuinReward.kt | 6 +- core/src/com/unciv/models/ruleset/Ruleset.kt | 2 +- .../unciv/models/ruleset/tech/Technology.kt | 3 +- .../com/unciv/models/ruleset/tile/Terrain.kt | 19 +- .../models/ruleset/tile/TileImprovement.kt | 1 - .../com/unciv/models/ruleset/unit/BaseUnit.kt | 14 +- core/src/com/unciv/models/stats/Stat.kt | 2 +- .../ui/civilopedia/CivilopediaCategories.kt | 20 +- .../unciv/ui/civilopedia/CivilopediaScreen.kt | 202 ++++-------------- .../unciv/ui/civilopedia/CivilopediaText.kt | 26 ++- .../ui/pickerscreens/PolicyPickerScreen.kt | 18 +- .../src/com/unciv/ui/trade/DiplomacyScreen.kt | 60 ++---- .../unciv/ui/victoryscreen/VictoryScreen.kt | 9 +- 22 files changed, 333 insertions(+), 283 deletions(-) diff --git a/android/assets/jsons/translations/template.properties b/android/assets/jsons/translations/template.properties index a6c0462606..7561037379 100644 --- a/android/assets/jsons/translations/template.properties +++ b/android/assets/jsons/translations/template.properties @@ -161,7 +161,6 @@ Declare Protection of [cityStateName]? = Build [improvementName] on [resourceName] (200 Gold) = Gift Improvement = - Cultured = Maritime = Mercantile = @@ -175,9 +174,12 @@ Personality = Influence = Reach 30 for friendship. = Reach highest influence above 60 for alliance. = - +When Friends: = +When Allies: = +The unique luxury is one of: = + # Trades - + Trade = Offer trade = Retract offer = @@ -989,9 +991,10 @@ Adopt free policy = Unlocked at = Gain 2 free technologies = All policies adopted = - -# Religions - +Policy branch: [branchName] = + +# Religions + Choose an Icon and name for your Religion = Choose a [beliefType] belief! = Found [religionName] = diff --git a/core/src/com/unciv/logic/civilization/CityStateType.kt b/core/src/com/unciv/logic/civilization/CityStateType.kt index d5169de74a..41409248c5 100644 --- a/core/src/com/unciv/logic/civilization/CityStateType.kt +++ b/core/src/com/unciv/logic/civilization/CityStateType.kt @@ -1,10 +1,10 @@ package com.unciv.logic.civilization -enum class CityStateType { - Cultured, - Maritime, - Mercantile, - Militaristic +enum class CityStateType(val color: String = "") { + Cultured("#8b60ff"), + Maritime("#38ff70"), + Mercantile("#ffd800"), + Militaristic("#ff0000") } enum class CityStatePersonality { diff --git a/core/src/com/unciv/logic/civilization/CivInfoStats.kt b/core/src/com/unciv/logic/civilization/CivInfoStats.kt index bdf4a05504..072f71d8fc 100644 --- a/core/src/com/unciv/logic/civilization/CivInfoStats.kt +++ b/core/src/com/unciv/logic/civilization/CivInfoStats.kt @@ -2,6 +2,7 @@ package com.unciv.logic.civilization import com.unciv.logic.civilization.diplomacy.RelationshipLevel import com.unciv.models.metadata.BASE_GAME_DURATION_TURNS +import com.unciv.models.ruleset.Policy import com.unciv.models.ruleset.tile.ResourceType import com.unciv.models.stats.Stat import com.unciv.models.stats.StatMap @@ -221,7 +222,7 @@ class CivInfoStats(val civInfo: CivilizationInfo) { if (civInfo.hasUnique("Provides 1 happiness per 2 additional social policies adopted")) { if (!statMap.containsKey("Policies")) statMap["Policies"] = 0f statMap["Policies"] = statMap["Policies"]!! + - civInfo.policies.getAdoptedPolicies().count { !it.endsWith("Complete") } / 2 + civInfo.policies.getAdoptedPolicies().count { !Policy.isBranchCompleteByName(it) } / 2 } var happinessPerNaturalWonder = 1f diff --git a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt index ecc62a1164..a1cf74bdf7 100644 --- a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt +++ b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt @@ -204,7 +204,7 @@ class CivilizationInfo { fun isAlive(): Boolean = !isDefeated() fun hasEverBeenFriendWith(otherCiv: CivilizationInfo): Boolean = getDiplomacyManager(otherCiv).everBeenFriends() fun hasMetCivTerritory(otherCiv: CivilizationInfo): Boolean = otherCiv.getCivTerritory().any { it in exploredTiles } - fun getCompletedPolicyBranchesCount(): Int = policies.adoptedPolicies.count { it.endsWith("Complete") } + fun getCompletedPolicyBranchesCount(): Int = policies.adoptedPolicies.count { Policy.isBranchCompleteByName(it) } private fun getCivTerritory() = cities.asSequence().flatMap { it.tiles.asSequence() } fun victoryType(): VictoryType { @@ -490,7 +490,7 @@ class CivilizationInfo { RankingType.Force -> units.sumBy { it.baseUnit.strength } RankingType.Happiness -> getHappiness() RankingType.Technologies -> tech.researchedTechnologies.size - RankingType.Culture -> policies.adoptedPolicies.count { !it.endsWith("Complete") } + RankingType.Culture -> policies.adoptedPolicies.count { !Policy.isBranchCompleteByName(it) } } } @@ -520,7 +520,7 @@ class CivilizationInfo { policies.civInfo = this if (policies.adoptedPolicies.size > 0 && policies.numberOfAdoptedPolicies == 0) - policies.numberOfAdoptedPolicies = policies.adoptedPolicies.count { !it.endsWith("Complete") } + policies.numberOfAdoptedPolicies = policies.adoptedPolicies.count { !Policy.isBranchCompleteByName(it) } policies.setTransients() questManager.civInfo = this diff --git a/core/src/com/unciv/logic/civilization/PolicyManager.kt b/core/src/com/unciv/logic/civilization/PolicyManager.kt index 2776acd0c8..484961329b 100644 --- a/core/src/com/unciv/logic/civilization/PolicyManager.kt +++ b/core/src/com/unciv/logic/civilization/PolicyManager.kt @@ -2,6 +2,7 @@ package com.unciv.logic.civilization import com.unciv.logic.map.MapSize import com.unciv.models.ruleset.Policy +import com.unciv.models.ruleset.Policy.PolicyBranchType import com.unciv.models.ruleset.UniqueMap import com.unciv.models.ruleset.UniqueTriggerActivation import com.unciv.models.translations.equalsPlaceholderText @@ -124,7 +125,7 @@ class PolicyManager { */ fun isAdoptable(policy: Policy, checkEra: Boolean = true): Boolean { if (isAdopted(policy.name)) return false - if (policy.name.endsWith("Complete")) return false + if (policy.policyBranchType == PolicyBranchType.BranchComplete) return false if (!getAdoptedPolicies().containsAll(policy.requires!!)) return false if (checkEra && civInfo.gameInfo.ruleSet.getEraNumber(policy.branch.era) > civInfo.getEraNumber()) return false if (policy.uniqueObjects.any { it.placeholderText == "Incompatible with []" && adoptedPolicies.contains(it.params[0]) }) return false diff --git a/core/src/com/unciv/models/ruleset/Belief.kt b/core/src/com/unciv/models/ruleset/Belief.kt index 1156a17e12..fe79be4422 100644 --- a/core/src/com/unciv/models/ruleset/Belief.kt +++ b/core/src/com/unciv/models/ruleset/Belief.kt @@ -2,8 +2,10 @@ package com.unciv.models.ruleset import com.unciv.UncivGame import com.unciv.models.stats.INamed +import com.unciv.models.translations.tr import com.unciv.ui.civilopedia.FormattedLine import com.unciv.ui.civilopedia.ICivilopediaText +import java.text.Collator import java.util.ArrayList class Belief : INamed, ICivilopediaText, IHasUniques { @@ -15,12 +17,16 @@ class Belief : INamed, ICivilopediaText, IHasUniques { override var civilopediaText = listOf() override fun makeLink() = "Belief/$name" + override fun getCivilopediaTextHeader() = FormattedLine(name, icon = makeLink(), header = 2, color = if (type == BeliefType.None) "#e34a2b" else "") override fun replacesCivilopediaDescription() = true override fun hasCivilopediaTextLines() = true + override fun getSortGroup(ruleset: Ruleset) = type.ordinal + override fun getIconName() = if (type == BeliefType.None) "Religion" else type.name override fun getCivilopediaTextLines(ruleset: Ruleset): List { val textList = ArrayList() - textList += FormattedLine("{Type}: $type", color=type.color ) + if (type != BeliefType.None) + textList += FormattedLine("{Type}: $type", color = type.color ) uniqueObjects.forEach { textList += FormattedLine(it) } @@ -49,7 +55,17 @@ class Belief : INamed, ICivilopediaText, IHasUniques { val matchingBeliefs = getBeliefsMatching(name, ruleset) if (matchingBeliefs.none()) return@sequence if (withSeeAlso) { yield(FormattedLine()); yield(FormattedLine("{See also}:")) } - yieldAll(matchingBeliefs.map { FormattedLine(it.name, link=it.makeLink(), indent = 1) }) + yieldAll(matchingBeliefs.map { FormattedLine(it.name, link = it.makeLink(), indent = 1) }) + } + + fun getCivilopediaReligionEntry(ruleset: Ruleset) = Belief().apply { + name = "Religions" + val lines = ArrayList() + lines += FormattedLine(separator = true) + ruleset.religions.sortedWith(compareBy(Collator.getInstance(), { it.tr() })).forEach { + lines += FormattedLine(it, icon = "Belief/$it") + } + civilopediaText = lines } } } diff --git a/core/src/com/unciv/models/ruleset/Era.kt b/core/src/com/unciv/models/ruleset/Era.kt index e36f4583eb..a73fe2200a 100644 --- a/core/src/com/unciv/models/ruleset/Era.kt +++ b/core/src/com/unciv/models/ruleset/Era.kt @@ -31,9 +31,27 @@ class Era : INamed { repeat(startingMilitaryUnitCount) {startingUnits.add(startingMilitaryUnit)} return startingUnits } - + fun getColor(): Color { if (iconRGB == null) return Color.WHITE.cpy() return colorFromRGB(iconRGB!![0], iconRGB!![1], iconRGB!![2]) } + + fun getHexColor() = "#" + getColor().toString().substring(0,6) + + companion object { + // User for CS bonuses in case the Eras file is missing (legacy mods) + fun getLegacyCityStateBonusEra(eraNumber: Int) = Era().apply { + val cultureBonus = if(eraNumber in 0..1) 3 else if (eraNumber in 2..3) 6 else 13 + val happinessBonus = if(eraNumber in 0..1) 2 else 3 + friendBonus[CityStateType.Militaristic.name] = arrayListOf("Provides military units every [20] turns") + friendBonus[CityStateType.Cultured.name] = arrayListOf("Provides [$cultureBonus] [Culture] per turn") + friendBonus[CityStateType.Mercantile.name] = arrayListOf("Provides [$happinessBonus] Happiness") + friendBonus[CityStateType.Maritime.name] = arrayListOf("Provides [2] [Food] [in capital]") + allyBonus[CityStateType.Militaristic.name] = arrayListOf("Provides military units every [17] turns") + allyBonus[CityStateType.Cultured.name] = arrayListOf("Provides [${cultureBonus*2}] [Culture] per turn") + allyBonus[CityStateType.Mercantile.name] = arrayListOf("Provides [$happinessBonus] Happiness", "Provides a unique luxury") + allyBonus[CityStateType.Maritime.name] = arrayListOf("Provides [2] [Food] [in capital]", "Provides [1] [Food] [in all cities]") + } + } } \ No newline at end of file diff --git a/core/src/com/unciv/models/ruleset/Nation.kt b/core/src/com/unciv/models/ruleset/Nation.kt index 91f17a8c68..76a2f9e94b 100644 --- a/core/src/com/unciv/models/ruleset/Nation.kt +++ b/core/src/com/unciv/models/ruleset/Nation.kt @@ -2,6 +2,7 @@ import com.badlogic.gdx.graphics.Color import com.unciv.Constants +import com.unciv.UncivGame import com.unciv.logic.civilization.CityStateType import com.unciv.models.stats.INamed import com.unciv.models.translations.squareBraceRegex @@ -195,8 +196,15 @@ class Nation : INamed, ICivilopediaText, IHasUniques { override fun makeLink() = "Nation/$name" override fun replacesCivilopediaDescription() = true override fun hasCivilopediaTextLines() = true + override fun getSortGroup(ruleset: Ruleset) = when { + isCityState() -> 1 + isBarbarian() -> 9 + else -> 0 + } override fun getCivilopediaTextLines(ruleset: Ruleset): List { + if (isCityState()) return getCityStateInfo(ruleset) + val textList = ArrayList() if (leaderName.isNotEmpty()) { @@ -235,6 +243,50 @@ class Nation : INamed, ICivilopediaText, IHasUniques { return textList } + private fun getCityStateInfo(ruleset: Ruleset): List { + val textList = ArrayList() + + textList += FormattedLine("Type: [$cityStateType]", header = 4, color = cityStateType!!.color) + val viewingCiv = UncivGame.Current.gameInfo.currentPlayerCiv + val era = viewingCiv.getEraObject() ?: Era.getLegacyCityStateBonusEra(viewingCiv.getEraNumber()) + var showResources = false + + val friendBonus = era.friendBonus[cityStateType!!.name] + if (friendBonus != null && friendBonus.isNotEmpty()) { + textList += FormattedLine() + textList += FormattedLine("When Friends: ") + friendBonus.forEach { + textList += FormattedLine(Unique(it), indent = 1) + if (it == "Provides a unique luxury") showResources = true + } + } + + val allyBonus = era.allyBonus[cityStateType!!.name] + if (allyBonus != null && allyBonus.isNotEmpty()) { + textList += FormattedLine() + textList += FormattedLine("When Allies: ") + allyBonus.forEach { + textList += FormattedLine(Unique(it), indent = 1) + if (it == "Provides a unique luxury") showResources = true + } + } + + if (showResources) { + val allMercantileResources = ruleset.tileResources.values + .filter { it.unique == "Can only be created by Mercantile City-States" } + if (allMercantileResources.isNotEmpty()) { + textList += FormattedLine() + textList += FormattedLine("The unique luxury is one of:") + allMercantileResources.forEach { + textList += FormattedLine(it.name, it.makeLink(), indent = 1) + } + } + } + + // personality is not a nation property, it gets assigned to the civ randomly + return textList + } + @JvmName("addUniqueBuildingsText1") // These overloads are too similar - but I hope to remove the other one soon private fun addUniqueBuildingsText(textList: ArrayList, ruleset: Ruleset) { for (building in ruleset.buildings.values) { @@ -305,10 +357,10 @@ class Nation : INamed, ICivilopediaText, IHasUniques { link = "Promotion/$promotion", indent = 1 ) } } else if (unit.replaces != null) { - textList += FormattedLine("Replaces [${unit.replaces}], which is not found in the ruleset!", indent=1) + textList += FormattedLine("Replaces [${unit.replaces}], which is not found in the ruleset!", indent = 1) } else { textList += unit.getCivilopediaTextLines(ruleset).map { - FormattedLine(it.text, link=it.link, indent = it.indent + 1, color=it.color) + FormattedLine(it.text, link = it.link, indent = it.indent + 1, color = it.color) } } @@ -321,16 +373,16 @@ class Nation : INamed, ICivilopediaText, IHasUniques { for (improvement in ruleset.tileImprovements.values) { if (improvement.uniqueTo != name ) continue - textList += FormattedLine(improvement.name, link="Improvement/${improvement.name}") - textList += FormattedLine(improvement.clone().toString(), indent=1) // = (improvement as Stats).toString minus import plus copy overhead + textList += FormattedLine(improvement.name, link = "Improvement/${improvement.name}") + textList += FormattedLine(improvement.clone().toString(), indent = 1) // = (improvement as Stats).toString minus import plus copy overhead if (improvement.terrainsCanBeBuiltOn.isNotEmpty()) { improvement.terrainsCanBeBuiltOn.withIndex().forEach { textList += FormattedLine(if (it.index == 0) "{Can be built on} {${it.value}}" else "or [${it.value}]", - link="Terrain/${it.value}", indent=if (it.index == 0) 1 else 2) + link = "Terrain/${it.value}", indent = if (it.index == 0) 1 else 2) } } for (unique in improvement.uniques) - textList += FormattedLine(unique, indent=1) + textList += FormattedLine(unique, indent = 1) } } diff --git a/core/src/com/unciv/models/ruleset/Policy.kt b/core/src/com/unciv/models/ruleset/Policy.kt index 3498723e79..2224f41e9b 100644 --- a/core/src/com/unciv/models/ruleset/Policy.kt +++ b/core/src/com/unciv/models/ruleset/Policy.kt @@ -1,8 +1,11 @@ package com.unciv.models.ruleset import com.unciv.models.stats.INamed +import com.unciv.models.translations.tr +import com.unciv.ui.civilopedia.FormattedLine +import com.unciv.ui.civilopedia.ICivilopediaText -open class Policy : INamed, IHasUniques { +open class Policy : INamed, IHasUniques, ICivilopediaText { lateinit var branch: PolicyBranch // not in json - added in gameBasics override lateinit var name: String @@ -12,6 +15,94 @@ open class Policy : INamed, IHasUniques { var column: Int = 0 var requires: ArrayList? = null + override var civilopediaText = listOf() + + /** Indicates whether a [Policy] is a [PolicyBranch] starting policy, a normal one, or the branch completion */ + enum class PolicyBranchType {BranchStart, Member, BranchComplete} + /** Indicates whether this [Policy] is a [PolicyBranch] starting policy, a normal one, or the branch completion */ + val policyBranchType: PolicyBranchType by lazy { when { + this is PolicyBranch -> PolicyBranchType.BranchStart + isBranchCompleteByName(name) -> PolicyBranchType.BranchComplete + else -> PolicyBranchType.Member + } } + companion object { + const val branchCompleteSuffix = " Complete" + /** Some tests to count policies by completion or not use only the String collection without instantiating them. + * To keep the hardcoding in one place, this is public and should be used instead of duplicating it. + */ + fun isBranchCompleteByName(name: String) = name.endsWith(branchCompleteSuffix) + } + override fun toString() = name + + /** Used in PolicyPickerScreen to display Policy properties */ + fun getDescription(): String { + val policyText = ArrayList() + policyText += name + policyText += uniques + + if (policyBranchType != PolicyBranchType.BranchComplete) { + policyText += if (requires!!.isNotEmpty()) + "Requires [" + requires!!.joinToString { it.tr() } + "]" + else + "{Unlocked at} {${branch.era}}" + } + return policyText.joinToString("\n") { it.tr() } + } + + override fun makeLink() = "Policy/$name" + override fun replacesCivilopediaDescription() = true + override fun hasCivilopediaTextLines() = true + override fun getSortGroup(ruleset: Ruleset) = + ruleset.getEraNumber(branch.era) * 10000 + + ruleset.policyBranches.keys.indexOf(branch.name) * 100 + + policyBranchType.ordinal + + override fun getCivilopediaTextLines(ruleset: Ruleset): List { + val lineList = ArrayList() + + lineList += if (this is PolicyBranch) { + val eraColor = ruleset.eras[era]?.getHexColor() ?: "" + FormattedLine("{Unlocked at} {${branch.era}}", header = 4, color = eraColor) + } else { + FormattedLine("Policy branch: [${branch.name}]", link = branch.makeLink()) + } + + if (policyBranchType != PolicyBranchType.BranchComplete && requires != null && requires!!.isNotEmpty()) { + lineList += FormattedLine() + if (requires!!.size == 1) + requires!!.first().let { lineList += FormattedLine("Requires: [$it]", link = "Policy/$it") } + else { + lineList += FormattedLine("Requires all of the following:") + requires!!.forEach { + lineList += FormattedLine(it, link = "Policy/$it") + } + } + } + + val leadsTo = ruleset.policies.values.filter { + it.requires != null && name in it.requires!! + && it.policyBranchType != PolicyBranchType.BranchComplete + } + if (leadsTo.isNotEmpty()) { + lineList += FormattedLine() + if (leadsTo.size == 1) + leadsTo.first().let { lineList += FormattedLine("Leads to [${it.name}]", link = it.makeLink()) } + else { + lineList += FormattedLine("Leads to:") + leadsTo.forEach { + lineList += FormattedLine(it.name, link = it.makeLink(), indent = 1) + } + } + } + + if (uniques.isNotEmpty()) { + lineList += FormattedLine() + for (unique in uniqueObjects) lineList += FormattedLine(unique) + } + + return lineList + } + } diff --git a/core/src/com/unciv/models/ruleset/RuinReward.kt b/core/src/com/unciv/models/ruleset/RuinReward.kt index 81a2b367f3..be1ab9bedc 100644 --- a/core/src/com/unciv/models/ruleset/RuinReward.kt +++ b/core/src/com/unciv/models/ruleset/RuinReward.kt @@ -4,12 +4,12 @@ import com.unciv.models.stats.INamed import com.unciv.ui.civilopedia.FormattedLine import com.unciv.ui.civilopedia.ICivilopediaText -class RuinReward : INamed, ICivilopediaText { +class RuinReward : INamed, ICivilopediaText, IHasUniques { override lateinit var name: String // Displayed in Civilopedia! val notification: String = "" - val uniques: List = listOf() + override var uniques = ArrayList() @delegate:Transient // Defense in depth against mad modders - val uniqueObjects: List by lazy { uniques.map { Unique(it) } } + override val uniqueObjects: List by lazy { uniques.map { Unique(it) } } val excludedDifficulties: List = listOf() val weight: Int = 1 val color: String = "" // For Civilopedia diff --git a/core/src/com/unciv/models/ruleset/Ruleset.kt b/core/src/com/unciv/models/ruleset/Ruleset.kt index 9b145defd9..18fcbb5bcc 100644 --- a/core/src/com/unciv/models/ruleset/Ruleset.kt +++ b/core/src/com/unciv/models/ruleset/Ruleset.kt @@ -206,7 +206,7 @@ class Ruleset { if (policy.requires == null) policy.requires = arrayListOf(branch.name) policies[policy.name] = policy } - branch.policies.last().name = branch.name + " Complete" + branch.policies.last().name = branch.name + Policy.branchCompleteSuffix } } diff --git a/core/src/com/unciv/models/ruleset/tech/Technology.kt b/core/src/com/unciv/models/ruleset/tech/Technology.kt index 35d6f3c653..477adc70e7 100644 --- a/core/src/com/unciv/models/ruleset/tech/Technology.kt +++ b/core/src/com/unciv/models/ruleset/tech/Technology.kt @@ -150,7 +150,8 @@ class Technology: INamed, ICivilopediaText, IHasUniques { override fun getCivilopediaTextLines(ruleset: Ruleset): List { val lineList = ArrayList() - lineList += FormattedLine(era(), header = 3, color = "#8080ff") + val eraColor = ruleset.eras[era()]?.getHexColor() ?: "" + lineList += FormattedLine(era(), header = 3, color = eraColor) lineList += FormattedLine() lineList += FormattedLine("{Cost}: $cost${Fonts.science}") diff --git a/core/src/com/unciv/models/ruleset/tile/Terrain.kt b/core/src/com/unciv/models/ruleset/tile/Terrain.kt index cd40ab0dc9..a0fbc3baec 100644 --- a/core/src/com/unciv/models/ruleset/tile/Terrain.kt +++ b/core/src/com/unciv/models/ruleset/tile/Terrain.kt @@ -127,21 +127,12 @@ class Terrain : NamedStats(), ICivilopediaText { if (defenceBonus != 0f) textList += FormattedLine("{Defence bonus}: ${(defenceBonus * 100).toInt()}%") - val seeAlso = ( - //todo: Could vastly be simplified using upcoming INonPerpetualConstruction - ruleset.buildings.values.asSequence() - .filter { - building -> building.uniqueObjects.any { - unique -> unique.params.any { it == name } - } - } + - ruleset.units.values.asSequence() - .filter { - unit -> unit.uniqueObjects.any { - unique -> unique.params.any { it == name } - } + val seeAlso = (ruleset.buildings.values.asSequence() + ruleset.units.values.asSequence()) + .filter { + construction -> construction.uniqueObjects.any { + unique -> unique.params.any { it == name } } - ).map { FormattedLine(it.name, it.makeLink(), indent=1) } + + }.map { FormattedLine(it.name, it.makeLink(), indent=1) } + Belief.getCivilopediaTextMatching(name, ruleset, false) if (seeAlso.any()) { textList += FormattedLine() diff --git a/core/src/com/unciv/models/ruleset/tile/TileImprovement.kt b/core/src/com/unciv/models/ruleset/tile/TileImprovement.kt index 67998f8d28..839bd4031a 100644 --- a/core/src/com/unciv/models/ruleset/tile/TileImprovement.kt +++ b/core/src/com/unciv/models/ruleset/tile/TileImprovement.kt @@ -3,7 +3,6 @@ package com.unciv.models.ruleset.tile import com.unciv.Constants import com.unciv.UncivGame import com.unciv.logic.civilization.CivilizationInfo -import com.unciv.logic.civilization.RuinsManager.RuinsManager import com.unciv.models.ruleset.Belief import com.unciv.logic.map.RoadStatus import com.unciv.models.ruleset.IHasUniques diff --git a/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt b/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt index d64133a4c9..7a56325587 100644 --- a/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt +++ b/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt @@ -200,10 +200,10 @@ class BaseUnit : INamed, INonPerpetualConstruction, ICivilopediaText { var productionCost = cost.toFloat() if (civInfo.isCityState()) productionCost *= 1.5f - if (civInfo.isPlayerCivilization()) - productionCost *= civInfo.getDifficulty().unitCostModifier - else - productionCost *= civInfo.gameInfo.getDifficulty().aiUnitCostModifier + productionCost *= if (civInfo.isPlayerCivilization()) + civInfo.getDifficulty().unitCostModifier + else + civInfo.gameInfo.getDifficulty().aiUnitCostModifier productionCost *= civInfo.gameInfo.gameParameters.gameSpeed.modifier return productionCost.toInt() } @@ -298,8 +298,8 @@ class BaseUnit : INamed, INonPerpetualConstruction, ICivilopediaText { for ((resource, amount) in getResourceRequirements()) if (civInfo.getCivResourcesByName()[resource]!! < amount) { - if (amount == 1) return "Consumes 1 [$resource]" // Again, to preserve existing translations - else return "Consumes [$amount] [$resource]" + return if (amount == 1) "Consumes 1 [$resource]" // Again, to preserve existing translations + else "Consumes [$amount] [$resource]" } if (uniques.contains(Constants.settlerUnique) && civInfo.isCityState()) return "No settler for city-states" @@ -322,7 +322,7 @@ class BaseUnit : INamed, INonPerpetualConstruction, ICivilopediaText { override fun postBuildEvent(cityConstructions: CityConstructions, wasBought: Boolean): Boolean { val civInfo = cityConstructions.cityInfo.civInfo val unit = civInfo.placeUnitNearTile(cityConstructions.cityInfo.location, name) - if (unit == null) return false // couldn't place the unit, so there's actually no unit =( + ?: return false // couldn't place the unit, so there's actually no unit =( //movement penalty if (wasBought && !civInfo.gameInfo.gameParameters.godMode && !unit.hasUnique("Can move immediately once bought")) diff --git a/core/src/com/unciv/models/stats/Stat.kt b/core/src/com/unciv/models/stats/Stat.kt index 35202fea13..a3462ef0bc 100644 --- a/core/src/com/unciv/models/stats/Stat.kt +++ b/core/src/com/unciv/models/stats/Stat.kt @@ -16,7 +16,7 @@ enum class Stat( Culture(NotificationIcon.Culture, UncivSound.Paper, Fonts.culture), Happiness(NotificationIcon.Happiness, UncivSound.Click, Fonts.happiness), Faith(NotificationIcon.Faith, UncivSound.Choir, Fonts.faith); - + companion object { val statsUsableToBuy = listOf(Gold, Food, Science, Culture, Faith) } diff --git a/core/src/com/unciv/ui/civilopedia/CivilopediaCategories.kt b/core/src/com/unciv/ui/civilopedia/CivilopediaCategories.kt index a34e7ab07d..2c3675531c 100644 --- a/core/src/com/unciv/ui/civilopedia/CivilopediaCategories.kt +++ b/core/src/com/unciv/ui/civilopedia/CivilopediaCategories.kt @@ -17,6 +17,7 @@ import java.io.File /** Encapsulates the knowledge on how to get an icon for each of the Civilopedia categories */ object CivilopediaImageGetters { private const val policyIconFolder = "PolicyIcons" + private const val policyInnerSize = 0.25f // Todo: potential synergy with map editor fun terrainImage(terrain: Terrain, ruleset: Ruleset, imageSize: Float): Actor { @@ -48,7 +49,7 @@ object CivilopediaImageGetters { val construction = { name: String, size: Float -> ImageGetter.getConstructionImage(name) - .surroundWithCircle(size, color = Color.WHITE) + .surroundWithCircle(size) } val improvement = { name: String, size: Float -> ImageGetter.getImprovementIcon(name, size) @@ -59,8 +60,16 @@ object CivilopediaImageGetters { else ImageGetter.getNationIndicator(nation, size) } val policy = { name: String, size: Float -> - ImageGetter.getImage(policyIconFolder + File.separator + name) - .apply { setSize(size,size) } + // policy branch start and complete have no icons but are linked -> nonexistence must be passed down + val fileName = policyIconFolder + File.separator + name + if (ImageGetter.imageExists(fileName)) + ImageGetter.getImage(fileName) + .apply { + setSize(size * policyInnerSize,size * policyInnerSize) + color = Color.BROWN + } + .surroundWithCircle(size) + else null } val resource = { name: String, size: Float -> ImageGetter.getResourceImage(name, size) @@ -97,6 +106,7 @@ object CivilopediaImageGetters { /** Enum used as keys for Civilopedia "pages" (categories). * * Note names are singular on purpose - a "link" allows both key and label + * Order of values determines ordering of the categories in the Civilopedia top bar * * @param label Translatable caption for the Civilopedia button */ @@ -114,10 +124,10 @@ enum class CivilopediaCategories ( Nation ("Nations", false, CivilopediaImageGetters.nation ), Technology ("Technologies", false, CivilopediaImageGetters.technology ), Promotion ("Promotions", false, CivilopediaImageGetters.promotion ), - Policy ("Policies", true, CivilopediaImageGetters.policy ), + Policy ("Policies", false, CivilopediaImageGetters.policy ), + Belief("Religions and Beliefs", false, CivilopediaImageGetters.belief ), Tutorial ("Tutorials", false, null ), Difficulty ("Difficulty levels", false, null ), - Belief("Religions and Beliefs", false, CivilopediaImageGetters.belief) ; companion object { diff --git a/core/src/com/unciv/ui/civilopedia/CivilopediaScreen.kt b/core/src/com/unciv/ui/civilopedia/CivilopediaScreen.kt index ec0c100ca5..6d590c81ba 100644 --- a/core/src/com/unciv/ui/civilopedia/CivilopediaScreen.kt +++ b/core/src/com/unciv/ui/civilopedia/CivilopediaScreen.kt @@ -6,6 +6,7 @@ import com.badlogic.gdx.scenes.scene2d.Touchable import com.badlogic.gdx.scenes.scene2d.ui.* import com.unciv.Constants import com.unciv.UncivGame +import com.unciv.models.ruleset.Belief import com.unciv.models.ruleset.Ruleset import com.unciv.models.ruleset.Unique import com.unciv.models.ruleset.VictoryType @@ -77,7 +78,7 @@ class CivilopediaScreen( /** Select a specified category * @param name Category name or label */ - fun selectCategory(name: String) { + private fun selectCategory(name: String) { val category = CivilopediaCategories.fromLink(name) ?: return // silently ignore unknown category names in links selectCategory(category) @@ -86,7 +87,7 @@ class CivilopediaScreen( /** Select a specified category - unselects entry, rebuilds left side buttons. * @param category Category key */ - fun selectCategory(category: CivilopediaCategories) { + private fun selectCategory(category: CivilopediaCategories) { currentCategory = category entrySelectTable.clear() entryIndex.clear() @@ -173,139 +174,53 @@ class CivilopediaScreen( onBackButtonClicked { UncivGame.Current.setWorldScreen() } val hideReligionItems = !game.gameInfo.hasReligionEnabled() + val noCulturalVictory = VictoryType.Cultural !in game.gameInfo.gameParameters.victoryTypes - categoryToEntries[CivilopediaCategories.Building] = ruleset.buildings.values - .filter { shouldBeDisplayed(it.uniqueObjects) - && !it.isAnyWonder() } - .map { - CivilopediaEntry( - it.name, - "", - CivilopediaCategories.Building.getImage?.invoke(it.name, imageSize), - (it as? ICivilopediaText).takeUnless { ct -> ct==null || ct.isCivilopediaTextEmpty() } - ) - } - categoryToEntries[CivilopediaCategories.Wonder] = ruleset.buildings.values - .filter { shouldBeDisplayed(it.uniqueObjects) - && it.isAnyWonder() } - .map { - CivilopediaEntry( - it.name, - "", - CivilopediaCategories.Wonder.getImage?.invoke(it.name, imageSize), - (it as? ICivilopediaText).takeUnless { ct -> ct==null || ct.isCivilopediaTextEmpty() } - ) - } - categoryToEntries[CivilopediaCategories.Resource] = ruleset.tileResources.values - .map { - CivilopediaEntry( - it.name, - "", - CivilopediaCategories.Resource.getImage?.invoke(it.name, imageSize), - (it as? ICivilopediaText).takeUnless { ct -> ct==null || ct.isCivilopediaTextEmpty() } - ) - } - categoryToEntries[CivilopediaCategories.Terrain] = ruleset.terrains.values - .filter { shouldBeDisplayed(it.uniqueObjects) } - .map { - CivilopediaEntry( - it.name, - "", - CivilopediaCategories.Terrain.getImage?.invoke(it.name, imageSize), - (it as? ICivilopediaText).takeUnless { ct -> ct==null || ct.isCivilopediaTextEmpty() } - ) - } - categoryToEntries[CivilopediaCategories.Improvement] = ruleset.tileImprovements.values - .filter { shouldBeDisplayed(it.uniqueObjects) } - .map { - CivilopediaEntry( - it.name, - "", - CivilopediaCategories.Improvement.getImage?.invoke(it.name, imageSize), - (it as? ICivilopediaText).takeUnless { ct -> ct==null || ct.isCivilopediaTextEmpty() } - ) - } - categoryToEntries[CivilopediaCategories.Unit] = ruleset.units.values - .filter { shouldBeDisplayed(it.uniqueObjects) } - .map { - CivilopediaEntry( - it.name, - "", - CivilopediaCategories.Unit.getImage?.invoke(it.name, imageSize), - (it as? ICivilopediaText).takeUnless { ct -> ct==null || ct.isCivilopediaTextEmpty() } - ) - } - categoryToEntries[CivilopediaCategories.Nation] = ruleset.nations.values - .filter { shouldBeDisplayed(it.uniqueObjects) && it.isMajorCiv() } - .map { - CivilopediaEntry( - it.name, - "", - CivilopediaCategories.Nation.getImage?.invoke(it.name, imageSize), - (it as? ICivilopediaText).takeUnless { ct -> ct==null || ct.isCivilopediaTextEmpty() } - ) - } - categoryToEntries[CivilopediaCategories.Technology] = ruleset.technologies.values - .filter { shouldBeDisplayed(it.uniqueObjects) } - .map { - CivilopediaEntry( - it.name, - "", - CivilopediaCategories.Technology.getImage?.invoke(it.name, imageSize), - (it as? ICivilopediaText).takeUnless { ct -> ct==null || ct.isCivilopediaTextEmpty() } - ) - } - categoryToEntries[CivilopediaCategories.Promotion] = ruleset.unitPromotions.values - .filter { shouldBeDisplayed(it.uniqueObjects) } - .map { - CivilopediaEntry( - it.name, - "", - CivilopediaCategories.Promotion.getImage?.invoke(it.name, imageSize), - (it as? ICivilopediaText).takeUnless { ct -> ct==null || ct.isCivilopediaTextEmpty() } - ) - } + fun shouldBeDisplayed(uniqueObjects: List): Boolean { + val uniques = uniqueObjects.map { it.placeholderText } - categoryToEntries[CivilopediaCategories.Tutorial] = tutorialController.getCivilopediaTutorials() - .map { - CivilopediaEntry( - it.name, - "", -// CivilopediaCategories.Tutorial.getImage?.invoke(it.name, imageSize) - flavour = it - ) - } + return Constants.hideFromCivilopediaUnique !in uniques + && !(hideReligionItems && Constants.hiddenWithoutReligionUnique in uniques) + && !(uniqueObjects.filter { unique -> unique.placeholderText == "Hidden when [] Victory is disabled"}.any { + unique -> !game.gameInfo.gameParameters.victoryTypes.contains(VictoryType.valueOf(unique.params[0] )) + }) + // Deprecated since 3.15.14 + && !(noCulturalVictory && "Hidden when cultural victory is disabled" in uniques) + // + } - categoryToEntries[CivilopediaCategories.Difficulty] = ruleset.difficulties.values - .map { - CivilopediaEntry( - it.name, - "", -// CivilopediaCategories.Difficulty.getImage?.invoke(it.name, imageSize) - flavour = (it as? ICivilopediaText) - ) - } + fun getCategoryIterator(category: CivilopediaCategories): Collection = + when (category) { + CivilopediaCategories.Building -> ruleset.buildings.values.filter { !it.isAnyWonder() } + CivilopediaCategories.Wonder -> ruleset.buildings.values.filter { it.isAnyWonder() } + CivilopediaCategories.Resource -> ruleset.tileResources.values + CivilopediaCategories.Terrain -> ruleset.terrains.values + CivilopediaCategories.Improvement -> ruleset.tileImprovements.values + CivilopediaCategories.Unit -> ruleset.units.values + CivilopediaCategories.Nation -> ruleset.nations.values.filter { !it.isSpectator() } + CivilopediaCategories.Technology -> ruleset.technologies.values + CivilopediaCategories.Promotion -> ruleset.unitPromotions.values + CivilopediaCategories.Policy -> ruleset.policies.values + CivilopediaCategories.Tutorial -> tutorialController.getCivilopediaTutorials() + CivilopediaCategories.Difficulty -> ruleset.difficulties.values + CivilopediaCategories.Belief -> (ruleset.beliefs.values.asSequence() + + Belief.getCivilopediaReligionEntry(ruleset)).toList() + } + + for (loopCategory in CivilopediaCategories.values()) { + if (loopCategory.hide) continue + if (hideReligionItems && loopCategory == CivilopediaCategories.Belief) continue + categoryToEntries[loopCategory] = + getCategoryIterator(loopCategory) + .filter { it.getUniquesAsObjects()?.let { uniques -> shouldBeDisplayed(uniques) } ?: true } + .map { CivilopediaEntry( + (it as INamed).name, "", + loopCategory.getImage?.invoke(it.getIconName(), imageSize), + it.takeUnless { ct -> ct.isCivilopediaTextEmpty() }, + sortBy = it.getSortGroup(ruleset) + ) } + } - if (!hideReligionItems) - categoryToEntries[CivilopediaCategories.Belief] = ( - ruleset.beliefs.values.asSequence() - .map { - CivilopediaEntry( - it.name, - "", - CivilopediaCategories.Belief.getImage?.invoke(it.type.name, imageSize), - (it as? ICivilopediaText).takeUnless { ct -> ct==null || ct.isCivilopediaTextEmpty() }, - sortBy = it.type.ordinal - ) - } + CivilopediaEntry( - "Religions", - "", - CivilopediaCategories.Belief.getImage?.invoke("Religion", imageSize), - getReligionText(), - sortBy = -1 - ) - ).toList() - val buttonTable = Table() buttonTable.pad(15f) buttonTable.defaults().pad(10f) @@ -364,31 +279,6 @@ class CivilopediaScreen( selectEntry(link, noScrollAnimation = true) } - private fun getReligionText(): ICivilopediaText { - val lines = ArrayList() - lines += FormattedLine("Religions", header=2, color="#e34a2b") - lines += FormattedLine(separator=true) - ruleset.religions.sortedWith(compareBy(Collator.getInstance(), { it.tr() })).forEach { - lines += FormattedLine(it, icon="Belief/$it") - } - return SimpleCivilopediaText(lines, true) - } - - private fun shouldBeDisplayed(uniqueObjects: List): Boolean { - val uniques = uniqueObjects.map { it.placeholderText } - val hideReligionItems = !game.gameInfo.hasReligionEnabled() - val noCulturalVictory = VictoryType.Cultural !in game.gameInfo.gameParameters.victoryTypes - - return Constants.hideFromCivilopediaUnique !in uniques - && !(hideReligionItems && Constants.hiddenWithoutReligionUnique in uniques) - && !(uniqueObjects.filter { unique -> unique.placeholderText == "Hidden when [] Victory is disabled"}.any { - unique -> !game.gameInfo.gameParameters.victoryTypes.contains(VictoryType.valueOf(unique.params[0] )) - }) - // Deprecated since 3.15.14 - && !(noCulturalVictory && "Hidden when cultural victory is disabled" in uniques) - // - } - override fun resize(width: Int, height: Int) { if (stage.viewport.screenWidth != width || stage.viewport.screenHeight != height) { game.setScreen(CivilopediaScreen(game.worldScreen.gameInfo.ruleSet, currentCategory, currentEntry)) diff --git a/core/src/com/unciv/ui/civilopedia/CivilopediaText.kt b/core/src/com/unciv/ui/civilopedia/CivilopediaText.kt index f3e45ca59a..1b1540eb2f 100644 --- a/core/src/com/unciv/ui/civilopedia/CivilopediaText.kt +++ b/core/src/com/unciv/ui/civilopedia/CivilopediaText.kt @@ -7,6 +7,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.utils.Align import com.unciv.UncivGame import com.unciv.models.metadata.BaseRuleset +import com.unciv.models.ruleset.IHasUniques import com.unciv.models.ruleset.Ruleset import com.unciv.models.ruleset.RulesetCache import com.unciv.models.ruleset.Unique @@ -141,7 +142,7 @@ class FormattedLine ( /** Padding distance per [indent] level */ const val indentPad = 30f /** Where indent==1 will be, measured as icon count */ - const val indentOneAtNumIcons = 3 + const val indentOneAtNumIcons = 2 private var rulesetCachedInNameMap: Ruleset? = null // Cache to quickly match Categories to names. Takes a few ms to build on a slower desktop and will use just a few 10k bytes. @@ -378,11 +379,6 @@ object MarkupRenderer { } } -/** Storage class for interface [ICivilopediaText] for use as base class */ -@Deprecated("As of 3.16.1, use ICivilopediaText directly please") -abstract class CivilopediaText : ICivilopediaText { - override var civilopediaText = listOf() -} /** Storage class for instantiation of the simplest form containing only the lines collection */ open class SimpleCivilopediaText( override var civilopediaText: List, @@ -401,7 +397,7 @@ open class SimpleCivilopediaText( /** Addon common to most ruleset game objects managing civilopedia display * * ### Usage: - * 1. Let [Ruleset] object implement this (e.g. by inheriting class [CivilopediaText] or adding var [civilopediaText] itself) + * 1. Let [Ruleset] object implement this (by inheriting and implementing class [ICivilopediaText]) * 2. Add `"civilopediaText": ["",…],` in the json for these objects * 3. Optionally override [getCivilopediaTextHeader] to supply a different header line * 4. Optionally override [getCivilopediaTextLines] to supply automatic stuff like tech prerequisites, uniques, etc. @@ -484,4 +480,20 @@ interface ICivilopediaText { /** Create the correct string for a Civilopedia link */ fun makeLink(): String + + /** This just marshals access to the uniques so they can be queried as part of the ICivilopediaText interface. + * Used exclusively by CivilopediaScreen, named to avoid JVM signature confusion + * (a getUniqueObjects exists in IHasUniques and most civilopedia objects will implement that interface) + */ + fun getUniquesAsObjects() = (this as? IHasUniques)?.uniqueObjects + + /** Overrides alphabetical sorting in Civilopedia + * @param ruleset The current ruleset in case the function needs to do lookups + */ + fun getSortGroup(ruleset: Ruleset): Int = 0 + + /** Overrides Icon used for Civilopedia entry list (where you select the instance) + * This will still be passed to the category-specific image getter. + */ + fun getIconName() = if (this is INamed) name else "" } diff --git a/core/src/com/unciv/ui/pickerscreens/PolicyPickerScreen.kt b/core/src/com/unciv/ui/pickerscreens/PolicyPickerScreen.kt index 2cbc52b568..4a60be8371 100644 --- a/core/src/com/unciv/ui/pickerscreens/PolicyPickerScreen.kt +++ b/core/src/com/unciv/ui/pickerscreens/PolicyPickerScreen.kt @@ -9,6 +9,7 @@ import com.unciv.models.Tutorial import com.unciv.models.UncivSound import com.unciv.models.ruleset.Policy import com.unciv.models.ruleset.PolicyBranch +import com.unciv.models.ruleset.Policy.PolicyBranchType import com.unciv.models.translations.tr import com.unciv.ui.utils.* import com.unciv.ui.worldscreen.WorldScreen @@ -110,7 +111,7 @@ class PolicyPickerScreen(val worldScreen: WorldScreen, civInfo: CivilizationInfo || worldScreen.viewingCiv.isSpectator() // viewingCiv var points to selectedCiv in case of spectator || viewingCiv.isDefeated() || viewingCiv.policies.isAdopted(policy.name) - || policy.name.endsWith("Complete") + || policy.policyBranchType == PolicyBranchType.BranchComplete || !viewingCiv.policies.isAdoptable(policy) || !viewingCiv.policies.canAdoptPolicy()) { rightSideButton.disable() @@ -123,17 +124,8 @@ class PolicyPickerScreen(val worldScreen: WorldScreen, civInfo: CivilizationInfo game.setScreen(PolicyPickerScreen(worldScreen)) } pickedPolicy = policy - val policyText = mutableListOf() - policyText += policy.name - policyText += policy.uniques - - if (!policy.name.endsWith("Complete")) { - if (policy.requires!!.isNotEmpty()) - policyText += "Requires [" + policy.requires!!.joinToString { it.tr() } + "]" - else - policyText += "{Unlocked at} {" + policy.branch.era + "}" - } - descriptionLabel.setText(policyText.joinToString("\n") { it.tr() }) + + descriptionLabel.setText(policy.getDescription()) } /** @@ -151,7 +143,7 @@ class PolicyPickerScreen(val worldScreen: WorldScreen, civInfo: CivilizationInfo var currentColumn = 1 val branchTable = Table() for (policy in branch.policies) { - if (policy.name.endsWith("Complete")) continue + if (policy.policyBranchType == PolicyBranchType.BranchComplete) continue if (policy.row > currentRow) { branchTable.row().pad(2.5f) currentRow++ diff --git a/core/src/com/unciv/ui/trade/DiplomacyScreen.kt b/core/src/com/unciv/ui/trade/DiplomacyScreen.kt index 9ec9195f52..c58ca69834 100644 --- a/core/src/com/unciv/ui/trade/DiplomacyScreen.kt +++ b/core/src/com/unciv/ui/trade/DiplomacyScreen.kt @@ -16,6 +16,7 @@ import com.unciv.logic.civilization.diplomacy.RelationshipLevel import com.unciv.logic.trade.TradeLogic import com.unciv.logic.trade.TradeOffer import com.unciv.logic.trade.TradeType +import com.unciv.models.ruleset.Era import com.unciv.models.ruleset.ModOptionsConstants import com.unciv.models.ruleset.Quest import com.unciv.models.ruleset.tile.ResourceType @@ -158,67 +159,38 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() { else -> "Reach highest influence above 60 for alliance." } diplomacyTable.add(getRelationshipTable(otherCivDiplomacyManager)).row() - if (nextLevelString != "") { + if (nextLevelString.isNotEmpty()) { diplomacyTable.add(nextLevelString.toLabel()).row() } - var friendBonusText = "When Friends: ".tr() - val eraInfo = viewingCiv.getEraObject() - val friendBonuses = - if (eraInfo == null) null - else eraInfo.friendBonus[otherCiv.cityStateType.name] - friendBonusText += - if (friendBonuses != null) { - friendBonuses.joinToString(separator = ", ") { it.tr() } - } else { - // Deprecated, assume Civ V values for compatibility - val cultureBonus = if(viewingCiv.getEraNumber() in 0..1) "3" else if (viewingCiv.getEraNumber() in 2..3) "6" else "13" - val happinessBonus = if(viewingCiv.getEraNumber() in 0..1) "2" else "3" - when (otherCiv.cityStateType) { - CityStateType.Militaristic -> "Provides military units every [20] turns".tr() - CityStateType.Cultured -> ("Provides [" + cultureBonus + "] [Culture] per turn").tr() - CityStateType.Mercantile -> ("Provides [" + happinessBonus + "] Happiness").tr() - CityStateType.Maritime -> "Provides [2] [Food] [in capital]".tr() - } - } + val eraInfo = viewingCiv.getEraObject() ?: Era.getLegacyCityStateBonusEra(viewingCiv.getEraNumber()) + var friendBonusText = "{When Friends:} ".tr() + val friendBonuses = eraInfo.friendBonus[otherCiv.cityStateType.name] + friendBonusText += friendBonuses?.joinToString(separator = ", ") { it.tr() } ?: "" - var allyBonusText = "When Allies: " - val allyBonuses = - if (eraInfo == null) null - else eraInfo.allyBonus[otherCiv.cityStateType.name] - if (allyBonuses != null) { - allyBonusText += allyBonuses.joinToString(separator = ", ") { it.tr() } - } else { - // Deprecated, assume Civ V values for compatibility - val cultureBonus = if(viewingCiv.getEraNumber() in 0..1) "6" else if (viewingCiv.getEraNumber() in 2..3) "12" else "26" - val happinessBonus = if(viewingCiv.getEraNumber() in 0..1) "2" else "3" - allyBonusText += when (otherCiv.cityStateType) { - CityStateType.Militaristic -> "Provides military units every [20] turns".tr() - CityStateType.Cultured -> ("Provides [" + cultureBonus + "] [Culture] per turn").tr() - CityStateType.Mercantile -> ("Provides [" + happinessBonus + "] Happiness").tr() + ", " + "Provides a unique luxury".tr() - CityStateType.Maritime -> "Provides [2] [Food] [in capital]".tr() + ", " + "Provides [1] [Food] [in all cities]".tr() - } - } + var allyBonusText = "{When Allies:} ".tr() + val allyBonuses = eraInfo.allyBonus[otherCiv.cityStateType.name] + allyBonusText += allyBonuses?.joinToString(separator = ", ") { it.tr() } ?: "" - val friendBonusLabelColor: Color - if (otherCivDiplomacyManager.relationshipLevel() >= RelationshipLevel.Friend) { - friendBonusLabelColor = Color.GREEN + val relationLevel = otherCivDiplomacyManager.relationshipLevel() + if (relationLevel >= RelationshipLevel.Friend) { // RelationshipChange = Ally -> Friend or Friend -> Favorable val turnsToRelationshipChange = otherCivDiplomacyManager.getTurnsToRelationshipChange() diplomacyTable.add("Relationship changes in another [$turnsToRelationshipChange] turns".toLabel()) .row() - } else - friendBonusLabelColor = Color.GRAY + } + val friendBonusLabelColor = if (relationLevel >= RelationshipLevel.Friend) Color.GREEN else Color.GRAY val friendBonusLabel = friendBonusText.toLabel(friendBonusLabelColor) .apply { setAlignment(Align.center) } diplomacyTable.add(friendBonusLabel).row() - val allyBonusLabelColor = if (otherCivDiplomacyManager.relationshipLevel() == RelationshipLevel.Ally) Color.GREEN else Color.GRAY + + val allyBonusLabelColor = if (relationLevel == RelationshipLevel.Ally) Color.GREEN else Color.GRAY val allyBonusLabel = allyBonusText.toLabel(allyBonusLabelColor) .apply { setAlignment(Align.center) } diplomacyTable.add(allyBonusLabel).row() - + return diplomacyTable } diff --git a/core/src/com/unciv/ui/victoryscreen/VictoryScreen.kt b/core/src/com/unciv/ui/victoryscreen/VictoryScreen.kt index 3edf260808..8db7db3979 100644 --- a/core/src/com/unciv/ui/victoryscreen/VictoryScreen.kt +++ b/core/src/com/unciv/ui/victoryscreen/VictoryScreen.kt @@ -5,6 +5,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.scenes.scene2d.ui.TextButton import com.badlogic.gdx.utils.Align import com.unciv.logic.civilization.CivilizationInfo +import com.unciv.models.ruleset.Policy import com.unciv.models.ruleset.VictoryType import com.unciv.models.translations.getPlaceholderParameters import com.unciv.models.translations.tr @@ -202,11 +203,11 @@ class VictoryScreen(val worldScreen: WorldScreen) : PickerScreen() { policyVictoryColumn.add("Branches completed".toLabel()).row() policyVictoryColumn.addSeparator() - data class civToBranchesCompleted(val civ: CivilizationInfo, val branchesCompleted: Int) + data class CivToBranchesCompleted(val civ: CivilizationInfo, val branchesCompleted: Int) - val civsToBranchesCompleted = - majorCivs.map { civToBranchesCompleted(it, it.policies.adoptedPolicies.count { pol -> pol.endsWith("Complete") }) } - .sortedByDescending { it.branchesCompleted } + val civsToBranchesCompleted = majorCivs.map { + CivToBranchesCompleted(it, it.policies.adoptedPolicies.count { pol -> Policy.isBranchCompleteByName(pol) }) + }.sortedByDescending { it.branchesCompleted } for (entry in civsToBranchesCompleted) { val civToBranchesHaveCompleted = EmpireOverviewScreen.getCivGroup(entry.civ, " - " + entry.branchesCompleted, playerCivInfo)