mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-30 15:30:43 -04:00
Game can handle policies "disappearing" between mod versions
Added policy map to ruleset for simpler policy location
This commit is contained in:
parent
67bcc26ab7
commit
a8e0f270a0
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,8 +65,7 @@ object NextTurnAutomation {
|
|||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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
|
||||||
@ -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) {
|
||||||
@ -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
|
||||||
|
|
||||||
@ -521,7 +526,8 @@ 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)
|
||||||
|
@ -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,7 +39,7 @@ 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)
|
||||||
@ -50,9 +51,6 @@ class PolicyManager {
|
|||||||
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()
|
||||||
}
|
}
|
||||||
@ -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)
|
||||||
|
|
||||||
@ -160,8 +156,10 @@ class PolicyManager {
|
|||||||
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!!
|
||||||
|
@ -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"
|
||||||
}
|
}
|
||||||
|
@ -25,15 +25,14 @@ 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!!)
|
||||||
@ -42,8 +41,7 @@ class PolicyPickerScreen(val worldScreen: WorldScreen, civInfo: CivilizationInfo
|
|||||||
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)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user