Spruced up Civilopedia - phase 5 - buildings (#4391)

* Spruced up Civilopedia - phase 5 - buildings

* Finish merging master into Civilopedia-Buildings

* Spruced up Civilopedia - phase 5 - buildings - patch

* Spruced up Civilopedia - phase 5 - buildings - patch2

* Spruced up Civilopedia - phase 5 - buildings - patch3

* Spruced up Civilopedia - phase 5 - buildings - patch4

* Spruced up Civilopedia - phase 5 - buildings - patch5
This commit is contained in:
SomeTroglodyte
2021-07-19 20:48:51 +02:00
committed by GitHub
parent 118c1fc888
commit 50cec97354
9 changed files with 183 additions and 36 deletions

View File

@ -10,11 +10,13 @@ class GreatPersonManager {
var greatGeneralPoints = 0
var freeGreatPeople = 0
val statToGreatPersonMapping = HashMap<Stat, String>().apply {
put(Stat.Science, "Great Scientist")
put(Stat.Production, "Great Engineer")
put(Stat.Gold, "Great Merchant")
put(Stat.Culture, "Great Artist")
companion object {
val statToGreatPersonMapping = hashMapOf<Stat, String>(
Stat.Science to "Great Scientist",
Stat.Production to "Great Scientist",
Stat.Gold to "Great Scientist",
Stat.Culture to "Great Scientist",
)
}
fun clone(): GreatPersonManager {

View File

@ -4,6 +4,7 @@ import com.unciv.logic.city.CityConstructions
import com.unciv.logic.city.CityInfo
import com.unciv.logic.city.IConstruction
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.civilization.GreatPersonManager
import com.unciv.models.Counter
import com.unciv.models.ruleset.tile.TileImprovement
import com.unciv.models.stats.NamedStats
@ -11,13 +12,15 @@ import com.unciv.models.stats.Stat
import com.unciv.models.stats.Stats
import com.unciv.models.translations.fillPlaceholders
import com.unciv.models.translations.tr
import com.unciv.ui.civilopedia.FormattedLine
import com.unciv.ui.civilopedia.ICivilopediaText
import java.util.*
import kotlin.collections.ArrayList
import kotlin.collections.HashMap
import kotlin.math.pow
class Building : NamedStats(), IConstruction {
class Building : NamedStats(), IConstruction, ICivilopediaText {
var requiredTech: String? = null
@ -65,6 +68,8 @@ class Building : NamedStats(), IConstruction {
var replacementTextForUniques = ""
val uniqueObjects: List<Unique> by lazy { uniques.map { Unique(it) } }
override var civilopediaText = listOf<FormattedLine>()
fun getShortDescription(ruleset: Ruleset): String { // should fit in one line
val infoList = mutableListOf<String>()
val str = getStats(null).toString()
@ -98,19 +103,12 @@ class Building : NamedStats(), IConstruction {
return finalUniques
}
fun getDescription(forBuildingPickerScreen: Boolean, cityInfo: CityInfo?, ruleset: Ruleset): String {
fun getDescription(cityInfo: CityInfo?, ruleset: Ruleset): String {
val stats = getStats(cityInfo)
val stringBuilder = StringBuilder()
if (uniqueTo != null) stringBuilder.appendLine("Unique to [$uniqueTo], replaces [$replaces]".tr())
if (!forBuildingPickerScreen) stringBuilder.appendLine("{Cost}: $cost".tr())
if (isWonder) stringBuilder.appendLine("Wonder".tr())
if (isNationalWonder) stringBuilder.appendLine("National Wonder".tr())
if (!forBuildingPickerScreen && requiredTech != null)
stringBuilder.appendLine("Required tech: [$requiredTech]".tr())
if (!forBuildingPickerScreen && requiredBuilding != null)
stringBuilder.appendLine("Requires [$requiredBuilding] to be built in the city".tr())
if (!forBuildingPickerScreen && requiredBuildingInAllCities != null)
stringBuilder.appendLine("Requires [$requiredBuildingInAllCities] to be built in all cities".tr())
for ((resource, amount) in getResourceRequirements()) {
if (amount == 1) stringBuilder.appendLine("Consumes 1 [$resource]".tr()) // For now, to keep the existing translations
else stringBuilder.appendLine("Consumes [$amount] [$resource]".tr())
@ -197,6 +195,131 @@ class Building : NamedStats(), IConstruction {
return stats
}
fun makeLink() = if (isWonder || isNationalWonder) "Wonder/$name" else "Building/$name"
override fun getCivilopediaTextHeader() = FormattedLine(name, header=2, icon=makeLink())
override fun hasCivilopediaTextLines() = true
override fun replacesCivilopediaDescription() = true
override fun getCivilopediaTextLines(ruleset: Ruleset): List<FormattedLine> {
fun Float.formatSignedInt() = (if (this > 0f) "+" else "") + this.toInt().toString()
val textList = ArrayList<FormattedLine>()
if (isWonder || isNationalWonder) {
textList += FormattedLine( if (isWonder) "Wonder" else "National Wonder", color="#CA4", header=3 )
}
if (uniqueTo != null) {
textList += FormattedLine()
textList += FormattedLine("Unique to [$uniqueTo]", link="Nation/$uniqueTo")
if (replaces != null) {
val replacesBuilding = ruleset.buildings[replaces]
textList += FormattedLine("Replaces [$replaces]", link=replacesBuilding?.makeLink() ?: "", indent=1)
}
}
if (cost > 0) {
textList += FormattedLine()
textList += FormattedLine("{Cost}: $cost")
}
if (requiredTech != null || requiredBuilding != null || requiredBuildingInAllCities != null)
textList += FormattedLine()
if (requiredTech != null)
textList += FormattedLine("Required tech: [$requiredTech]",
link="Technology/$requiredTech")
if (requiredBuilding != null)
textList += FormattedLine("Requires [$requiredBuilding] to be built in the city",
link="Building/$requiredBuilding")
if (requiredBuildingInAllCities != null)
textList += FormattedLine("Requires [$requiredBuildingInAllCities] to be built in all cities",
link="Building/$requiredBuildingInAllCities")
val resourceRequirements = getResourceRequirements()
if (resourceRequirements.isNotEmpty()) {
textList += FormattedLine()
for ((resource, amount) in resourceRequirements) {
textList += FormattedLine(
// the 1 variant should deprecate some time
if (amount == 1) "Consumes 1 [$resource]" else "Consumes [$amount] [$resource]",
link="Resources/$resource", color="#F42" )
}
}
if (providesFreeBuilding != null) {
textList += FormattedLine()
textList += FormattedLine("Provides a free [$providesFreeBuilding] in the city",
link="Building/$providesFreeBuilding")
}
val stats = this.clone()
val percentStats = getStatPercentageBonuses(null)
val specialists = newSpecialists()
if (uniques.isNotEmpty() || !stats.isEmpty() || !percentStats.isEmpty() || this.greatPersonPoints != null || specialists.isNotEmpty())
textList += FormattedLine()
if (uniques.isNotEmpty()) {
if (replacementTextForUniques.isNotEmpty())
textList += FormattedLine(replacementTextForUniques)
else
for (unique in getUniquesStrings()) textList += FormattedLine(unique)
}
if (!stats.isEmpty()) {
textList += FormattedLine(stats.toString())
}
if (!percentStats.isEmpty()) {
for ( (key, value) in percentStats.toHashMap()) {
if (value == 0f) continue
textList += FormattedLine(value.formatSignedInt() + "% {$key}")
}
}
if (greatPersonPoints != null) {
for ( (key, value) in greatPersonPoints!!.toHashMap()) {
if (value == 0f) continue
val gppName = GreatPersonManager.statToGreatPersonMapping[key]
?: continue
textList += FormattedLine(value.formatSignedInt() + " " + "[$gppName] points".tr(),
link = "Unit/$gppName")
}
}
if (specialists.isNotEmpty()) {
for ((specialistName, amount) in specialists)
textList += FormattedLine("+$amount " + "[$specialistName] slots".tr())
}
if (requiredNearbyImprovedResources != null) {
textList += FormattedLine()
textList += FormattedLine("Requires at least one of the following resources worked near the city:")
requiredNearbyImprovedResources!!.forEach {
textList += FormattedLine(it, indent = 1, link = "Resource/$it")
}
}
if (cityStrength != 0 || cityHealth != 0 || xpForNewUnits != 0 || maintenance != 0) textList += FormattedLine()
if (cityStrength != 0) textList += FormattedLine("{City strength} +$cityStrength")
if (cityHealth != 0) textList += FormattedLine("{City health} +$cityHealth")
if (xpForNewUnits != 0) textList += FormattedLine("+$xpForNewUnits {XP for new units}")
if (maintenance != 0) textList += FormattedLine("{Maintenance cost}: $maintenance {Gold}")
val seeAlso = ArrayList<FormattedLine>()
for ((other, building) in ruleset.buildings) {
if (building.replaces == name || building.providesFreeBuilding == name || uniques.contains("[$name]") ) {
seeAlso += FormattedLine(other, link=building.makeLink(), indent=1)
}
}
if (seeAlso.isNotEmpty()) {
textList += FormattedLine()
textList += FormattedLine("{See also}:")
textList += seeAlso
}
return textList
}
override fun canBePurchased(): Boolean {
return !isWonder && !isNationalWonder && "Cannot be purchased" !in uniques
}
@ -399,7 +522,7 @@ class Building : NamedStats(), IConstruction {
if (!civInfo.gameInfo.gameParameters.victoryTypes.contains(VictoryType.Scientific)
&& "Enables construction of Spaceship parts" in uniques)
return "Can't construct spaceship parts if scientific victory is not enabled!"
return ""
}

View File

@ -1,7 +1,6 @@
package com.unciv.ui.cityscreen
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.Touchable
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.utils.Align
import com.unciv.UncivGame
@ -65,9 +64,7 @@ class CityInfoTable(private val cityScreen: CityScreen) : Table(CameraStageBaseS
private fun addBuildingInfo(building: Building, destinationTable: Table) {
val icon = ImageGetter.getConstructionImage(building.name).surroundWithCircle(30f)
val buildingNameAndIconTable = ExpanderTab(building.name, 18, icon, false, 5f) {
//todo: getDescription signature changes with civilopedia phase 5
val detailsString = building.getDescription(true,
cityScreen.city, cityScreen.city.civInfo.gameInfo.ruleSet)
val detailsString = building.getDescription(cityScreen.city, cityScreen.city.civInfo.gameInfo.ruleSet)
it.add(detailsString.toLabel().apply { wrap = true })
.width(cityScreen.stage.width / 4 - 2 * pad).row() // when you set wrap, then you need to manually set the size of the label
if (building.isSellable()) {
@ -211,7 +208,7 @@ class CityInfoTable(private val cityScreen: CityScreen) : Table(CameraStageBaseS
private fun Table.addGreatPersonPointInfo(cityInfo: CityInfo) {
val greatPersonPoints = cityInfo.getGreatPersonPointsForNextTurn()
val statToGreatPerson = GreatPersonManager().statToGreatPersonMapping
val statToGreatPerson = GreatPersonManager.statToGreatPersonMapping
for (stat in Stat.values()) {
if (!statToGreatPerson.containsKey(stat)) continue
if (greatPersonPoints.all { it.value.get(stat) == 0f }) continue

View File

@ -59,7 +59,7 @@ class ConstructionInfoTable(val city: CityInfo): Table() {
val description: String = when (construction) {
is BaseUnit -> construction.getDescription()
is Building -> construction.getDescription(true, city, city.civInfo.gameInfo.ruleSet)
is Building -> construction.getDescription(city, city.civInfo.gameInfo.ruleSet)
is PerpetualConstruction -> construction.description.replace("[rate]", "[${construction.getConversionRate(city)}]").tr()
else -> "" // Should never happen
}

View File

@ -7,6 +7,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.*
import com.unciv.Constants
import com.unciv.UncivGame
import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.VictoryType
import com.unciv.models.stats.INamed
import com.unciv.models.translations.tr
import com.unciv.ui.utils.*
@ -163,22 +164,31 @@ class CivilopediaScreen(
val imageSize = 50f
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 { "Will not be displayed in Civilopedia" !in it.uniques && !(it.isWonder || it.isNationalWonder) }
.filter { "Will not be displayed in Civilopedia" !in it.uniques
&& !(hideReligionItems && "Hidden when religion is disabled" in it.uniques)
&& !(noCulturalVictory && "Hidden when cultural victory is disabled" in it.uniques)
&& !(it.isWonder || it.isNationalWonder) }
.map {
CivilopediaEntry(
it.name,
it.getDescription(false, null, ruleset),
"",
CivilopediaCategories.Building.getImage?.invoke(it.name, imageSize),
(it as? ICivilopediaText).takeUnless { ct -> ct==null || ct.isCivilopediaTextEmpty() }
)
}
categoryToEntries[CivilopediaCategories.Wonder] = ruleset.buildings.values
.filter { "Will not be displayed in Civilopedia" !in it.uniques && (it.isWonder || it.isNationalWonder) }
.filter { "Will not be displayed in Civilopedia" !in it.uniques
&& !(hideReligionItems && "Hidden when religion is disabled" in it.uniques)
&& !(noCulturalVictory && "Hidden when cultural victory is disabled" in it.uniques)
&& (it.isWonder || it.isNationalWonder) }
.map {
CivilopediaEntry(
it.name,
it.getDescription(false, null, ruleset),
"",
CivilopediaCategories.Wonder.getImage?.invoke(it.name, imageSize),
(it as? ICivilopediaText).takeUnless { ct -> ct==null || ct.isCivilopediaTextEmpty() }
)

View File

@ -212,7 +212,7 @@ class FormattedLine (
}
if (textToDisplay.isNotEmpty()) {
val usedWidth = iconCount * (iconSize + iconPad)
val padIndent = when {
val indentWidth = when {
centered -> -usedWidth
indent == 0 && iconCount == 0 -> 0f
indent == 0 -> iconPad
@ -224,10 +224,10 @@ class FormattedLine (
label.setAlignment(align)
if (labelWidth == 0f)
table.add(label)
.padLeft(padIndent).align(align)
.padLeft(indentWidth).align(align)
else
table.add(label).width(labelWidth - usedWidth - padIndent)
.padLeft(padIndent).align(align)
table.add(label).width(labelWidth - usedWidth - indentWidth)
.padLeft(indentWidth).align(align)
}
return table
}

View File

@ -4,6 +4,7 @@ import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.ui.Slider
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.civilization.GreatPersonManager
import com.unciv.models.translations.tr
import com.unciv.ui.utils.*
import kotlin.math.roundToInt
@ -120,7 +121,7 @@ class StatsOverviewTable (
greatPeopleTable.add("Current points".tr())
greatPeopleTable.add("Points per turn".tr()).row()
val mapping = viewingPlayer.greatPeople.statToGreatPersonMapping
val mapping = GreatPersonManager.statToGreatPersonMapping
for(entry in mapping){
greatPeopleTable.add(entry.value.tr())
greatPeopleTable.add(greatPersonPoints[entry.key]!!.toInt().toString()+"/"+pointsToGreatPerson)