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

@ -27,8 +27,8 @@ object NextTurnAutomation {
respondToPopupAlerts(civInfo) respondToPopupAlerts(civInfo)
respondToTradeRequests(civInfo) respondToTradeRequests(civInfo)
if(civInfo.isMajorCiv()) { if (civInfo.isMajorCiv()) {
if(!civInfo.gameInfo.ruleSet.modOptions.uniques.contains(ModOptionsConstants.diplomaticRelationshipsCannotChange)) { if (!civInfo.gameInfo.ruleSet.modOptions.uniques.contains(ModOptionsConstants.diplomaticRelationshipsCannotChange)) {
declareWar(civInfo) declareWar(civInfo)
offerPeaceTreaty(civInfo) offerPeaceTreaty(civInfo)
// offerDeclarationOfFriendship(civInfo) // offerDeclarationOfFriendship(civInfo)
@ -52,7 +52,7 @@ object NextTurnAutomation {
} }
private fun respondToTradeRequests(civInfo: CivilizationInfo) { private fun respondToTradeRequests(civInfo: CivilizationInfo) {
for(tradeRequest in civInfo.tradeRequests.toList()){ for (tradeRequest in civInfo.tradeRequests.toList()) {
val otherCiv = civInfo.gameInfo.getCivilization(tradeRequest.requestingCiv) val otherCiv = civInfo.gameInfo.getCivilization(tradeRequest.requestingCiv)
val tradeLogic = TradeLogic(civInfo, otherCiv) val tradeLogic = TradeLogic(civInfo, otherCiv)
tradeLogic.currentTrade.set(tradeRequest.trade) tradeLogic.currentTrade.set(tradeRequest.trade)
@ -62,11 +62,10 @@ object NextTurnAutomation {
* the same resource to ANOTHER civ in this turn. Complicated! * the same resource to ANOTHER civ in this turn. Complicated!
*/ */
civInfo.tradeRequests.remove(tradeRequest) civInfo.tradeRequests.remove(tradeRequest)
if(TradeEvaluation().isTradeAcceptable(tradeLogic.currentTrade,civInfo,otherCiv)){ if (TradeEvaluation().isTradeAcceptable(tradeLogic.currentTrade, civInfo, otherCiv)) {
tradeLogic.acceptTrade() tradeLogic.acceptTrade()
otherCiv.addNotification("[${civInfo.civName}] has accepted your trade request", Color.GOLD) otherCiv.addNotification("[${civInfo.civName}] has accepted your trade request", Color.GOLD)
} } else {
else {
otherCiv.addNotification("[${civInfo.civName}] has denied your trade request", Color.GOLD) otherCiv.addNotification("[${civInfo.civName}] has denied your trade request", Color.GOLD)
} }
} }
@ -74,7 +73,7 @@ object NextTurnAutomation {
} }
private fun respondToPopupAlerts(civInfo: CivilizationInfo) { private fun respondToPopupAlerts(civInfo: CivilizationInfo) {
for(popupAlert in civInfo.popupAlerts) { for (popupAlert in civInfo.popupAlerts) {
if (popupAlert.type == AlertType.DemandToStopSettlingCitiesNear) { // we're called upon to make a decision if (popupAlert.type == AlertType.DemandToStopSettlingCitiesNear) { // we're called upon to make a decision
val demandingCiv = civInfo.gameInfo.getCivilization(popupAlert.value) val demandingCiv = civInfo.gameInfo.getCivilization(popupAlert.value)
val diploManager = civInfo.getDiplomacyManager(demandingCiv) val diploManager = civInfo.getDiplomacyManager(demandingCiv)
@ -96,7 +95,7 @@ object NextTurnAutomation {
civInfo.popupAlerts.clear() // AIs don't care about popups. civInfo.popupAlerts.clear() // AIs don't care about popups.
} }
private fun tryGainInfluence(civInfo: CivilizationInfo, cityState:CivilizationInfo) { private fun tryGainInfluence(civInfo: CivilizationInfo, cityState: CivilizationInfo) {
if (civInfo.gold < 250) return // save up if (civInfo.gold < 250) return // save up
if (cityState.getDiplomacyManager(civInfo).influence < 20) { if (cityState.getDiplomacyManager(civInfo).influence < 20) {
civInfo.giveGoldGift(cityState, 250) civInfo.giveGoldGift(cityState, 250)
@ -180,8 +179,7 @@ object NextTurnAutomation {
private fun adoptPolicy(civInfo: CivilizationInfo) { private fun adoptPolicy(civInfo: CivilizationInfo) {
while (civInfo.policies.canAdoptPolicy()) { while (civInfo.policies.canAdoptPolicy()) {
val adoptablePolicies = civInfo.gameInfo.ruleSet.policyBranches.values val adoptablePolicies = civInfo.gameInfo.ruleSet.policies.values
.flatMap { it.policies.union(listOf(it)) }
.filter { civInfo.policies.isAdoptable(it) } .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 // This can happen if the player is crazy enough to have the game continue forever and he disabled cultural victory
@ -209,7 +207,7 @@ object NextTurnAutomation {
} }
} }
private fun potentialLuxuryTrades(civInfo:CivilizationInfo, otherCivInfo:CivilizationInfo): ArrayList<Trade> { private fun potentialLuxuryTrades(civInfo: CivilizationInfo, otherCivInfo: CivilizationInfo): ArrayList<Trade> {
val tradeLogic = TradeLogic(civInfo, otherCivInfo) val tradeLogic = TradeLogic(civInfo, otherCivInfo)
val ourTradableLuxuryResources = tradeLogic.ourAvailableOffers val ourTradableLuxuryResources = tradeLogic.ourAvailableOffers
.filter { it.type == TradeType.Luxury_Resource && it.amount > 1 } .filter { it.type == TradeType.Luxury_Resource && it.amount > 1 }
@ -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 // 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 // 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) for (otherCiv in knownCivs.filter {
&& !civInfo.getDiplomacyManager(it).hasFlag(DiplomacyFlags.DeclinedLuxExchange)}) { it.isMajorCiv() && !it.isAtWarWith(civInfo)
&& !civInfo.getDiplomacyManager(it).hasFlag(DiplomacyFlags.DeclinedLuxExchange)
}) {
val relationshipLevel = civInfo.getDiplomacyManager(otherCiv).relationshipLevel() val relationshipLevel = civInfo.getDiplomacyManager(otherCiv).relationshipLevel()
if (relationshipLevel <= RelationshipLevel.Enemy) if (relationshipLevel <= RelationshipLevel.Enemy)
@ -263,11 +263,12 @@ object NextTurnAutomation {
private fun offerDeclarationOfFriendship(civInfo: CivilizationInfo) { private fun offerDeclarationOfFriendship(civInfo: CivilizationInfo) {
val civsThatWeCanDeclareFriendshipWith = civInfo.getKnownCivs() val civsThatWeCanDeclareFriendshipWith = civInfo.getKnownCivs()
.asSequence() .asSequence()
.filter { it.isMajorCiv() } .filter {
.filter { !it.isAtWarWith(civInfo) } it.isMajorCiv() && !it.isAtWarWith(civInfo)
.filter { it.getDiplomacyManager(civInfo).relationshipLevel() > RelationshipLevel.Neutral } && it.getDiplomacyManager(civInfo).relationshipLevel() > RelationshipLevel.Neutral
.filter { !civInfo.getDiplomacyManager(it).hasFlag(DiplomacyFlags.DeclarationOfFriendship) } && !civInfo.getDiplomacyManager(it).hasFlag(DiplomacyFlags.DeclarationOfFriendship)
.filter { !civInfo.getDiplomacyManager(it).hasFlag(DiplomacyFlags.Denunceation) } && !civInfo.getDiplomacyManager(it).hasFlag(DiplomacyFlags.Denunceation)
}
.sortedByDescending { it.getDiplomacyManager(civInfo).relationshipLevel() } .sortedByDescending { it.getDiplomacyManager(civInfo).relationshipLevel() }
for (civ in civsThatWeCanDeclareFriendshipWith) { for (civ in civsThatWeCanDeclareFriendshipWith) {
// Default setting is 5, this will be changed according to different civ. // Default setting is 5, this will be changed according to different civ.
@ -281,8 +282,10 @@ object NextTurnAutomation {
val canSignResearchAgreementCiv = civInfo.getKnownCivs() val canSignResearchAgreementCiv = civInfo.getKnownCivs()
.asSequence() .asSequence()
.filter { civInfo.canSignResearchAgreementsWith(it) .filter {
&& !civInfo.getDiplomacyManager(it).hasFlag(DiplomacyFlags.DeclinedResearchAgreement) } civInfo.canSignResearchAgreementsWith(it)
&& !civInfo.getDiplomacyManager(it).hasFlag(DiplomacyFlags.DeclinedResearchAgreement)
}
.sortedByDescending { it.statsForNextTurn.science } .sortedByDescending { it.statsForNextTurn.science }
for (otherCiv in canSignResearchAgreementCiv) { for (otherCiv in canSignResearchAgreementCiv) {
@ -306,13 +309,13 @@ object NextTurnAutomation {
.filterNot { it == civInfo || it.isBarbarian() || it.cities.isEmpty() } .filterNot { it == civInfo || it.isBarbarian() || it.cities.isEmpty() }
.filter { !civInfo.getDiplomacyManager(it).hasFlag(DiplomacyFlags.DeclinedPeace) } .filter { !civInfo.getDiplomacyManager(it).hasFlag(DiplomacyFlags.DeclinedPeace) }
// Don't allow AIs to offer peace to ity states allied with their enemies // Don't allow AIs to offer peace to ity states allied with their enemies
.filterNot { it.isCityState() && it.getAllyCiv()!="" && civInfo.isAtWarWith(civInfo.gameInfo.getCivilization(it.getAllyCiv())) } .filterNot { it.isCityState() && it.getAllyCiv() != "" && civInfo.isAtWarWith(civInfo.gameInfo.getCivilization(it.getAllyCiv())) }
for (enemy in enemiesCiv) { for (enemy in enemiesCiv) {
val enemiesStrength = Automation.evaluteCombatStrength(enemy) val enemiesStrength = Automation.evaluteCombatStrength(enemy)
// If we don't have an unobstructed path to the enemy, offer peace even though we can beat them // If we don't have an unobstructed path to the enemy, offer peace even though we can beat them
val canReachEnemy = BFS(civInfo.getCapital().getCenterTile()){ it.canCivEnter(civInfo) } val canReachEnemy = BFS(civInfo.getCapital().getCenterTile()) { it.canCivEnter(civInfo) }
canReachEnemy.stepToEnd() canReachEnemy.stepToEnd()
if (enemy.cities.any { canReachEnemy.hasReachedTile(it.getCenterTile()) } if (enemy.cities.any { canReachEnemy.hasReachedTile(it.getCenterTile()) }
@ -368,8 +371,10 @@ object NextTurnAutomation {
//evaluate war //evaluate war
val enemyCivs = civInfo.getKnownCivs() val enemyCivs = civInfo.getKnownCivs()
.filterNot { it == civInfo || it.cities.isEmpty() || !civInfo.getDiplomacyManager(it).canDeclareWar() .filterNot {
|| (it.cities.none { civInfo.exploredTiles.contains(it.location) }) } 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, // 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 // and end up at a massive disadvantage
@ -383,7 +388,7 @@ object NextTurnAutomation {
civInfo.getDiplomacyManager(civWithBestMotivationToAttack.first).declareWar() civInfo.getDiplomacyManager(civWithBestMotivationToAttack.first).declareWar()
} }
private fun motivationToAttack(civInfo:CivilizationInfo, otherCiv:CivilizationInfo): Int { private fun motivationToAttack(civInfo: CivilizationInfo, otherCiv: CivilizationInfo): Int {
val ourCombatStrength = Automation.evaluteCombatStrength(civInfo).toFloat() val ourCombatStrength = Automation.evaluteCombatStrength(civInfo).toFloat()
val theirCombatStrength = Automation.evaluteCombatStrength(otherCiv) val theirCombatStrength = Automation.evaluteCombatStrength(otherCiv)
if (theirCombatStrength > ourCombatStrength) return 0 if (theirCombatStrength > ourCombatStrength) return 0
@ -417,13 +422,13 @@ object NextTurnAutomation {
modifierMap["No land path"] = -10 modifierMap["No land path"] = -10
val diplomacyManager = civInfo.getDiplomacyManager(otherCiv) val diplomacyManager = civInfo.getDiplomacyManager(otherCiv)
if(diplomacyManager.hasFlag(DiplomacyFlags.ResearchAgreement)) if (diplomacyManager.hasFlag(DiplomacyFlags.ResearchAgreement))
modifierMap["Research Agreement"] = -5 modifierMap["Research Agreement"] = -5
if(diplomacyManager.hasFlag(DiplomacyFlags.DeclarationOfFriendship)) if (diplomacyManager.hasFlag(DiplomacyFlags.DeclarationOfFriendship))
modifierMap["Declaration of Friendship"] = -10 modifierMap["Declaration of Friendship"] = -10
val relationshipModifier = when(diplomacyManager.relationshipLevel()){ val relationshipModifier = when (diplomacyManager.relationshipLevel()) {
RelationshipLevel.Unforgivable -> 10 RelationshipLevel.Unforgivable -> 10
RelationshipLevel.Enemy -> 5 RelationshipLevel.Enemy -> 5
RelationshipLevel.Ally -> -5 // this is so that ally + DoF is not too unbalanced - RelationshipLevel.Ally -> -5 // this is so that ally + DoF is not too unbalanced -
@ -432,10 +437,10 @@ object NextTurnAutomation {
} }
modifierMap["Relationship"] = relationshipModifier modifierMap["Relationship"] = relationshipModifier
if(diplomacyManager.resourcesFromTrade().any { it.amount > 0 }) if (diplomacyManager.resourcesFromTrade().any { it.amount > 0 })
modifierMap["Receiving trade resources"] = -5 modifierMap["Receiving trade resources"] = -5
if(theirCity.getTiles().none { it.neighbors.any { it.getOwner()==theirCity.civInfo && it.getCity() != theirCity } }) if (theirCity.getTiles().none { it.neighbors.any { it.getOwner() == theirCity.civInfo && it.getCity() != theirCity } })
modifierMap["Isolated city"] = 15 modifierMap["Isolated city"] = 15
return modifierMap.values.sum() return modifierMap.values.sum()
@ -518,18 +523,19 @@ object NextTurnAutomation {
} }
} }
private fun onCitySettledNearBorders(civInfo: CivilizationInfo, otherCiv:CivilizationInfo){ private fun onCitySettledNearBorders(civInfo: CivilizationInfo, otherCiv: CivilizationInfo) {
val diplomacyManager = civInfo.getDiplomacyManager(otherCiv) val diplomacyManager = civInfo.getDiplomacyManager(otherCiv)
when { when {
diplomacyManager.hasFlag(DiplomacyFlags.IgnoreThemSettlingNearUs) -> {} diplomacyManager.hasFlag(DiplomacyFlags.IgnoreThemSettlingNearUs) -> {
}
diplomacyManager.hasFlag(DiplomacyFlags.AgreedToNotSettleNearUs) -> { diplomacyManager.hasFlag(DiplomacyFlags.AgreedToNotSettleNearUs) -> {
otherCiv.popupAlerts.add(PopupAlert(AlertType.CitySettledNearOtherCivDespiteOurPromise, civInfo.civName)) otherCiv.popupAlerts.add(PopupAlert(AlertType.CitySettledNearOtherCivDespiteOurPromise, civInfo.civName))
diplomacyManager.setFlag(DiplomacyFlags.IgnoreThemSettlingNearUs,100) diplomacyManager.setFlag(DiplomacyFlags.IgnoreThemSettlingNearUs, 100)
diplomacyManager.setModifier(DiplomaticModifiers.BetrayedPromiseToNotSettleCitiesNearUs,-20f) diplomacyManager.setModifier(DiplomaticModifiers.BetrayedPromiseToNotSettleCitiesNearUs, -20f)
} }
else -> { else -> {
val threatLevel = Automation.threatAssessment(civInfo,otherCiv) val threatLevel = Automation.threatAssessment(civInfo, otherCiv)
if(threatLevel<ThreatLevel.High) // don't piss them off for no reason please. if (threatLevel < ThreatLevel.High) // don't piss them off for no reason please.
otherCiv.popupAlerts.add(PopupAlert(AlertType.DemandToStopSettlingCitiesNear, civInfo.civName)) otherCiv.popupAlerts.add(PopupAlert(AlertType.DemandToStopSettlingCitiesNear, civInfo.civName))
} }
} }
@ -537,10 +543,10 @@ object NextTurnAutomation {
} }
fun getMinDistanceBetweenCities(civ1: CivilizationInfo, civ2: CivilizationInfo): Int { fun getMinDistanceBetweenCities(civ1: CivilizationInfo, civ2: CivilizationInfo): Int {
return getClosestCities(civ1,civ2).aerialDistance return getClosestCities(civ1, civ2).aerialDistance
} }
data class CityDistance(val city1:CityInfo, val city2:CityInfo, val aerialDistance: Int) data class CityDistance(val city1: CityInfo, val city2: CityInfo, val aerialDistance: Int)
fun getClosestCities(civ1: CivilizationInfo, civ2: CivilizationInfo): CityDistance { fun getClosestCities(civ1: CivilizationInfo, civ2: CivilizationInfo): CityDistance {
val cityDistances = arrayListOf<CityDistance>() val cityDistances = arrayListOf<CityDistance>()

View File

@ -1,10 +1,8 @@
package com.unciv.logic.civilization package com.unciv.logic.civilization
import com.unciv.Constants
import com.unciv.models.ruleset.Policy import com.unciv.models.ruleset.Policy
import com.unciv.models.ruleset.UniqueMap import com.unciv.models.ruleset.UniqueMap
import com.unciv.models.ruleset.UniqueTriggerActivation import com.unciv.models.ruleset.UniqueTriggerActivation
import com.unciv.models.ruleset.VictoryType
import kotlin.math.min import kotlin.math.min
import kotlin.math.pow import kotlin.math.pow
import kotlin.math.roundToInt import kotlin.math.roundToInt
@ -12,10 +10,13 @@ import kotlin.math.roundToInt
class PolicyManager { class PolicyManager {
@Transient lateinit var civInfo: CivilizationInfo @Transient
lateinit var civInfo: CivilizationInfo
// Needs to be separate from the actual adopted policies, so that // Needs to be separate from the actual adopted policies, so that
// in different game versions, policies can have different effects // in different game versions, policies can have different effects
@Transient internal val policyUniques = UniqueMap() @Transient
internal val policyUniques = UniqueMap()
var freePolicies = 0 var freePolicies = 0
var storedCulture = 0 var storedCulture = 0
@ -38,26 +39,23 @@ class PolicyManager {
return toReturn return toReturn
} }
fun getPolicyByName(name:String): Policy = getAllPolicies().first { it.name==name } fun getPolicyByName(name: String): Policy = civInfo.gameInfo.ruleSet.policies[name]!!
fun setTransients() { fun setTransients() {
for (policyName in adoptedPolicies) for (policyName in adoptedPolicies)
addPolicyToTransients(getPolicyByName(policyName)) addPolicyToTransients(getPolicyByName(policyName))
} }
fun addPolicyToTransients(policy: Policy){ fun addPolicyToTransients(policy: Policy) {
for(unique in policy.uniqueObjects) for (unique in policy.uniqueObjects)
policyUniques.addUnique(unique) policyUniques.addUnique(unique)
} }
private fun getAllPolicies() = civInfo.gameInfo.ruleSet.policyBranches.values.asSequence()
.flatMap { it.policies.asSequence()+sequenceOf(it) }
fun startTurn() { fun startTurn() {
tryAddLegalismBuildings() tryAddLegalismBuildings()
} }
fun addCulture(culture: Int){ fun addCulture(culture: Int) {
val couldAdoptPolicyBefore = canAdoptPolicy() val couldAdoptPolicyBefore = canAdoptPolicy()
storedCulture += culture storedCulture += culture
if (!couldAdoptPolicyBefore && canAdoptPolicy()) if (!couldAdoptPolicyBefore && canAdoptPolicy())
@ -80,7 +78,7 @@ class PolicyManager {
// Use "Culture cost of adopting new Policies reduced by [10]%" and "Each city founded increases culture cost of policies [33]% less than normal" instead // Use "Culture cost of adopting new Policies reduced by [10]%" and "Each city founded increases culture cost of policies [33]% less than normal" instead
if (civInfo.hasUnique("Each city founded increases culture cost of policies 33% less than normal")) if (civInfo.hasUnique("Each city founded increases culture cost of policies 33% less than normal"))
cityModifier *= (2 / 3f) cityModifier *= (2 / 3f)
for(unique in civInfo.getMatchingUniques("Culture cost of adopting new Policies reduced by 10%")) for (unique in civInfo.getMatchingUniques("Culture cost of adopting new Policies reduced by 10%"))
policyCultureCost *= 0.9 policyCultureCost *= 0.9
for (unique in civInfo.getMatchingUniques("Each city founded increases culture cost of policies []% less than normal")) for (unique in civInfo.getMatchingUniques("Each city founded increases culture cost of policies []% less than normal"))
@ -99,7 +97,7 @@ class PolicyManager {
fun isAdopted(policyName: String): Boolean = adoptedPolicies.contains(policyName) fun isAdopted(policyName: String): Boolean = adoptedPolicies.contains(policyName)
fun isAdoptable(policy: Policy): Boolean { fun isAdoptable(policy: Policy): Boolean {
if(isAdopted(policy.name)) return false if (isAdopted(policy.name)) return false
if (policy.name.endsWith("Complete")) return false if (policy.name.endsWith("Complete")) return false
if (!getAdoptedPolicies().containsAll(policy.requires!!)) return false if (!getAdoptedPolicies().containsAll(policy.requires!!)) return false
if (civInfo.gameInfo.ruleSet.getEraNumber(policy.branch.era) > civInfo.getEraNumber()) return false if (civInfo.gameInfo.ruleSet.getEraNumber(policy.branch.era) > civInfo.getEraNumber()) return false
@ -110,7 +108,7 @@ class PolicyManager {
if (freePolicies == 0 && storedCulture < getCultureNeededForNextPolicy()) if (freePolicies == 0 && storedCulture < getCultureNeededForNextPolicy())
return false return false
val hasAdoptablePolicies = getAllPolicies() val hasAdoptablePolicies = civInfo.gameInfo.ruleSet.policies.values
.any { civInfo.policies.isAdoptable(it) } .any { civInfo.policies.isAdoptable(it) }
return hasAdoptablePolicies return hasAdoptablePolicies
} }
@ -138,8 +136,6 @@ class PolicyManager {
} }
} }
val hasCapital = civInfo.cities.any { it.isCapital() }
for (unique in policy.uniqueObjects) for (unique in policy.uniqueObjects)
UniqueTriggerActivation.triggerCivwideUnique(unique, civInfo) UniqueTriggerActivation.triggerCivwideUnique(unique, civInfo)
@ -153,15 +149,17 @@ class PolicyManager {
} }
fun tryAddLegalismBuildings() { fun tryAddLegalismBuildings() {
if(!civInfo.hasUnique("Immediately creates a cheapest available cultural building in each of your first 4 cities for free")) if (!civInfo.hasUnique("Immediately creates a cheapest available cultural building in each of your first 4 cities for free"))
return return
if(legalismState.size >= 4) return if (legalismState.size >= 4) return
val candidateCities = civInfo.cities val candidateCities = civInfo.cities
.sortedBy { it.turnAcquired } .sortedBy { it.turnAcquired }
.subList(0, min(4, civInfo.cities.size)) .subList(0, min(4, civInfo.cities.size))
.filter { it.id !in legalismState .filter {
&& it.cityConstructions.hasBuildableCultureBuilding() } it.id !in legalismState
&& it.cityConstructions.hasBuildableCultureBuilding()
}
for (city in candidateCities) { for (city in candidateCities) {
val builtBuilding = city.cityConstructions.addCultureBuilding() val builtBuilding = city.cityConstructions.addCultureBuilding()
legalismState[city.id] = builtBuilding!! legalismState[city.id] = builtBuilding!!

View File

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

View File

@ -25,28 +25,26 @@ class PolicyPickerScreen(val worldScreen: WorldScreen, civInfo: CivilizationInfo
rightSideButton.setText("{Adopt policy}\r\n(".tr() + policies.storedCulture + "/" + policies.getCultureNeededForNextPolicy() + ")") 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()) rightSideButton.setText("All policies adopted".tr())
setDefaultCloseAction() setDefaultCloseAction()
if (policies.freePolicies > 0) { if (policies.freePolicies > 0) {
rightSideButton.setText("Adopt free policy".tr()) rightSideButton.setText("Adopt free policy".tr())
if (policies.canAdoptPolicy()) closeButton.disable() if (policies.canAdoptPolicy()) closeButton.disable()
} } else onBackButtonClicked { UncivGame.Current.setWorldScreen() }
else onBackButtonClicked { UncivGame.Current.setWorldScreen() }
rightSideButton.onClick(UncivSound.Policy) { rightSideButton.onClick(UncivSound.Policy) {
viewingCiv.policies.adopt(pickedPolicy!!) viewingCiv.policies.adopt(pickedPolicy!!)
// If we've moved to another screen in the meantime (great person pick, victory screen) ignore this // If we've moved to another screen in the meantime (great person pick, victory screen) ignore this
if(game.screen !is PolicyPickerScreen || !policies.canAdoptPolicy()){ if (game.screen !is PolicyPickerScreen || !policies.canAdoptPolicy()) {
game.setWorldScreen() game.setWorldScreen()
dispose() dispose()
} } else game.setScreen(PolicyPickerScreen(worldScreen)) // update policies
else game.setScreen(PolicyPickerScreen(worldScreen)) // update policies
} }
if(!UncivGame.Current.worldScreen.canChangeState) if (!UncivGame.Current.worldScreen.canChangeState)
rightSideButton.disable() rightSideButton.disable()
topTable.row().pad(30f) topTable.row().pad(30f)
@ -107,7 +105,7 @@ class PolicyPickerScreen(val worldScreen: WorldScreen, civInfo: CivilizationInfo
if (!policy.name.endsWith("Complete")) { if (!policy.name.endsWith("Complete")) {
if (policy.requires!!.isNotEmpty()) if (policy.requires!!.isNotEmpty())
policyText += "Requires [" + policy.requires!!.joinToString { it.tr() }+"]" policyText += "Requires [" + policy.requires!!.joinToString { it.tr() } + "]"
else else
policyText += "{Unlocked at} {" + policy.branch.era + "}" policyText += "{Unlocked at} {" + policy.branch.era + "}"
} }