mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-25 12:54:06 -04:00
Allow for replacement improvements (#11369)
* Allow for replacement improvements * imports * Forgot the most important change, lol * Docs * Replacement description, validation, and filter * Move more into ImprovementDescriptions * Whoops, forgot to yield * Fix some copy-paste artifacts * New translations * Fix double see also * Add space for translation engine
This commit is contained in:
parent
0caf0cb4fa
commit
3ea1e4a539
@ -1538,6 +1538,7 @@ Unique to [civName], replaces [unitName] =
|
|||||||
Unique to [civName] =
|
Unique to [civName] =
|
||||||
Tutorials =
|
Tutorials =
|
||||||
Cost =
|
Cost =
|
||||||
|
Turns to build =
|
||||||
May contain [listOfResources] =
|
May contain [listOfResources] =
|
||||||
May contain: =
|
May contain: =
|
||||||
Can upgrade from [unit] =
|
Can upgrade from [unit] =
|
||||||
@ -1557,6 +1558,7 @@ Improvements that provide this resource =
|
|||||||
Buildings that require this resource worked near the city =
|
Buildings that require this resource worked near the city =
|
||||||
Units that consume this resource =
|
Units that consume this resource =
|
||||||
Can be built on =
|
Can be built on =
|
||||||
|
Cannot be built on =
|
||||||
or [terrainType] =
|
or [terrainType] =
|
||||||
Can be constructed by =
|
Can be constructed by =
|
||||||
Can be created instantly by =
|
Can be created instantly by =
|
||||||
|
@ -275,7 +275,7 @@ object Automation {
|
|||||||
): Boolean {
|
): Boolean {
|
||||||
if (construction !is Building) return true
|
if (construction !is Building) return true
|
||||||
if (!construction.hasCreateOneImprovementUnique()) return true // redundant but faster???
|
if (!construction.hasCreateOneImprovementUnique()) return true // redundant but faster???
|
||||||
val improvement = construction.getImprovementToCreate(city.getRuleset()) ?: return true
|
val improvement = construction.getImprovementToCreate(city.getRuleset(), civInfo) ?: return true
|
||||||
return city.getTiles().any {
|
return city.getTiles().any {
|
||||||
it.improvementFunctions.canBuildImprovement(improvement, civInfo)
|
it.improvementFunctions.canBuildImprovement(improvement, civInfo)
|
||||||
}
|
}
|
||||||
|
@ -655,7 +655,7 @@ class CityConstructions : IsPartOfGameInfoSerialization {
|
|||||||
tile: Tile? = null
|
tile: Tile? = null
|
||||||
): Boolean {
|
): Boolean {
|
||||||
// Support UniqueType.CreatesOneImprovement: it is active when getImprovementToCreate returns an improvement
|
// Support UniqueType.CreatesOneImprovement: it is active when getImprovementToCreate returns an improvement
|
||||||
val improvementToPlace = (construction as? Building)?.getImprovementToCreate(city.getRuleset())
|
val improvementToPlace = (construction as? Building)?.getImprovementToCreate(city.getRuleset(), city.civ)
|
||||||
if (improvementToPlace != null) {
|
if (improvementToPlace != null) {
|
||||||
// If active without a predetermined tile to place the improvement on, automate a tile
|
// If active without a predetermined tile to place the improvement on, automate a tile
|
||||||
val finalTile = tile
|
val finalTile = tile
|
||||||
@ -716,7 +716,7 @@ class CityConstructions : IsPartOfGameInfoSerialization {
|
|||||||
|
|
||||||
/** Support for [UniqueType.CreatesOneImprovement] - if an Improvement-creating Building was auto-queued, auto-choose a tile: */
|
/** Support for [UniqueType.CreatesOneImprovement] - if an Improvement-creating Building was auto-queued, auto-choose a tile: */
|
||||||
val building = getCurrentConstruction() as? Building ?: return
|
val building = getCurrentConstruction() as? Building ?: return
|
||||||
val improvement = building.getImprovementToCreate(city.getRuleset()) ?: return
|
val improvement = building.getImprovementToCreate(city.getRuleset(), city.civ) ?: return
|
||||||
if (getTileForImprovement(improvement.name) != null) return
|
if (getTileForImprovement(improvement.name) != null) return
|
||||||
val newTile = Automation.getTileForConstructionImprovement(city, improvement) ?: return
|
val newTile = Automation.getTileForConstructionImprovement(city, improvement) ?: return
|
||||||
newTile.improvementFunctions.markForCreatesOneImprovement(improvement.name)
|
newTile.improvementFunctions.markForCreatesOneImprovement(improvement.name)
|
||||||
@ -778,7 +778,7 @@ class CityConstructions : IsPartOfGameInfoSerialization {
|
|||||||
// UniqueType.CreatesOneImprovement support
|
// UniqueType.CreatesOneImprovement support
|
||||||
val construction = getConstruction(constructionName)
|
val construction = getConstruction(constructionName)
|
||||||
if (construction is Building) {
|
if (construction is Building) {
|
||||||
val improvement = construction.getImprovementToCreate(city.getRuleset())
|
val improvement = construction.getImprovementToCreate(city.getRuleset(), city.civ)
|
||||||
if (improvement != null) {
|
if (improvement != null) {
|
||||||
getTileForImprovement(improvement.name)?.stopWorkingOnImprovement()
|
getTileForImprovement(improvement.name)?.stopWorkingOnImprovement()
|
||||||
}
|
}
|
||||||
@ -846,7 +846,7 @@ class CityConstructions : IsPartOfGameInfoSerialization {
|
|||||||
* (skip if none found), then un-mark the tile and place the improvement unless [removeOnly] is set.
|
* (skip if none found), then un-mark the tile and place the improvement unless [removeOnly] is set.
|
||||||
*/
|
*/
|
||||||
private fun applyCreateOneImprovement(building: Building, removeOnly: Boolean = false) {
|
private fun applyCreateOneImprovement(building: Building, removeOnly: Boolean = false) {
|
||||||
val improvement = building.getImprovementToCreate(city.getRuleset())
|
val improvement = building.getImprovementToCreate(city.getRuleset(), city.civ)
|
||||||
?: return
|
?: return
|
||||||
val tileForImprovement = getTileForImprovement(improvement.name) ?: return
|
val tileForImprovement = getTileForImprovement(improvement.name) ?: return
|
||||||
tileForImprovement.stopWorkingOnImprovement() // clears mark
|
tileForImprovement.stopWorkingOnImprovement() // clears mark
|
||||||
@ -866,7 +866,7 @@ class CityConstructions : IsPartOfGameInfoSerialization {
|
|||||||
val ruleset = city.getRuleset()
|
val ruleset = city.getRuleset()
|
||||||
val indexToRemove = constructionQueue.withIndex().firstNotNullOfOrNull {
|
val indexToRemove = constructionQueue.withIndex().firstNotNullOfOrNull {
|
||||||
val construction = getConstruction(it.value)
|
val construction = getConstruction(it.value)
|
||||||
val buildingImprovement = (construction as? Building)?.getImprovementToCreate(ruleset)?.name
|
val buildingImprovement = (construction as? Building)?.getImprovementToCreate(ruleset, city.civ)?.name
|
||||||
it.index.takeIf { buildingImprovement == improvement }
|
it.index.takeIf { buildingImprovement == improvement }
|
||||||
} ?: return
|
} ?: return
|
||||||
|
|
||||||
|
@ -45,6 +45,7 @@ import com.unciv.models.ruleset.nation.Personality
|
|||||||
import com.unciv.models.ruleset.tech.Era
|
import com.unciv.models.ruleset.tech.Era
|
||||||
import com.unciv.models.ruleset.tile.ResourceSupplyList
|
import com.unciv.models.ruleset.tile.ResourceSupplyList
|
||||||
import com.unciv.models.ruleset.tile.ResourceType
|
import com.unciv.models.ruleset.tile.ResourceType
|
||||||
|
import com.unciv.models.ruleset.tile.TileImprovement
|
||||||
import com.unciv.models.ruleset.tile.TileResource
|
import com.unciv.models.ruleset.tile.TileResource
|
||||||
import com.unciv.models.ruleset.unique.StateForConditionals
|
import com.unciv.models.ruleset.unique.StateForConditionals
|
||||||
import com.unciv.models.ruleset.unique.TemporaryUnique
|
import com.unciv.models.ruleset.unique.TemporaryUnique
|
||||||
@ -544,6 +545,22 @@ class Civilization : IsPartOfGameInfoSerialization {
|
|||||||
return baseBuilding
|
return baseBuilding
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getEquivalentTileImprovement(tileImprovementName: String): TileImprovement {
|
||||||
|
val tileImprovement = gameInfo.ruleset.tileImprovements[tileImprovementName]
|
||||||
|
?: throw UncivShowableException("Improvement $tileImprovementName doesn't seem to exist!")
|
||||||
|
return getEquivalentTileImprovement(tileImprovement)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getEquivalentTileImprovement(tileImprovement: TileImprovement): TileImprovement {
|
||||||
|
if (tileImprovement.replaces != null)
|
||||||
|
return getEquivalentTileImprovement(tileImprovement.replaces!!)
|
||||||
|
|
||||||
|
for (improvement in cache.uniqueImprovements)
|
||||||
|
if (improvement.replaces == tileImprovement.name)
|
||||||
|
return improvement
|
||||||
|
return tileImprovement
|
||||||
|
}
|
||||||
|
|
||||||
fun getEquivalentUnit(baseUnitName: String): BaseUnit {
|
fun getEquivalentUnit(baseUnitName: String): BaseUnit {
|
||||||
val baseUnit = gameInfo.ruleset.units[baseUnitName]
|
val baseUnit = gameInfo.ruleset.units[baseUnitName]
|
||||||
?: throw UncivShowableException("Unit $baseUnitName doesn't seem to exist!")
|
?: throw UncivShowableException("Unit $baseUnitName doesn't seem to exist!")
|
||||||
|
@ -14,6 +14,7 @@ import com.unciv.logic.map.tile.Tile
|
|||||||
import com.unciv.models.ruleset.Building
|
import com.unciv.models.ruleset.Building
|
||||||
import com.unciv.models.ruleset.tile.ResourceSupplyList
|
import com.unciv.models.ruleset.tile.ResourceSupplyList
|
||||||
import com.unciv.models.ruleset.tile.ResourceType
|
import com.unciv.models.ruleset.tile.ResourceType
|
||||||
|
import com.unciv.models.ruleset.tile.TileImprovement
|
||||||
import com.unciv.models.ruleset.unique.StateForConditionals
|
import com.unciv.models.ruleset.unique.StateForConditionals
|
||||||
import com.unciv.models.ruleset.unique.UniqueTarget
|
import com.unciv.models.ruleset.unique.UniqueTarget
|
||||||
import com.unciv.models.ruleset.unique.UniqueTriggerActivation
|
import com.unciv.models.ruleset.unique.UniqueTriggerActivation
|
||||||
@ -35,6 +36,9 @@ class CivInfoTransientCache(val civInfo: Civilization) {
|
|||||||
@Transient
|
@Transient
|
||||||
val uniqueUnits = hashSetOf<BaseUnit>()
|
val uniqueUnits = hashSetOf<BaseUnit>()
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
val uniqueImprovements = hashSetOf<TileImprovement>()
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
val uniqueBuildings = hashSetOf<Building>()
|
val uniqueBuildings = hashSetOf<Building>()
|
||||||
|
|
||||||
@ -64,6 +68,10 @@ class CivInfoTransientCache(val civInfo: Civilization) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (improvement in ruleset.tileImprovements.values)
|
||||||
|
if (improvement.uniqueTo == civInfo.civName)
|
||||||
|
uniqueImprovements.add(improvement)
|
||||||
|
|
||||||
for (unit in ruleset.units.values) {
|
for (unit in ruleset.units.values) {
|
||||||
if (unit.uniqueTo == civInfo.civName) {
|
if (unit.uniqueTo == civInfo.civName) {
|
||||||
uniqueUnits.add(unit)
|
uniqueUnits.add(unit)
|
||||||
|
@ -20,6 +20,7 @@ enum class ImprovementBuildingProblem(
|
|||||||
/** `true` if the ImprovementPicker should report this problem */
|
/** `true` if the ImprovementPicker should report this problem */
|
||||||
val reportable: Boolean = false
|
val reportable: Boolean = false
|
||||||
) {
|
) {
|
||||||
|
Replaced(permanent = true),
|
||||||
WrongCiv(permanent = true),
|
WrongCiv(permanent = true),
|
||||||
MissingTech(reportable = true),
|
MissingTech(reportable = true),
|
||||||
Unbuildable(permanent = true),
|
Unbuildable(permanent = true),
|
||||||
@ -45,6 +46,8 @@ class TileInfoImprovementFunctions(val tile: Tile) {
|
|||||||
|
|
||||||
if (improvement.uniqueTo != null && improvement.uniqueTo != civInfo.civName)
|
if (improvement.uniqueTo != null && improvement.uniqueTo != civInfo.civName)
|
||||||
yield(ImprovementBuildingProblem.WrongCiv)
|
yield(ImprovementBuildingProblem.WrongCiv)
|
||||||
|
if (civInfo.cache.uniqueImprovements.any { it.replaces == improvement.name })
|
||||||
|
yield(ImprovementBuildingProblem.Replaced)
|
||||||
if (improvement.techRequired != null && !civInfo.tech.isResearched(improvement.techRequired!!))
|
if (improvement.techRequired != null && !civInfo.tech.isResearched(improvement.techRequired!!))
|
||||||
yield(ImprovementBuildingProblem.MissingTech)
|
yield(ImprovementBuildingProblem.MissingTech)
|
||||||
if (improvement.getMatchingUniques(UniqueType.Unbuildable, StateForConditionals.IgnoreConditionals)
|
if (improvement.getMatchingUniques(UniqueType.Unbuildable, StateForConditionals.IgnoreConditionals)
|
||||||
|
@ -551,6 +551,10 @@ class Building : RulesetStatsObject(), INonPerpetualConstruction {
|
|||||||
}
|
}
|
||||||
return _getImprovementToCreate
|
return _getImprovementToCreate
|
||||||
}
|
}
|
||||||
|
fun getImprovementToCreate(ruleset: Ruleset, civInfo: Civilization): TileImprovement? {
|
||||||
|
val improvement = getImprovementToCreate(ruleset) ?: return null
|
||||||
|
return civInfo.getEquivalentTileImprovement(improvement)
|
||||||
|
}
|
||||||
|
|
||||||
fun isSellable() = !isAnyWonder() && !hasUnique(UniqueType.Unsellable)
|
fun isSellable() = !isAnyWonder() && !hasUnique(UniqueType.Unsellable)
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ import com.unciv.models.translations.tr
|
|||||||
import com.unciv.ui.components.extensions.colorFromRGB
|
import com.unciv.ui.components.extensions.colorFromRGB
|
||||||
import com.unciv.ui.objectdescriptions.BaseUnitDescriptions
|
import com.unciv.ui.objectdescriptions.BaseUnitDescriptions
|
||||||
import com.unciv.ui.objectdescriptions.BuildingDescriptions
|
import com.unciv.ui.objectdescriptions.BuildingDescriptions
|
||||||
|
import com.unciv.ui.objectdescriptions.ImprovementDescriptions
|
||||||
import com.unciv.ui.objectdescriptions.uniquesToCivilopediaTextLines
|
import com.unciv.ui.objectdescriptions.uniquesToCivilopediaTextLines
|
||||||
import com.unciv.ui.screens.civilopediascreen.CivilopediaScreen.Companion.showReligionInCivilopedia
|
import com.unciv.ui.screens.civilopediascreen.CivilopediaScreen.Companion.showReligionInCivilopedia
|
||||||
import com.unciv.ui.screens.civilopediascreen.FormattedLine
|
import com.unciv.ui.screens.civilopediascreen.FormattedLine
|
||||||
@ -246,17 +247,15 @@ class Nation : RulesetObject() {
|
|||||||
yield(FormattedLine(separator = true))
|
yield(FormattedLine(separator = true))
|
||||||
yield(FormattedLine(improvement.name, link = "Improvement/${improvement.name}"))
|
yield(FormattedLine(improvement.name, link = "Improvement/${improvement.name}"))
|
||||||
yield(FormattedLine(improvement.cloneStats().toString(), indent = 1)) // = (improvement as Stats).toString minus import plus copy overhead
|
yield(FormattedLine(improvement.cloneStats().toString(), indent = 1)) // = (improvement as Stats).toString minus import plus copy overhead
|
||||||
if (improvement.terrainsCanBeBuiltOn.isNotEmpty()) {
|
if (improvement.replaces != null && ruleset.tileImprovements.containsKey(improvement.replaces!!)) {
|
||||||
improvement.terrainsCanBeBuiltOn.withIndex().forEach {
|
val originalImprovement = ruleset.tileImprovements[improvement.replaces!!]!!
|
||||||
yield(
|
yield(FormattedLine("Replaces [${originalImprovement.name}]", link = originalImprovement.makeLink(), indent=1))
|
||||||
FormattedLine(if (it.index == 0) "{Can be built on} {${it.value}}" else "or [${it.value}]",
|
yieldAll(ImprovementDescriptions.getDifferences(ruleset, originalImprovement, improvement))
|
||||||
link = "Terrain/${it.value}", indent = if (it.index == 0) 1 else 2)
|
yield(FormattedLine())
|
||||||
)
|
} else if (improvement.replaces != null) {
|
||||||
}
|
yield(FormattedLine("Replaces [${improvement.replaces}], which is not found in the ruleset!", indent=1))
|
||||||
}
|
} else {
|
||||||
for (unique in improvement.uniqueObjects) {
|
yieldAll(improvement.getShortDecription())
|
||||||
if (unique.isHiddenToUsers()) continue
|
|
||||||
yield(FormattedLine(unique, indent = 1))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,28 +1,24 @@
|
|||||||
package com.unciv.models.ruleset.tile
|
package com.unciv.models.ruleset.tile
|
||||||
|
|
||||||
import com.unciv.Constants
|
import com.unciv.Constants
|
||||||
import com.unciv.UncivGame
|
|
||||||
import com.unciv.logic.MultiFilter
|
import com.unciv.logic.MultiFilter
|
||||||
import com.unciv.logic.civilization.Civilization
|
import com.unciv.logic.civilization.Civilization
|
||||||
import com.unciv.logic.map.mapunit.MapUnit
|
import com.unciv.logic.map.mapunit.MapUnit
|
||||||
import com.unciv.logic.map.tile.RoadStatus
|
import com.unciv.logic.map.tile.RoadStatus
|
||||||
import com.unciv.models.ruleset.Belief
|
|
||||||
import com.unciv.models.ruleset.Ruleset
|
import com.unciv.models.ruleset.Ruleset
|
||||||
import com.unciv.models.ruleset.RulesetStatsObject
|
import com.unciv.models.ruleset.RulesetStatsObject
|
||||||
import com.unciv.models.ruleset.unique.StateForConditionals
|
import com.unciv.models.ruleset.unique.StateForConditionals
|
||||||
import com.unciv.models.ruleset.unique.UniqueTarget
|
import com.unciv.models.ruleset.unique.UniqueTarget
|
||||||
import com.unciv.models.ruleset.unique.UniqueType
|
import com.unciv.models.ruleset.unique.UniqueType
|
||||||
import com.unciv.models.ruleset.unit.BaseUnit
|
import com.unciv.models.ruleset.unit.BaseUnit
|
||||||
import com.unciv.models.translations.tr
|
|
||||||
import com.unciv.ui.components.extensions.toPercent
|
import com.unciv.ui.components.extensions.toPercent
|
||||||
import com.unciv.ui.objectdescriptions.uniquesToCivilopediaTextLines
|
import com.unciv.ui.objectdescriptions.ImprovementDescriptions
|
||||||
import com.unciv.ui.objectdescriptions.uniquesToDescription
|
|
||||||
import com.unciv.ui.screens.civilopediascreen.CivilopediaScreen.Companion.showReligionInCivilopedia
|
|
||||||
import com.unciv.ui.screens.civilopediascreen.FormattedLine
|
import com.unciv.ui.screens.civilopediascreen.FormattedLine
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
class TileImprovement : RulesetStatsObject() {
|
class TileImprovement : RulesetStatsObject() {
|
||||||
|
|
||||||
|
var replaces: String? = null
|
||||||
var terrainsCanBeBuiltOn: Collection<String> = ArrayList()
|
var terrainsCanBeBuiltOn: Collection<String> = ArrayList()
|
||||||
var techRequired: String? = null
|
var techRequired: String? = null
|
||||||
var uniqueTo: String? = null
|
var uniqueTo: String? = null
|
||||||
@ -44,29 +40,8 @@ class TileImprovement : RulesetStatsObject() {
|
|||||||
// In some weird cases it was possible for something to take 0 turns, leading to it instead never finishing
|
// In some weird cases it was possible for something to take 0 turns, leading to it instead never finishing
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getDescription(ruleset: Ruleset): String {
|
fun getDescription(ruleset: Ruleset): String = ImprovementDescriptions.getDescription(this, ruleset)
|
||||||
val lines = ArrayList<String>()
|
fun getShortDecription() = ImprovementDescriptions.getShortDescription(this)
|
||||||
|
|
||||||
val statsDesc = cloneStats().toString()
|
|
||||||
if (statsDesc.isNotEmpty()) lines += statsDesc
|
|
||||||
if (!terrainsCanBeBuiltOn.isEmpty()) {
|
|
||||||
val terrainsCanBeBuiltOnString: ArrayList<String> = arrayListOf()
|
|
||||||
for (i in terrainsCanBeBuiltOn) {
|
|
||||||
terrainsCanBeBuiltOnString.add(i.tr())
|
|
||||||
}
|
|
||||||
lines += "Can be built on".tr() + terrainsCanBeBuiltOnString.joinToString(", ", " ") //language can be changed when setting changes.
|
|
||||||
}
|
|
||||||
for (resource: TileResource in ruleset.tileResources.values.filter { it.isImprovedBy(name) }) {
|
|
||||||
if (resource.improvementStats == null) continue
|
|
||||||
val statsString = resource.improvementStats.toString()
|
|
||||||
lines += "[${statsString}] <in [${resource.name}] tiles>".tr()
|
|
||||||
}
|
|
||||||
if (techRequired != null) lines += "Required tech: [$techRequired]".tr()
|
|
||||||
|
|
||||||
uniquesToDescription(lines)
|
|
||||||
|
|
||||||
return lines.joinToString("\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isGreatImprovement() = hasUnique(UniqueType.GreatImprovement)
|
fun isGreatImprovement() = hasUnique(UniqueType.GreatImprovement)
|
||||||
fun isRoad() = RoadStatus.values().any { it != RoadStatus.None && it.name == this.name }
|
fun isRoad() = RoadStatus.values().any { it != RoadStatus.None && it.name == this.name }
|
||||||
@ -100,6 +75,7 @@ class TileImprovement : RulesetStatsObject() {
|
|||||||
private fun matchesSingleFilter(filter: String): Boolean {
|
private fun matchesSingleFilter(filter: String): Boolean {
|
||||||
return when (filter) {
|
return when (filter) {
|
||||||
name -> true
|
name -> true
|
||||||
|
replaces -> true
|
||||||
in Constants.all -> true
|
in Constants.all -> true
|
||||||
"Improvement" -> true // For situations involving tileFilter
|
"Improvement" -> true // For situations involving tileFilter
|
||||||
"All Road" -> isRoad()
|
"All Road" -> isRoad()
|
||||||
@ -111,95 +87,10 @@ class TileImprovement : RulesetStatsObject() {
|
|||||||
|
|
||||||
override fun makeLink() = "Improvement/$name"
|
override fun makeLink() = "Improvement/$name"
|
||||||
|
|
||||||
override fun getCivilopediaTextLines(ruleset: Ruleset): List<FormattedLine> {
|
override fun getCivilopediaTextLines(ruleset: Ruleset): List<FormattedLine> =
|
||||||
val textList = ArrayList<FormattedLine>()
|
ImprovementDescriptions.getCivilopediaTextLines(this, ruleset)
|
||||||
|
|
||||||
val statsDesc = cloneStats().toString()
|
fun getConstructorUnits(ruleset: Ruleset): List<BaseUnit> {
|
||||||
if (statsDesc.isNotEmpty()) textList += FormattedLine(statsDesc)
|
|
||||||
|
|
||||||
if (uniqueTo != null) {
|
|
||||||
textList += FormattedLine()
|
|
||||||
textList += FormattedLine("Unique to [$uniqueTo]", link="Nation/$uniqueTo")
|
|
||||||
}
|
|
||||||
|
|
||||||
val constructorUnits = getConstructorUnits(ruleset)
|
|
||||||
val creatingUnits = getCreatingUnits(ruleset)
|
|
||||||
val creatorExists = constructorUnits.isNotEmpty() || creatingUnits.isNotEmpty()
|
|
||||||
|
|
||||||
if (creatorExists && terrainsCanBeBuiltOn.isNotEmpty()) {
|
|
||||||
textList += FormattedLine()
|
|
||||||
if (terrainsCanBeBuiltOn.size == 1) {
|
|
||||||
with (terrainsCanBeBuiltOn.first()) {
|
|
||||||
textList += FormattedLine("{Can be built on} {$this}", link="Terrain/$this")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
textList += FormattedLine("{Can be built on}:")
|
|
||||||
terrainsCanBeBuiltOn.forEach {
|
|
||||||
textList += FormattedLine(it, link="Terrain/$it", indent=1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var addedLineBeforeResourceBonus = false
|
|
||||||
for (resource in ruleset.tileResources.values) {
|
|
||||||
if (resource.improvementStats == null || !resource.isImprovedBy(name)) continue
|
|
||||||
if (!addedLineBeforeResourceBonus) {
|
|
||||||
addedLineBeforeResourceBonus = true
|
|
||||||
textList += FormattedLine()
|
|
||||||
}
|
|
||||||
val statsString = resource.improvementStats.toString()
|
|
||||||
// Line intentionally modeled as UniqueType.Stats + ConditionalInTiles
|
|
||||||
textList += FormattedLine("[${statsString}] <in [${resource.name}] tiles>", link = resource.makeLink())
|
|
||||||
}
|
|
||||||
|
|
||||||
if (techRequired != null) {
|
|
||||||
textList += FormattedLine()
|
|
||||||
textList += FormattedLine("Required tech: [$techRequired]", link="Technology/$techRequired")
|
|
||||||
}
|
|
||||||
|
|
||||||
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?
|
|
||||||
if (creatorExists &&
|
|
||||||
!isEmpty() && // Has any Stats
|
|
||||||
!hasUnique(UniqueType.NoFeatureRemovalNeeded) &&
|
|
||||||
!hasUnique(UniqueType.RemovesFeaturesIfBuilt) &&
|
|
||||||
terrainsCanBeBuiltOn.none { it in ruleset.terrains }
|
|
||||||
)
|
|
||||||
textList += FormattedLine("Needs removal of terrain features to be built")
|
|
||||||
|
|
||||||
if (isAncientRuinsEquivalent() && ruleset.ruinRewards.isNotEmpty()) {
|
|
||||||
val difficulty = if (!UncivGame.isCurrentInitialized() || UncivGame.Current.gameInfo == null)
|
|
||||||
"Prince" // most factors == 1
|
|
||||||
else UncivGame.Current.gameInfo!!.gameParameters.difficulty
|
|
||||||
val religionEnabled = showReligionInCivilopedia(ruleset)
|
|
||||||
textList += FormattedLine()
|
|
||||||
textList += FormattedLine("The possible rewards are:")
|
|
||||||
ruleset.ruinRewards.values.asSequence()
|
|
||||||
.filter { reward ->
|
|
||||||
difficulty !in reward.excludedDifficulties &&
|
|
||||||
(religionEnabled || !reward.hasUnique(UniqueType.HiddenWithoutReligion))
|
|
||||||
}
|
|
||||||
.forEach { reward ->
|
|
||||||
textList += FormattedLine(reward.name, starred = true, color = reward.color)
|
|
||||||
textList += reward.civilopediaText
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (creatorExists)
|
|
||||||
textList += FormattedLine()
|
|
||||||
for (unit in constructorUnits)
|
|
||||||
textList += FormattedLine("{Can be constructed by} {$unit}", unit.makeLink())
|
|
||||||
for (unit in creatingUnits)
|
|
||||||
textList += FormattedLine("{Can be created instantly by} {$unit}", unit.makeLink())
|
|
||||||
|
|
||||||
textList += Belief.getCivilopediaTextMatching(name, ruleset)
|
|
||||||
|
|
||||||
return textList
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getConstructorUnits(ruleset: Ruleset): List<BaseUnit> {
|
|
||||||
//todo Why does this have to be so complicated? A unit's "Can build [Land] improvements on tiles"
|
//todo Why does this have to be so complicated? A unit's "Can build [Land] improvements on tiles"
|
||||||
// creates the _justified_ expectation that an improvement it can build _will_ have
|
// creates the _justified_ expectation that an improvement it can build _will_ have
|
||||||
// `matchesFilter("Land")==true` - but that's not the case.
|
// `matchesFilter("Land")==true` - but that's not the case.
|
||||||
@ -251,7 +142,7 @@ class TileImprovement : RulesetStatsObject() {
|
|||||||
}.toList()
|
}.toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getCreatingUnits(ruleset: Ruleset): List<BaseUnit> {
|
fun getCreatingUnits(ruleset: Ruleset): List<BaseUnit> {
|
||||||
return ruleset.units.values.asSequence()
|
return ruleset.units.values.asSequence()
|
||||||
.filter { unit ->
|
.filter { unit ->
|
||||||
unit.getMatchingUniques(UniqueType.ConstructImprovementInstantly, StateForConditionals.IgnoreConditionals)
|
unit.getMatchingUniques(UniqueType.ConstructImprovementInstantly, StateForConditionals.IgnoreConditionals)
|
||||||
|
@ -401,13 +401,15 @@ class RulesetValidator(val ruleset: Ruleset) {
|
|||||||
for (improvement in ruleset.tileImprovements.values) {
|
for (improvement in ruleset.tileImprovements.values) {
|
||||||
if (improvement.techRequired != null && !ruleset.technologies.containsKey(improvement.techRequired!!))
|
if (improvement.techRequired != null && !ruleset.technologies.containsKey(improvement.techRequired!!))
|
||||||
lines.add("${improvement.name} requires tech ${improvement.techRequired} which does not exist!", sourceObject = improvement)
|
lines.add("${improvement.name} requires tech ${improvement.techRequired} which does not exist!", sourceObject = improvement)
|
||||||
|
if (improvement.replaces != null && !ruleset.tileImprovements.containsKey(improvement.replaces))
|
||||||
|
lines.add("${improvement.name} replaces ${improvement.replaces} which does not exist!", sourceObject = improvement)
|
||||||
for (terrain in improvement.terrainsCanBeBuiltOn)
|
for (terrain in improvement.terrainsCanBeBuiltOn)
|
||||||
if (!ruleset.terrains.containsKey(terrain) && terrain != "Land" && terrain != "Water")
|
if (!ruleset.terrains.containsKey(terrain) && terrain != "Land" && terrain != "Water")
|
||||||
lines.add("${improvement.name} can be built on terrain $terrain which does not exist!", sourceObject = improvement)
|
lines.add("${improvement.name} can be built on terrain $terrain which does not exist!", sourceObject = improvement)
|
||||||
if (improvement.terrainsCanBeBuiltOn.isEmpty()
|
if (improvement.terrainsCanBeBuiltOn.isEmpty()
|
||||||
&& !improvement.hasUnique(UniqueType.CanOnlyImproveResource)
|
&& !improvement.hasUnique(UniqueType.CanOnlyImproveResource)
|
||||||
&& !improvement.hasUnique(UniqueType.Unbuildable)
|
&& !improvement.hasUnique(UniqueType.Unbuildable)
|
||||||
&& !improvement.name.startsWith(Constants.remove)
|
&& improvement !in ruleset.tileRemovals
|
||||||
&& improvement.name !in RoadStatus.values().map { it.removeAction }
|
&& improvement.name !in RoadStatus.values().map { it.removeAction }
|
||||||
&& improvement.name != Constants.cancelImprovementOrder
|
&& improvement.name != Constants.cancelImprovementOrder
|
||||||
) {
|
) {
|
||||||
|
@ -0,0 +1,197 @@
|
|||||||
|
package com.unciv.ui.objectdescriptions
|
||||||
|
|
||||||
|
import com.unciv.UncivGame
|
||||||
|
import com.unciv.models.ruleset.Belief
|
||||||
|
import com.unciv.models.ruleset.Ruleset
|
||||||
|
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.UniqueType
|
||||||
|
import com.unciv.models.translations.tr
|
||||||
|
import com.unciv.ui.screens.civilopediascreen.CivilopediaScreen
|
||||||
|
import com.unciv.ui.screens.civilopediascreen.FormattedLine
|
||||||
|
|
||||||
|
object ImprovementDescriptions {
|
||||||
|
/**
|
||||||
|
* Lists differences: how a nation-unique Improvement compares to its replacement.
|
||||||
|
*
|
||||||
|
* Result as indented, non-linking [FormattedLine]s
|
||||||
|
*
|
||||||
|
* @param originalImprovement The "standard" Improvement
|
||||||
|
* @param replacementImprovement The "uniqueTo" Improvement
|
||||||
|
*/
|
||||||
|
fun getDifferences(
|
||||||
|
ruleset: Ruleset, originalImprovement: TileImprovement, replacementImprovement: TileImprovement
|
||||||
|
): Sequence<FormattedLine> = sequence {
|
||||||
|
for ((key, value) in replacementImprovement)
|
||||||
|
if (value != originalImprovement[key])
|
||||||
|
yield(FormattedLine( key.name.tr() + " " +"[${value.toInt()}] vs [${originalImprovement[key].toInt()}]".tr(), indent=1))
|
||||||
|
|
||||||
|
for (terrain in replacementImprovement.terrainsCanBeBuiltOn)
|
||||||
|
if (terrain !in originalImprovement.terrainsCanBeBuiltOn)
|
||||||
|
yield(FormattedLine("Can be built on [${terrain}]", link = ruleset.terrains[terrain]?.makeLink() ?: "", indent = 1))
|
||||||
|
for (terrain in originalImprovement.terrainsCanBeBuiltOn)
|
||||||
|
if (terrain !in replacementImprovement.terrainsCanBeBuiltOn)
|
||||||
|
yield(FormattedLine("Cannot be built on [${terrain}]", link = ruleset.terrains[terrain]?.makeLink() ?: "", indent = 1))
|
||||||
|
|
||||||
|
if (replacementImprovement.turnsToBuild != originalImprovement.turnsToBuild)
|
||||||
|
yield(FormattedLine("{Turns to build} ".tr() + "[${replacementImprovement.turnsToBuild}] vs [${originalImprovement.turnsToBuild}]".tr(), indent=1))
|
||||||
|
|
||||||
|
val newAbilityPredicate: (Unique)->Boolean = { it.text in originalImprovement.uniques || it.isHiddenToUsers() }
|
||||||
|
for (unique in replacementImprovement.uniqueObjects.filterNot(newAbilityPredicate))
|
||||||
|
yield(FormattedLine(unique.text, indent=1)) // FormattedLine(unique) would look worse - no indent and autolinking could distract
|
||||||
|
|
||||||
|
val lostAbilityPredicate: (Unique)->Boolean = { it.text in replacementImprovement.uniques || it.isHiddenToUsers() }
|
||||||
|
for (unique in originalImprovement.uniqueObjects.filterNot(lostAbilityPredicate)) {
|
||||||
|
// Need double translation of the "ability" here - unique texts may contain square brackets
|
||||||
|
yield(FormattedLine("Lost ability (vs [${originalImprovement.name}]): [${unique.text.tr()}]", indent=1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getCivilopediaTextLines(improvement: TileImprovement, ruleset: Ruleset): List<FormattedLine> {
|
||||||
|
val textList = ArrayList<FormattedLine>()
|
||||||
|
|
||||||
|
val statsDesc = improvement.cloneStats().toString()
|
||||||
|
if (statsDesc.isNotEmpty()) textList += FormattedLine(statsDesc)
|
||||||
|
|
||||||
|
if (improvement.uniqueTo != null) {
|
||||||
|
textList += FormattedLine()
|
||||||
|
textList += FormattedLine("Unique to [${improvement.uniqueTo}]", link="Nation/${improvement.uniqueTo}")
|
||||||
|
}
|
||||||
|
if (improvement.replaces != null) {
|
||||||
|
val replaceImprovement = ruleset.tileImprovements[improvement.replaces]
|
||||||
|
textList += FormattedLine("Replaces [${improvement.replaces}]", link=replaceImprovement?.makeLink() ?: "", indent = 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
val constructorUnits = improvement.getConstructorUnits(ruleset)
|
||||||
|
val creatingUnits = improvement.getCreatingUnits(ruleset)
|
||||||
|
val creatorExists = constructorUnits.isNotEmpty() || creatingUnits.isNotEmpty()
|
||||||
|
|
||||||
|
if (creatorExists && improvement.terrainsCanBeBuiltOn.isNotEmpty()) {
|
||||||
|
textList += FormattedLine()
|
||||||
|
if (improvement.terrainsCanBeBuiltOn.size == 1) {
|
||||||
|
with (improvement.terrainsCanBeBuiltOn.first()) {
|
||||||
|
textList += FormattedLine("{Can be built on} {$this}", link="Terrain/$this")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
textList += FormattedLine("{Can be built on}:")
|
||||||
|
improvement.terrainsCanBeBuiltOn.forEach {
|
||||||
|
textList += FormattedLine(it, link="Terrain/$it", indent=1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var addedLineBeforeResourceBonus = false
|
||||||
|
for (resource in ruleset.tileResources.values) {
|
||||||
|
if (resource.improvementStats == null || !resource.isImprovedBy(improvement.name)) continue
|
||||||
|
if (!addedLineBeforeResourceBonus) {
|
||||||
|
addedLineBeforeResourceBonus = true
|
||||||
|
textList += FormattedLine()
|
||||||
|
}
|
||||||
|
val statsString = resource.improvementStats.toString()
|
||||||
|
// Line intentionally modeled as UniqueType.Stats + ConditionalInTiles
|
||||||
|
textList += FormattedLine("[${statsString}] <in [${resource.name}] tiles>", link = resource.makeLink())
|
||||||
|
}
|
||||||
|
|
||||||
|
if (improvement.techRequired != null) {
|
||||||
|
textList += FormattedLine()
|
||||||
|
textList += FormattedLine("Required tech: [${improvement.techRequired}]", link="Technology/${improvement.techRequired}")
|
||||||
|
}
|
||||||
|
|
||||||
|
improvement.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?
|
||||||
|
if (creatorExists &&
|
||||||
|
!improvement.isEmpty() && // Has any Stats
|
||||||
|
!improvement.hasUnique(UniqueType.NoFeatureRemovalNeeded) &&
|
||||||
|
!improvement.hasUnique(UniqueType.RemovesFeaturesIfBuilt) &&
|
||||||
|
improvement.terrainsCanBeBuiltOn.none { it in ruleset.terrains }
|
||||||
|
)
|
||||||
|
textList += FormattedLine("Needs removal of terrain features to be built")
|
||||||
|
|
||||||
|
if (improvement.isAncientRuinsEquivalent() && ruleset.ruinRewards.isNotEmpty()) {
|
||||||
|
val difficulty = if (!UncivGame.isCurrentInitialized() || UncivGame.Current.gameInfo == null)
|
||||||
|
"Prince" // most factors == 1
|
||||||
|
else UncivGame.Current.gameInfo!!.gameParameters.difficulty
|
||||||
|
val religionEnabled = CivilopediaScreen.showReligionInCivilopedia(ruleset)
|
||||||
|
textList += FormattedLine()
|
||||||
|
textList += FormattedLine("The possible rewards are:")
|
||||||
|
ruleset.ruinRewards.values.asSequence()
|
||||||
|
.filter { reward ->
|
||||||
|
difficulty !in reward.excludedDifficulties &&
|
||||||
|
(religionEnabled || !reward.hasUnique(UniqueType.HiddenWithoutReligion))
|
||||||
|
}
|
||||||
|
.forEach { reward ->
|
||||||
|
textList += FormattedLine(reward.name, starred = true, color = reward.color)
|
||||||
|
textList += reward.civilopediaText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (creatorExists)
|
||||||
|
textList += FormattedLine()
|
||||||
|
for (unit in constructorUnits)
|
||||||
|
textList += FormattedLine("{Can be constructed by} {$unit}", unit.makeLink())
|
||||||
|
for (unit in creatingUnits)
|
||||||
|
textList += FormattedLine("{Can be created instantly by} {$unit}", unit.makeLink())
|
||||||
|
|
||||||
|
val seeAlso = ArrayList<FormattedLine>()
|
||||||
|
for (alsoImprovement in ruleset.tileImprovements.values) {
|
||||||
|
if (alsoImprovement.replaces == improvement.name)
|
||||||
|
seeAlso += FormattedLine(alsoImprovement.name, link = alsoImprovement.makeLink(), indent = 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
seeAlso += Belief.getCivilopediaTextMatching(improvement.name, ruleset, false)
|
||||||
|
|
||||||
|
if (seeAlso.isNotEmpty()) {
|
||||||
|
textList += FormattedLine()
|
||||||
|
textList += FormattedLine("{See also}:")
|
||||||
|
textList += seeAlso
|
||||||
|
}
|
||||||
|
|
||||||
|
return textList
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getDescription(improvement: TileImprovement, ruleset: Ruleset): String {
|
||||||
|
val lines = ArrayList<String>()
|
||||||
|
|
||||||
|
val statsDesc = improvement.cloneStats().toString()
|
||||||
|
if (statsDesc.isNotEmpty()) lines += statsDesc
|
||||||
|
if (improvement.uniqueTo != null) lines += "Unique to [${improvement.uniqueTo}]".tr()
|
||||||
|
if (improvement.replaces != null) lines += "Replaces [${improvement.replaces}]".tr()
|
||||||
|
if (!improvement.terrainsCanBeBuiltOn.isEmpty()) {
|
||||||
|
val terrainsCanBeBuiltOnString: ArrayList<String> = arrayListOf()
|
||||||
|
for (i in improvement.terrainsCanBeBuiltOn) {
|
||||||
|
terrainsCanBeBuiltOnString.add(i.tr())
|
||||||
|
}
|
||||||
|
lines += "Can be built on".tr() + terrainsCanBeBuiltOnString.joinToString(", ", " ") //language can be changed when setting changes.
|
||||||
|
}
|
||||||
|
for (resource: TileResource in ruleset.tileResources.values.filter { it.isImprovedBy(improvement.name) }) {
|
||||||
|
if (resource.improvementStats == null) continue
|
||||||
|
val statsString = resource.improvementStats.toString()
|
||||||
|
lines += "[${statsString}] <in [${resource.name}] tiles>".tr()
|
||||||
|
}
|
||||||
|
if (improvement.techRequired != null) lines += "Required tech: [${improvement.techRequired}]".tr()
|
||||||
|
|
||||||
|
improvement.uniquesToDescription(lines)
|
||||||
|
|
||||||
|
return lines.joinToString("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getShortDescription(improvement: TileImprovement) = sequence {
|
||||||
|
if (improvement.terrainsCanBeBuiltOn.isNotEmpty()) {
|
||||||
|
improvement.terrainsCanBeBuiltOn.withIndex().forEach {
|
||||||
|
yield(
|
||||||
|
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
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (unique in improvement.uniqueObjects) {
|
||||||
|
if (unique.isHiddenToUsers()) continue
|
||||||
|
yield(FormattedLine(unique, indent = 1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -660,7 +660,8 @@ class CityConstructionsTable(private val cityScreen: CityScreen) {
|
|||||||
return cityScreen.startPickTileForCreatesOneImprovement(construction, stat, true)
|
return cityScreen.startPickTileForCreatesOneImprovement(construction, stat, true)
|
||||||
// Buying a UniqueType.CreatesOneImprovement building from queue must pass down
|
// Buying a UniqueType.CreatesOneImprovement building from queue must pass down
|
||||||
// the already selected tile, otherwise a new one is chosen from Automation code.
|
// the already selected tile, otherwise a new one is chosen from Automation code.
|
||||||
val improvement = construction.getImprovementToCreate(cityScreen.city.getRuleset())!!
|
val improvement = construction.getImprovementToCreate(
|
||||||
|
cityScreen.city.getRuleset(), cityScreen.city.civ)!!
|
||||||
val tileForImprovement = cityScreen.city.cityConstructions.getTileForImprovement(improvement.name)
|
val tileForImprovement = cityScreen.city.cityConstructions.getTileForImprovement(improvement.name)
|
||||||
askToBuyConstruction(construction, stat, tileForImprovement)
|
askToBuyConstruction(construction, stat, tileForImprovement)
|
||||||
}
|
}
|
||||||
|
@ -454,7 +454,7 @@ class CityScreen(
|
|||||||
fun selectConstruction(newConstruction: IConstruction) {
|
fun selectConstruction(newConstruction: IConstruction) {
|
||||||
selectedConstruction = newConstruction
|
selectedConstruction = newConstruction
|
||||||
if (newConstruction is Building && newConstruction.hasCreateOneImprovementUnique()) {
|
if (newConstruction is Building && newConstruction.hasCreateOneImprovementUnique()) {
|
||||||
val improvement = newConstruction.getImprovementToCreate(city.getRuleset())
|
val improvement = newConstruction.getImprovementToCreate(city.getRuleset(), city.civ)
|
||||||
selectedQueueEntryTargetTile = if (improvement == null) null
|
selectedQueueEntryTargetTile = if (improvement == null) null
|
||||||
else city.cityConstructions.getTileForImprovement(improvement.name)
|
else city.cityConstructions.getTileForImprovement(improvement.name)
|
||||||
} else {
|
} else {
|
||||||
@ -472,7 +472,7 @@ class CityScreen(
|
|||||||
fun clearSelection() = selectTile(null)
|
fun clearSelection() = selectTile(null)
|
||||||
|
|
||||||
fun startPickTileForCreatesOneImprovement(construction: Building, stat: Stat, isBuying: Boolean) {
|
fun startPickTileForCreatesOneImprovement(construction: Building, stat: Stat, isBuying: Boolean) {
|
||||||
val improvement = construction.getImprovementToCreate(city.getRuleset()) ?: return
|
val improvement = construction.getImprovementToCreate(city.getRuleset(), city.civ) ?: return
|
||||||
pickTileData = PickTileForImprovementData(construction, improvement, isBuying, stat)
|
pickTileData = PickTileForImprovementData(construction, improvement, isBuying, stat)
|
||||||
updateTileGroups()
|
updateTileGroups()
|
||||||
ToastPopup("Please select a tile for this building's [${improvement.name}]", this)
|
ToastPopup("Please select a tile for this building's [${improvement.name}]", this)
|
||||||
|
@ -45,6 +45,7 @@ Each improvement has the following structure:
|
|||||||
| name | String | Required | [^A] |
|
| name | String | Required | [^A] |
|
||||||
| terrainsCanBeBuiltOn | List of Strings | empty | Terrains that this improvement can be built on [^B]. Removable terrain features will need to be removed before building an improvement [^C]. Must be in [Terrains.json](#terrainsjson) |
|
| terrainsCanBeBuiltOn | List of Strings | empty | Terrains that this improvement can be built on [^B]. Removable terrain features will need to be removed before building an improvement [^C]. Must be in [Terrains.json](#terrainsjson) |
|
||||||
| techRequired | String | none | The name of the technology required to build this improvement |
|
| techRequired | String | none | The name of the technology required to build this improvement |
|
||||||
|
| replaces | String | none | The name of a improvement that should be replaced by this improvement. Must be in [TileImprovements.json](#TileImprovementsjson) |
|
||||||
| uniqueTo | String | none | The name of the nation this improvement is unique for |
|
| uniqueTo | String | none | The name of the nation this improvement is unique for |
|
||||||
| [`<stats>`](#stats) | Integer | 0 | Per-turn bonus yield for the tile |
|
| [`<stats>`](#stats) | Integer | 0 | Per-turn bonus yield for the tile |
|
||||||
| turnsToBuild | Integer | -1 | Number of turns a worker spends building this. If -1, the improvement is unbuildable [^D]. If 0, the improvement is always built in one turn |
|
| turnsToBuild | Integer | -1 | Number of turns a worker spends building this. If -1, the improvement is unbuildable [^D]. If 0, the improvement is always built in one turn |
|
||||||
|
Loading…
x
Reference in New Issue
Block a user