Deprecate all mods without an eras.json file (#4809)

* Enforce the existence of an eras.json file for mods

* Merged `getEra()` and `getEraObject()`

* Hide mods we have deemed outdated

* Fixed compile errors that I didn't notice before

* Fixed unit tests
This commit is contained in:
Xander Lenstra 2021-09-06 13:50:38 +02:00 committed by GitHub
parent 8079a8dc7b
commit 486e2a7a8a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 81 additions and 137 deletions

View File

@ -0,0 +1,9 @@
[
"https://github.com/k4zoo/Civ5ExpansionMod",
"https://github.com/k4zoo/Civilization-6-Mod",
"https://github.com/9kgsofrice/DeCiv",
"https://github.com/k4zoo/EmpireOfSmokySkies",
"https://github.com/shannaurelle/ph-bonifacio-unciv",
"https://github.com/ID1m0nI/PolyCiv",
"https://github.com/CrispyXYZ/Optimize-tech-mod"
]

View File

@ -143,7 +143,7 @@ object GameStarter {
civInfo.tech.addTechnology(tech.name) civInfo.tech.addTechnology(tech.name)
for (tech in ruleset.technologies.values for (tech in ruleset.technologies.values
.filter { ruleset.getEraNumber(it.era()) < ruleset.getEraNumber(gameSetupInfo.gameParameters.startingEra) }) .filter { ruleset.eras[it.era()]!!.eraNumber < ruleset.eras[gameSetupInfo.gameParameters.startingEra]!!.eraNumber })
if (!civInfo.tech.isResearched(tech.name)) if (!civInfo.tech.isResearched(tech.name))
civInfo.tech.addTechnology(tech.name) civInfo.tech.addTechnology(tech.name)
@ -154,12 +154,7 @@ object GameStarter {
private fun addCivStats(gameInfo: GameInfo) { private fun addCivStats(gameInfo: GameInfo) {
val ruleSet = gameInfo.ruleSet val ruleSet = gameInfo.ruleSet
val startingEra = gameInfo.gameParameters.startingEra val startingEra = gameInfo.gameParameters.startingEra
val era = val era = ruleSet.eras[startingEra]!!
if (startingEra in ruleSet.eras.keys) {
ruleSet.eras[startingEra]!!
} else {
Era()
}
for (civInfo in gameInfo.civilizations.filter { !it.isBarbarian() }) { for (civInfo in gameInfo.civilizations.filter { !it.isBarbarian() }) {
civInfo.addGold((era.startingGold * gameInfo.gameParameters.gameSpeed.modifier).toInt()) civInfo.addGold((era.startingGold * gameInfo.gameParameters.gameSpeed.modifier).toInt())
civInfo.policies.addCulture((era.startingCulture * gameInfo.gameParameters.gameSpeed.modifier).toInt()) civInfo.policies.addCulture((era.startingCulture * gameInfo.gameParameters.gameSpeed.modifier).toInt())
@ -277,35 +272,9 @@ object GameStarter {
civ.placeUnitNearTile(startingLocation.position, unitName) civ.placeUnitNearTile(startingLocation.position, unitName)
} }
// We are using an older mod, so we only look at the difficulty file
if (ruleSet.eras.isEmpty()) {
startingUnits = (when {
civ.isPlayerCivilization() -> gameInfo.getDifficulty().startingUnits
civ.isMajorCiv() -> gameInfo.getDifficulty().aiMajorCivStartingUnits
else -> gameInfo.getDifficulty().aiCityStateStartingUnits
}).toMutableList()
val warriorEquivalent = ruleSet.units.values
.filter { it.isLandUnit() && it.isMilitary() && it.isBuildable(civ) }
.maxByOrNull {max(it.strength, it.rangedStrength)}
?.name
for (unit in startingUnits) {
val unitToAdd = if (unit == "Warrior") warriorEquivalent else unit
if (unitToAdd != null) placeNearStartingPosition(unitToAdd)
}
continue
}
// Determine starting units based on starting era // Determine starting units based on starting era
if (startingEra in ruleSet.eras.keys) { startingUnits = ruleSet.eras[startingEra]!!.getStartingUnits().toMutableList()
startingUnits = ruleSet.eras[startingEra]!!.getStartingUnits().toMutableList() eraUnitReplacement = ruleSet.eras[startingEra]!!.startingMilitaryUnit
eraUnitReplacement = ruleSet.eras[startingEra]!!.startingMilitaryUnit
} else {
startingUnits = Era().getStartingUnits().toMutableList()
eraUnitReplacement = Era().startingMilitaryUnit
}
// Add extra units granted by difficulty // Add extra units granted by difficulty
startingUnits.addAll(when { startingUnits.addAll(when {

View File

@ -120,8 +120,7 @@ class CityInfo {
val ruleset = civInfo.gameInfo.ruleSet val ruleset = civInfo.gameInfo.ruleSet
workedTiles = hashSetOf() //reassign 1st working tile workedTiles = hashSetOf() //reassign 1st working tile
if (startingEra in ruleset.eras) population.setPopulation(ruleset.eras[startingEra]!!.settlerPopulation)
population.setPopulation(ruleset.eras[startingEra]!!.settlerPopulation)
if (civInfo.religionManager.religionState == ReligionState.Pantheon) { if (civInfo.religionManager.religionState == ReligionState.Pantheon) {
religion.addPressure( religion.addPressure(
@ -141,13 +140,11 @@ class CityInfo {
if (civInfo.cities.size == 1) cityConstructions.addBuilding(capitalCityIndicator()) if (civInfo.cities.size == 1) cityConstructions.addBuilding(capitalCityIndicator())
// Add buildings and pop we get from starting in this era // Add buildings and pop we get from starting in this era
if (startingEra in ruleset.eras) { for (buildingName in ruleset.eras[startingEra]!!.settlerBuildings) {
for (buildingName in ruleset.eras[startingEra]!!.settlerBuildings) { val building = ruleset.buildings[buildingName] ?: continue
val building = ruleset.buildings[buildingName] ?: continue val uniqueBuilding = civInfo.getEquivalentBuilding(building)
val uniqueBuilding = civInfo.getEquivalentBuilding(building) if (uniqueBuilding.isBuildable(cityConstructions))
if (uniqueBuilding.isBuildable(cityConstructions)) cityConstructions.addBuilding(uniqueBuilding.name)
cityConstructions.addBuilding(uniqueBuilding.name)
}
} }
civInfo.policies.tryToAddPolicyBuildings() civInfo.policies.tryToAddPolicyBuildings()

View File

@ -113,9 +113,9 @@ class CityStats(val cityInfo: CityInfo) {
for (otherCiv in cityInfo.civInfo.getKnownCivs()) { for (otherCiv in cityInfo.civInfo.getKnownCivs()) {
if (otherCiv.isCityState() && otherCiv.getDiplomacyManager(cityInfo.civInfo).relationshipLevel() >= RelationshipLevel.Friend) { if (otherCiv.isCityState() && otherCiv.getDiplomacyManager(cityInfo.civInfo).relationshipLevel() >= RelationshipLevel.Friend) {
val eraInfo = cityInfo.civInfo.getEraObject() val eraInfo = cityInfo.civInfo.getEra()
if (eraInfo == null || eraInfo.friendBonus[otherCiv.cityStateType.name] == null || eraInfo.allyBonus[otherCiv.cityStateType.name] == null) { if (eraInfo.friendBonus[otherCiv.cityStateType.name] == null || eraInfo.allyBonus[otherCiv.cityStateType.name] == null) {
// Deprecated, assume Civ V values for compatibility // Deprecated, assume Civ V values for compatibility
if (otherCiv.cityStateType == CityStateType.Maritime && otherCiv.getDiplomacyManager(cityInfo.civInfo).relationshipLevel() == RelationshipLevel.Ally) if (otherCiv.cityStateType == CityStateType.Maritime && otherCiv.getDiplomacyManager(cityInfo.civInfo).relationshipLevel() == RelationshipLevel.Ally)
stats.food += 1 stats.food += 1

View File

@ -73,7 +73,7 @@ interface INonPerpetualConstruction : IConstruction, INamed, IHasUniques {
// Can be purchased with [Stat] [cityFilter] // Can be purchased with [Stat] [cityFilter]
if (getMatchingUniques("Can be purchased with [] []") if (getMatchingUniques("Can be purchased with [] []")
.any { it.params[0] == stat.name && cityInfo.matchesFilter(it.params[1])} .any { it.params[0] == stat.name && cityInfo.matchesFilter(it.params[1])}
) return cityInfo.civInfo.gameInfo.ruleSet.eras[cityInfo.civInfo.getEra()]!!.baseUnitBuyCost ) return cityInfo.civInfo.getEra().baseUnitBuyCost
return null return null
} }
} }

View File

@ -316,9 +316,8 @@ class CityStateFunctions(val civInfo: CivilizationInfo) {
fun canGiveStat(statType: Stat): Boolean { fun canGiveStat(statType: Stat): Boolean {
if (!civInfo.isCityState()) if (!civInfo.isCityState())
return false return false
val eraInfo = civInfo.getEraObject() val eraInfo = civInfo.getEra()
val allyBonuses = if (eraInfo == null) null val allyBonuses = eraInfo.allyBonus[civInfo.cityStateType.name]
else eraInfo.allyBonus[civInfo.cityStateType.name]
if (allyBonuses != null) { if (allyBonuses != null) {
// Defined city states in json // Defined city states in json
val bonuses = allyBonuses + eraInfo!!.friendBonus[civInfo.cityStateType.name]!! val bonuses = allyBonuses + eraInfo!!.friendBonus[civInfo.cityStateType.name]!!

View File

@ -100,16 +100,12 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
.relationshipLevel() >= RelationshipLevel.Friend .relationshipLevel() >= RelationshipLevel.Friend
) { ) {
val cityStateBonus = Stats() val cityStateBonus = Stats()
val eraInfo = civInfo.getEraObject() val eraInfo = civInfo.getEra()
val relevantBonuses = val relevantBonuses =
when { if (otherCiv.getDiplomacyManager(civInfo.civName).relationshipLevel() == RelationshipLevel.Friend)
eraInfo == null -> null eraInfo.friendBonus[otherCiv.cityStateType.name]
otherCiv.getDiplomacyManager(civInfo.civName) else eraInfo.allyBonus[otherCiv.cityStateType.name]
.relationshipLevel() == RelationshipLevel.Friend ->
eraInfo.friendBonus[otherCiv.cityStateType.name]
else -> eraInfo.allyBonus[otherCiv.cityStateType.name]
}
if (relevantBonuses != null) { if (relevantBonuses != null) {
for (bonus in relevantBonuses) { for (bonus in relevantBonuses) {
@ -299,16 +295,11 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
if (otherCiv.isCityState() && otherCiv.getDiplomacyManager(civInfo) if (otherCiv.isCityState() && otherCiv.getDiplomacyManager(civInfo)
.relationshipLevel() >= RelationshipLevel.Friend .relationshipLevel() >= RelationshipLevel.Friend
) { ) {
val eraInfo = civInfo.getEraObject() val eraInfo = civInfo.getEra()
val relevantBonuses = val relevantBonuses =
when { if (otherCiv.getDiplomacyManager(civInfo).relationshipLevel() == RelationshipLevel.Friend)
eraInfo == null -> null eraInfo.friendBonus[otherCiv.cityStateType.name]
otherCiv.getDiplomacyManager(civInfo) else eraInfo.allyBonus[otherCiv.cityStateType.name]
.relationshipLevel() == RelationshipLevel.Friend ->
eraInfo.friendBonus[otherCiv.cityStateType.name]
else ->
eraInfo.allyBonus[otherCiv.cityStateType.name]
}
if (relevantBonuses != null) { if (relevantBonuses != null) {
for (bonus in relevantBonuses) { for (bonus in relevantBonuses) {

View File

@ -428,20 +428,18 @@ class CivilizationInfo {
else -> getCivUnits().none() else -> getCivUnits().none()
} }
fun getEra(): String { fun getEra(): Era {
if (gameInfo.ruleSet.technologies.isEmpty()) return "None" if (gameInfo.ruleSet.technologies.isEmpty() || tech.researchedTechnologies.isEmpty())
if (tech.researchedTechnologies.isEmpty()) return Era()
return gameInfo.ruleSet.getEras().first() val eraName = tech.researchedTechnologies
return tech.researchedTechnologies
.asSequence() .asSequence()
.map { it.column!! } .map { it.column!! }
.maxByOrNull { it.columnNumber }!! .maxByOrNull { it.columnNumber }!!
.era .era
return gameInfo.ruleSet.eras[eraName]!!
} }
fun getEraNumber(): Int = gameInfo.ruleSet.getEraNumber(getEra()) fun getEraNumber(): Int = getEra().eraNumber
fun getEraObject(): Era? = gameInfo.ruleSet.eras[getEra()]
fun isAtWarWith(otherCiv: CivilizationInfo): Boolean { fun isAtWarWith(otherCiv: CivilizationInfo): Boolean {
if (otherCiv.civName == civName) return false // never at war with itself if (otherCiv.civName == civName) return false // never at war with itself
@ -864,8 +862,9 @@ class CivilizationInfo {
fun getResearchAgreementCost(): Int { fun getResearchAgreementCost(): Int {
// https://forums.civfanatics.com/resources/research-agreements-bnw.25568/ // https://forums.civfanatics.com/resources/research-agreements-bnw.25568/
val era = if (getEra() in gameInfo.ruleSet.eras) gameInfo.ruleSet.eras[getEra()]!! else Era() return (
return (era.researchAgreementCost * gameInfo.gameParameters.gameSpeed.modifier).toInt() getEra().researchAgreementCost * gameInfo.gameParameters.gameSpeed.modifier
).toInt()
} }
//////////////////////// City State wrapper functions //////////////////////// //////////////////////// City State wrapper functions ////////////////////////

View File

@ -114,7 +114,7 @@ class PolicyManager {
if (isAdopted(policy.name)) return false if (isAdopted(policy.name)) return false
if (policy.policyBranchType == PolicyBranchType.BranchComplete) return false if (policy.policyBranchType == PolicyBranchType.BranchComplete) return false
if (!getAdoptedPolicies().containsAll(policy.requires!!)) return false if (!getAdoptedPolicies().containsAll(policy.requires!!)) return false
if (checkEra && civInfo.gameInfo.ruleSet.getEraNumber(policy.branch.era) > civInfo.getEraNumber()) return false if (checkEra && civInfo.gameInfo.ruleSet.eras[policy.branch.era]!!.eraNumber > civInfo.getEraNumber()) return false
if (policy.uniqueObjects.any { it.placeholderText == "Incompatible with []" && adoptedPolicies.contains(it.params[0]) }) return false if (policy.uniqueObjects.any { it.placeholderText == "Incompatible with []" && adoptedPolicies.contains(it.params[0]) }) return false
return true return true
} }

View File

@ -255,7 +255,7 @@ class TechManager {
knownCiv.addNotification("[${civInfo.civName}] has entered the [$currentEra]!", civInfo.civName, NotificationIcon.Science) knownCiv.addNotification("[${civInfo.civName}] has entered the [$currentEra]!", civInfo.civName, NotificationIcon.Science)
} }
} }
for (it in getRuleset().policyBranches.values.filter { it.era == currentEra && civInfo.policies.isAdoptable(it) }) { for (it in getRuleset().policyBranches.values.filter { it.era == currentEra.name && civInfo.policies.isAdoptable(it) }) {
civInfo.addNotification("[" + it.name + "] policy branch unlocked!", NotificationIcon.Culture) civInfo.addNotification("[" + it.name + "] policy branch unlocked!", NotificationIcon.Culture)
} }
} }

View File

@ -531,18 +531,15 @@ class DiplomacyManager() {
revertToZero(DiplomaticModifiers.DeclarationOfFriendship, 1 / 2f) //decreases slowly and will revert to full if it is declared later revertToZero(DiplomaticModifiers.DeclarationOfFriendship, 1 / 2f) //decreases slowly and will revert to full if it is declared later
if (otherCiv().isCityState()) { if (otherCiv().isCityState()) {
val eraInfo = civInfo.getEraObject() val eraInfo = civInfo.getEra()
if (relationshipLevel() < RelationshipLevel.Friend) { if (relationshipLevel() < RelationshipLevel.Friend) {
if (hasFlag(DiplomacyFlags.ProvideMilitaryUnit)) removeFlag(DiplomacyFlags.ProvideMilitaryUnit) if (hasFlag(DiplomacyFlags.ProvideMilitaryUnit)) removeFlag(DiplomacyFlags.ProvideMilitaryUnit)
} else { } else {
val relevantBonuses = val relevantBonuses =
when { if (relationshipLevel() == RelationshipLevel.Friend)
eraInfo == null -> null eraInfo.friendBonus[otherCiv().cityStateType.name]
relationshipLevel() == RelationshipLevel.Friend -> else eraInfo.allyBonus[otherCiv().cityStateType.name]
eraInfo.friendBonus[otherCiv().cityStateType.name]
else -> eraInfo.allyBonus[otherCiv().cityStateType.name]
}
if (relevantBonuses == null && otherCiv().cityStateType == CityStateType.Militaristic) { if (relevantBonuses == null && otherCiv().cityStateType == CityStateType.Militaristic) {
// Deprecated, assume Civ V values for compatibility // Deprecated, assume Civ V values for compatibility

View File

@ -504,9 +504,8 @@ class Building : NamedStats(), INonPerpetualConstruction, ICivilopediaText {
ruleSet.policies.contains(filter) -> ruleSet.policies.contains(filter) ->
if (!civInfo.policies.isAdopted(filter)) if (!civInfo.policies.isAdopted(filter))
rejectionReasons.add(RejectionReason.RequiresPolicy.apply { errorMessage = unique.text }) rejectionReasons.add(RejectionReason.RequiresPolicy.apply { errorMessage = unique.text })
// ToDo: Fix this when eras.json is required ruleSet.eras.contains(filter) ->
ruleSet.getEraNumber(filter) != -1 -> if (civInfo.getEraNumber() < ruleSet.eras[filter]!!.eraNumber)
if (civInfo.getEraNumber() < ruleSet.getEraNumber(filter))
rejectionReasons.add(RejectionReason.UnlockedWithEra.apply { errorMessage = unique.text }) rejectionReasons.add(RejectionReason.UnlockedWithEra.apply { errorMessage = unique.text })
ruleSet.buildings.contains(filter) -> ruleSet.buildings.contains(filter) ->
if (civInfo.cities.none { it.cityConstructions.containsBuildingOrEquivalent(filter) }) if (civInfo.cities.none { it.cityConstructions.containsBuildingOrEquivalent(filter) })
@ -526,7 +525,7 @@ class Building : NamedStats(), INonPerpetualConstruction, ICivilopediaText {
rejectionReasons.add(RejectionReason.CityStateWonder) rejectionReasons.add(RejectionReason.CityStateWonder)
val startingEra = civInfo.gameInfo.gameParameters.startingEra val startingEra = civInfo.gameInfo.gameParameters.startingEra
if (startingEra in ruleSet.eras && name in ruleSet.eras[startingEra]!!.startingObsoleteWonders) if (name in ruleSet.eras[startingEra]!!.startingObsoleteWonders)
rejectionReasons.add(RejectionReason.WonderDisabledEra) rejectionReasons.add(RejectionReason.WonderDisabledEra)
} }

View File

@ -7,6 +7,7 @@ import com.unciv.ui.utils.colorFromRGB
class Era : INamed { class Era : INamed {
override var name: String = "" override var name: String = ""
var eraNumber: Int = -1
var researchAgreementCost = 300 var researchAgreementCost = 300
var startingSettlerCount = 1 var startingSettlerCount = 1
var startingSettlerUnit = "Settler" // For mods which have differently named settlers var startingSettlerUnit = "Settler" // For mods which have differently named settlers
@ -39,30 +40,4 @@ class Era : INamed {
} }
fun getHexColor() = "#" + getColor().toString().substring(0, 6) fun getHexColor() = "#" + getColor().toString().substring(0, 6)
companion object {
// User for CS bonuses in case the Eras file is missing (legacy mods)
fun getLegacyCityStateBonusEra(eraNumber: Int) = Era().apply {
val cultureBonus = if (eraNumber in 0..1) 3 else if (eraNumber in 2..3) 6 else 13
val happinessBonus = if (eraNumber in 0..1) 2 else 3
friendBonus[CityStateType.Militaristic.name] =
arrayListOf("Provides military units every [20] turns")
friendBonus[CityStateType.Cultured.name] =
arrayListOf("Provides [$cultureBonus] [Culture] per turn")
friendBonus[CityStateType.Mercantile.name] =
arrayListOf("Provides [$happinessBonus] Happiness")
friendBonus[CityStateType.Maritime.name] =
arrayListOf("Provides [2] [Food] [in capital]")
allyBonus[CityStateType.Militaristic.name] =
arrayListOf("Provides military units every [17] turns")
allyBonus[CityStateType.Cultured.name] =
arrayListOf("Provides [${cultureBonus * 2}] [Culture] per turn")
allyBonus[CityStateType.Mercantile.name] =
arrayListOf("Provides [$happinessBonus] Happiness", "Provides a unique luxury")
allyBonus[CityStateType.Maritime.name] = arrayListOf(
"Provides [2] [Food] [in capital]",
"Provides [1] [Food] [in all cities]"
)
}
}
} }

View File

@ -248,7 +248,7 @@ class Nation : INamed, ICivilopediaText, IHasUniques {
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 viewingCiv = UncivGame.Current.gameInfo.currentPlayerCiv
val era = viewingCiv.getEraObject() ?: Era.getLegacyCityStateBonusEra(viewingCiv.getEraNumber()) val era = viewingCiv.getEra()
var showResources = false var showResources = false
val friendBonus = era.friendBonus[cityStateType!!.name] val friendBonus = era.friendBonus[cityStateType!!.name]

View File

@ -54,7 +54,7 @@ open class Policy : INamed, IHasUniques, ICivilopediaText {
override fun replacesCivilopediaDescription() = true override fun replacesCivilopediaDescription() = true
override fun hasCivilopediaTextLines() = true override fun hasCivilopediaTextLines() = true
override fun getSortGroup(ruleset: Ruleset) = override fun getSortGroup(ruleset: Ruleset) =
ruleset.getEraNumber(branch.era) * 10000 + ruleset.eras[branch.era]!!.eraNumber * 10000 +
ruleset.policyBranches.keys.indexOf(branch.name) * 100 + ruleset.policyBranches.keys.indexOf(branch.name) * 100 +
policyBranchType.ordinal policyBranchType.ordinal

View File

@ -179,6 +179,10 @@ class Ruleset {
val erasFile = folderHandle.child("Eras.json") val erasFile = folderHandle.child("Eras.json")
if (erasFile.exists()) eras += createHashmap(jsonParser.getFromJson(Array<Era>::class.java, erasFile)) if (erasFile.exists()) eras += createHashmap(jsonParser.getFromJson(Array<Era>::class.java, erasFile))
// While `eras.values.toList()` might seem more logical, eras.values is a MutableCollection and
// therefore does not guarantee keeping the order of elements like a LinkedHashMap does.
// Using a map sidesteps this problem
eras.map { it.value }.withIndex().forEach { it.value.eraNumber = it.index }
val unitTypesFile = folderHandle.child("UnitTypes.json") val unitTypesFile = folderHandle.child("UnitTypes.json")
if (unitTypesFile.exists()) unitTypes += createHashmap(jsonParser.getFromJson(Array<UnitType>::class.java, unitTypesFile)) if (unitTypesFile.exists()) unitTypes += createHashmap(jsonParser.getFromJson(Array<UnitType>::class.java, unitTypesFile))
@ -251,10 +255,8 @@ class Ruleset {
} }
} }
fun getEras(): List<String> = technologies.values.map { it.column!!.era }.distinct()
fun hasReligion() = beliefs.any() && modWithReligionLoaded fun hasReligion() = beliefs.any() && modWithReligionLoaded
fun getEraNumber(era: String) = getEras().indexOf(era)
fun getSummary(): String { fun getSummary(): String {
val stringList = ArrayList<String>() val stringList = ArrayList<String>()
if (modOptions.isBaseRuleset) stringList += "Base Ruleset" if (modOptions.isBaseRuleset) stringList += "Base Ruleset"
@ -428,15 +430,15 @@ class Ruleset {
warningCount++ warningCount++
} }
} }
// eras.isNotEmpty() is only for mod compatibility, it should be removed at some point. if (tech.era() !in eras)
if (eras.isNotEmpty() && tech.era() !in eras)
lines += "Unknown era ${tech.era()} referenced in column of tech ${tech.name}" lines += "Unknown era ${tech.era()} referenced in column of tech ${tech.name}"
} }
if(eras.isEmpty()){ if (eras.isEmpty()) {
lines += "Eras file is empty! This mod will be unusable in the near future!" lines += "Eras file is empty! This will likely lead to crashes. Ask the mod maker to update this mod!"
warningCount++ warningCount++
} }
for (era in eras) { for (era in eras) {
for (wonder in era.value.startingObsoleteWonders) for (wonder in era.value.startingObsoleteWonders)
if (wonder !in buildings) if (wonder !in buildings)

View File

@ -220,7 +220,7 @@ class BaseUnit : INamed, INonPerpetualConstruction, ICivilopediaText {
.any { .any {
matchesFilter(it.params[0]) matchesFilter(it.params[0])
&& cityInfo.matchesFilter(it.params[3]) && cityInfo.matchesFilter(it.params[3])
&& cityInfo.civInfo.getEraNumber() >= ruleset.getEraNumber(it.params[4]) && cityInfo.civInfo.getEraNumber() >= ruleset.eras[it.params[4]]!!.eraNumber
&& it.params[2] == stat.name && it.params[2] == stat.name
} }
) return true ) return true
@ -241,7 +241,7 @@ class BaseUnit : INamed, INonPerpetualConstruction, ICivilopediaText {
.filter { .filter {
matchesFilter(it.params[0]) matchesFilter(it.params[0])
&& cityInfo.matchesFilter(it.params[3]) && cityInfo.matchesFilter(it.params[3])
&& cityInfo.civInfo.getEraNumber() >= ruleset.getEraNumber(it.params[4]) && cityInfo.civInfo.getEraNumber() >= ruleset.eras[it.params[4]]!!.eraNumber
&& it.params[2] == stat.name && it.params[2] == stat.name
}.map { }.map {
getCostForConstructionsIncreasingInPrice( getCostForConstructionsIncreasingInPrice(
@ -334,9 +334,8 @@ class BaseUnit : INamed, INonPerpetualConstruction, ICivilopediaText {
ruleSet.policies.contains(filter) -> ruleSet.policies.contains(filter) ->
if (!civInfo.policies.isAdopted(filter)) if (!civInfo.policies.isAdopted(filter))
rejectionReasons.add(RejectionReason.RequiresPolicy.apply { errorMessage = unique.text }) rejectionReasons.add(RejectionReason.RequiresPolicy.apply { errorMessage = unique.text })
// ToDo: Fix this when eras.json is required ruleSet.eras.contains(filter) ->
ruleSet.getEraNumber(filter) != -1 -> if (civInfo.getEraNumber() < ruleSet.eras[filter]!!.eraNumber)
if (civInfo.getEraNumber() < ruleSet.getEraNumber(filter))
rejectionReasons.add(RejectionReason.UnlockedWithEra.apply { errorMessage = unique.text }) rejectionReasons.add(RejectionReason.UnlockedWithEra.apply { errorMessage = unique.text })
ruleSet.buildings.contains(filter) -> ruleSet.buildings.contains(filter) ->
if (civInfo.cities.none { it.cityConstructions.containsBuildingOrEquivalent(filter) }) if (civInfo.cities.none { it.cityConstructions.containsBuildingOrEquivalent(filter) })
@ -392,7 +391,7 @@ class BaseUnit : INamed, INonPerpetualConstruction, ICivilopediaText {
.any { .any {
matchesFilter(it.params[0]) matchesFilter(it.params[0])
&& cityConstructions.cityInfo.matchesFilter(it.params[3]) && cityConstructions.cityInfo.matchesFilter(it.params[3])
&& cityConstructions.cityInfo.civInfo.getEraNumber() >= ruleset.getEraNumber(it.params[4]) && cityConstructions.cityInfo.civInfo.getEraNumber() >= ruleset.eras[it.params[4]]!!.eraNumber
&& it.params[2] == boughtWith.name && it.params[2] == boughtWith.name
} }
) { ) {

View File

@ -177,6 +177,11 @@ class ModManagementScreen: PickerScreen(disableScroll = true) {
for (repo in repoSearch.items) { for (repo in repoSearch.items) {
if (stopBackgroundTasks) return@postRunnable if (stopBackgroundTasks) return@postRunnable
repo.name = repo.name.replace('-', ' ') repo.name = repo.name.replace('-', ' ')
// Mods we have manually decided to remove for instability are removed here
// If at some later point these mods are updated, we should definitely remove
// this piece of code. This is a band-aid, not a full solution.
if (repo.html_url in modsToHide) continue
modDescriptionsOnline[repo.name] = modDescriptionsOnline[repo.name] =
(repo.description ?: "-{No description provided}-".tr()) + (repo.description ?: "-{No description provided}-".tr()) +
@ -503,4 +508,9 @@ class ModManagementScreen: PickerScreen(disableScroll = true) {
game.setScreen(ModManagementScreen()) game.setScreen(ModManagementScreen())
} }
} }
companion object {
private val blockedModsFile = FileHandle("jsons/ManuallyBlockedMods.json")
val modsToHide = JsonParser().getFromJson(Array<String>::class.java, blockedModsFile)
}
} }

View File

@ -239,7 +239,7 @@ open class TileGroup(var tileInfo: TileInfo, var tileSetStrings:TileSetStrings,
var locationToCheck = baseLocation var locationToCheck = baseLocation
if (tileInfo.owningCity != null) { if (tileInfo.owningCity != null) {
val ownersEra = tileInfo.getOwner()!!.getEra() val ownersEra = tileInfo.getOwner()!!.getEra()
val eraSpecificLocation = tileSetStrings.getString(locationToCheck, tileSetStrings.tag, ownersEra) val eraSpecificLocation = tileSetStrings.getString(locationToCheck, tileSetStrings.tag, ownersEra.name)
if (ImageGetter.imageExists(eraSpecificLocation)) if (ImageGetter.imageExists(eraSpecificLocation))
locationToCheck = eraSpecificLocation locationToCheck = eraSpecificLocation
} }

View File

@ -177,7 +177,7 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
diplomacyTable.add(nextLevelString.toLabel()).row() diplomacyTable.add(nextLevelString.toLabel()).row()
} }
val eraInfo = viewingCiv.getEraObject() ?: Era.getLegacyCityStateBonusEra(viewingCiv.getEraNumber()) val eraInfo = viewingCiv.getEra()
var friendBonusText = "{When Friends:} ".tr() var friendBonusText = "{When Friends:} ".tr()
val friendBonuses = eraInfo.friendBonus[otherCiv.cityStateType.name] val friendBonuses = eraInfo.friendBonus[otherCiv.cityStateType.name]

View File

@ -347,10 +347,7 @@ object ImageGetter {
fun getTechIconGroup(techName: String, circleSize: Float) = getTechIcon(techName).surroundWithCircle(circleSize) fun getTechIconGroup(techName: String, circleSize: Float) = getTechIcon(techName).surroundWithCircle(circleSize)
fun getTechIcon(techName: String): Image { fun getTechIcon(techName: String): Image {
val era = ruleset.technologies[techName]!!.era() val techIconColor = ruleset.eras[ruleset.technologies[techName]!!.era()]!!.getColor()
val techIconColor =
if (era !in ruleset.eras) Era().getColor()
else ruleset.eras[ruleset.technologies[techName]!!.era()]!!.getColor()
return getImage("TechIcons/$techName").apply { color = techIconColor.lerp(Color.BLACK, 0.6f) } return getImage("TechIcons/$techName").apply { color = techIconColor.lerp(Color.BLACK, 0.6f) }
} }

View File

@ -49,6 +49,7 @@ class SerializationTests {
players.add(Player("Rome").apply { playerType = PlayerType.Human }) players.add(Player("Rome").apply { playerType = PlayerType.Human })
players.add(Player("Greece")) players.add(Player("Greece"))
religionEnabled = true religionEnabled = true
startingEra = "Ancient era"
} }
val mapParameters = MapParameters().apply { val mapParameters = MapParameters().apply {
mapSize = MapSizeNew(MapSize.Tiny) mapSize = MapSizeNew(MapSize.Tiny)