mirror of
https://github.com/yairm210/Unciv.git
synced 2025-07-25 15:19:51 +07:00
Spruced up Civilopedia - phase 6 - uniques (#4587)
This commit is contained in:
@ -29,7 +29,7 @@ class Building : NamedStats(), IConstruction, ICivilopediaText {
|
|||||||
private var percentStatBonus: Stats? = null
|
private var percentStatBonus: Stats? = null
|
||||||
var specialistSlots: Counter<String>? = null
|
var specialistSlots: Counter<String>? = null
|
||||||
fun newSpecialists(): Counter<String> {
|
fun newSpecialists(): Counter<String> {
|
||||||
if (specialistSlots == null) return Counter<String>()
|
if (specialistSlots == null) return Counter()
|
||||||
// Could have old specialist values of "gold", "science" etc - change them to the new specialist names
|
// Could have old specialist values of "gold", "science" etc - change them to the new specialist names
|
||||||
val counter = Counter<String>()
|
val counter = Counter<String>()
|
||||||
for ((entry, amount) in specialistSlots!!) {
|
for ((entry, amount) in specialistSlots!!) {
|
||||||
@ -90,18 +90,24 @@ class Building : NamedStats(), IConstruction, ICivilopediaText {
|
|||||||
return infoList.joinToString("; ") { it.tr() }
|
return infoList.joinToString("; ") { it.tr() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getUniquesStrings(): ArrayList<String> {
|
private fun getUniquesStrings() = sequence {
|
||||||
val tileBonusHashmap = HashMap<String, ArrayList<String>>()
|
val tileBonusHashmap = HashMap<String, ArrayList<String>>()
|
||||||
val finalUniques = ArrayList<String>()
|
for (unique in uniqueObjects) when {
|
||||||
for (unique in uniqueObjects)
|
unique.placeholderText == "[] from [] tiles []" && unique.params[2] == "in this city" -> {
|
||||||
if (unique.placeholderText == "[] from [] tiles []" && unique.params[2] == "in this city") {
|
|
||||||
val stats = unique.params[0]
|
val stats = unique.params[0]
|
||||||
if (!tileBonusHashmap.containsKey(stats)) tileBonusHashmap[stats] = ArrayList()
|
if (!tileBonusHashmap.containsKey(stats)) tileBonusHashmap[stats] = ArrayList()
|
||||||
tileBonusHashmap[stats]!!.add(unique.params[1])
|
tileBonusHashmap[stats]!!.add(unique.params[1])
|
||||||
} else if (unique.placeholderText != "Consumes [] []") finalUniques += unique.text
|
}
|
||||||
|
unique.placeholderText == "Consumes [] []" -> Unit // skip these,
|
||||||
|
else -> yield(unique.text)
|
||||||
|
}
|
||||||
for ((key, value) in tileBonusHashmap)
|
for ((key, value) in tileBonusHashmap)
|
||||||
finalUniques += "[stats] from [tileFilter] tiles in this city".fillPlaceholders(key, value.joinToString { it.tr() })
|
yield( "[stats] from [tileFilter] tiles in this city"
|
||||||
return finalUniques
|
.fillPlaceholders( key,
|
||||||
|
// A single tileFilter will be properly translated later due to being within []
|
||||||
|
// advantage to not translate prematurely: FormatLine.formatUnique will recognize it
|
||||||
|
if (value.size == 1) value[0] else value.joinToString { it.tr() }
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getDescription(cityInfo: CityInfo?, ruleset: Ruleset): String {
|
fun getDescription(cityInfo: CityInfo?, ruleset: Ruleset): String {
|
||||||
@ -118,7 +124,7 @@ class Building : NamedStats(), IConstruction, ICivilopediaText {
|
|||||||
stringBuilder.appendLine("Provides a free [$providesFreeBuilding] in the city".tr())
|
stringBuilder.appendLine("Provides a free [$providesFreeBuilding] in the city".tr())
|
||||||
if (uniques.isNotEmpty()) {
|
if (uniques.isNotEmpty()) {
|
||||||
if (replacementTextForUniques != "") stringBuilder.appendLine(replacementTextForUniques)
|
if (replacementTextForUniques != "") stringBuilder.appendLine(replacementTextForUniques)
|
||||||
else stringBuilder.appendLine(getUniquesStrings().asSequence().map { it.tr() }.joinToString("\n"))
|
else stringBuilder.appendLine(getUniquesStrings().map { it.tr() }.joinToString("\n"))
|
||||||
}
|
}
|
||||||
if (!stats.isEmpty())
|
if (!stats.isEmpty())
|
||||||
stringBuilder.appendLine(stats.toString())
|
stringBuilder.appendLine(stats.toString())
|
||||||
@ -180,8 +186,7 @@ class Building : NamedStats(), IConstruction, ICivilopediaText {
|
|||||||
|
|
||||||
fun getStatPercentageBonuses(cityInfo: CityInfo?): Stats {
|
fun getStatPercentageBonuses(cityInfo: CityInfo?): Stats {
|
||||||
val stats = if (percentStatBonus == null) Stats() else percentStatBonus!!.clone()
|
val stats = if (percentStatBonus == null) Stats() else percentStatBonus!!.clone()
|
||||||
val civInfo = cityInfo?.civInfo
|
val civInfo = cityInfo?.civInfo ?: return stats // initial stats
|
||||||
if (civInfo == null) return stats // initial stats
|
|
||||||
|
|
||||||
val baseBuildingName = getBaseBuilding(civInfo.gameInfo.ruleSet).name
|
val baseBuildingName = getBaseBuilding(civInfo.gameInfo.ruleSet).name
|
||||||
|
|
||||||
@ -262,7 +267,8 @@ class Building : NamedStats(), IConstruction, ICivilopediaText {
|
|||||||
if (replacementTextForUniques.isNotEmpty())
|
if (replacementTextForUniques.isNotEmpty())
|
||||||
textList += FormattedLine(replacementTextForUniques)
|
textList += FormattedLine(replacementTextForUniques)
|
||||||
else
|
else
|
||||||
for (unique in getUniquesStrings()) textList += FormattedLine(unique)
|
for (unique in getUniquesStrings())
|
||||||
|
textList += FormattedLine(Unique(unique))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!stats.isEmpty()) {
|
if (!stats.isEmpty()) {
|
||||||
@ -504,8 +510,8 @@ class Building : NamedStats(), IConstruction, ICivilopediaText {
|
|||||||
|
|
||||||
for ((resource, amount) in getResourceRequirements())
|
for ((resource, amount) in getResourceRequirements())
|
||||||
if (civInfo.getCivResourcesByName()[resource]!! < amount) {
|
if (civInfo.getCivResourcesByName()[resource]!! < amount) {
|
||||||
if (amount == 1) return "Consumes 1 [$resource]" // Again, to preserve existing translations
|
return if (amount == 1) "Consumes 1 [$resource]" // Again, to preserve existing translations
|
||||||
else return "Consumes [$amount] [$resource]"
|
else "Consumes [$amount] [$resource]"
|
||||||
}
|
}
|
||||||
|
|
||||||
if (requiredNearbyImprovedResources != null) {
|
if (requiredNearbyImprovedResources != null) {
|
||||||
@ -599,14 +605,14 @@ class Building : NamedStats(), IConstruction, ICivilopediaText {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getBaseBuilding(ruleset: Ruleset): Building {
|
fun getBaseBuilding(ruleset: Ruleset): Building {
|
||||||
if (replaces == null) return this
|
return if (replaces == null) this
|
||||||
else return ruleset.buildings[replaces!!]!!
|
else ruleset.buildings[replaces!!]!!
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getImprovement(ruleset: Ruleset): TileImprovement? {
|
fun getImprovement(ruleset: Ruleset): TileImprovement? {
|
||||||
val improvementUnique = uniqueObjects
|
val improvementUnique = uniqueObjects
|
||||||
.firstOrNull { it.placeholderText == "Creates a [] improvement on a specific tile" }
|
.firstOrNull { it.placeholderText == "Creates a [] improvement on a specific tile" }
|
||||||
if (improvementUnique == null) return null
|
?: return null
|
||||||
return ruleset.tileImprovements[improvementUnique.params[0]]
|
return ruleset.tileImprovements[improvementUnique.params[0]]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,14 +103,8 @@ class BaseUnit : INamed, IConstruction, CivilopediaText() {
|
|||||||
textList += FormattedLine(replacementTextForUniques)
|
textList += FormattedLine(replacementTextForUniques)
|
||||||
} else if (uniques.isNotEmpty()) {
|
} else if (uniques.isNotEmpty()) {
|
||||||
textList += FormattedLine()
|
textList += FormattedLine()
|
||||||
for (uniqueObject in uniqueObjects.sortedBy { it.text }) {
|
for (uniqueObject in uniqueObjects.sortedBy { it.text })
|
||||||
if (uniqueObject.placeholderText == "Can construct []") {
|
textList += FormattedLine(uniqueObject)
|
||||||
val improvement = uniqueObject.params[0]
|
|
||||||
textList += FormattedLine(uniqueObject.text, link="Improvement/$improvement")
|
|
||||||
} else {
|
|
||||||
textList += FormattedLine(uniqueObject.text)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val resourceRequirements = getResourceRequirements()
|
val resourceRequirements = getResourceRequirements()
|
||||||
|
@ -5,7 +5,9 @@ import com.badlogic.gdx.graphics.Color
|
|||||||
import com.badlogic.gdx.scenes.scene2d.Actor
|
import com.badlogic.gdx.scenes.scene2d.Actor
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||||
import com.badlogic.gdx.utils.Align
|
import com.badlogic.gdx.utils.Align
|
||||||
|
import com.unciv.UncivGame
|
||||||
import com.unciv.models.ruleset.Ruleset
|
import com.unciv.models.ruleset.Ruleset
|
||||||
|
import com.unciv.models.ruleset.Unique
|
||||||
import com.unciv.models.stats.INamed
|
import com.unciv.models.stats.INamed
|
||||||
import com.unciv.ui.utils.*
|
import com.unciv.ui.utils.*
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
@ -66,6 +68,9 @@ class FormattedLine (
|
|||||||
// from json in the primary constructor parameters above. Everything else should be a fun(),
|
// from json in the primary constructor parameters above. Everything else should be a fun(),
|
||||||
// have no backing field, be `by lazy` or use @Transient, Thank you.
|
// have no backing field, be `by lazy` or use @Transient, Thank you.
|
||||||
|
|
||||||
|
/** Looks for linkable ruleset objects in [Unique] parameters and returns a linked [FormattedLine] if successful, a plain one otherwise */
|
||||||
|
constructor(unique: Unique) : this(unique.text, getUniqueLink(unique))
|
||||||
|
|
||||||
/** Link types that can be used for [FormattedLine.link] */
|
/** Link types that can be used for [FormattedLine.link] */
|
||||||
enum class LinkType {
|
enum class LinkType {
|
||||||
None,
|
None,
|
||||||
@ -133,6 +138,43 @@ class FormattedLine (
|
|||||||
const val iconPad = 5f
|
const val iconPad = 5f
|
||||||
/** Padding distance per [indent] level */
|
/** Padding distance per [indent] level */
|
||||||
const val indentPad = 30f
|
const val indentPad = 30f
|
||||||
|
|
||||||
|
// Helper for constructor(Unique)
|
||||||
|
private fun getUniqueLink(unique: Unique): String {
|
||||||
|
for (parameter in unique.params) {
|
||||||
|
val category = allObjectNamesCategoryMap[parameter] ?: continue
|
||||||
|
return category.name + "/" + parameter
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
// 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.
|
||||||
|
private val allObjectNamesCategoryMap: HashMap<String, CivilopediaCategories> by lazy {
|
||||||
|
//val startTime = System.nanoTime()
|
||||||
|
val ruleSet = UncivGame.Current.gameInfo.ruleSet
|
||||||
|
// order these with the categories that should take precedence in case of name conflicts (e.g. Railroad) _last_
|
||||||
|
val allObjectMapsSequence = sequence {
|
||||||
|
yield(CivilopediaCategories.Difficulty to ruleSet.difficulties)
|
||||||
|
yield(CivilopediaCategories.Promotion to ruleSet.unitPromotions)
|
||||||
|
yield(CivilopediaCategories.Policy to ruleSet.policies)
|
||||||
|
yield(CivilopediaCategories.Terrain to ruleSet.terrains)
|
||||||
|
yield(CivilopediaCategories.Improvement to ruleSet.tileImprovements)
|
||||||
|
yield(CivilopediaCategories.Resource to ruleSet.tileResources)
|
||||||
|
yield(CivilopediaCategories.Nation to ruleSet.nations)
|
||||||
|
yield(CivilopediaCategories.Unit to ruleSet.units)
|
||||||
|
yield(CivilopediaCategories.Technology to ruleSet.technologies)
|
||||||
|
yield(CivilopediaCategories.Building to ruleSet.buildings.filter { !it.value.isAnyWonder() })
|
||||||
|
yield(CivilopediaCategories.Wonder to ruleSet.buildings.filter { it.value.isAnyWonder() })
|
||||||
|
}
|
||||||
|
val result = HashMap<String,CivilopediaCategories>()
|
||||||
|
allObjectMapsSequence.filter { !it.first.hide }
|
||||||
|
.flatMap { pair -> pair.second.keys.asSequence().map { key -> pair.first to key } }
|
||||||
|
.forEach {
|
||||||
|
result[it.second] = it.first
|
||||||
|
//println(" ${it.second} is a ${it.first}")
|
||||||
|
}
|
||||||
|
//println("allObjectNamesCategoryMap took ${System.nanoTime()-startTime}ns to initialize")
|
||||||
|
result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Extension: determines if a [String] looks like a link understood by the OS */
|
/** Extension: determines if a [String] looks like a link understood by the OS */
|
||||||
|
Reference in New Issue
Block a user