From a4e93d89f17bd5d9be04222a6eb304c6e37a202d Mon Sep 17 00:00:00 2001 From: Yair Morgenstern Date: Mon, 21 Dec 2020 22:02:40 +0200 Subject: [PATCH] Resolved #3384 - Civ uniques now take all researched tech uniques! --- core/src/com/unciv/logic/city/CityStats.kt | 2 +- .../src/com/unciv/logic/city/IConstruction.kt | 4 +- .../logic/civilization/CivilizationInfo.kt | 13 +++-- .../unciv/logic/civilization/TechManager.kt | 48 +++++++++++-------- core/src/com/unciv/logic/map/MapUnit.kt | 2 +- core/src/com/unciv/logic/trade/TradeLogic.kt | 19 ++++---- .../com/unciv/ui/worldscreen/WorldScreen.kt | 2 +- 7 files changed, 51 insertions(+), 39 deletions(-) diff --git a/core/src/com/unciv/logic/city/CityStats.kt b/core/src/com/unciv/logic/city/CityStats.kt index 6b0945415a..e90ce20507 100644 --- a/core/src/com/unciv/logic/city/CityStats.kt +++ b/core/src/com/unciv/logic/city/CityStats.kt @@ -102,7 +102,7 @@ class CityStats { private fun getStatPercentBonusesFromComputers(): Stats { val stats = Stats() - if (cityInfo.civInfo.tech.getTechUniques().contains("+10% science and production in all cities")) { + if (cityInfo.civInfo.hasUnique("+10% science and production in all cities")) { stats.production += 10f stats.science += 10f } diff --git a/core/src/com/unciv/logic/city/IConstruction.kt b/core/src/com/unciv/logic/city/IConstruction.kt index 86b3b6a149..1355097f36 100644 --- a/core/src/com/unciv/logic/city/IConstruction.kt +++ b/core/src/com/unciv/logic/city/IConstruction.kt @@ -32,7 +32,7 @@ open class PerpetualConstruction(override var name: String, val description: Str const val CONVERSION_RATE: Int = 4 val science = object : PerpetualConstruction("Science", "Convert production to science at a rate of [rate] to 1") { override fun isBuildable(cityConstructions: CityConstructions): Boolean { - return cityConstructions.cityInfo.civInfo.tech.getTechUniques().contains("Enables conversion of city production to science") + return cityConstructions.cityInfo.civInfo.hasUnique("Enables conversion of city production to science") } override fun getProductionTooltip(cityInfo: CityInfo): String { return "\r\n${(cityInfo.cityStats.currentCityStats.production / getConversionRate(cityInfo)).roundToInt()}/${Fonts.turn}" @@ -41,7 +41,7 @@ open class PerpetualConstruction(override var name: String, val description: Str } val gold = object : PerpetualConstruction("Gold", "Convert production to gold at a rate of $CONVERSION_RATE to 1") { override fun isBuildable(cityConstructions: CityConstructions): Boolean { - return cityConstructions.cityInfo.civInfo.tech.getTechUniques().contains("Enables conversion of city production to gold") + return cityConstructions.cityInfo.civInfo.hasUnique("Enables conversion of city production to gold") } } val idle = object : PerpetualConstruction("Nothing", "The city will not produce anything.") { diff --git a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt index c0b9e67210..8adbc686c3 100644 --- a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt +++ b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt @@ -11,7 +11,6 @@ import com.unciv.logic.city.CityInfo import com.unciv.logic.civilization.diplomacy.DiplomacyFlags import com.unciv.logic.civilization.diplomacy.DiplomacyManager import com.unciv.logic.civilization.diplomacy.DiplomaticStatus -import com.unciv.logic.civilization.diplomacy.RelationshipLevel import com.unciv.logic.map.MapUnit import com.unciv.logic.map.TileInfo import com.unciv.logic.trade.TradeEvaluation @@ -34,6 +33,7 @@ class CivilizationInfo { @Transient lateinit var gameInfo: GameInfo + @Transient lateinit var nation: Nation @@ -44,8 +44,10 @@ class CivilizationInfo { */ @Transient private var units = listOf() + @Transient var viewableTiles = setOf() + @Transient var viewableInvisibleUnitsTiles = setOf() @@ -56,14 +58,18 @@ class CivilizationInfo { /** This is for performance since every movement calculation depends on this, see MapUnit comment */ @Transient var hasActiveGreatWall = false + @Transient var statsForNextTurn = Stats() + @Transient var happinessForNextTurn = 0 + @Transient var detailedCivResources = ResourceSupplyList() var playerType = PlayerType.AI + /** Used in online multiplayer for human players */ var playerId = "" var gold = 0 @@ -223,7 +229,8 @@ class CivilizationInfo { fun getMatchingUniques(uniqueTemplate: String): Sequence { return nation.uniqueObjects.asSequence().filter { it.placeholderText == uniqueTemplate } + cities.asSequence().flatMap { it.cityConstructions.builtBuildingUniqueMap.getUniques(uniqueTemplate).asSequence() } + - policies.policyUniques.getUniques(uniqueTemplate) + policies.policyUniques.getUniques(uniqueTemplate) + + tech.getTechUniques() } //region Units @@ -365,7 +372,7 @@ class CivilizationInfo { fun canSignResearchAgreement(): Boolean { if (!isMajorCiv()) return false - if (!tech.getTechUniques().contains("Enables Research agreements")) return false + if (!hasUnique("Enables Research agreements")) return false if (gameInfo.ruleSet.technologies.values .none { tech.canBeResearched(it.name) && !tech.isResearched(it.name) }) return false return true diff --git a/core/src/com/unciv/logic/civilization/TechManager.kt b/core/src/com/unciv/logic/civilization/TechManager.kt index 2dc81cdf61..7745b52a9a 100644 --- a/core/src/com/unciv/logic/civilization/TechManager.kt +++ b/core/src/com/unciv/logic/civilization/TechManager.kt @@ -2,7 +2,6 @@ package com.unciv.logic.civilization import com.badlogic.gdx.graphics.Color -import com.unciv.Constants import com.unciv.logic.map.MapSize import com.unciv.logic.map.RoadStatus import com.unciv.models.ruleset.Unique @@ -17,18 +16,26 @@ import kotlin.math.max import kotlin.math.min class TechManager { - @Transient lateinit var civInfo: CivilizationInfo - @Transient var researchedTechnologies = ArrayList() - @Transient private var researchedTechUniques = ArrayList() + @Transient + lateinit var civInfo: CivilizationInfo + @Transient + var researchedTechnologies = ArrayList() + @Transient + private var researchedTechUniques = ArrayList() // MapUnit.canPassThrough is the most called function in the game, and having these extremey specific booleans is or way of improving the time cost - @Transient var wayfinding = false - @Transient var unitsCanEmbark = false - @Transient var embarkedUnitsCanEnterOcean = false + @Transient + var wayfinding = false + @Transient + var unitsCanEmbark = false + @Transient + var embarkedUnitsCanEnterOcean = false // UnitMovementAlgorithms.getMovementCostBetweenAdjacentTiles is a close second =) - @Transient var movementSpeedOnRoadsImproved = false - @Transient var roadsConnectAcrossRivers = false + @Transient + var movementSpeedOnRoadsImproved = false + @Transient + var roadsConnectAcrossRivers = false var freeTechs = 0 @@ -167,7 +174,7 @@ class TechManager { private fun scienceFromResearchAgreements(): Int { // https://forums.civfanatics.com/resources/research-agreements-bnw.25568/ var researchAgreementModifier = 0.5f - for(unique in civInfo.getMatchingUniques("Science gained from research agreements +50%")) + for (unique in civInfo.getMatchingUniques("Science gained from research agreements +50%")) researchAgreementModifier += 0.25f return (scienceFromResearchAgreements / 3 * researchAgreementModifier).toInt() } @@ -194,7 +201,7 @@ class TechManager { addScience(finalScienceToAdd) } - fun addScience(scienceGet : Int) { + fun addScience(scienceGet: Int) { val currentTechnology = currentTechnologyName() if (currentTechnology == null) return techsInProgress[currentTechnology] = researchOfTech(currentTechnology) + scienceGet @@ -225,7 +232,7 @@ class TechManager { techsToResearch.remove(techName) researchedTechnologies = researchedTechnologies.withItem(newTech) for (unique in newTech.uniques) { - researchedTechUniques = researchedTechUniques.withItem(unique) + researchedTechUniques = researchedTechUniques.withItem(Unique(unique)) UniqueTriggerActivation.triggerCivwideUnique(Unique(unique), civInfo) } updateTransientBooleans() @@ -277,12 +284,11 @@ class TechManager { if (constructionName in obsoleteUnits) { val text = "[$constructionName] has been obsolete and will be removed from construction queue in [${city.name}]!" civInfo.addNotification(text, city.location, Color.BROWN) - } - else city.cityConstructions.constructionQueue.add(newConstructionName) + } else city.cityConstructions.constructionQueue.add(newConstructionName) } } - for(unique in civInfo.getMatchingUniques("Receive free [] when you discover []")) { + for (unique in civInfo.getMatchingUniques("Receive free [] when you discover []")) { if (unique.params[1] != techName) continue civInfo.addUnit(unique.params[0]) } @@ -290,17 +296,17 @@ class TechManager { fun setTransients() { researchedTechnologies.addAll(techsResearched.map { getRuleset().technologies[it]!! }) - researchedTechUniques.addAll(researchedTechnologies.flatMap { it.uniques }) + researchedTechUniques.addAll(researchedTechnologies.asSequence().flatMap { it.uniques.asSequence() }.map { Unique(it) }) updateTransientBooleans() } fun updateTransientBooleans() { wayfinding = civInfo.hasUnique("Can embark and move over Coasts and Oceans immediately") - unitsCanEmbark = wayfinding || researchedTechUniques.contains("Enables embarkation for land units") + unitsCanEmbark = wayfinding || civInfo.hasUnique("Enables embarkation for land units") - embarkedUnitsCanEnterOcean = wayfinding || researchedTechUniques.contains("Enables embarked units to enter ocean tiles") - movementSpeedOnRoadsImproved = researchedTechUniques.contains("Improves movement speed on roads") - roadsConnectAcrossRivers = researchedTechUniques.contains("Roads connect tiles across rivers") + embarkedUnitsCanEnterOcean = wayfinding || civInfo.hasUnique("Enables embarked units to enter ocean tiles") + movementSpeedOnRoadsImproved = civInfo.hasUnique("Improves movement speed on roads") + roadsConnectAcrossRivers = civInfo.hasUnique("Roads connect tiles across rivers") } fun getBestRoadAvailable(): RoadStatus { @@ -308,7 +314,7 @@ class TechManager { if (roadImprovement == null || !isResearched(roadImprovement.techRequired!!)) return RoadStatus.None val railroadImprovement = RoadStatus.Railroad.improvement(getRuleset()) - val canBuildRailroad = railroadImprovement!=null && isResearched(railroadImprovement.techRequired!!) + val canBuildRailroad = railroadImprovement != null && isResearched(railroadImprovement.techRequired!!) return if (canBuildRailroad) RoadStatus.Railroad else RoadStatus.Road } diff --git a/core/src/com/unciv/logic/map/MapUnit.kt b/core/src/com/unciv/logic/map/MapUnit.kt index acac7716b5..48eefceaf4 100644 --- a/core/src/com/unciv/logic/map/MapUnit.kt +++ b/core/src/com/unciv/logic/map/MapUnit.kt @@ -234,7 +234,7 @@ class MapUnit { fun getEmbarkedMovement(): Int { var movement = 2 - movement += civInfo.tech.getTechUniques().count { it == "Increases embarked movement +1" } + movement += civInfo.getMatchingUniques("Increases embarked movement +1").count() if (civInfo.hasUnique("+1 Movement for all embarked units")) movement += 1 return movement } diff --git a/core/src/com/unciv/logic/trade/TradeLogic.kt b/core/src/com/unciv/logic/trade/TradeLogic.kt index e404b80ea3..e9dd8fd381 100644 --- a/core/src/com/unciv/logic/trade/TradeLogic.kt +++ b/core/src/com/unciv/logic/trade/TradeLogic.kt @@ -8,11 +8,11 @@ import com.unciv.models.ruleset.ModOptionsConstants import com.unciv.models.ruleset.tile.ResourceType import com.unciv.models.translations.tr -class TradeLogic(val ourCivilization:CivilizationInfo, val otherCivilization: CivilizationInfo){ +class TradeLogic(val ourCivilization:CivilizationInfo, val otherCivilization: CivilizationInfo) { /** Contains everything we could offer the other player, whether we've actually offered it or not */ - val ourAvailableOffers = getAvailableOffers(ourCivilization,otherCivilization) - val theirAvailableOffers = getAvailableOffers(otherCivilization,ourCivilization) + val ourAvailableOffers = getAvailableOffers(ourCivilization, otherCivilization) + val theirAvailableOffers = getAvailableOffers(otherCivilization, ourCivilization) val currentTrade = Trade() fun getAvailableOffers(civInfo: CivilizationInfo, otherCivilization: CivilizationInfo): TradeOffersList { @@ -21,16 +21,16 @@ class TradeLogic(val ourCivilization:CivilizationInfo, val otherCivilization: Ci if (civInfo.isAtWarWith(otherCivilization)) offers.add(TradeOffer(Constants.peaceTreaty, TradeType.Treaty)) - if(!otherCivilization.getDiplomacyManager(civInfo).hasOpenBorders + if (!otherCivilization.getDiplomacyManager(civInfo).hasOpenBorders && !otherCivilization.isCityState() - && civInfo.tech.getTechUniques().contains("Enables Open Borders agreements") - && otherCivilization.tech.getTechUniques().contains("Enables Open Borders agreements")) { + && civInfo.hasUnique("Enables Open Borders agreements") + && otherCivilization.hasUnique("Enables Open Borders agreements")) { offers.add(TradeOffer(Constants.openBorders, TradeType.Agreement)) } - for(entry in civInfo.getCivResources() + for (entry in civInfo.getCivResources() .filterNot { it.resource.resourceType == ResourceType.Bonus }) { - val resourceTradeType = if(entry.resource.resourceType== ResourceType.Luxury) TradeType.Luxury_Resource + val resourceTradeType = if (entry.resource.resourceType == ResourceType.Luxury) TradeType.Luxury_Resource else TradeType.Strategic_Resource offers.add(TradeOffer(entry.resource.name, resourceTradeType, entry.amount)) } @@ -116,5 +116,4 @@ class TradeLogic(val ourCivilization:CivilizationInfo, val otherCivilization: Ci transferTrade(ourCivilization, otherCivilization, currentTrade) transferTrade(otherCivilization, ourCivilization, currentTrade.reverse()) } -} - +} \ No newline at end of file diff --git a/core/src/com/unciv/ui/worldscreen/WorldScreen.kt b/core/src/com/unciv/ui/worldscreen/WorldScreen.kt index f5df13aba7..32311e83a6 100644 --- a/core/src/com/unciv/ui/worldscreen/WorldScreen.kt +++ b/core/src/com/unciv/ui/worldscreen/WorldScreen.kt @@ -653,7 +653,7 @@ class WorldScreen(val viewingCiv:CivilizationInfo) : CameraStageBaseScreen() { } displayTutorial(Tutorial.ApolloProgram) { viewingCiv.hasUnique("Enables construction of Spaceship parts") } displayTutorial(Tutorial.SiegeUnits) { viewingCiv.getCivUnits().any { it.type == UnitType.Siege } } - displayTutorial(Tutorial.Embarking) { viewingCiv.tech.getTechUniques().contains("Enables embarkation for land units") } + displayTutorial(Tutorial.Embarking) { viewingCiv.hasUnique("Enables embarkation for land units") } displayTutorial(Tutorial.NaturalWonders) { viewingCiv.naturalWonders.size > 0 } }