diff --git a/android/assets/jsons/Civ V - Vanilla/Buildings.json b/android/assets/jsons/Civ V - Vanilla/Buildings.json index 90a313bffa..4a2fb7e723 100644 --- a/android/assets/jsons/Civ V - Vanilla/Buildings.json +++ b/android/assets/jsons/Civ V - Vanilla/Buildings.json @@ -908,7 +908,7 @@ "name": "SS Booster", "requiredResource": "Aluminum", "requiredTech": "Robotics", - "uniques": ["Spaceship part"] + "uniques": ["Spaceship part", "Cannot be purchased"] }, { "name": "Apollo Program", @@ -935,18 +935,18 @@ "name": "SS Cockpit", "requiredResource": "Aluminum", "requiredTech": "Satellites", - "uniques": ["Spaceship part"] + "uniques": ["Spaceship part", "Cannot be purchased"] }, { "name": "SS Engine", "requiredResource": "Aluminum", "requiredTech": "Particle Physics", - "uniques": ["Spaceship part"] + "uniques": ["Spaceship part", "Cannot be purchased"] }, { "name": "SS Stasis Chamber", "requiredResource": "Aluminum", "requiredTech": "Nanotechnology", - "uniques": ["Spaceship part"] + "uniques": ["Spaceship part", "Cannot be purchased"] } ] diff --git a/android/assets/jsons/Civ V - Vanilla/Difficulties.json b/android/assets/jsons/Civ V - Vanilla/Difficulties.json index 6228790146..fb34d3139f 100644 --- a/android/assets/jsons/Civ V - Vanilla/Difficulties.json +++ b/android/assets/jsons/Civ V - Vanilla/Difficulties.json @@ -9,6 +9,7 @@ "policyCostModifier": 0.5, "unhappinessModifier": 0.4, "barbarianBonus": 0.75, + "startingUnits": ["Settler", "Warrior"], "aiCityGrowthModifier": 1.6, // that is to say it'll take them 1.6 times as long to grow the city "aiUnitCostModifier": 1.75, "aiBuildingCostModifier": 1.6, @@ -16,7 +17,8 @@ "aiBuildingMaintenanceModifier": 1, "aiUnitMaintenanceModifier": 1, "aiFreeTechs": [], - "aiFreeUnits": [], + "aiMajorCivStartingUnits": ["Settler", "Warrior"], + "aiCityStateStartingUnits": ["Settler", "Warrior"], "aiUnhappinessModifier": 1, "aisExchangeTechs": false, "turnBarbariansCanEnterPlayerTiles": 10000, @@ -32,6 +34,7 @@ "policyCostModifier": 0.67, "unhappinessModifier": 0.6, "barbarianBonus": 0.5, + "startingUnits": ["Settler", "Warrior"], "aiCityGrowthModifier": 1.3, "aiUnitCostModifier": 1.3, "aiBuildingCostModifier": 1.3, @@ -39,7 +42,8 @@ "aiBuildingMaintenanceModifier": 1, "aiUnitMaintenanceModifier": 1, "aiFreeTechs": [], - "aiFreeUnits": [], + "aiMajorCivStartingUnits": ["Settler", "Warrior"], + "aiCityStateStartingUnits": ["Settler", "Warrior"], "aiUnhappinessModifier": 1, "aisExchangeTechs": false, "turnBarbariansCanEnterPlayerTiles": 60, @@ -55,6 +59,7 @@ "policyCostModifier": 0.85, "unhappinessModifier": 0.75, "barbarianBonus": 0.4, + "startingUnits": ["Settler", "Warrior"], "aiCityGrowthModifier": 1.1, "aiUnitCostModifier": 1.1, "aiBuildingCostModifier": 1.1, @@ -62,7 +67,8 @@ "aiBuildingMaintenanceModifier": 1, "aiUnitMaintenanceModifier": 1, "aiFreeTechs": [], - "aiFreeUnits": [], + "aiMajorCivStartingUnits": ["Settler", "Warrior"], + "aiCityStateStartingUnits": ["Settler", "Warrior"], "aiUnhappinessModifier": 1, "aisExchangeTechs": false, "turnBarbariansCanEnterPlayerTiles": 20, @@ -78,6 +84,7 @@ "policyCostModifier": 1, "unhappinessModifier": 1, "barbarianBonus": 0.33, + "startingUnits": ["Settler", "Warrior"], "aiCityGrowthModifier": 1, "aiUnitCostModifier": 1, "aiBuildingCostModifier": 1, @@ -85,7 +92,8 @@ "aiBuildingMaintenanceModifier": 1, "aiUnitMaintenanceModifier": 0.85, "aiFreeTechs": [], - "aiFreeUnits": [], + "aiMajorCivStartingUnits": ["Settler", "Warrior"], + "aiCityStateStartingUnits": ["Settler", "Warrior"], "aiUnhappinessModifier": 1, "aisExchangeTechs": true, "turnBarbariansCanEnterPlayerTiles": 0, @@ -101,6 +109,7 @@ "policyCostModifier": 1, "unhappinessModifier": 1, "barbarianBonus": 0.25, + "startingUnits": ["Settler", "Warrior"], "aiCityGrowthModifier": 0.9, "aiUnitCostModifier": 0.85, "aiBuildingCostModifier": 0.85, @@ -108,7 +117,8 @@ "aiBuildingMaintenanceModifier": 0.85, "aiUnitMaintenanceModifier": 0.8, "aiFreeTechs": ["Pottery"], - "aiFreeUnits": ["Warrior"], + "aiMajorCivStartingUnits": ["Settler", "Warrior", "Warrior"], + "aiCityStateStartingUnits": ["Settler", "Warrior"], "aiUnhappinessModifier": 0.9, "aisExchangeTechs": true, "turnBarbariansCanEnterPlayerTiles": 0, @@ -124,6 +134,7 @@ "policyCostModifier": 1, "unhappinessModifier": 1, "barbarianBonus": 0.2, + "startingUnits": ["Settler", "Warrior"], "aiCityGrowthModifier": 0.85, "aiUnitCostModifier": 0.8, "aiBuildingCostModifier": 0.8, @@ -131,7 +142,8 @@ "aiBuildingMaintenanceModifier": 0.8, "aiUnitMaintenanceModifier": 0.75, "aiFreeTechs": ["Pottery","Animal Husbandry"], - "aiFreeUnits": ["Warrior", "Scout"], + "aiMajorCivStartingUnits": ["Settler", "Warrior", "Warrior", "Scout"], + "aiCityStateStartingUnits": ["Settler", "Warrior"], "aiUnhappinessModifier": 0.85, "aisExchangeTechs": true, "turnBarbariansCanEnterPlayerTiles": 0, @@ -147,6 +159,7 @@ "policyCostModifier": 1, "unhappinessModifier": 1, "barbarianBonus": 0.1, + "startingUnits": ["Settler", "Warrior"], "aiCityGrowthModifier": 0.75, "aiUnitCostModifier": 0.65, "aiBuildingCostModifier": 0.65, @@ -154,7 +167,8 @@ "aiBuildingMaintenanceModifier": 0.65, "aiUnitMaintenanceModifier": 0.65, "aiFreeTechs": ["Pottery","Animal Husbandry","Mining"], - "aiFreeUnits": ["Warrior", "Warrior", "Worker", "Scout"], + "aiMajorCivStartingUnits": ["Settler", "Warrior", "Warrior", "Warrior", "Worker", "Scout"], + "aiCityStateStartingUnits": ["Settler", "Warrior"], "aiUnhappinessModifier": 0.75, "aisExchangeTechs": true, "turnBarbariansCanEnterPlayerTiles": 0, @@ -170,6 +184,7 @@ "policyCostModifier": 1, "unhappinessModifier": 1, "barbarianBonus": 0, + "startingUnits": ["Settler", "Warrior"], "aiCityGrowthModifier": 0.6, "aiUnitCostModifier": 0.5, "aiBuildingCostModifier": 0.5, @@ -177,7 +192,8 @@ "aiBuildingMaintenanceModifier": 0.5, "aiUnitMaintenanceModifier": 0.5, "aiFreeTechs": ["Pottery","Animal Husbandry","Mining","The Wheel"], - "aiFreeUnits": ["Settler", "Warrior", "Warrior", "Worker", "Worker", "Scout"], + "aiMajorCivStartingUnits": ["Settler", "Warrior", "Settler", "Warrior", "Warrior", "Worker", "Worker", "Scout"], + "aiCityStateStartingUnits": ["Settler", "Warrior"], "aiUnhappinessModifier": 0.6, "aisExchangeTechs": true, "turnBarbariansCanEnterPlayerTiles": 0, diff --git a/android/assets/jsons/translations/template.properties b/android/assets/jsons/translations/template.properties index 28ccf51ecd..490adeb275 100644 --- a/android/assets/jsons/translations/template.properties +++ b/android/assets/jsons/translations/template.properties @@ -38,6 +38,7 @@ Requires a [buildingName] in all cities = Requires a [buildingName] in this city = Consumes 1 [resource] = Required tech: [requiredTech] = +Cannot be purchased = Current construction = Construction queue = diff --git a/core/src/com/unciv/logic/GameStarter.kt b/core/src/com/unciv/logic/GameStarter.kt index 98bbca2a71..6a5027a723 100644 --- a/core/src/com/unciv/logic/GameStarter.kt +++ b/core/src/com/unciv/logic/GameStarter.kt @@ -156,15 +156,16 @@ object GameStarter { fun placeNearStartingPosition(unitName: String) { civ.placeUnitNearTile(startingLocation.position, unitName) } - placeNearStartingPosition(Constants.settler) val warriorEquivalent = getWarriorEquivalent(civ) - if(warriorEquivalent!=null) placeNearStartingPosition(warriorEquivalent) - - if (!civ.isPlayerCivilization() && civ.isMajorCiv()) { - for (unit in gameInfo.getDifficulty().aiFreeUnits) { - val unitToAdd = if (unit == "Warrior") warriorEquivalent else unit - if (unitToAdd != null) placeNearStartingPosition(unitToAdd) - } + val startingUnits = when { + civ.isPlayerCivilization() -> gameInfo.getDifficulty().startingUnits + civ.isMajorCiv() -> gameInfo.getDifficulty().aiMajorCivStartingUnits + else -> gameInfo.getDifficulty().aiCityStateStartingUnits + } + + for (unit in startingUnits) { + val unitToAdd = if (unit == "Warrior") warriorEquivalent else unit + if (unitToAdd != null) placeNearStartingPosition(unitToAdd) } } } diff --git a/core/src/com/unciv/logic/map/TileInfo.kt b/core/src/com/unciv/logic/map/TileInfo.kt index e151e9f579..11a1c53a52 100644 --- a/core/src/com/unciv/logic/map/TileInfo.kt +++ b/core/src/com/unciv/logic/map/TileInfo.kt @@ -184,7 +184,7 @@ open class TileInfo { for (unique in cityWideUniques + civWideUniques) { val tileType = unique.params[1] if (baseTerrain == tileType || terrainFeature == tileType - || resource == tileType + || (resource == tileType && hasViewableResource(observingCiv)) || (tileType == "Water" && isWater) || (tileType == "Strategic resource" && hasViewableResource(observingCiv) && getTileResource().resourceType == ResourceType.Strategic) || (tileType == "Water resource" && isWater && hasViewableResource(observingCiv)) @@ -258,7 +258,8 @@ open class TileInfo { if (unique.placeholderText == "[] for each adjacent []") { val adjacent = unique.params[1] val numberOfBonuses = neighbors.count { it.improvement == adjacent - || it.baseTerrain==adjacent || it.terrainFeature==adjacent } + || it.baseTerrain==adjacent || it.terrainFeature==adjacent + || it.roadStatus.name==adjacent} stats.add(Stats.parse(unique.params[0]).times(numberOfBonuses.toFloat())) } diff --git a/core/src/com/unciv/models/ruleset/Building.kt b/core/src/com/unciv/models/ruleset/Building.kt index c6e13447c7..72bae24afd 100644 --- a/core/src/com/unciv/models/ruleset/Building.kt +++ b/core/src/com/unciv/models/ruleset/Building.kt @@ -177,7 +177,7 @@ class Building : NamedStats(), IConstruction { } override fun canBePurchased(): Boolean { - return !isWonder && !isNationalWonder && ("Spaceship part" !in uniques) + return !isWonder && !isNationalWonder && ("Cannot be purchased" !in uniques) } diff --git a/core/src/com/unciv/models/ruleset/Difficulty.kt b/core/src/com/unciv/models/ruleset/Difficulty.kt index eb592e570c..adbf24f7b8 100644 --- a/core/src/com/unciv/models/ruleset/Difficulty.kt +++ b/core/src/com/unciv/models/ruleset/Difficulty.kt @@ -1,5 +1,6 @@ package com.unciv.models.ruleset +import com.unciv.Constants import com.unciv.models.stats.INamed import com.unciv.models.translations.tr import java.util.* @@ -15,6 +16,7 @@ class Difficulty: INamed { var policyCostModifier:Float = 1f var unhappinessModifier:Float = 1f var barbarianBonus:Float = 0f + var startingUnits = ArrayList() var aiCityGrowthModifier:Float = 1f var aiUnitCostModifier:Float = 1f @@ -23,11 +25,23 @@ class Difficulty: INamed { var aiBuildingMaintenanceModifier:Float = 1f var aiUnitMaintenanceModifier = 1f var aiFreeTechs = ArrayList() + @Deprecated("Deprecated as of 3.10.4. Use aiMajorCivStartingUnits instead") var aiFreeUnits = ArrayList() + var aiMajorCivStartingUnits = ArrayList() + var aiCityStateStartingUnits = ArrayList() var aiUnhappinessModifier = 1f var turnBarbariansCanEnterPlayerTiles = 0 var clearBarbarianCampReward = 25 + init { + // For compatibility with old mods that use deprecated var aiFreeUnits and do not have startingUnits, aiCityStateStartingUnits, aiMajorCivStartingUnits + if (startingUnits.isEmpty()) { + startingUnits.add(Constants.settler) + startingUnits.add("Warrior") + aiCityStateStartingUnits.addAll(startingUnits) + aiMajorCivStartingUnits.addAll(startingUnits + aiFreeUnits) + } + } fun getDescription(): String { val lines = ArrayList() @@ -40,6 +54,7 @@ class Difficulty: INamed { lines += " - {Policy cost modifier}: $policyCostModifier" lines += " - {Unhappiness modifier}: $unhappinessModifier" lines += " - {Bonus vs. Barbarians}: $barbarianBonus" +// lines += " - {Starting units}: $startingUnits" lines += "" lines += "AI settings" lines += " - {AI city growth modifier}: $aiCityGrowthModifier" @@ -49,7 +64,8 @@ class Difficulty: INamed { lines += " - {AI building maintenance modifier}: $aiBuildingMaintenanceModifier" lines += " - {AI unit maintenance modifier}: $aiUnitMaintenanceModifier" // lines += " - {AI free techs}: $aiFreeTechs" -// lines += " - {AI free units}: $aiFreeUnits" +// lines += " - {AI major civilizations starting units}: $aiMajorCivStartingUnits" +// lines += " - {AI city-state starting units}: $aiCityStateStartingUnits" lines += " - {AI unhappiness modifier}: $aiUnhappinessModifier" lines += "" lines += "{Turns until barbarians enter player tiles}: $turnBarbariansCanEnterPlayerTiles" @@ -58,4 +74,4 @@ class Difficulty: INamed { return lines.joinToString("\n") { it.tr() } } -} \ No newline at end of file +} diff --git a/core/src/com/unciv/models/ruleset/Nation.kt b/core/src/com/unciv/models/ruleset/Nation.kt index 36b3880137..3a433d3b82 100644 --- a/core/src/com/unciv/models/ruleset/Nation.kt +++ b/core/src/com/unciv/models/ruleset/Nation.kt @@ -92,7 +92,7 @@ class Nation : INamed { } if (uniqueName != "") textList += uniqueName.tr() + ":" - textList += " " + uniques.joinToString(", ").tr() + textList += " " + uniques.joinToString(", ") { it.tr() } textList += "" if (startBias.isNotEmpty()) { @@ -103,7 +103,7 @@ class Nation : INamed { addUniqueUnitsText(textList, ruleset) addUniqueImprovementsText(textList, ruleset) - return textList.joinToString("\n").tr().trim() + return textList.joinToString("\n") } private fun addUniqueBuildingsText(textList: ArrayList, ruleset: Ruleset) { diff --git a/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt b/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt index eb2903533f..c3db7a1173 100644 --- a/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt +++ b/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt @@ -89,7 +89,7 @@ class BaseUnit : INamed, IConstruction { return unit } - override fun canBePurchased() = true + override fun canBePurchased() = "Cannot be purchased" !in uniques override fun getProductionCost(civInfo: CivilizationInfo): Int { var productionCost = cost.toFloat() diff --git a/core/src/com/unciv/ui/newgamescreen/GameOptionsTable.kt b/core/src/com/unciv/ui/newgamescreen/GameOptionsTable.kt index 4dc6959939..cfdda19a5b 100644 --- a/core/src/com/unciv/ui/newgamescreen/GameOptionsTable.kt +++ b/core/src/com/unciv/ui/newgamescreen/GameOptionsTable.kt @@ -133,7 +133,7 @@ class GameOptionsTable(val previousScreen: IPreviousScreen, val updatePlayerPick private fun Table.addEraSelectBox() { if (ruleset.technologies.isEmpty()) return // scenario with no techs - val eras = ruleset.technologies.values.map { it.era() }.distinct() + val eras = ruleset.technologies.values.filter { !it.uniques.contains("Starting tech") }.map { it.era() }.distinct() addSelectBox("{Starting Era}:", eras, gameParameters.startingEra) { gameParameters.startingEra = it } } diff --git a/core/src/com/unciv/ui/newgamescreen/PlayerPickerTable.kt b/core/src/com/unciv/ui/newgamescreen/PlayerPickerTable.kt index 773491c601..e76a3e829e 100644 --- a/core/src/com/unciv/ui/newgamescreen/PlayerPickerTable.kt +++ b/core/src/com/unciv/ui/newgamescreen/PlayerPickerTable.kt @@ -93,7 +93,7 @@ class PlayerPickerTable(val previousScreen: IPreviousScreen, var gameParameters: */ private fun reassignRemovedModReferences() { for (player in gameParameters.players) { - if (!previousScreen.ruleset.nations.containsKey(player.chosenCiv)) + if (!previousScreen.ruleset.nations.containsKey(player.chosenCiv) || previousScreen.ruleset.nations[player.chosenCiv]!!.isCityState()) player.chosenCiv = Constants.random } }