Fix a Nation Picker crash (#5311)

This commit is contained in:
SomeTroglodyte 2021-09-24 14:49:56 +02:00 committed by GitHub
parent 12302deef6
commit c05bf0a2a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 74 additions and 160 deletions

View File

@ -73,7 +73,7 @@ interface INonPerpetualConstruction : IConstruction, INamed, IHasUniques {
class RejectionReasons(): HashSet<RejectionReason>() { class RejectionReasons: HashSet<RejectionReason>() {
fun filterTechPolicyEraWonderRequirements(): HashSet<RejectionReason> { fun filterTechPolicyEraWonderRequirements(): HashSet<RejectionReason> {
return filterNot { it in techPolicyEraWonderRequirements }.toHashSet() return filterNot { it in techPolicyEraWonderRequirements }.toHashSet()
@ -130,7 +130,7 @@ enum class RejectionReason(val shouldShow: Boolean, var errorMessage: String) {
MustNotBeOnTile(false, "Must not be on a specific tile"), MustNotBeOnTile(false, "Must not be on a specific tile"),
MustBeNextToTile(false, "Must be next to a specific tile"), MustBeNextToTile(false, "Must be next to a specific tile"),
MustNotBeNextToTile(false, "Must not be next to a specific tile"), MustNotBeNextToTile(false, "Must not be next to a specific tile"),
MustOwnTile(false, "Must own a specific tile closeby"), MustOwnTile(false, "Must own a specific tile close by"),
WaterUnitsInCoastalCities(false, "May only built water units in coastal cities"), WaterUnitsInCoastalCities(false, "May only built water units in coastal cities"),
CanOnlyBeBuiltInSpecificCities(false, "Can only be built in specific cities"), CanOnlyBeBuiltInSpecificCities(false, "Can only be built in specific cities"),
@ -140,7 +140,7 @@ enum class RejectionReason(val shouldShow: Boolean, var errorMessage: String) {
Obsoleted(false, "Obsolete"), Obsoleted(false, "Obsolete"),
RequiresTech(false, "Required tech not researched"), RequiresTech(false, "Required tech not researched"),
RequiresPolicy(false, "Requires a specific policy!"), RequiresPolicy(false, "Requires a specific policy!"),
UnlockedWithEra(false, "Unlocked when reacing a specific era"), UnlockedWithEra(false, "Unlocked when reaching a specific era"),
MorePolicyBranches(false, "Hidden until more policy branches are fully adopted"), MorePolicyBranches(false, "Hidden until more policy branches are fully adopted"),
RequiresNearbyResource(false, "Requires a certain resource being exploited nearby"), RequiresNearbyResource(false, "Requires a certain resource being exploited nearby"),
@ -165,12 +165,10 @@ enum class RejectionReason(val shouldShow: Boolean, var errorMessage: String) {
PopulationRequirement(true, "Requires more population"), PopulationRequirement(true, "Requires more population"),
NoSettlerForOneCityPlayers(false, "No settlers for city-states or one-city challangers"); NoSettlerForOneCityPlayers(false, "No settlers for city-states or one-city challengers");
} }
open class PerpetualConstruction(override var name: String, val description: String) : IConstruction { open class PerpetualConstruction(override var name: String, val description: String) : IConstruction {
override fun shouldBeDisplayed(cityConstructions: CityConstructions) = isBuildable(cityConstructions) override fun shouldBeDisplayed(cityConstructions: CityConstructions) = isBuildable(cityConstructions)

View File

@ -1,7 +1,6 @@
package com.unciv.models.ruleset package com.unciv.models.ruleset
import com.unciv.Constants import com.unciv.Constants
import com.unciv.UncivGame
import com.unciv.logic.city.* import com.unciv.logic.city.*
import com.unciv.logic.civilization.CivilizationInfo import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.models.Counter import com.unciv.models.Counter
@ -22,6 +21,7 @@ import com.unciv.ui.utils.Fonts
import com.unciv.ui.utils.toPercent import com.unciv.ui.utils.toPercent
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
import kotlin.collections.HashMap import kotlin.collections.HashMap
import kotlin.math.pow
class Building : NamedStats(), INonPerpetualConstruction, ICivilopediaText { class Building : NamedStats(), INonPerpetualConstruction, ICivilopediaText {
@ -229,7 +229,9 @@ class Building : NamedStats(), INonPerpetualConstruction, ICivilopediaText {
if (cost > 0) { if (cost > 0) {
val stats = mutableListOf("$cost${Fonts.production}") val stats = mutableListOf("$cost${Fonts.production}")
if (canBePurchasedWithStat(null, Stat.Gold)) { if (canBePurchasedWithStat(null, Stat.Gold)) {
stats += "${getBaseGoldCost(UncivGame.Current.gameInfo.currentPlayerCiv).toInt() / 10 * 10}${Fonts.gold}" // We need what INonPerpetualConstruction.getBaseGoldCost calculates but without any game- or civ-specific modifiers
val buyCost = 30.0 * cost.toFloat().pow(0.75f) * hurryCostModifier.toPercent() / 10 * 10
stats += "$buyCost${Fonts.gold}"
} }
textList += FormattedLine(stats.joinToString(", ", "{Cost}: ")) textList += FormattedLine(stats.joinToString(", ", "{Cost}: "))
} }

View File

@ -99,104 +99,6 @@ class Nation : INamed, ICivilopediaText, IHasUniques {
var cities: ArrayList<String> = arrayListOf() var cities: ArrayList<String> = arrayListOf()
/** Used only by NewGame Nation picker */
fun getUniqueString(ruleset: Ruleset): String {
val textList = ArrayList<String>()
if (uniqueName != "") textList += uniqueName.tr() + ":"
if (uniqueText != "") {
textList += " " + uniqueText.tr()
} else {
textList += " " + uniques.joinToString(", ") { it.tr() }
textList += ""
}
if (startBias.isNotEmpty()) {
textList += "Start bias:".tr() + startBias.joinToString(", ", " ") { it.tr() }
textList += ""
}
addUniqueBuildingsText(textList, ruleset)
addUniqueUnitsText(textList, ruleset)
addUniqueImprovementsText(textList, ruleset)
return textList.joinToString("\n")
}
private fun addUniqueBuildingsText(textList: ArrayList<String>, ruleset: Ruleset) {
for (building in ruleset.buildings.values
.filter { it.uniqueTo == name && Constants.hideFromCivilopediaUnique !in it.uniques }) {
if (building.replaces != null && ruleset.buildings.containsKey(building.replaces!!)) {
val originalBuilding = ruleset.buildings[building.replaces!!]!!
textList += building.name.tr() + " - " + "Replaces [${originalBuilding.name}]".tr()
for ((key, value) in building)
if (value != originalBuilding[key])
textList += " " + key.name.tr() + " " + "[${value.toInt()}] vs [${originalBuilding[key].toInt()}]".tr()
for (unique in building.uniques.filter { it !in originalBuilding.uniques })
textList += " " + unique.tr()
if (building.maintenance != originalBuilding.maintenance)
textList += " {Maintenance} " + "[${building.maintenance}] vs [${originalBuilding.maintenance}]".tr()
if (building.cost != originalBuilding.cost)
textList += " {Cost} " + "[${building.cost}] vs [${originalBuilding.cost}]".tr()
if (building.cityStrength != originalBuilding.cityStrength)
textList += " {City strength} " + "[${building.cityStrength}] vs [${originalBuilding.cityStrength}]".tr()
if (building.cityHealth != originalBuilding.cityHealth)
textList += " {City health} " + "[${building.cityHealth}] vs [${originalBuilding.cityHealth}]".tr()
textList += ""
} else if (building.replaces != null) {
textList += building.name.tr() + " - " + "Replaces [${building.replaces}], which is not found in the ruleset!".tr()
} else textList += building.getShortDescription(ruleset)
}
}
private fun addUniqueUnitsText(textList: ArrayList<String>, ruleset: Ruleset) {
for (unit in ruleset.units.values
.filter { it.uniqueTo == name && Constants.hideFromCivilopediaUnique !in it.uniques }) {
if (unit.replaces != null && ruleset.units.containsKey(unit.replaces!!)) {
val originalUnit = ruleset.units[unit.replaces!!]!!
textList += unit.name.tr() + " - " + "Replaces [${originalUnit.name}]".tr()
if (unit.cost != originalUnit.cost)
textList += " {Cost} " + "[${unit.cost}] vs [${originalUnit.cost}]".tr()
if (unit.strength != originalUnit.strength)
textList += " ${Fonts.strength} " + "[${unit.strength}] vs [${originalUnit.strength}]".tr()
if (unit.rangedStrength != originalUnit.rangedStrength)
textList += " ${Fonts.rangedStrength} " + "[${unit.rangedStrength}] vs [${originalUnit.rangedStrength}]".tr()
if (unit.range != originalUnit.range)
textList += " ${Fonts.range} " + "[${unit.range}] vs [${originalUnit.range}]".tr()
if (unit.movement != originalUnit.movement)
textList += " ${Fonts.movement} " + "[${unit.movement}] vs [${originalUnit.movement}]".tr()
for (resource in originalUnit.getResourceRequirements().keys)
if (!unit.getResourceRequirements().containsKey(resource))
textList += " " + "[$resource] not required".tr()
for (unique in unit.uniques.filterNot { it in originalUnit.uniques })
textList += " " + unique.tr()
for (unique in originalUnit.uniques.filterNot { it in unit.uniques })
textList += " " + "Lost ability".tr() + "(" + "vs [${originalUnit.name}]".tr() + "): " + unique.tr()
for (promotion in unit.promotions.filter { it !in originalUnit.promotions })
textList += " " + promotion.tr() + " (" + ruleset.unitPromotions[promotion]!!.uniquesWithEffect().joinToString(",") { it.tr() } + ")"
} else if (unit.replaces != null) {
textList += unit.name.tr() + " - " + "Replaces [${unit.replaces}], which is not found in the ruleset!".tr()
} else {
textList += unit.name.tr()
textList += " " + unit.getDescription().split("\n").joinToString("\n ")
}
textList += ""
}
}
private fun addUniqueImprovementsText(textList: ArrayList<String>, ruleset: Ruleset) {
for (improvement in ruleset.tileImprovements.values
.filter { it.uniqueTo == name }) {
textList += improvement.name.tr()
textList += " " + improvement.clone().toString()
for (unique in improvement.uniques)
textList += " " + unique.tr()
}
}
override fun makeLink() = "Nation/$name" override fun makeLink() = "Nation/$name"
override fun getSortGroup(ruleset: Ruleset) = when { override fun getSortGroup(ruleset: Ruleset) = when {
isCityState() -> 1 isCityState() -> 1
@ -250,8 +152,11 @@ class Nation : INamed, ICivilopediaText, IHasUniques {
val textList = ArrayList<FormattedLine>() val textList = ArrayList<FormattedLine>()
textList += FormattedLine("Type: [$cityStateType]", header = 4, color = cityStateType!!.color) textList += FormattedLine("Type: [$cityStateType]", header = 4, color = cityStateType!!.color)
val viewingCiv = UncivGame.Current.gameInfo.currentPlayerCiv
val era = viewingCiv.getEra() val era = if (UncivGame.isCurrentInitialized() && UncivGame.Current.isGameInfoInitialized())
UncivGame.Current.gameInfo.currentPlayerCiv.getEra()
else
ruleset.eras.values.first()
var showResources = false var showResources = false
val friendBonus = era.friendBonus[cityStateType!!.name] val friendBonus = era.friendBonus[cityStateType!!.name]
@ -292,7 +197,6 @@ class Nation : INamed, ICivilopediaText, IHasUniques {
return textList return textList
} }
@JvmName("addUniqueBuildingsText1") // These overloads are too similar - but I hope to remove the other one soon
private fun addUniqueBuildingsText(textList: ArrayList<FormattedLine>, ruleset: Ruleset) { private fun addUniqueBuildingsText(textList: ArrayList<FormattedLine>, ruleset: Ruleset) {
for (building in ruleset.buildings.values) { for (building in ruleset.buildings.values) {
if (building.uniqueTo != name || Constants.hideFromCivilopediaUnique in building.uniques) continue if (building.uniqueTo != name || Constants.hideFromCivilopediaUnique in building.uniques) continue
@ -324,7 +228,6 @@ class Nation : INamed, ICivilopediaText, IHasUniques {
} }
} }
@JvmName("addUniqueUnitsText1")
private fun addUniqueUnitsText(textList: ArrayList<FormattedLine>, ruleset: Ruleset) { private fun addUniqueUnitsText(textList: ArrayList<FormattedLine>, ruleset: Ruleset) {
for (unit in ruleset.units.values) { for (unit in ruleset.units.values) {
if (unit.uniqueTo != name || Constants.hideFromCivilopediaUnique in unit.uniques) continue if (unit.uniqueTo != name || Constants.hideFromCivilopediaUnique in unit.uniques) continue
@ -373,7 +276,6 @@ class Nation : INamed, ICivilopediaText, IHasUniques {
} }
} }
@JvmName("addUniqueImprovementsText1")
private fun addUniqueImprovementsText(textList: ArrayList<FormattedLine>, ruleset: Ruleset) { private fun addUniqueImprovementsText(textList: ArrayList<FormattedLine>, ruleset: Ruleset) {
for (improvement in ruleset.tileImprovements.values) { for (improvement in ruleset.tileImprovements.values) {
if (improvement.uniqueTo != name ) continue if (improvement.uniqueTo != name ) continue

View File

@ -165,8 +165,15 @@ class TileImprovement : NamedStats(), ICivilopediaText, IHasUniques {
} }
if (isAncientRuinsEquivalent() && ruleset.ruinRewards.isNotEmpty()) { if (isAncientRuinsEquivalent() && ruleset.ruinRewards.isNotEmpty()) {
val difficulty = UncivGame.Current.gameInfo.gameParameters.difficulty val difficulty: String
val religionEnabled = UncivGame.Current.gameInfo.isReligionEnabled() val religionEnabled: Boolean
if (UncivGame.isCurrentInitialized() && UncivGame.Current.isGameInfoInitialized()) {
difficulty = UncivGame.Current.gameInfo.gameParameters.difficulty
religionEnabled = UncivGame.Current.gameInfo.isReligionEnabled()
} else {
difficulty = "Prince" // most factors == 1
religionEnabled = true
}
textList += FormattedLine() textList += FormattedLine()
textList += FormattedLine("The possible rewards are:") textList += FormattedLine("The possible rewards are:")
ruleset.ruinRewards.values.asSequence() ruleset.ruinRewards.values.asSequence()

View File

@ -1,7 +1,6 @@
package com.unciv.models.ruleset.unit package com.unciv.models.ruleset.unit
import com.unciv.Constants import com.unciv.Constants
import com.unciv.UncivGame
import com.unciv.logic.city.* import com.unciv.logic.city.*
import com.unciv.logic.civilization.CivilizationInfo import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.map.MapUnit import com.unciv.logic.map.MapUnit
@ -127,8 +126,11 @@ class BaseUnit : INamed, INonPerpetualConstruction, ICivilopediaText {
if (cost > 0) { if (cost > 0) {
stats.clear() stats.clear()
stats += "$cost${Fonts.production}" stats += "$cost${Fonts.production}"
if (canBePurchasedWithStat(null, Stat.Gold)) if (canBePurchasedWithStat(null, Stat.Gold)) {
stats += "${getBaseGoldCost(UncivGame.Current.gameInfo.currentPlayerCiv).toInt() / 10 * 10}${Fonts.gold}" // We need what INonPerpetualConstruction.getBaseGoldCost calculates but without any game- or civ-specific modifiers
val buyCost = 30.0 * cost.toFloat().pow(0.75f) * hurryCostModifier.toPercent() / 10 * 10
stats += "$buyCost${Fonts.gold}"
}
textList += FormattedLine(stats.joinToString(", ", "{Cost}: ")) textList += FormattedLine(stats.joinToString(", ", "{Cost}: "))
} }

View File

@ -433,6 +433,9 @@ interface ICivilopediaText {
else null else null
/** Generate automatic lines from object metadata. /** Generate automatic lines from object metadata.
*
* Please do not rely on a UncivGame.Current.gameInfo being initialized, this should be able to run from the main menu.
* (And the info displayed should be about the **ruleset**, not the player situation)
* *
* Default implementation is empty - no need to call super in overrides. * Default implementation is empty - no need to call super in overrides.
* *