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> {
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"),
MustBeNextToTile(false, "Must 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"),
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"),
RequiresTech(false, "Required tech not researched"),
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"),
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"),
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 {
override fun shouldBeDisplayed(cityConstructions: CityConstructions) = isBuildable(cityConstructions)

View File

@ -1,7 +1,6 @@
package com.unciv.models.ruleset
import com.unciv.Constants
import com.unciv.UncivGame
import com.unciv.logic.city.*
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.models.Counter
@ -22,6 +21,7 @@ import com.unciv.ui.utils.Fonts
import com.unciv.ui.utils.toPercent
import kotlin.collections.ArrayList
import kotlin.collections.HashMap
import kotlin.math.pow
class Building : NamedStats(), INonPerpetualConstruction, ICivilopediaText {
@ -229,7 +229,9 @@ class Building : NamedStats(), INonPerpetualConstruction, ICivilopediaText {
if (cost > 0) {
val stats = mutableListOf("$cost${Fonts.production}")
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}: "))
}

View File

@ -99,104 +99,6 @@ class Nation : INamed, ICivilopediaText, IHasUniques {
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 getSortGroup(ruleset: Ruleset) = when {
isCityState() -> 1
@ -250,8 +152,11 @@ class Nation : INamed, ICivilopediaText, IHasUniques {
val textList = ArrayList<FormattedLine>()
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
val friendBonus = era.friendBonus[cityStateType!!.name]
@ -292,7 +197,6 @@ class Nation : INamed, ICivilopediaText, IHasUniques {
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) {
for (building in ruleset.buildings.values) {
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) {
for (unit in ruleset.units.values) {
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) {
for (improvement in ruleset.tileImprovements.values) {
if (improvement.uniqueTo != name ) continue

View File

@ -165,8 +165,15 @@ class TileImprovement : NamedStats(), ICivilopediaText, IHasUniques {
}
if (isAncientRuinsEquivalent() && ruleset.ruinRewards.isNotEmpty()) {
val difficulty = UncivGame.Current.gameInfo.gameParameters.difficulty
val religionEnabled = UncivGame.Current.gameInfo.isReligionEnabled()
val difficulty: String
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("The possible rewards are:")
ruleset.ruinRewards.values.asSequence()

View File

@ -1,7 +1,6 @@
package com.unciv.models.ruleset.unit
import com.unciv.Constants
import com.unciv.UncivGame
import com.unciv.logic.city.*
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.map.MapUnit
@ -127,8 +126,11 @@ class BaseUnit : INamed, INonPerpetualConstruction, ICivilopediaText {
if (cost > 0) {
stats.clear()
stats += "$cost${Fonts.production}"
if (canBePurchasedWithStat(null, Stat.Gold))
stats += "${getBaseGoldCost(UncivGame.Current.gameInfo.currentPlayerCiv).toInt() / 10 * 10}${Fonts.gold}"
if (canBePurchasedWithStat(null, Stat.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}: "))
}

View File

@ -433,6 +433,9 @@ interface ICivilopediaText {
else null
/** 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.
*