diff --git a/android/assets/jsons/translations/template.properties b/android/assets/jsons/translations/template.properties index 9b1bc4424c..6bfc134acc 100644 --- a/android/assets/jsons/translations/template.properties +++ b/android/assets/jsons/translations/template.properties @@ -492,6 +492,8 @@ Invalid map: Area ([area]) does not match saved dimensions ([dimensions]). = The dimensions have now been fixed for you. = River generation failed! = Please don't use step 'Landmass' with map type 'Empty', create a new empty map instead. = +This map has errors: = +The incompatible elements have been removed. = ## Map/Tool names My new map = @@ -1183,6 +1185,8 @@ Base terrain [terrain] does not exist in ruleset! = Terrain feature [feature] does not exist in ruleset! = Resource [resource] does not exist in ruleset! = Improvement [improvement] does not exist in ruleset! = +Nation [nation] does not exist in ruleset! = +Natural Wonder [naturalWonder] does not exist in ruleset! = # Civilopedia difficulty levels Player settings = diff --git a/core/src/com/unciv/logic/GameInfo.kt b/core/src/com/unciv/logic/GameInfo.kt index e933afd93e..14ee8e2534 100644 --- a/core/src/com/unciv/logic/GameInfo.kt +++ b/core/src/com/unciv/logic/GameInfo.kt @@ -393,8 +393,8 @@ class GameInfo { gameParameters.mods = LinkedHashSet(gameParameters.mods.filter { it != baseRulesetInMods }) } - ruleSet = RulesetCache.getComplexRuleset(gameParameters.mods, gameParameters.baseRuleset) - + ruleSet = RulesetCache.getComplexRuleset(gameParameters) + // any mod the saved game lists that is currently not installed causes null pointer // exceptions in this routine unless it contained no new objects or was very simple. // Player's fault, so better complain early: diff --git a/core/src/com/unciv/logic/GameStarter.kt b/core/src/com/unciv/logic/GameStarter.kt index a5c2e64f08..d35eb18548 100644 --- a/core/src/com/unciv/logic/GameStarter.kt +++ b/core/src/com/unciv/logic/GameStarter.kt @@ -43,7 +43,7 @@ object GameStarter { gameSetupInfo.gameParameters.baseRuleset = RulesetCache.getVanillaRuleset().name gameInfo.gameParameters = gameSetupInfo.gameParameters - val ruleset = RulesetCache.getComplexRuleset(gameInfo.gameParameters.mods, gameInfo.gameParameters.baseRuleset) + val ruleset = RulesetCache.getComplexRuleset(gameInfo.gameParameters) val mapGen = MapGenerator(ruleset) if (gameSetupInfo.mapParameters.name != "") runAndMeasure("loadMap") { diff --git a/core/src/com/unciv/models/ruleset/Ruleset.kt b/core/src/com/unciv/models/ruleset/Ruleset.kt index a115d91931..deaee29f06 100644 --- a/core/src/com/unciv/models/ruleset/Ruleset.kt +++ b/core/src/com/unciv/models/ruleset/Ruleset.kt @@ -7,9 +7,11 @@ import com.unciv.Constants import com.unciv.JsonParser import com.unciv.logic.BackwardCompatibility.updateDeprecations import com.unciv.logic.UncivShowableException +import com.unciv.logic.map.MapParameters import com.unciv.models.Counter import com.unciv.models.ModConstants import com.unciv.models.metadata.BaseRuleset +import com.unciv.models.metadata.GameParameters import com.unciv.models.ruleset.tech.TechColumn import com.unciv.models.ruleset.tech.Technology import com.unciv.models.ruleset.tile.Terrain @@ -909,10 +911,19 @@ object RulesetCache : HashMap() { ) ) } - + + /** Creates a combined [Ruleset] from a list of mods contained in [parameters]. */ + fun getComplexRuleset(parameters: MapParameters) = + getComplexRuleset(parameters.mods, parameters.baseRuleset) + + /** Creates a combined [Ruleset] from a list of mods contained in [parameters]. */ + fun getComplexRuleset(parameters: GameParameters) = + getComplexRuleset(parameters.mods, parameters.baseRuleset) + /** - * Creates a combined [Ruleset] from a list of mods. If no baseRuleset is listed in [mods], - * then the vanilla Ruleset is included automatically. + * Creates a combined [Ruleset] from a list of mods. + * If no baseRuleset is passed in [optionalBaseRuleset] (or a non-existing one), then the vanilla Ruleset is included automatically. + * Any mods in the [mods] parameter marked as base ruleset (or not loaded in [RulesetCache]) are ignored. */ fun getComplexRuleset(mods: LinkedHashSet, optionalBaseRuleset: String? = null): Ruleset { val newRuleset = Ruleset() diff --git a/core/src/com/unciv/ui/mapeditor/GameParametersScreen.kt b/core/src/com/unciv/ui/mapeditor/GameParametersScreen.kt index 52bd5576ed..be02a29a41 100644 --- a/core/src/com/unciv/ui/mapeditor/GameParametersScreen.kt +++ b/core/src/com/unciv/ui/mapeditor/GameParametersScreen.kt @@ -25,5 +25,5 @@ import com.unciv.ui.utils.* @Deprecated("As of 4.0.x") class GameParametersScreen(var mapEditorScreen: MapEditorScreen): IPreviousScreen, PickerScreen(disableScroll = true) { override var gameSetupInfo = GameSetupInfo(mapParameters = mapEditorScreen.newMapParameters) - override var ruleset = RulesetCache.getComplexRuleset(gameSetupInfo.gameParameters.mods, gameSetupInfo.gameParameters.baseRuleset) + override var ruleset = RulesetCache.getComplexRuleset(gameSetupInfo.gameParameters) } diff --git a/core/src/com/unciv/ui/mapeditor/MapEditorEditTab.kt b/core/src/com/unciv/ui/mapeditor/MapEditorEditTab.kt index 23f208abfb..720fedf324 100644 --- a/core/src/com/unciv/ui/mapeditor/MapEditorEditTab.kt +++ b/core/src/com/unciv/ui/mapeditor/MapEditorEditTab.kt @@ -62,7 +62,7 @@ class MapEditorEditTab( Improvements("Improvements", 'i', "OtherIcons/Improvements", { parent, ruleset -> MapEditorEditImprovementsTab(parent, ruleset) }), Rivers("Rivers", 'v', "OtherIcons/Star", { parent, ruleset -> MapEditorEditRiversTab(parent, ruleset) }), StartingLocations("Starting locations", 's', "OtherIcons/Nations", { parent, ruleset -> MapEditorEditStartsTab(parent, ruleset) }), - Units("Units", 'u', "OtherIcons/Shield", { parent, ruleset -> MapEditorEditUnitsTab(parent, ruleset) }), + // Units("Units", 'u', "OtherIcons/Shield", { parent, ruleset -> MapEditorEditUnitsTab(parent, ruleset) }), } init { diff --git a/core/src/com/unciv/ui/mapeditor/MapEditorFilesTable.kt b/core/src/com/unciv/ui/mapeditor/MapEditorFilesTable.kt index 16a4c63af3..4e2741c691 100644 --- a/core/src/com/unciv/ui/mapeditor/MapEditorFilesTable.kt +++ b/core/src/com/unciv/ui/mapeditor/MapEditorFilesTable.kt @@ -93,13 +93,13 @@ class MapEditorFilesTable( layout() } - fun noMapsAvailable(includeMods: Boolean = false): Boolean { - if (MapSaver.getMaps().any()) return true - if (!includeMods) return false + fun noMapsAvailable(): Boolean { + if (MapSaver.getMaps().any()) return false + if (!includeMods) return true for (modFolder in RulesetCache.values.mapNotNull { it.folderLocation }) { val mapsFolder = modFolder.child(MapSaver.mapsFolder) - if (mapsFolder.exists() && mapsFolder.list().any()) return true + if (mapsFolder.exists() && mapsFolder.list().any()) return false } - return false + return true } } diff --git a/core/src/com/unciv/ui/mapeditor/MapEditorGenerateTab.kt b/core/src/com/unciv/ui/mapeditor/MapEditorGenerateTab.kt index 558edecd31..d892b88287 100644 --- a/core/src/com/unciv/ui/mapeditor/MapEditorGenerateTab.kt +++ b/core/src/com/unciv/ui/mapeditor/MapEditorGenerateTab.kt @@ -103,7 +103,7 @@ class MapEditorGenerateTab( try { val (newRuleset, generator) = if (step > MapGeneratorSteps.Landmass) null to null else { - val newRuleset = RulesetCache.getComplexRuleset(mapParameters.mods, mapParameters.baseRuleset) + val newRuleset = RulesetCache.getComplexRuleset(mapParameters) newRuleset to MapGenerator(newRuleset) } when (step) { diff --git a/core/src/com/unciv/ui/mapeditor/MapEditorLoadTab.kt b/core/src/com/unciv/ui/mapeditor/MapEditorLoadTab.kt index dc282619d6..670a08e4a0 100644 --- a/core/src/com/unciv/ui/mapeditor/MapEditorLoadTab.kt +++ b/core/src/com/unciv/ui/mapeditor/MapEditorLoadTab.kt @@ -100,8 +100,8 @@ class MapEditorLoadTab( val newBaseRuleset = map.mapParameters.mods.filter { it !in missingMods }.firstOrNull { RulesetCache[it]!!.modOptions.isBaseRuleset } if (newBaseRuleset != null) map.mapParameters.baseRuleset = newBaseRuleset // - if (map.mapParameters.baseRuleset !in RulesetCache) missingMods += map.mapParameters.baseRuleset + if (missingMods.isNotEmpty()) { Gdx.app.postRunnable { needPopup = false @@ -118,7 +118,17 @@ class MapEditorLoadTab( map.mapParameters.mods -= modBaseRuleset } - editorScreen.loadMap(map) + val ruleset = RulesetCache.getComplexRuleset(map.mapParameters) + val rulesetIncompatibilities = map.getRulesetIncompatibility(ruleset) + if (rulesetIncompatibilities.isNotEmpty()) { + map.removeMissingTerrainModReferences(ruleset) + val message = "{This map has errors:}\n\n".tr() + + rulesetIncompatibilities.sorted().joinToString("\n") { it.tr() } + + "\n\n{The incompatible elements have been removed.}" + ToastPopup(message, editorScreen, 4000L) + } + + editorScreen.loadMap(map, ruleset) needPopup = false popup?.close() } catch (ex: Throwable) { diff --git a/core/src/com/unciv/ui/mapeditor/MapEditorScreen.kt b/core/src/com/unciv/ui/mapeditor/MapEditorScreen.kt index 10951a61e5..c18faadd53 100644 --- a/core/src/com/unciv/ui/mapeditor/MapEditorScreen.kt +++ b/core/src/com/unciv/ui/mapeditor/MapEditorScreen.kt @@ -20,7 +20,7 @@ import com.unciv.ui.utils.* //todo normalize properly -//todo functional Tab for Units +//todo functional Tab for Units (empty Tab is prepared but commented out in MapEditorEditTab.AllEditSubTabs) //todo copy/paste tile areas? (As tool tab, brush sized, floodfill forbidden, tab displays copied area) //todo Synergy with Civilopedia for drawing loose tiles / terrain icons //todo left-align everything so a half-open drawer is more useful @@ -38,7 +38,6 @@ import com.unciv.ui.utils.* //todo "random nation" starting location (maybe no new internal representation = all major nations) //todo Nat Wonder step generator: Needs tweaks to avoid placing duplicates or wonders too close together //todo Music? Different suffix? Off? 20% Volume? -//todo Unciv Europe Map Example - does not load due to "Gold / Gold ore": Solve problem that multiple errors are not shown nicely, and re-enable fixing the map and displaying it //todo See #6610 - re-layout after the map size dropdown changes to custom and new widgets are inserted - can reach "Create" only by dragging the _header_ of the sub-TabbedPager class MapEditorScreen(map: TileMap? = null): BaseScreen() { @@ -76,8 +75,7 @@ class MapEditorScreen(map: TileMap? = null): BaseScreen() { mapParameters.mapSize = MapSizeNew(MapSize.Tiny) } } else { - ruleset = map.ruleset ?: - RulesetCache.getComplexRuleset(map.mapParameters.mods, map.mapParameters.baseRuleset) + ruleset = map.ruleset ?: RulesetCache.getComplexRuleset(map.mapParameters) tileMap = map } @@ -148,8 +146,7 @@ class MapEditorScreen(map: TileMap? = null): BaseScreen() { mapHolder.remove() tileMap = map checkAndFixMapSize() - ruleset = newRuleset ?: - RulesetCache.getComplexRuleset(map.mapParameters.mods, map.mapParameters.baseRuleset) + ruleset = newRuleset ?: RulesetCache.getComplexRuleset(map.mapParameters) mapHolder = newMapHolder() isDirty = false Gdx.input.inputProcessor = stage diff --git a/core/src/com/unciv/ui/newgamescreen/GameOptionsTable.kt b/core/src/com/unciv/ui/newgamescreen/GameOptionsTable.kt index 8245e14ad1..c30b04244b 100644 --- a/core/src/com/unciv/ui/newgamescreen/GameOptionsTable.kt +++ b/core/src/com/unciv/ui/newgamescreen/GameOptionsTable.kt @@ -252,12 +252,12 @@ class GameOptionsTable( fun reloadRuleset() { ruleset.clear() - val newRuleset = RulesetCache.getComplexRuleset(gameParameters.mods, gameParameters.baseRuleset) + val newRuleset = RulesetCache.getComplexRuleset(gameParameters) ruleset.add(newRuleset) ruleset.mods += gameParameters.baseRuleset ruleset.mods += gameParameters.mods ruleset.modOptions = newRuleset.modOptions - + ImageGetter.setNewRuleset(ruleset) UncivGame.Current.musicController.setModList(gameParameters.getModsAndBaseRuleset()) } @@ -267,7 +267,7 @@ class GameOptionsTable( onChooseMod(it) } } - + private fun onChooseMod(mod: String) { val activeMods: LinkedHashSet = LinkedHashSet(gameParameters.getModsAndBaseRuleset()) UncivGame.Current.translations.translationActiveMods = activeMods diff --git a/core/src/com/unciv/ui/newgamescreen/NewGameScreen.kt b/core/src/com/unciv/ui/newgamescreen/NewGameScreen.kt index 860f7076e0..1086f7607d 100644 --- a/core/src/com/unciv/ui/newgamescreen/NewGameScreen.kt +++ b/core/src/com/unciv/ui/newgamescreen/NewGameScreen.kt @@ -33,7 +33,7 @@ class NewGameScreen( ): IPreviousScreen, PickerScreen() { override val gameSetupInfo = _gameSetupInfo ?: GameSetupInfo.fromSettings() - override var ruleset = RulesetCache.getComplexRuleset(gameSetupInfo.gameParameters.mods, gameSetupInfo.gameParameters.baseRuleset) // needs to be set because the GameOptionsTable etc. depend on this + override var ruleset = RulesetCache.getComplexRuleset(gameSetupInfo.gameParameters) // needs to be set because the GameOptionsTable etc. depend on this private val newGameOptionsTable: GameOptionsTable private val playerPickerTable: PlayerPickerTable private val mapOptionsTable: MapOptionsTable @@ -256,7 +256,7 @@ class NewGameScreen( fun updateRuleset() { ruleset.clear() - ruleset.add(RulesetCache.getComplexRuleset(gameSetupInfo.gameParameters.mods, gameSetupInfo.gameParameters.baseRuleset)) + ruleset.add(RulesetCache.getComplexRuleset(gameSetupInfo.gameParameters)) ImageGetter.setNewRuleset(ruleset) game.musicController.setModList(gameSetupInfo.gameParameters.getModsAndBaseRuleset()) }