mirror of
https://github.com/yairm210/Unciv.git
synced 2025-02-11 11:28:03 +07:00
Caught more mod failure conditions, removed certain assumptions from map creation (#6076)
* Caught more mod failure conditions, removed certain assumptions from map creation * Military unit in Era can be "Era Specific Unit" * Resolved #6078 - even more ruleset assumptions removed :) * We now catch missing military units from the difficulties as well, as well as missing settler and worker units from eras
This commit is contained in:
parent
499b5e5b2f
commit
9674ddf04e
@ -306,7 +306,7 @@ object GameStarter {
|
||||
fun getEquivalentUnit(civ: CivilizationInfo, unitParam: String): String? {
|
||||
var unit = unitParam // We want to change it and this is the easiest way to do so
|
||||
if (unit == Constants.eraSpecificUnit) unit = eraUnitReplacement
|
||||
if (unit == "Settler" && "Settler" !in ruleSet.units) {
|
||||
if (unit == Constants.settler && Constants.settler !in ruleSet.units) {
|
||||
val buildableSettlerLikeUnits =
|
||||
settlerLikeUnits.filter {
|
||||
it.value.isBuildable(civ)
|
||||
|
@ -266,7 +266,10 @@ class CivilizationInfo {
|
||||
//region pure functions
|
||||
fun getDifficulty(): Difficulty {
|
||||
if (isPlayerCivilization()) return gameInfo.getDifficulty()
|
||||
return gameInfo.ruleSet.difficulties["Chieftain"]!!
|
||||
// TODO We should be able to mark a difficulty as 'default AI difficulty' somehow
|
||||
val chieftainDifficulty = gameInfo.ruleSet.difficulties["Chieftain"]
|
||||
if (chieftainDifficulty != null) return chieftainDifficulty
|
||||
return gameInfo.ruleSet.difficulties.values.first()
|
||||
}
|
||||
|
||||
fun getDiplomacyManager(civInfo: CivilizationInfo) = getDiplomacyManager(civInfo.civName)
|
||||
|
@ -23,6 +23,7 @@ class MapGenerator(val ruleset: Ruleset) {
|
||||
}
|
||||
|
||||
private var randomness = MapGenerationRandomness()
|
||||
private val firstLandTerrain = ruleset.terrains.values.first { it.type==TerrainType.Land }
|
||||
|
||||
fun generateMap(mapParameters: MapParameters, civilizations: List<CivilizationInfo> = emptyList()): TileMap {
|
||||
val mapSize = mapParameters.mapSize
|
||||
@ -406,7 +407,7 @@ class MapGenerator(val ruleset: Ruleset) {
|
||||
temperature <= 1.0 -> if (humidity < 0.7) Constants.desert else Constants.plains
|
||||
else -> {
|
||||
println("applyHumidityAndTemperature: Invalid temperature $temperature")
|
||||
Constants.grassland
|
||||
firstLandTerrain.name
|
||||
}
|
||||
}
|
||||
if (ruleset.terrains.containsKey(autoTerrain)) tile.baseTerrain = autoTerrain
|
||||
@ -421,7 +422,7 @@ class MapGenerator(val ruleset: Ruleset) {
|
||||
|
||||
if (matchingTerrain != null) tile.baseTerrain = matchingTerrain.terrain.name
|
||||
else {
|
||||
tile.baseTerrain = ruleset.terrains.values.firstOrNull { it.type == TerrainType.Land }?.name ?: Constants.grassland
|
||||
tile.baseTerrain = firstLandTerrain.name
|
||||
println("applyHumidityAndTemperature: No terrain found for temperature: $temperature, humidity: $humidity")
|
||||
}
|
||||
tile.setTerrainTransients()
|
||||
|
@ -11,11 +11,14 @@ import kotlin.math.pow
|
||||
|
||||
class MapLandmassGenerator(val ruleset: Ruleset, val randomness: MapGenerationRandomness) {
|
||||
|
||||
private val firstLandTerrain = ruleset.terrains.values.first { it.type==TerrainType.Land }
|
||||
private val firstWaterTerrain = ruleset.terrains.values.firstOrNull { it.type==TerrainType.Water }
|
||||
|
||||
fun generateLand(tileMap: TileMap) {
|
||||
// This is to accommodate land-only mods
|
||||
if (ruleset.terrains.values.none { it.type == TerrainType.Water }) {
|
||||
if (firstWaterTerrain==null) {
|
||||
for (tile in tileMap.values)
|
||||
tile.baseTerrain = ruleset.terrains.keys.first()
|
||||
tile.baseTerrain = firstLandTerrain.name
|
||||
return
|
||||
}
|
||||
|
||||
@ -32,8 +35,8 @@ class MapLandmassGenerator(val ruleset: Ruleset, val randomness: MapGenerationRa
|
||||
|
||||
private fun spawnLandOrWater(tile: TileInfo, elevation: Double, threshold: Double) {
|
||||
when {
|
||||
elevation < threshold -> tile.baseTerrain = Constants.ocean
|
||||
else -> tile.baseTerrain = Constants.grassland
|
||||
elevation < threshold -> tile.baseTerrain = firstWaterTerrain!!.name
|
||||
else -> tile.baseTerrain = firstLandTerrain.name
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1449,7 +1449,12 @@ class MapRegions (val ruleset: Ruleset){
|
||||
val resourceUnique = ruleset.terrains[terrain]!!.getMatchingUniques(UniqueType.RegionExtraResource).firstOrNull()
|
||||
// If this region has an explicit "this is the bonus" unique go with that, else random appropriate
|
||||
val resource = if (resourceUnique != null) ruleset.tileResources[resourceUnique.params[0]]!!
|
||||
else ruleset.tileResources.values.filter { it.resourceType == ResourceType.Bonus && terrain in it.terrainsCanBeFoundOn }.random()
|
||||
else {
|
||||
val possibleResources =
|
||||
ruleset.tileResources.values.filter { it.resourceType == ResourceType.Bonus && terrain in it.terrainsCanBeFoundOn }
|
||||
if (possibleResources.isEmpty()) continue
|
||||
possibleResources.random()
|
||||
}
|
||||
val candidateTiles = tileMap[region.startPosition!!].getTilesAtDistance(3).shuffled()
|
||||
val amount = if (resourceUnique != null) 2 else 1 // Place an extra if the region type requests it
|
||||
if (tryAddingResourceToTiles(resource, amount, candidateTiles) == 0) {
|
||||
@ -1728,10 +1733,9 @@ class Region (val tileMap: TileMap, val rect: Rectangle, val continentID: Int =
|
||||
for (tile in tileMap.getTilesInRectangle(rect, evenQ = true).filter {
|
||||
continentID == -1 || it.getContinent() == continentID } ) {
|
||||
val fertility = tile.getTileFertility(continentID != -1)
|
||||
if (fertility != 0) { // If fertility is 0 this is candidate for trimming
|
||||
tiles.add(tile)
|
||||
totalFertility += fertility
|
||||
}
|
||||
tiles.add(tile)
|
||||
totalFertility += fertility
|
||||
|
||||
|
||||
if (affectedByWorldWrap)
|
||||
columnHasTile.add(HexMath.hex2EvenQCoords(tile.position).x.toInt())
|
||||
|
@ -2,6 +2,7 @@ package com.unciv.models.ruleset
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.files.FileHandle
|
||||
import com.unciv.Constants
|
||||
import com.unciv.JsonParser
|
||||
import com.unciv.logic.UncivShowableException
|
||||
import com.unciv.models.Counter
|
||||
@ -10,6 +11,7 @@ import com.unciv.models.metadata.BaseRuleset
|
||||
import com.unciv.models.ruleset.tech.TechColumn
|
||||
import com.unciv.models.ruleset.tech.Technology
|
||||
import com.unciv.models.ruleset.tile.Terrain
|
||||
import com.unciv.models.ruleset.tile.TerrainType
|
||||
import com.unciv.models.ruleset.tile.TileImprovement
|
||||
import com.unciv.models.ruleset.tile.TileResource
|
||||
import com.unciv.models.ruleset.unique.Unique
|
||||
@ -20,7 +22,6 @@ import com.unciv.models.ruleset.unit.Promotion
|
||||
import com.unciv.models.ruleset.unit.UnitType
|
||||
import com.unciv.models.stats.INamed
|
||||
import com.unciv.models.stats.NamedStats
|
||||
import com.unciv.models.stats.Stat
|
||||
import com.unciv.models.stats.Stats
|
||||
import com.unciv.models.translations.fillPlaceholders
|
||||
import com.unciv.models.translations.tr
|
||||
@ -481,7 +482,11 @@ class Ruleset {
|
||||
// Quit here when no base ruleset is loaded - references cannot be checked
|
||||
if (!modOptions.isBaseRuleset) return lines
|
||||
|
||||
val baseRuleset = RulesetCache.getVanillaRuleset() // for UnitTypes fallback
|
||||
val vanillaRuleset = RulesetCache.getVanillaRuleset() // for UnitTypes fallback
|
||||
|
||||
|
||||
if (units.values.none { it.uniques.contains(UniqueType.FoundCity.text) })
|
||||
lines += "No city-founding units in ruleset!"
|
||||
|
||||
for (unit in units.values) {
|
||||
if (unit.requiredTech != null && !technologies.containsKey(unit.requiredTech!!))
|
||||
@ -498,7 +503,7 @@ class Ruleset {
|
||||
for (promotion in unit.promotions)
|
||||
if (!unitPromotions.containsKey(promotion))
|
||||
lines += "${unit.name} contains promotion $promotion which does not exist!"
|
||||
if (!unitTypes.containsKey(unit.unitType) && (unitTypes.isNotEmpty() || !baseRuleset.unitTypes.containsKey(unit.unitType)))
|
||||
if (!unitTypes.containsKey(unit.unitType) && (unitTypes.isNotEmpty() || !vanillaRuleset.unitTypes.containsKey(unit.unitType)))
|
||||
lines += "${unit.name} is of type ${unit.unitType}, which does not exist!"
|
||||
for (unique in unit.getMatchingUniques(UniqueType.ConstructImprovementConsumingUnit)) {
|
||||
val improvementName = unique.params[0]
|
||||
@ -557,6 +562,8 @@ class Ruleset {
|
||||
checkUniques(improvement, lines, UniqueType.UniqueComplianceErrorSeverity.RulesetSpecific)
|
||||
}
|
||||
|
||||
if (terrains.values.none { it.type==TerrainType.Land && !it.impassable })
|
||||
lines += "No passable land terrains exist!"
|
||||
for (terrain in terrains.values) {
|
||||
for (baseTerrain in terrain.occursOn)
|
||||
if (!terrains.containsKey(baseTerrain))
|
||||
@ -597,6 +604,13 @@ class Ruleset {
|
||||
lines += "Eras file is empty! This will likely lead to crashes. Ask the mod maker to update this mod!"
|
||||
}
|
||||
|
||||
val allDifficultiesStartingUnits = hashSetOf<String>()
|
||||
for (difficulty in difficulties.values){
|
||||
allDifficultiesStartingUnits.addAll(difficulty.aiCityStateBonusStartingUnits)
|
||||
allDifficultiesStartingUnits.addAll(difficulty.aiMajorCivBonusStartingUnits)
|
||||
allDifficultiesStartingUnits.addAll(difficulty.playerBonusStartingUnits)
|
||||
}
|
||||
|
||||
for (era in eras.values) {
|
||||
for (wonder in era.startingObsoleteWonders)
|
||||
if (wonder !in buildings)
|
||||
@ -604,7 +618,13 @@ class Ruleset {
|
||||
for (building in era.settlerBuildings)
|
||||
if (building !in buildings)
|
||||
lines += "Nonexistent building $building built by settlers when starting in ${era.name}"
|
||||
if (era.startingMilitaryUnit !in units)
|
||||
// todo the whole 'starting unit' thing needs to be redone, there's no reason we can't have a single list containing all the starting units.
|
||||
if (era.startingSettlerUnit !in units && (era.startingSettlerUnit!=Constants.settler || units.values.none { it.hasUnique(UniqueType.FoundCity) }))
|
||||
lines += "Nonexistent unit ${era.startingSettlerUnit} marked as starting unit when starting in ${era.name}"
|
||||
if (era.startingWorkerCount!=0 && era.startingWorkerUnit !in units)
|
||||
lines += "Nonexistent unit ${era.startingWorkerUnit} marked as starting unit when starting in ${era.name}"
|
||||
|
||||
if ((era.startingMilitaryUnitCount !=0 || allDifficultiesStartingUnits.contains(Constants.eraSpecificUnit)) && era.startingMilitaryUnit !in units)
|
||||
lines += "Nonexistent unit ${era.startingMilitaryUnit} marked as starting unit when starting in ${era.name}"
|
||||
if (era.researchAgreementCost < 0 || era.startingSettlerCount < 0 || era.startingWorkerCount < 0 || era.startingMilitaryUnitCount < 0 || era.startingGold < 0 || era.startingCulture < 0)
|
||||
lines += "Unexpected negative number found while parsing era ${era.name}"
|
||||
@ -621,7 +641,7 @@ class Ruleset {
|
||||
if (nation.favoredReligion != null && nation.favoredReligion !in religions)
|
||||
lines += "${nation.name} has ${nation.favoredReligion} as their favored religion, which does not exist!"
|
||||
}
|
||||
|
||||
|
||||
for (policy in policies.values) {
|
||||
if (policy.requires != null)
|
||||
for (prereq in policy.requires!!)
|
||||
@ -641,14 +661,19 @@ class Ruleset {
|
||||
if (!unitPromotions.containsKey(prereq))
|
||||
lines.add("${promotion.name} requires promotion $prereq which does not exist!", RulesetErrorSeverity.Warning)
|
||||
for (unitType in promotion.unitTypes)
|
||||
if (!unitTypes.containsKey(unitType) && (unitTypes.isNotEmpty() || !baseRuleset.unitTypes.containsKey(unitType)))
|
||||
if (!unitTypes.containsKey(unitType) && (unitTypes.isNotEmpty() || !vanillaRuleset.unitTypes.containsKey(unitType)))
|
||||
lines.add("${promotion.name} references unit type $unitType, which does not exist!", RulesetErrorSeverity.Warning)
|
||||
checkUniques(promotion, lines, UniqueType.UniqueComplianceErrorSeverity.RulesetSpecific)
|
||||
}
|
||||
for (unitType in unitTypes.values) {
|
||||
checkUniques(unitType, lines, UniqueType.UniqueComplianceErrorSeverity.RulesetSpecific)
|
||||
}
|
||||
|
||||
|
||||
for (difficulty in difficulties.values)
|
||||
for (unitName in difficulty.aiCityStateBonusStartingUnits + difficulty.aiMajorCivBonusStartingUnits + difficulty.playerBonusStartingUnits)
|
||||
if (unitName!=Constants.eraSpecificUnit && !units.containsKey(unitName))
|
||||
lines += "Difficulty ${difficulty.name} contains starting unit $unitName which does not exist!"
|
||||
|
||||
if (modOptions.maxXPfromBarbarians != 30) {
|
||||
lines.add("maxXPfromBarbarians is moved to the constants object, instead use: \nconstants: {\n maxXPfromBarbarians: ${modOptions.maxXPfromBarbarians},\n}", RulesetErrorSeverity.Warning)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user