Allow modders to hide individual Uniques from Civilopedia (#10394)

* Allow hiding individual Uniques from Civilopedia via a conditional-type modifier

* Fix oversight

* Fix another oversight
This commit is contained in:
SomeTroglodyte 2023-11-02 23:09:11 +01:00 committed by GitHub
parent 25aed40686
commit 9970549543
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 133 additions and 111 deletions

View File

@ -2,9 +2,9 @@ package com.unciv.models.ruleset
import com.unciv.Constants
import com.unciv.UncivGame
import com.unciv.models.ruleset.unique.UniqueFlag
import com.unciv.models.ruleset.unique.UniqueTarget
import com.unciv.models.translations.tr
import com.unciv.ui.objectdescriptions.uniquesToCivilopediaTextLines
import com.unciv.ui.screens.civilopediascreen.CivilopediaScreen.Companion.showReligionInCivilopedia
import com.unciv.ui.screens.civilopediascreen.FormattedLine
@ -27,6 +27,7 @@ class Belief() : RulesetObject() {
return getCivilopediaTextLines(false)
}
// This special overload is called from Religion overview and Religion picker
fun getCivilopediaTextLines(withHeader: Boolean): List<FormattedLine> {
val textList = ArrayList<FormattedLine>()
if (withHeader) {
@ -35,10 +36,7 @@ class Belief() : RulesetObject() {
}
if (type != BeliefType.None)
textList += FormattedLine("{Type}: {$type}", color = type.color, centered = withHeader)
uniqueObjects.forEach {
if (!it.hasFlag(UniqueFlag.HiddenToUsers))
textList += FormattedLine(it)
}
uniquesToCivilopediaTextLines(textList, leadingSeparator = null)
return textList
}

View File

@ -9,7 +9,6 @@ import com.unciv.models.ruleset.tile.TileImprovement
import com.unciv.models.ruleset.unique.LocalUniqueCache
import com.unciv.models.ruleset.unique.StateForConditionals
import com.unciv.models.ruleset.unique.Unique
import com.unciv.models.ruleset.unique.UniqueFlag
import com.unciv.models.ruleset.unique.UniqueParameterType
import com.unciv.models.ruleset.unique.UniqueTarget
import com.unciv.models.ruleset.unique.UniqueType
@ -21,6 +20,7 @@ import com.unciv.ui.components.extensions.getConsumesAmountString
import com.unciv.ui.components.extensions.getNeedMoreAmountString
import com.unciv.ui.components.extensions.toPercent
import com.unciv.ui.components.fonts.Fonts
import com.unciv.ui.objectdescriptions.uniquesToCivilopediaTextLines
import com.unciv.ui.screens.civilopediascreen.FormattedLine
@ -100,7 +100,7 @@ class Building : RulesetStatsObject(), INonPerpetualConstruction {
* @param filterUniques If provided, include only uniques for which this function returns true.
*/
private fun getUniquesStringsWithoutDisablers(filterUniques: ((Unique) -> Boolean)? = null) = getUniquesStrings {
!it.hasFlag(UniqueFlag.HiddenToUsers)
!it.isHiddenToUsers()
&& filterUniques?.invoke(it) ?: true
}
@ -262,15 +262,8 @@ class Building : RulesetStatsObject(), INonPerpetualConstruction {
if (replacementTextForUniques.isNotEmpty()) {
textList += FormattedLine(replacementTextForUniques)
} else if (uniques.isNotEmpty()) {
for (unique in uniqueObjects) {
if (unique.hasFlag(UniqueFlag.HiddenToUsers)) continue
if (unique.type == UniqueType.ConsumesResources) {
textList += FormattedLine(unique.text, link = "Resources/${unique.params[1]}", color = "#F42")
continue
}
textList += FormattedLine(unique)
}
} else {
uniquesToCivilopediaTextLines(textList, colorConsumesResources = true)
}
if (!stats.isEmpty()) {

View File

@ -1,11 +1,10 @@
package com.unciv.models.ruleset
import com.unciv.models.ruleset.unique.StateForConditionals
import com.unciv.models.ruleset.unique.UniqueFlag
import com.unciv.models.ruleset.unique.UniqueTarget
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.translations.getPlaceholderText
import com.unciv.models.translations.tr
import com.unciv.ui.objectdescriptions.uniquesToCivilopediaTextLines
import com.unciv.ui.screens.civilopediascreen.FormattedLine
open class Policy : RulesetObject() {
@ -18,12 +17,14 @@ open class Policy : RulesetObject() {
/** 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.
@ -34,16 +35,13 @@ open class Policy : RulesetObject() {
/** Used in PolicyPickerScreen to display Policy properties */
fun getDescription(): String {
var text = uniques
.filter {
!it.getPlaceholderText().contains(UniqueType.OnlyAvailableWhen.placeholderText) &&
!it.getPlaceholderText().contains(UniqueType.OneTimeGlobalAlert.placeholderText)
return (if (policyBranchType == PolicyBranchType.Member) name.tr() + "\n" else "") +
uniqueObjects.filterNot {
it.isHiddenToUsers()
|| it.isOfType(UniqueType.OnlyAvailableWhen)
|| it.isOfType(UniqueType.OneTimeGlobalAlert)
}
.joinToString("\n", transform = { "${it.tr()}" })
if (policyBranchType != PolicyBranchType.BranchStart
&& policyBranchType != PolicyBranchType.BranchComplete)
text = name.tr() + "\n" + text
return text
.joinToString("\n") { "${it.text.tr()}" }
}
override fun makeLink() = "Policy/$name"
@ -126,17 +124,9 @@ open class Policy : RulesetObject() {
lineList += FormattedLine(unit.name, link = unit.makeLink(), indent = 1)
}
if (uniques.isNotEmpty()) {
lineList += FormattedLine()
uniqueObjects.forEach {
if (!it.hasFlag(UniqueFlag.HiddenToUsers))
lineList += FormattedLine(it)
}
}
uniquesToCivilopediaTextLines(lineList)
return lineList
}
}

View File

@ -54,6 +54,7 @@ class Speed : RulesetObject(), IsPartOfGameInfoSerialization {
const val DEFAULTFORSIMULATION: String = "Standard"
}
// Note: Speed is IHasUniques, but no implementation reads them, thus no UniqueType accepts this target
override fun getUniqueTarget(): UniqueTarget = UniqueTarget.Speed
override fun makeLink(): String = "Speed/$name"

View File

@ -4,15 +4,15 @@ import com.badlogic.gdx.graphics.Color
import com.unciv.Constants
import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.RulesetObject
import com.unciv.models.ruleset.unique.UniqueFlag
import com.unciv.models.ruleset.unique.UniqueTarget
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.translations.squareBraceRegex
import com.unciv.models.translations.tr
import com.unciv.ui.components.extensions.colorFromRGB
import com.unciv.ui.objectdescriptions.BaseUnitDescriptions
import com.unciv.ui.objectdescriptions.uniquesToCivilopediaTextLines
import com.unciv.ui.screens.civilopediascreen.CivilopediaScreen.Companion.showReligionInCivilopedia
import com.unciv.ui.screens.civilopediascreen.FormattedLine
import com.unciv.ui.objectdescriptions.BaseUnitDescriptions
import kotlin.math.pow
class Nation : RulesetObject() {
@ -111,12 +111,9 @@ class Nation : RulesetObject() {
if (uniqueText != "") {
textList += FormattedLine(uniqueText, indent = 1)
} else {
uniqueObjects.forEach {
if (!it.hasFlag(UniqueFlag.HiddenToUsers))
textList += FormattedLine(it)
}
textList += FormattedLine()
uniquesToCivilopediaTextLines(textList, leadingSeparator = null)
}
textList += FormattedLine()
if (startBias.isNotEmpty()) {
startBias.withIndex().forEach {

View File

@ -10,6 +10,7 @@ import com.unciv.models.ruleset.unique.UniqueTarget
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.ui.components.extensions.colorFromRGB
import com.unciv.ui.components.fonts.Fonts
import com.unciv.ui.objectdescriptions.uniquesToCivilopediaTextLines
import com.unciv.ui.screens.civilopediascreen.FormattedLine
class Era : RulesetObject() {
@ -53,8 +54,7 @@ class Era : RulesetObject() {
.filter { it.era() == name }
.map { FormattedLine(it.name, it.makeLink()) })
if (uniques.isNotEmpty()) yield(FormattedLine())
yieldAll(uniqueObjects.asSequence().map { FormattedLine(it) })
yieldAll(uniquesToCivilopediaTextLines())
val eraGatedObjects = getEraGatedObjects(ruleset).toList()
if (eraGatedObjects.isEmpty()) return@sequence

View File

@ -5,11 +5,11 @@ import com.unciv.Constants
import com.unciv.models.ruleset.Belief
import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.RulesetStatsObject
import com.unciv.models.ruleset.unique.UniqueFlag
import com.unciv.models.ruleset.unique.UniqueTarget
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.ui.screens.civilopediascreen.FormattedLine
import com.unciv.ui.components.extensions.colorFromRGB
import com.unciv.ui.objectdescriptions.uniquesToCivilopediaTextLines
import com.unciv.ui.screens.civilopediascreen.FormattedLine
class Terrain : RulesetStatsObject() {
@ -118,10 +118,7 @@ class Terrain : RulesetStatsObject() {
// For now, natural wonders show no "open terrain" - may change later
if (turnsInto == null && displayAs(TerrainType.Land, ruleset) && !isRough())
textList += FormattedLine("Open terrain") // Rough is in uniques
uniqueObjects.forEach {
if (!it.hasFlag(UniqueFlag.HiddenToUsers))
textList += FormattedLine(it)
}
uniquesToCivilopediaTextLines(textList, leadingSeparator = null)
textList += FormattedLine()
textList += if (impassable) FormattedLine(Constants.impassable, color="#A00")

View File

@ -14,6 +14,8 @@ import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.ruleset.unit.BaseUnit
import com.unciv.models.translations.tr
import com.unciv.ui.components.extensions.toPercent
import com.unciv.ui.objectdescriptions.uniquesToCivilopediaTextLines
import com.unciv.ui.objectdescriptions.uniquesToDescription
import com.unciv.ui.screens.civilopediascreen.CivilopediaScreen.Companion.showReligionInCivilopedia
import com.unciv.ui.screens.civilopediascreen.FormattedLine
import kotlin.math.roundToInt
@ -58,8 +60,7 @@ class TileImprovement : RulesetStatsObject() {
}
if (techRequired != null) lines += "Required tech: [$techRequired]".tr()
for (unique in uniques)
lines += unique.tr()
uniquesToDescription(lines)
return lines.joinToString("\n")
}
@ -145,11 +146,7 @@ class TileImprovement : RulesetStatsObject() {
textList += FormattedLine("Required tech: [$techRequired]", link="Technology/$techRequired")
}
if (uniques.isNotEmpty()) {
textList += FormattedLine()
for (unique in uniqueObjects)
textList += FormattedLine(unique)
}
uniquesToCivilopediaTextLines(textList)
// Be clearer when one needs to chop down a Forest first... A "Can be built on Plains" is clear enough,
// but a "Can be built on Land" is not - how is the user to know Forest is _not_ Land?

View File

@ -6,10 +6,10 @@ import com.unciv.models.ruleset.Belief
import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.RulesetStatsObject
import com.unciv.models.ruleset.unique.StateForConditionals
import com.unciv.models.ruleset.unique.UniqueFlag
import com.unciv.models.ruleset.unique.UniqueTarget
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.stats.Stats
import com.unciv.ui.objectdescriptions.uniquesToCivilopediaTextLines
import com.unciv.ui.screens.civilopediascreen.FormattedLine
class TileResource : RulesetStatsObject() {
@ -43,13 +43,7 @@ class TileResource : RulesetStatsObject() {
textList += FormattedLine("${resourceType.name} resource", header = 4, color = resourceType.color)
textList += FormattedLine()
if (uniques.any()){
textList += FormattedLine()
for (unique in uniqueObjects.sortedBy { it.text }) {
if (unique.hasFlag(UniqueFlag.HiddenToUsers)) continue
textList += FormattedLine(unique)
}
}
uniquesToCivilopediaTextLines(textList, sorted = true)
textList += FormattedLine(cloneStats().toString())

View File

@ -44,6 +44,7 @@ class Unique(val text: String, val sourceObjectType: UniqueTarget? = null, val s
val isLocalEffect = params.contains("in this city") || conditionals.any { it.type == UniqueType.ConditionalInThisCity }
fun hasFlag(flag: UniqueFlag) = type != null && type.flags.contains(flag)
fun isHiddenToUsers() = hasFlag(UniqueFlag.HiddenToUsers) || conditionals.any { it.type == UniqueType.ConditionalHideUniqueFromUsers }
fun hasTriggerConditional(): Boolean {
if (conditionals.none()) return false
@ -204,6 +205,7 @@ class Unique(val text: String, val sourceObjectType: UniqueTarget? = null, val s
return when (condition.type) {
// These are 'what to do' and not 'when to do' conditionals
UniqueType.ConditionalTimedUnique -> true
UniqueType.ConditionalHideUniqueFromUsers -> true // allowed to be attached to any Unique to hide it, no-op otherwise
UniqueType.ConditionalChance -> stateBasedRandom.nextFloat() < condition.params[0].toFloat() / 100f
UniqueType.ConditionalBeforeTurns -> checkOnCiv { gameInfo.turns < condition.params[0].toInt() }

View File

@ -777,6 +777,7 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
UniqueTarget.Unit, UniqueTarget.UnitType, UniqueTarget.Improvement, UniqueTarget.Tech,
UniqueTarget.Terrain, UniqueTarget.Resource, UniqueTarget.Policy, UniqueTarget.Promotion,
UniqueTarget.Nation, UniqueTarget.Ruins, flags = UniqueFlag.setOfHiddenToUsers),
ConditionalHideUniqueFromUsers("hidden from users", UniqueTarget.Conditional),
// Declarative Mod compatibility (so far rudimentary):
ModIncompatibleWith("Mod is incompatible with [modFilter]", UniqueTarget.ModOptions),

View File

@ -61,6 +61,7 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction {
lateinit var ruleset: Ruleset
/** Generate short description as comma-separated string for Technology description "Units enabled" and GreatPersonPickerScreen */
fun getShortDescription() = BaseUnitDescriptions.getShortDescription(this)
/** Generate description as multi-line string for CityScreen addSelectedConstructionTable

View File

@ -2,10 +2,11 @@ package com.unciv.models.ruleset.unit
import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.RulesetObject
import com.unciv.models.ruleset.unique.UniqueFlag
import com.unciv.models.ruleset.unique.UniqueTarget
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.translations.tr
import com.unciv.ui.objectdescriptions.uniquesToCivilopediaTextLines
import com.unciv.ui.objectdescriptions.uniquesToDescription
import com.unciv.ui.screens.civilopediascreen.FormattedLine
import com.unciv.ui.screens.pickerscreens.PromotionPickerScreen
@ -45,9 +46,7 @@ class Promotion : RulesetObject() {
fun getDescription(promotionsForUnitType: Collection<Promotion>):String {
val textList = ArrayList<String>()
for (unique in uniques) {
textList += unique.tr()
}
uniquesToDescription(textList)
if (prerequisites.isNotEmpty()) {
val prerequisitesString: ArrayList<String> = arrayListOf()
@ -64,10 +63,7 @@ class Promotion : RulesetObject() {
override fun getCivilopediaTextLines(ruleset: Ruleset): List<FormattedLine> {
val textList = ArrayList<FormattedLine>()
uniqueObjects.forEach {
if (!it.hasFlag(UniqueFlag.HiddenToUsers))
textList += FormattedLine(it)
}
uniquesToCivilopediaTextLines(textList, leadingSeparator = null)
val filteredPrerequisites = prerequisites.mapNotNull {
ruleset.unitPromotions[it]

View File

@ -349,7 +349,7 @@ object TranslationFileWriter {
}
fun submitString(string: String, unique: Unique) {
if (unique.hasFlag(UniqueFlag.HiddenToUsers))
if (unique.isHiddenToUsers())
return // We don't need to translate this at all, not user-visible
val stringToTranslate = string.removeConditionals()

View File

@ -9,7 +9,6 @@ import com.unciv.models.ruleset.IRulesetObject
import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.unique.StateForConditionals
import com.unciv.models.ruleset.unique.Unique
import com.unciv.models.ruleset.unique.UniqueFlag
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.ruleset.unit.BaseUnit
import com.unciv.models.ruleset.unit.UnitMovementType
@ -25,6 +24,7 @@ import com.unciv.ui.screens.civilopediascreen.MarkupRenderer
object BaseUnitDescriptions {
/** Generate short description as comma-separated string for Technology description "Units enabled" and GreatPersonPickerScreen */
fun getShortDescription(baseUnit: BaseUnit): String {
val infoList = mutableListOf<String>()
if (baseUnit.strength != 0) infoList += "${baseUnit.strength}${Fonts.strength}"
@ -33,8 +33,7 @@ object BaseUnitDescriptions {
for (promotion in baseUnit.promotions)
infoList += promotion.tr()
if (baseUnit.replacementTextForUniques != "") infoList += baseUnit.replacementTextForUniques
else for (unique in baseUnit.uniqueObjects) if (!unique.hasFlag(UniqueFlag.HiddenToUsers))
infoList += unique.text.tr()
else baseUnit.uniquesToDescription(infoList)
return infoList.joinToString()
}
@ -59,11 +58,7 @@ object BaseUnitDescriptions {
lines += "$strengthLine${baseUnit.movement}${Fonts.movement}"
if (baseUnit.replacementTextForUniques != "") lines += baseUnit.replacementTextForUniques
else for (unique in baseUnit.uniqueObjects.filterNot {
it.type == UniqueType.Unbuildable
|| it.type?.flags?.contains(UniqueFlag.HiddenToUsers) == true
})
lines += unique.text.tr()
else baseUnit.uniquesToDescription(lines) { isOfType(UniqueType.Unbuildable) }
if (baseUnit.promotions.isNotEmpty()) {
val prefix = "Free promotion${if (baseUnit.promotions.size == 1) "" else "s"}:".tr() + " "
@ -106,16 +101,8 @@ object BaseUnitDescriptions {
if (baseUnit.replacementTextForUniques.isNotEmpty()) {
textList += FormattedLine()
textList += FormattedLine(baseUnit.replacementTextForUniques)
} else if (baseUnit.uniques.isNotEmpty()) {
textList += FormattedLine()
for (unique in baseUnit.uniqueObjects.sortedBy { it.text }) {
if (unique.hasFlag(UniqueFlag.HiddenToUsers)) continue
if (unique.type == UniqueType.ConsumesResources) {
textList += FormattedLine(unique.text, link = "Resources/${unique.params[1]}", color = "#F42")
continue
}
textList += FormattedLine(unique)
}
} else {
baseUnit.uniquesToCivilopediaTextLines(textList, sorted = true, colorConsumesResources = true)
}
if (baseUnit.requiredResource != null) {
@ -252,13 +239,8 @@ object BaseUnitDescriptions {
for (promotion in relevantPromotions)
yield(FormattedLine(promotion.name, promotion.makeLink()))
}
if (uniqueObjects.isNotEmpty()) {
yield(FormattedLine(separator = true))
for (unique in uniqueObjects) {
if (unique.hasFlag(UniqueFlag.HiddenToUsers)) continue
yield(FormattedLine(unique))
}
}
yieldAll(uniquesToCivilopediaTextLines(leadingSeparator = true))
}
return (if (name.startsWith("Domain: ")) getDomainLines() else getUnitTypeLines()).toList()
}
@ -303,12 +285,12 @@ object BaseUnitDescriptions {
if (betterUnit.replacementTextForUniques.isNotEmpty()) {
yield(betterUnit.replacementTextForUniques to null)
} else {
val newAbilityPredicate: (Unique)->Boolean = { it.text in originalUnit.uniques || it.hasFlag(UniqueFlag.HiddenToUsers) }
val newAbilityPredicate: (Unique)->Boolean = { it.text in originalUnit.uniques || it.isHiddenToUsers() }
for (unique in betterUnit.uniqueObjects.filterNot(newAbilityPredicate))
yield(unique.text to null)
}
val lostAbilityPredicate: (Unique)->Boolean = { it.text in betterUnit.uniques || it.hasFlag(UniqueFlag.HiddenToUsers) }
val lostAbilityPredicate: (Unique)->Boolean = { it.text in betterUnit.uniques || it.isHiddenToUsers() }
for (unique in originalUnit.uniqueObjects.filterNot(lostAbilityPredicate)) {
yield("Lost ability (vs [${originalUnit.name}]): [${unique.text}]" to null)
}

View File

@ -0,0 +1,74 @@
package com.unciv.ui.objectdescriptions
import com.unciv.models.ruleset.unique.IHasUniques
import com.unciv.models.ruleset.unique.Unique
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.translations.tr
import com.unciv.ui.screens.civilopediascreen.FormattedLine
/**
* Appends user-visible Uniques as translated text to a [line collection][lineList].
*
* Follows json order.
* @param exclude Predicate that can exclude Uniques by returning `true` (defaults to return `false`).
*/
fun IHasUniques.uniquesToDescription(
lineList: MutableCollection<String>,
exclude: Unique.() -> Boolean = {false}
) {
for (unique in uniqueObjects) {
if (unique.isHiddenToUsers()) continue
if (unique.exclude()) continue
lineList += unique.text.tr()
}
}
/**
* A Sequence of user-visible Uniques as [FormattedLine]s.
*
* @param leadingSeparator Tristate: If there are lines to display and this parameter is not `null`, a leading line is output, as separator or empty line.
* @param sorted If set, sorts alphabetically (**not** using a locale-specific Collator). Otherwise lists in json order.
* @param colorConsumesResources If set, ConsumesResources Uniques get a reddish color.
* @param exclude Predicate that can exclude Uniques by returning `true` (defaults to return `false`).
*/
fun IHasUniques.uniquesToCivilopediaTextLines(
leadingSeparator: Boolean? = false,
sorted: Boolean = false,
colorConsumesResources: Boolean = false,
exclude: Unique.() -> Boolean = {false}
) = sequence {
var orderedUniques = uniqueObjects.asSequence()
.filterNot { it.isHiddenToUsers() || it.exclude() }
if (sorted) orderedUniques = orderedUniques.sortedBy { it.text }
for ((index, unique) in orderedUniques.withIndex()) {
if (leadingSeparator != null && index == 0)
yield(FormattedLine(separator = leadingSeparator))
// Optionally special-case ConsumesResources to give it a reddish color. Also ensures link always points to the resource
// (the other constructor guesses the first object by name in the Unique parameters).
yield(
if (colorConsumesResources && unique.isOfType(UniqueType.ConsumesResources))
FormattedLine(unique.text, link = "Resources/${unique.params[1]}", color = "#F42")
else FormattedLine(unique)
)
}
}
/**
* Appends user-visible Uniques as [FormattedLine]s to [lineList].
*
* @param leadingSeparator Tristate: If there are lines to display and this parameter is not `null`, a leading line is output, as separator or empty line.
* @param sorted If set, sorts alphabetically (**not** using a locale-specific Collator). Otherwise lists in json order.
* @param colorConsumesResources If set, ConsumesResources Uniques get a reddish color.
* @param exclude Predicate that can exclude Uniques by returning `true` (defaults to return `false`).
*/
fun IHasUniques.uniquesToCivilopediaTextLines(
lineList: MutableCollection<FormattedLine>,
leadingSeparator: Boolean? = false,
sorted: Boolean = false,
colorConsumesResources: Boolean = false,
exclude: Unique.() -> Boolean = {false}
) {
uniquesToCivilopediaTextLines(leadingSeparator, sorted, colorConsumesResources, exclude)
.toCollection(lineList)
}

View File

@ -8,7 +8,6 @@ import com.unciv.models.ruleset.tech.Technology
import com.unciv.models.ruleset.tile.TileImprovement
import com.unciv.models.ruleset.tile.TileResource
import com.unciv.models.ruleset.unique.Unique
import com.unciv.models.ruleset.unique.UniqueFlag
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.ruleset.unit.BaseUnit
import com.unciv.models.translations.tr
@ -38,7 +37,8 @@ object TechnologyDescriptions {
if (pediaText.text.isEmpty() || pediaText.header != 0) continue
lineList += pediaText.text
}
for (unique in uniques) lineList += unique
uniquesToDescription(lineList)
lineList.addAll(
getAffectedImprovements(name, ruleset)
@ -191,13 +191,7 @@ object TechnologyDescriptions {
}
}
if (uniques.isNotEmpty()) {
lineList += FormattedLine()
uniqueObjects.forEach {
if (!it.hasFlag(UniqueFlag.HiddenToUsers))
lineList += FormattedLine(it)
}
}
uniquesToCivilopediaTextLines(lineList)
val affectedImprovements = getAffectedImprovements(name, ruleset)
if (affectedImprovements.any()) {

View File

@ -6,6 +6,7 @@ import com.unciv.models.ruleset.IRulesetObject
import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.RulesetObject
import com.unciv.models.stats.INamed
import com.unciv.ui.objectdescriptions.uniquesToCivilopediaTextLines
/** Addon common to most ruleset game objects managing civilopedia display
*
@ -39,6 +40,7 @@ interface ICivilopediaText {
* (And the info displayed should be about the **ruleset**, not the player situation)
*
* Default implementation is empty - no need to call super in overrides.
* Note that for inclusion of Uniques, two helpers named [uniquesToCivilopediaTextLines] exist (for Sequence or MutableCollection context).
*
* @param ruleset The current ruleset for the Civilopedia viewer
* @return A list of [FormattedLine]s that will be inserted before

View File

@ -2028,6 +2028,9 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
Applicable to: Conditional
??? example "&lt;hidden from users&gt;"
Applicable to: Conditional
## TriggerCondition uniques
!!! note ""