From 2e5e22115809ba841f194c5410945703d8f798ea Mon Sep 17 00:00:00 2001 From: Yair Morgenstern Date: Mon, 21 Nov 2022 20:30:52 +0200 Subject: [PATCH] CityStateType overhaul!!!! --- .../Civ V - Gods & Kings/CityStateTypes.json | 2 +- .../jsons/Civ V - Vanilla/CityStateTypes.json | 2 +- core/src/com/unciv/logic/GameInfo.kt | 3 +- .../logic/civilization/CityStateFunctions.kt | 9 ++--- .../logic/civilization/CityStateTypeOld.kt | 8 ----- .../unciv/logic/civilization/CivInfoStats.kt | 7 ++-- .../logic/civilization/CivilizationInfo.kt | 3 +- .../com/unciv/models/ruleset/CityStateType.kt | 5 +-- core/src/com/unciv/models/ruleset/Era.kt | 22 ++----------- core/src/com/unciv/models/ruleset/Nation.kt | 33 ++++++++----------- core/src/com/unciv/models/ruleset/Ruleset.kt | 2 +- .../CapitalConnectionsFinderTests.kt | 4 +-- .../com/unciv/uniques/GlobalUniquesTests.kt | 3 +- tests/src/com/unciv/uniques/TestGame.kt | 7 ++-- .../src/com/unciv/uniques/UnitUniquesTests.kt | 3 +- 15 files changed, 42 insertions(+), 71 deletions(-) diff --git a/android/assets/jsons/Civ V - Gods & Kings/CityStateTypes.json b/android/assets/jsons/Civ V - Gods & Kings/CityStateTypes.json index 5cba43e9d3..2a4acd4c81 100644 --- a/android/assets/jsons/Civ V - Gods & Kings/CityStateTypes.json +++ b/android/assets/jsons/Civ V - Gods & Kings/CityStateTypes.json @@ -6,7 +6,7 @@ "color": [139, 96, 255] }, { - "Maritime":"Maritime", + "name":"Maritime", "friendBonusUniques": ["[+2 Food] [in capital]"], "allyBonusUniques": ["[+2 Food] [in capital]", "[+1 Food] [in all cities]"], "color": [56, 255, 112] diff --git a/android/assets/jsons/Civ V - Vanilla/CityStateTypes.json b/android/assets/jsons/Civ V - Vanilla/CityStateTypes.json index 5cba43e9d3..2a4acd4c81 100644 --- a/android/assets/jsons/Civ V - Vanilla/CityStateTypes.json +++ b/android/assets/jsons/Civ V - Vanilla/CityStateTypes.json @@ -6,7 +6,7 @@ "color": [139, 96, 255] }, { - "Maritime":"Maritime", + "name":"Maritime", "friendBonusUniques": ["[+2 Food] [in capital]"], "allyBonusUniques": ["[+2 Food] [in capital]", "[+1 Food] [in all cities]"], "color": [56, 255, 112] diff --git a/core/src/com/unciv/logic/GameInfo.kt b/core/src/com/unciv/logic/GameInfo.kt index ba9562ce39..b5b3056dd2 100644 --- a/core/src/com/unciv/logic/GameInfo.kt +++ b/core/src/com/unciv/logic/GameInfo.kt @@ -480,11 +480,12 @@ class GameInfo : IsPartOfGameInfoSerialization, HasGameInfoSerializationVersion for (civInfo in civilizations) civInfo.gameInfo = this for (civInfo in civilizations) civInfo.setNationTransient() // must be done before updating tileMap, since unit uniques depend on civ uniques depend on allied city-state uniques depend on diplomacy - for (civInfo in civilizations) + for (civInfo in civilizations) { for (diplomacyManager in civInfo.diplomacy.values) { diplomacyManager.civInfo = civInfo diplomacyManager.updateHasOpenBorders() } + } tileMap.setTransients(ruleSet) diff --git a/core/src/com/unciv/logic/civilization/CityStateFunctions.kt b/core/src/com/unciv/logic/civilization/CityStateFunctions.kt index 8f53afcdca..c1b9142402 100644 --- a/core/src/com/unciv/logic/civilization/CityStateFunctions.kt +++ b/core/src/com/unciv/logic/civilization/CityStateFunctions.kt @@ -28,10 +28,11 @@ class CityStateFunctions(val civInfo: CivilizationInfo) { civInfo.tech.techsResearched.add(tech.name) // can't be .addTechnology because the civInfo isn't assigned yet val allMercantileResources = ruleset.tileResources.values.filter { it.hasUnique(UniqueType.CityStateOnlyResource) }.map { it.name } - val uniqueTypes = HashSet() // We look through these to determine what kind of city state we are - for (era in ruleset.eras.values) { - for (unique in era.friendBonusObjects.values.map { it.getAllUniques() } + era.allyBonusObjects.values.map { it.getAllUniques() }) - uniqueTypes.addAll(unique.mapNotNull { it.type }) + val uniqueTypes = HashSet() // We look through these to determine what kinds of city states we have + + for (cityStateType in ruleset.cityStateTypes.values){ + uniqueTypes.addAll(cityStateType.friendBonusUniqueMap.getAllUniques().mapNotNull { it.type }) + uniqueTypes.addAll(cityStateType.allyBonusUniqueMap.getAllUniques().mapNotNull { it.type }) } // CS Personality diff --git a/core/src/com/unciv/logic/civilization/CityStateTypeOld.kt b/core/src/com/unciv/logic/civilization/CityStateTypeOld.kt index fc92ee92b0..67e0338a4c 100644 --- a/core/src/com/unciv/logic/civilization/CityStateTypeOld.kt +++ b/core/src/com/unciv/logic/civilization/CityStateTypeOld.kt @@ -1,13 +1,5 @@ package com.unciv.logic.civilization -enum class CityStateTypeOld(val color: String = "") { - Cultured("#8b60ff"), - Maritime("#38ff70"), - Mercantile("#ffd800"), - Militaristic("#ff0000"), - Religious("#FFFFFF") -} - enum class CityStatePersonality { Friendly, Neutral, diff --git a/core/src/com/unciv/logic/civilization/CivInfoStats.kt b/core/src/com/unciv/logic/civilization/CivInfoStats.kt index 5527ba7eb5..9c67021235 100644 --- a/core/src/com/unciv/logic/civilization/CivInfoStats.kt +++ b/core/src/com/unciv/logic/civilization/CivInfoStats.kt @@ -142,7 +142,7 @@ class CivInfoStats(val civInfo: CivilizationInfo) { for (unique in civInfo.getMatchingUniques(UniqueType.Stats)) if (unique.sourceObjectType != UniqueTarget.Building && unique.sourceObjectType != UniqueTarget.Wonder) - statMap.add(unique.sourceObjectName!!, unique.stats) + statMap.add(unique.sourceObjectType!!.name, unique.stats) //City-States bonuses for (otherCiv in civInfo.getKnownCivs()) { @@ -333,8 +333,9 @@ class CivInfoStats(val civInfo: CivilizationInfo) { for (unique in civInfo.getMatchingUniques(UniqueType.Stats)) if (unique.sourceObjectType != UniqueTarget.Building && unique.sourceObjectType != UniqueTarget.Wonder && unique.stats.happiness != 0f){ - if (!statMap.containsKey(unique.sourceObjectName)) statMap[unique.sourceObjectName!!] = unique.stats.happiness - else statMap[unique.sourceObjectName!!] = statMap[unique.sourceObjectName]!! + unique.stats.happiness + val sourceObjectType = unique.sourceObjectType!!.name + if (!statMap.containsKey(sourceObjectType)) statMap[sourceObjectType] = unique.stats.happiness + else statMap[sourceObjectType] = statMap[sourceObjectType]!! + unique.stats.happiness } return statMap diff --git a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt index c750fa7d92..c56c60bd5c 100644 --- a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt +++ b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt @@ -22,6 +22,7 @@ import com.unciv.logic.trade.TradeEvaluation import com.unciv.logic.trade.TradeRequest import com.unciv.models.Counter import com.unciv.models.ruleset.Building +import com.unciv.models.ruleset.CityStateType import com.unciv.models.ruleset.Difficulty import com.unciv.models.ruleset.Era import com.unciv.models.ruleset.ModOptionsConstants @@ -346,7 +347,7 @@ class CivilizationInfo : IsPartOfGameInfoSerialization { fun isBarbarian() = nation.isBarbarian() fun isSpectator() = nation.isSpectator() fun isCityState(): Boolean = nation.isCityState() - val cityStateType: CityStateTypeOld get() = nation.cityStateType!! + val cityStateType: CityStateType by lazy { gameInfo.ruleSet.cityStateTypes[nation.cityStateType!!]!! } var cityStatePersonality: CityStatePersonality = CityStatePersonality.Neutral var cityStateResource: String? = null var cityStateUniqueUnit: String? = null // Unique unit for militaristic city state. Might still be null if there are no appropriate units diff --git a/core/src/com/unciv/models/ruleset/CityStateType.kt b/core/src/com/unciv/models/ruleset/CityStateType.kt index d978e85f04..c8c53aba1f 100644 --- a/core/src/com/unciv/models/ruleset/CityStateType.kt +++ b/core/src/com/unciv/models/ruleset/CityStateType.kt @@ -2,15 +2,16 @@ package com.unciv.models.ruleset import com.unciv.models.ruleset.unique.Unique import com.unciv.models.ruleset.unique.UniqueMap +import com.unciv.models.ruleset.unique.UniqueTarget import com.unciv.models.stats.INamed import com.unciv.ui.utils.extensions.colorFromRGB class CityStateType: INamed { override var name = "" var friendBonusUniques = ArrayList() - val friendBonusUniqueMap by lazy { UniqueMap().addUniques(friendBonusUniques.map { Unique(it) }) } + val friendBonusUniqueMap by lazy { UniqueMap().apply { addUniques(friendBonusUniques.map { Unique(it, sourceObjectType = UniqueTarget.CityState) }) } } var allyBonusUniques = ArrayList() - val allyBonusUniqueMap by lazy { UniqueMap().addUniques(allyBonusUniques.map { Unique(it) }) } + val allyBonusUniqueMap by lazy { UniqueMap().apply { addUniques(allyBonusUniques.map { Unique(it, sourceObjectType = UniqueTarget.CityState) }) } } lateinit var color:List private val colorObject by lazy { colorFromRGB(color) } diff --git a/core/src/com/unciv/models/ruleset/Era.kt b/core/src/com/unciv/models/ruleset/Era.kt index 209bdc3657..4b7df6e06a 100644 --- a/core/src/com/unciv/models/ruleset/Era.kt +++ b/core/src/com/unciv/models/ruleset/Era.kt @@ -1,11 +1,9 @@ package com.unciv.models.ruleset import com.badlogic.gdx.graphics.Color -import com.unciv.logic.civilization.CityStateTypeOld import com.unciv.logic.civilization.diplomacy.RelationshipLevel import com.unciv.models.ruleset.unique.StateForConditionals import com.unciv.models.ruleset.unique.Unique -import com.unciv.models.ruleset.unique.UniqueMap import com.unciv.models.ruleset.unique.UniqueTarget import com.unciv.models.ruleset.unique.UniqueType import com.unciv.ui.civilopedia.FormattedLine @@ -33,10 +31,6 @@ class Era : RulesetObject() { var friendBonus = HashMap>() var allyBonus = HashMap>() - @Suppress("MemberVisibilityCanBePrivate") - val friendBonusObjects: Map by lazy { initBonuses(friendBonus) } - @Suppress("MemberVisibilityCanBePrivate") - val allyBonusObjects: Map by lazy { initBonuses(allyBonus) } private var iconRGB: List? = null @@ -87,20 +81,10 @@ class Era : RulesetObject() { }.map { it.first }.distinct() } - private fun initBonuses(bonusMap: Map>): Map { - val objectMap = HashMap() - for ((cityStateType, bonusList) in bonusMap) { - val cityStateTypeUniqueMap = UniqueMap() - cityStateTypeUniqueMap.addUniques(bonusList.map { Unique(it, UniqueTarget.CityState)}) - objectMap[CityStateTypeOld.valueOf(cityStateType)] = cityStateTypeUniqueMap - } - return objectMap - } - - fun getCityStateBonuses(cityStateType: CityStateTypeOld, relationshipLevel: RelationshipLevel, uniqueType:UniqueType?=null): Sequence { + fun getCityStateBonuses(cityStateType: CityStateType, relationshipLevel: RelationshipLevel, uniqueType:UniqueType?=null): Sequence { val cityStateUniqueMap = when (relationshipLevel) { - RelationshipLevel.Ally -> allyBonusObjects[cityStateType] - RelationshipLevel.Friend -> friendBonusObjects[cityStateType] + RelationshipLevel.Ally -> cityStateType.allyBonusUniqueMap + RelationshipLevel.Friend -> cityStateType.friendBonusUniqueMap else -> null } ?: return emptySequence() return if (uniqueType == null) cityStateUniqueMap.getAllUniques() diff --git a/core/src/com/unciv/models/ruleset/Nation.kt b/core/src/com/unciv/models/ruleset/Nation.kt index d33d0692c3..1a3555f189 100644 --- a/core/src/com/unciv/models/ruleset/Nation.kt +++ b/core/src/com/unciv/models/ruleset/Nation.kt @@ -2,9 +2,6 @@ import com.badlogic.gdx.graphics.Color import com.unciv.Constants -import com.unciv.UncivGame -import com.unciv.logic.civilization.CityStateTypeOld -import com.unciv.models.ruleset.unique.Unique import com.unciv.models.ruleset.unique.UniqueFlag import com.unciv.models.ruleset.unique.UniqueTarget import com.unciv.models.ruleset.unique.UniqueType @@ -23,7 +20,7 @@ class Nation : RulesetObject() { val style = "" fun getStyleOrCivName() = style.ifEmpty { name } - var cityStateType: CityStateTypeOld? = null + var cityStateType: String? = null var preferredVictoryType: String = Constants.neutralVictoryType var declaringWar = "" var attacked = "" @@ -140,32 +137,28 @@ class Nation : RulesetObject() { private fun getCityStateInfo(ruleset: Ruleset): List { val textList = ArrayList() - textList += FormattedLine("{Type}: {$cityStateType}", header = 4, color = cityStateType!!.color) + val cityStateType = ruleset.cityStateTypes[cityStateType]!! + textList += FormattedLine("{Type}: {$cityStateType}", header = 4, color = cityStateType.getColor().toString()) - val era = if (UncivGame.isCurrentInitialized() && UncivGame.Current.gameInfo != null) { - UncivGame.Current.gameInfo!!.getCurrentPlayerCivilization().getEra() - } else { - ruleset.eras.values.first() - } var showResources = false - val friendBonus = era.friendBonus[cityStateType!!.name] - if (friendBonus != null && friendBonus.isNotEmpty()) { + val friendBonus = cityStateType.friendBonusUniqueMap + if (friendBonus.isNotEmpty()) { textList += FormattedLine() textList += FormattedLine("{When Friends:} ") - friendBonus.forEach { - textList += FormattedLine(Unique(it), indent = 1) - if (it == "Provides a unique luxury") showResources = true + friendBonus.getAllUniques().forEach { + textList += FormattedLine(it, indent = 1) + if (it.text == "Provides a unique luxury") showResources = true } } - val allyBonus = era.allyBonus[cityStateType!!.name] - if (allyBonus != null && allyBonus.isNotEmpty()) { + val allyBonus = cityStateType.allyBonusUniqueMap + if (allyBonus.isNotEmpty()) { textList += FormattedLine() textList += FormattedLine("{When Allies:} ") - allyBonus.forEach { - textList += FormattedLine(Unique(it), indent = 1) - if (it == "Provides a unique luxury") showResources = true + allyBonus.getAllUniques().forEach { + textList += FormattedLine(it, indent = 1) + if (it.text == "Provides a unique luxury") showResources = true } } diff --git a/core/src/com/unciv/models/ruleset/Ruleset.kt b/core/src/com/unciv/models/ruleset/Ruleset.kt index a44c095d02..857bd1c28c 100644 --- a/core/src/com/unciv/models/ruleset/Ruleset.kt +++ b/core/src/com/unciv/models/ruleset/Ruleset.kt @@ -367,7 +367,7 @@ class Ruleset { victories += createHashmap(json().fromJsonFile(Array::class.java, victoryTypesFile)) } - val cityStateTypesFile = folderHandle.child("VictoryTypes.json") + val cityStateTypesFile = folderHandle.child("CityStateTypes.json") if (cityStateTypesFile.exists()) { cityStateTypes += createHashmap(json().fromJsonFile(Array::class.java, cityStateTypesFile)) } diff --git a/tests/src/com/unciv/logic/civilization/CapitalConnectionsFinderTests.kt b/tests/src/com/unciv/logic/civilization/CapitalConnectionsFinderTests.kt index 384f34c7df..87dd6a8cfd 100644 --- a/tests/src/com/unciv/logic/civilization/CapitalConnectionsFinderTests.kt +++ b/tests/src/com/unciv/logic/civilization/CapitalConnectionsFinderTests.kt @@ -243,13 +243,13 @@ class CapitalConnectionsFinderTests { createCity(ourCiv, Vector2(0f, 4f), "Connected")) val openCiv = civilizations["Germany"]!! - openCiv.nation.cityStateType = CityStateTypeOld.Cultured + openCiv.nation.cityStateType = "Cultured" openCiv.cities = listOf( createCity(openCiv, Vector2(0f, 2f), "Berlin", true)) ourCiv.diplomacy["Germany"] = DiplomacyManager(ourCiv, "Germany") .apply { diplomaticStatus = DiplomaticStatus.Peace } val closedCiv = civilizations["Greece"]!! - closedCiv.nation.cityStateType = CityStateTypeOld.Cultured + closedCiv.nation.cityStateType = "Cultured" closedCiv.cities = listOf( createCity(closedCiv, Vector2(0f, -2f), "Athens", true)) ourCiv.diplomacy["Greece"] = DiplomacyManager(ourCiv, "Greece") .apply { diplomaticStatus = DiplomaticStatus.War } diff --git a/tests/src/com/unciv/uniques/GlobalUniquesTests.kt b/tests/src/com/unciv/uniques/GlobalUniquesTests.kt index d39d823085..252fedc8f4 100644 --- a/tests/src/com/unciv/uniques/GlobalUniquesTests.kt +++ b/tests/src/com/unciv/uniques/GlobalUniquesTests.kt @@ -3,7 +3,6 @@ package com.unciv.uniques import com.badlogic.gdx.math.Vector2 import com.unciv.Constants -import com.unciv.logic.civilization.CityStateTypeOld import com.unciv.logic.map.RoadStatus import com.unciv.models.ruleset.BeliefType import com.unciv.models.stats.Stats @@ -364,7 +363,7 @@ class GlobalUniquesTests { fun bonusStatsFromCityStates() { game.makeHexagonalMap(1) val civInfo = game.addCiv() - val cityState = game.addCiv(cityState = CityStateTypeOld.Maritime) + val cityState = game.addCiv(cityStateType = "Maritime") val tile = game.getTile(Vector2(0f,0f)) val city = game.addCity(civInfo, tile, true) diff --git a/tests/src/com/unciv/uniques/TestGame.kt b/tests/src/com/unciv/uniques/TestGame.kt index 43a26b5b18..d2a922286f 100644 --- a/tests/src/com/unciv/uniques/TestGame.kt +++ b/tests/src/com/unciv/uniques/TestGame.kt @@ -5,7 +5,6 @@ import com.unciv.Constants import com.unciv.UncivGame import com.unciv.logic.GameInfo import com.unciv.logic.city.CityInfo -import com.unciv.logic.civilization.CityStateTypeOld import com.unciv.logic.civilization.CivilizationInfo import com.unciv.logic.civilization.PlayerType import com.unciv.logic.map.MapSizeNew @@ -104,10 +103,10 @@ class TestGame { return tile } - fun addCiv(vararg uniques: String, isPlayer: Boolean = false, cityState: CityStateTypeOld? = null): CivilizationInfo { + fun addCiv(vararg uniques: String, isPlayer: Boolean = false, cityStateType: String? = null): CivilizationInfo { fun nationFactory() = Nation().apply { cities = arrayListOf("The Capital") - cityStateType = cityState + this.cityStateType = cityStateType } val nation = createRulesetObject(ruleset.nations, *uniques) { nationFactory() @@ -121,7 +120,7 @@ class TestGame { // Add 1 tech to the player so the era is computed correctly civInfo.tech.addTechnology(ruleset.technologies.values.minBy { it.era() }.name) - if (cityState != null) { + if (cityStateType != null) { civInfo.cityStateFunctions.initCityState(ruleset, "Ancient era", emptyList()) } gameInfo.civilizations.add(civInfo) diff --git a/tests/src/com/unciv/uniques/UnitUniquesTests.kt b/tests/src/com/unciv/uniques/UnitUniquesTests.kt index d3c765699c..f59fc3ee78 100644 --- a/tests/src/com/unciv/uniques/UnitUniquesTests.kt +++ b/tests/src/com/unciv/uniques/UnitUniquesTests.kt @@ -1,7 +1,6 @@ package com.unciv.uniques import com.badlogic.gdx.math.Vector2 -import com.unciv.logic.civilization.CityStateTypeOld import com.unciv.testing.GdxTestRunner import com.unciv.ui.worldscreen.unit.UnitActions import org.junit.Assert.assertNotNull @@ -22,7 +21,7 @@ class UnitUniquesTests { fun `Sweden can gift Great Persons to City States`() { // when game.makeHexagonalMap(1) - val cityState = game.addCiv(cityState = CityStateTypeOld.Cultured) + val cityState = game.addCiv(cityStateType = "Cultured") val cityStateCapitalTile = game.getTile(Vector2(0f, 0f)) val cityStateCapital = game.addCity(cityState, cityStateCapitalTile)