Game can handle policies "disappearing" between mod versions

Added policy map to ruleset for simpler policy location
This commit is contained in:
Yair Morgenstern 2021-01-12 17:10:38 +02:00
parent 67bcc26ab7
commit a8e0f270a0
5 changed files with 82 additions and 70 deletions

View File

@ -24,6 +24,7 @@ class UncivShowableException(missingMods: String) : Exception(missingMods)
class GameInfo {
@Transient
lateinit var difficultyObject: Difficulty // Since this is static game-wide, and was taking a large part of nextTurn
@Transient
lateinit var currentPlayerCiv: CivilizationInfo // this is called thousands of times, no reason to search for it with a find{} every time
@ -31,6 +32,7 @@ class GameInfo {
* that is inconsistent with the saved game on the cloud */
@Transient
var isUpToDate = false
@Transient
lateinit var ruleSet: Ruleset
@ -356,6 +358,9 @@ class GameInfo {
for (tech in civinfo.tech.techsResearched.toList())
if (!ruleSet.technologies.containsKey(tech))
civinfo.tech.techsResearched.remove(tech)
for (policy in civinfo.policies.adoptedPolicies.toList())
if (!ruleSet.policies.containsKey(policy))
civinfo.policies.adoptedPolicies.remove(policy)
}
}

View File

@ -65,8 +65,7 @@ object NextTurnAutomation {
if (TradeEvaluation().isTradeAcceptable(tradeLogic.currentTrade, civInfo, otherCiv)) {
tradeLogic.acceptTrade()
otherCiv.addNotification("[${civInfo.civName}] has accepted your trade request", Color.GOLD)
}
else {
} else {
otherCiv.addNotification("[${civInfo.civName}] has denied your trade request", Color.GOLD)
}
}
@ -180,8 +179,7 @@ object NextTurnAutomation {
private fun adoptPolicy(civInfo: CivilizationInfo) {
while (civInfo.policies.canAdoptPolicy()) {
val adoptablePolicies = civInfo.gameInfo.ruleSet.policyBranches.values
.flatMap { it.policies.union(listOf(it)) }
val adoptablePolicies = civInfo.gameInfo.ruleSet.policies.values
.filter { civInfo.policies.isAdoptable(it) }
// This can happen if the player is crazy enough to have the game continue forever and he disabled cultural victory
@ -245,8 +243,10 @@ object NextTurnAutomation {
// We should A. add some sort of timer (20? 30 turns?) between luxury trade requests if they're denied - see DeclinedLuxExchange
// B. have a way for the AI to keep track of the "pending offers" - see DiplomacyManager.resourcesFromTrade
for (otherCiv in knownCivs.filter { it.isMajorCiv() && !it.isAtWarWith(civInfo)
&& !civInfo.getDiplomacyManager(it).hasFlag(DiplomacyFlags.DeclinedLuxExchange)}) {
for (otherCiv in knownCivs.filter {
it.isMajorCiv() && !it.isAtWarWith(civInfo)
&& !civInfo.getDiplomacyManager(it).hasFlag(DiplomacyFlags.DeclinedLuxExchange)
}) {
val relationshipLevel = civInfo.getDiplomacyManager(otherCiv).relationshipLevel()
if (relationshipLevel <= RelationshipLevel.Enemy)
@ -263,11 +263,12 @@ object NextTurnAutomation {
private fun offerDeclarationOfFriendship(civInfo: CivilizationInfo) {
val civsThatWeCanDeclareFriendshipWith = civInfo.getKnownCivs()
.asSequence()
.filter { it.isMajorCiv() }
.filter { !it.isAtWarWith(civInfo) }
.filter { it.getDiplomacyManager(civInfo).relationshipLevel() > RelationshipLevel.Neutral }
.filter { !civInfo.getDiplomacyManager(it).hasFlag(DiplomacyFlags.DeclarationOfFriendship) }
.filter { !civInfo.getDiplomacyManager(it).hasFlag(DiplomacyFlags.Denunceation) }
.filter {
it.isMajorCiv() && !it.isAtWarWith(civInfo)
&& it.getDiplomacyManager(civInfo).relationshipLevel() > RelationshipLevel.Neutral
&& !civInfo.getDiplomacyManager(it).hasFlag(DiplomacyFlags.DeclarationOfFriendship)
&& !civInfo.getDiplomacyManager(it).hasFlag(DiplomacyFlags.Denunceation)
}
.sortedByDescending { it.getDiplomacyManager(civInfo).relationshipLevel() }
for (civ in civsThatWeCanDeclareFriendshipWith) {
// Default setting is 5, this will be changed according to different civ.
@ -281,8 +282,10 @@ object NextTurnAutomation {
val canSignResearchAgreementCiv = civInfo.getKnownCivs()
.asSequence()
.filter { civInfo.canSignResearchAgreementsWith(it)
&& !civInfo.getDiplomacyManager(it).hasFlag(DiplomacyFlags.DeclinedResearchAgreement) }
.filter {
civInfo.canSignResearchAgreementsWith(it)
&& !civInfo.getDiplomacyManager(it).hasFlag(DiplomacyFlags.DeclinedResearchAgreement)
}
.sortedByDescending { it.statsForNextTurn.science }
for (otherCiv in canSignResearchAgreementCiv) {
@ -368,8 +371,10 @@ object NextTurnAutomation {
//evaluate war
val enemyCivs = civInfo.getKnownCivs()
.filterNot { it == civInfo || it.cities.isEmpty() || !civInfo.getDiplomacyManager(it).canDeclareWar()
|| (it.cities.none { civInfo.exploredTiles.contains(it.location) }) }
.filterNot {
it == civInfo || it.cities.isEmpty() || !civInfo.getDiplomacyManager(it).canDeclareWar()
|| (it.cities.none { civInfo.exploredTiles.contains(it.location) })
}
// If the AI declares war on a civ without knowing the location of any cities, it'll just keep amassing an army and not sending it anywhere,
// and end up at a massive disadvantage
@ -521,7 +526,8 @@ object NextTurnAutomation {
private fun onCitySettledNearBorders(civInfo: CivilizationInfo, otherCiv: CivilizationInfo) {
val diplomacyManager = civInfo.getDiplomacyManager(otherCiv)
when {
diplomacyManager.hasFlag(DiplomacyFlags.IgnoreThemSettlingNearUs) -> {}
diplomacyManager.hasFlag(DiplomacyFlags.IgnoreThemSettlingNearUs) -> {
}
diplomacyManager.hasFlag(DiplomacyFlags.AgreedToNotSettleNearUs) -> {
otherCiv.popupAlerts.add(PopupAlert(AlertType.CitySettledNearOtherCivDespiteOurPromise, civInfo.civName))
diplomacyManager.setFlag(DiplomacyFlags.IgnoreThemSettlingNearUs, 100)

View File

@ -1,10 +1,8 @@
package com.unciv.logic.civilization
import com.unciv.Constants
import com.unciv.models.ruleset.Policy
import com.unciv.models.ruleset.UniqueMap
import com.unciv.models.ruleset.UniqueTriggerActivation
import com.unciv.models.ruleset.VictoryType
import kotlin.math.min
import kotlin.math.pow
import kotlin.math.roundToInt
@ -12,10 +10,13 @@ import kotlin.math.roundToInt
class PolicyManager {
@Transient lateinit var civInfo: CivilizationInfo
@Transient
lateinit var civInfo: CivilizationInfo
// Needs to be separate from the actual adopted policies, so that
// in different game versions, policies can have different effects
@Transient internal val policyUniques = UniqueMap()
@Transient
internal val policyUniques = UniqueMap()
var freePolicies = 0
var storedCulture = 0
@ -38,7 +39,7 @@ class PolicyManager {
return toReturn
}
fun getPolicyByName(name:String): Policy = getAllPolicies().first { it.name==name }
fun getPolicyByName(name: String): Policy = civInfo.gameInfo.ruleSet.policies[name]!!
fun setTransients() {
for (policyName in adoptedPolicies)
@ -50,9 +51,6 @@ class PolicyManager {
policyUniques.addUnique(unique)
}
private fun getAllPolicies() = civInfo.gameInfo.ruleSet.policyBranches.values.asSequence()
.flatMap { it.policies.asSequence()+sequenceOf(it) }
fun startTurn() {
tryAddLegalismBuildings()
}
@ -110,7 +108,7 @@ class PolicyManager {
if (freePolicies == 0 && storedCulture < getCultureNeededForNextPolicy())
return false
val hasAdoptablePolicies = getAllPolicies()
val hasAdoptablePolicies = civInfo.gameInfo.ruleSet.policies.values
.any { civInfo.policies.isAdoptable(it) }
return hasAdoptablePolicies
}
@ -138,8 +136,6 @@ class PolicyManager {
}
}
val hasCapital = civInfo.cities.any { it.isCapital() }
for (unique in policy.uniqueObjects)
UniqueTriggerActivation.triggerCivwideUnique(unique, civInfo)
@ -160,8 +156,10 @@ class PolicyManager {
val candidateCities = civInfo.cities
.sortedBy { it.turnAcquired }
.subList(0, min(4, civInfo.cities.size))
.filter { it.id !in legalismState
&& it.cityConstructions.hasBuildableCultureBuilding() }
.filter {
it.id !in legalismState
&& it.cityConstructions.hasBuildableCultureBuilding()
}
for (city in candidateCities) {
val builtBuilding = city.cityConstructions.addCultureBuilding()
legalismState[city.id] = builtBuilding!!

View File

@ -51,6 +51,7 @@ class Ruleset {
val quests = LinkedHashMap<String, Quest>()
val specialists = LinkedHashMap<String, Specialist>()
val policyBranches = LinkedHashMap<String, PolicyBranch>()
val policies = LinkedHashMap<String, Policy>()
val difficulties = LinkedHashMap<String, Difficulty>()
val mods = LinkedHashSet<String>()
var modOptions = ModOptions()
@ -74,6 +75,7 @@ class Ruleset {
difficulties.putAll(ruleset.difficulties)
nations.putAll(ruleset.nations)
policyBranches.putAll(ruleset.policyBranches)
policies.putAll(ruleset.policies)
quests.putAll(ruleset.quests)
specialists.putAll(ruleset.specialists)
technologies.putAll(ruleset.technologies)
@ -93,6 +95,7 @@ class Ruleset {
difficulties.clear()
nations.clear()
policyBranches.clear()
policies.clear()
quests.clear()
technologies.clear()
buildings.clear()
@ -159,9 +162,11 @@ class Ruleset {
for (branch in policyBranches.values) {
branch.requires = ArrayList()
branch.branch = branch
policies[branch.name] = branch
for (policy in branch.policies) {
policy.branch = branch
if (policy.requires == null) policy.requires = arrayListOf(branch.name)
policies[policy.name] = policy
}
branch.policies.last().name = branch.name + " Complete"
}

View File

@ -25,15 +25,14 @@ class PolicyPickerScreen(val worldScreen: WorldScreen, civInfo: CivilizationInfo
rightSideButton.setText("{Adopt policy}\r\n(".tr() + policies.storedCulture + "/" + policies.getCultureNeededForNextPolicy() + ")")
if (viewingCiv.gameInfo.ruleSet.policyBranches.values.flatMap { it.policies }.all { it.name in policies.adoptedPolicies})
if (viewingCiv.gameInfo.ruleSet.policies.values.all { it.name in policies.adoptedPolicies })
rightSideButton.setText("All policies adopted".tr())
setDefaultCloseAction()
if (policies.freePolicies > 0) {
rightSideButton.setText("Adopt free policy".tr())
if (policies.canAdoptPolicy()) closeButton.disable()
}
else onBackButtonClicked { UncivGame.Current.setWorldScreen() }
} else onBackButtonClicked { UncivGame.Current.setWorldScreen() }
rightSideButton.onClick(UncivSound.Policy) {
viewingCiv.policies.adopt(pickedPolicy!!)
@ -42,8 +41,7 @@ class PolicyPickerScreen(val worldScreen: WorldScreen, civInfo: CivilizationInfo
if (game.screen !is PolicyPickerScreen || !policies.canAdoptPolicy()) {
game.setWorldScreen()
dispose()
}
else game.setScreen(PolicyPickerScreen(worldScreen)) // update policies
} else game.setScreen(PolicyPickerScreen(worldScreen)) // update policies
}
if (!UncivGame.Current.worldScreen.canChangeState)