mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-22 10:54:19 -04:00
Implementation for establishing embassies in diplomacy (#13625)
* G&K feature - Embassy * fix spotted errors * add icon and gameplay test * fix invalid trade logic * make embassies work for G&K only * remove introduced bug * trade evaluation and decline embassy * update civilopedia for embassies * cleanup * diplomatic modifiers * fix embassies unique * make embassies unique global and bugfix * fix AI can not trade with cs * add embassies unique for mods * mods require uniques to enable embassies * fix mods require uniques to enable embassies * update uniques.md * apply reviewed changes * apply reviewed change 2 * bugfix and cleanup * remove obsolete import * null pointer bugfix * remove toList() and function rename
This commit is contained in:
parent
368bf8c84d
commit
0ddbb46c79
@ -1,6 +1,7 @@
|
||||
{
|
||||
"name": "Global uniques",
|
||||
"uniques": [
|
||||
"Requires establishing embassies to conduct advanced diplomacy",
|
||||
"[-75]% growth [in all cities] <when between [-10] and [-1] [Happiness]>",
|
||||
"Nullifies Growth [in all cities] <when below [-10] [Happiness]>",
|
||||
"[-50]% [Production] [in all cities] <when below [-10] [Happiness]>",
|
||||
|
@ -76,6 +76,7 @@
|
||||
"name": "Writing",
|
||||
"row": 3,
|
||||
"prerequisites": ["Pottery"],
|
||||
"uniques": ["Enables establishment of embassies"],
|
||||
"quote": "'He who destroys a good book kills reason itself.' - John Milton"
|
||||
},
|
||||
{
|
||||
|
@ -269,21 +269,49 @@
|
||||
"Ranged attacks can be done from a distance, dependent on the 'Range' value of the unit.\nWhile melee attacks allow the defender to damage the attacker in retaliation, ranged attacks do not."
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Embassies",
|
||||
"steps": [
|
||||
"Establishing an embassy in other players' Capital city shows the location of their Capital, likewise other players who establish an embassy in your Capital can see location of your Capital.",
|
||||
"Embassies thus allow Spies to be placed in another players' Capital City if Espionage is enabled.",
|
||||
"Mutual embassies are required to allow trading open borders and to sign Research Agreement and Defensive Pact.",
|
||||
"Declaring war on another player or denouncing them will remove embassies from both players' Capitals. You will have to re-establish them to use their effect.",
|
||||
"Re-establishing an embasy after denounciation from either side becomes available next turn, while re-establishing them when at war requires peacy treaty.",
|
||||
"Be cautious when accepting embassy from other players because they can spy on your capital, or worse may start planning to attack you.",
|
||||
"Embassies are available using the Gods and Kings ruleset."
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Open Borders",
|
||||
"civilopediaText": [
|
||||
{ text: "Open Borders from other player and vice versa allow units to freely pass trough their territoy." },
|
||||
{ text: "They also let Missionaries to enter other players' territory without suffering attrition." },
|
||||
{ text: "Open Borders expire depending on game speed and are canceled upon Declaration of War, the closure however takes effect only after war ends and need to be traded again." },
|
||||
{ text: "You gain diplomatic boost with other AI player if you both have Open Borders to each other" },
|
||||
{ text: "Be cautious when giving Open Borders because other player may settle a City near your lands in an area you are planning to use, they may also use your territory to attack your friends or City State allies." },
|
||||
{ text: "When playing with the Gods and Kings ruleset mutual embassies need to be established before Open Borders can be traded." },
|
||||
{ text: "See also: Embassies", "link": "Tutorials/Embassies" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Research Agreements",
|
||||
"steps": [
|
||||
"In Research Agreements, you and another civilization decide to jointly research technology.\nAt the end of the agreement, you will both receive a 'lump sum' of ⍾Science, which will go towards one of your unresearched technologies.",
|
||||
"The amount of ⍾Science you receive at the end is dependent on the ⍾Science generated by your cities and the other civilization's cities during the agreement - the more, the better!",
|
||||
"Note that before you can invest in a research agreement, you must have a Declaraction of Friendship, both Nations need the required Technology, and both Nations need enough Gold on hand for the agreement."
|
||||
"civilopediaText": [
|
||||
{ text: "In Research Agreements, you and another civilization decide to jointly research technology.\nAt the end of the agreement, you will both receive a 'lump sum' of ⍾Science, which will go towards one of your unresearched technologies." },
|
||||
{ text: "The amount of ⍾Science you receive at the end is dependent on the ⍾Science generated by your cities and the other civilization's cities during the agreement - the more, the better!" },
|
||||
{ text: "Note that before you can invest in a research agreement, you must have a Declaraction of Friendship, both Nations need the required Technology, and both Nations need enough Gold on hand for the agreement." },
|
||||
{ text: "When playing with the Gods and Kings ruleset mutual embassies need to be established before Research Agreement can be signed." },
|
||||
{ text: "See also: Embassies", "link": "Tutorials/Embassies" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Defensive Pacts",
|
||||
"steps": [
|
||||
"Defensive pacts allow you and another civ to protect one another from aggressors.\nOnce the defensive pact is signed, you will be drawn into their future defensive wars, just as they will be drawn into your future defensive wars. Declaring war on any Civ will remove all of your defensive pacts. You will have to re-sign them to use their effect.",
|
||||
"Be cautious when signing defensive pacts because they can bring you into wars that you might not want to be in.",
|
||||
"The AI is very careful and will not accept defensive pacts with less than 80 influence."
|
||||
]
|
||||
"civilopediaText": [
|
||||
{ text: "Defensive pacts allow you and another civ to protect one another from aggressors.\nOnce the defensive pact is signed, you will be drawn into their future defensive wars, just as they will be drawn into your future defensive wars. Declaring war on any Civ will remove all of your defensive pacts. You will have to re-sign them to use their effect." },
|
||||
{ text: "Be cautious when signing defensive pacts because they can bring you into wars that you might not want to be in." },
|
||||
{ text: "The AI is very careful and will not accept defensive pacts with less than 80 influence." },
|
||||
{ text: "When playing with the Gods and Kings ruleset mutual embassies need to be established before Defensive Pact can be signed." },
|
||||
{ text: "See also: Embassies", "link": "Tutorials/Embassies" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "City-States",
|
||||
|
@ -329,6 +329,7 @@ Cities =
|
||||
Technologies =
|
||||
Declarations of war =
|
||||
Peace Proposals =
|
||||
Accept Embassy =
|
||||
Introduction to [nation] =
|
||||
Declare war on [nation] =
|
||||
Make peace with [nation] =
|
||||
|
@ -51,6 +51,11 @@ object Constants {
|
||||
// Agreements
|
||||
const val openBorders = "Open Borders"
|
||||
|
||||
// Other trade items
|
||||
const val acceptEmbassy = "Accept Embassy"
|
||||
const val goldPerTurn = "Gold per turn"
|
||||
const val flatGold = "Gold"
|
||||
|
||||
/** Used as origin in StatMap or ResourceSupplyList, or the toggle button in DiplomacyOverviewTab */
|
||||
const val cityStates = "City-States"
|
||||
/** Used as origin in ResourceSupplyList */
|
||||
|
@ -108,20 +108,67 @@ object DiplomacyAutomation {
|
||||
return motivation > 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Try establishing embassy in other civs' capitals
|
||||
*
|
||||
* @param civInfo Civilization which initiates trade
|
||||
*/
|
||||
internal fun offerToEstablishEmbassy(civInfo: Civilization) {
|
||||
val civsThatWeCanEstablishEmbassyWith = civInfo.getKnownCivs().filter {
|
||||
civInfo.diplomacyFunctions.canEstablishEmbassyWith(it)
|
||||
&& !civInfo.getDiplomacyManager(it)!!.hasFlag(DiplomacyFlags.DeclinedEmbassy)
|
||||
&& !areWeOfferingTrade(civInfo, it, Constants.acceptEmbassy)
|
||||
}.sortedByDescending { it.getDiplomacyManager(civInfo)!!.relationshipLevel() }
|
||||
|
||||
for (otherCiv in civsThatWeCanEstablishEmbassyWith) {
|
||||
// Default setting is 3
|
||||
if ((1..10).random() < 7) continue
|
||||
if (wantsToAcceptEmbassy(civInfo, otherCiv)) {
|
||||
val tradeLogic = TradeLogic(civInfo, otherCiv)
|
||||
val embassyOffer = TradeOffer(Constants.acceptEmbassy, TradeOfferType.Embassy, speed = civInfo.gameInfo.speed)
|
||||
tradeLogic.currentTrade.theirOffers.add(embassyOffer)
|
||||
|
||||
// If possible offer mutual embassies (Civ V behavior) so we don't waste gold
|
||||
if (otherCiv.diplomacyFunctions.canEstablishEmbassyWith(civInfo)) {
|
||||
tradeLogic.currentTrade.ourOffers.add(embassyOffer)
|
||||
}
|
||||
else { // Otherwise offer GPT (prefered) or flat gold for embassy in their capital
|
||||
val embassyValue = TradeEvaluation().evaluateBuyCostWithInflation(embassyOffer, civInfo, otherCiv, tradeLogic.currentTrade)
|
||||
val embassyGptValue = embassyValue / civInfo.gameInfo.speed.dealDuration
|
||||
val ourGpt = civInfo.stats.statsForNextTurn.gold.toInt()
|
||||
if (embassyGptValue in 1..ourGpt)
|
||||
tradeLogic.currentTrade.ourOffers.add(TradeOffer(Constants.goldPerTurn, TradeOfferType.Gold_Per_Turn, embassyGptValue, civInfo.gameInfo.speed))
|
||||
else if (civInfo.gold >= embassyValue && ourGpt >= 0)
|
||||
tradeLogic.currentTrade.ourOffers.add(TradeOffer(Constants.flatGold, TradeOfferType.Gold, embassyValue, civInfo.gameInfo.speed))
|
||||
// else let them make counter offer
|
||||
}
|
||||
|
||||
otherCiv.tradeRequests.add(TradeRequest(civInfo.civName, tradeLogic.currentTrade.reverse()))
|
||||
}
|
||||
else {
|
||||
// Remember this for a few turns to save computation power
|
||||
civInfo.getDiplomacyManager(otherCiv)!!.setFlag(DiplomacyFlags.DeclinedEmbassy, 5)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun offerOpenBorders(civInfo: Civilization) {
|
||||
if (!civInfo.hasUnique(UniqueType.EnablesOpenBorders)) return
|
||||
val civsThatWeCanOpenBordersWith = civInfo.getKnownCivs()
|
||||
.filter {
|
||||
it.isMajorCiv() && !civInfo.isAtWarWith(it)
|
||||
&& it.hasUnique(UniqueType.EnablesOpenBorders)
|
||||
&& !civInfo.getDiplomacyManager(it)!!.hasOpenBorders
|
||||
&& !it.getDiplomacyManager(civInfo)!!.hasOpenBorders
|
||||
&& !civInfo.getDiplomacyManager(it)!!.hasFlag(DiplomacyFlags.DeclinedOpenBorders)
|
||||
&& !areWeOfferingTrade(civInfo, it, Constants.openBorders)
|
||||
}.sortedByDescending { it.getDiplomacyManager(civInfo)!!.relationshipLevel() }.toList()
|
||||
|
||||
val civsThatWeCanOpenBordersWith = civInfo.getKnownCivs().filter {
|
||||
val ourDiploManager = civInfo.getDiplomacyManager(it)!!
|
||||
it.isMajorCiv()
|
||||
&& !civInfo.isAtWarWith(it)
|
||||
&& it.hasUnique(UniqueType.EnablesOpenBorders)
|
||||
&& !ourDiploManager.hasOpenBorders
|
||||
&& !ourDiploManager.otherCivDiplomacy().hasOpenBorders
|
||||
&& civInfo.diplomacyFunctions.hasMutualEmbassyWith(it)
|
||||
&& !ourDiploManager.hasFlag(DiplomacyFlags.DeclinedOpenBorders)
|
||||
&& !areWeOfferingTrade(civInfo, it, Constants.openBorders)
|
||||
}.sortedByDescending { it.getDiplomacyManager(civInfo)!!.relationshipLevel() }
|
||||
|
||||
for (otherCiv in civsThatWeCanOpenBordersWith) {
|
||||
// Default setting is 3, this will be changed according to different civ.
|
||||
// Default setting is 3
|
||||
if ((1..10).random() < 7) continue
|
||||
if (wantsToOpenBorders(civInfo, otherCiv)) {
|
||||
val tradeLogic = TradeLogic(civInfo, otherCiv)
|
||||
@ -136,41 +183,67 @@ object DiplomacyAutomation {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if [otherCiv] wants to accept our embassy in their capital
|
||||
*/
|
||||
fun wantsToAcceptEmbassy(civInfo: Civilization, otherCiv: Civilization): Boolean {
|
||||
val theirDiploManager = otherCiv.getDiplomacyManager(civInfo)!!
|
||||
if (civInfo.getDiplomacyManager(otherCiv)!!.hasFlag(DiplomacyFlags.DeclinedEmbassy)) return false
|
||||
if (theirDiploManager.isRelationshipLevelLT(RelationshipLevel.Afraid)) return false
|
||||
|
||||
// Being able to see their capital can give us an advantage later on, especially with espionage enabled
|
||||
if (!civInfo.getCapital()!!.getCenterTile().isExplored(otherCiv)) return true
|
||||
|
||||
// Did they not discovered our capital yet?
|
||||
if (!otherCiv.getCapital()!!.getCenterTile().isExplored(civInfo)) {
|
||||
// If we're afraid of them deny embassy
|
||||
if (theirDiploManager.relationshipLevel() == RelationshipLevel.Afraid) return false
|
||||
|
||||
// If they're much stronger than us deny embassy
|
||||
val ourCombatStrength = civInfo.getStatForRanking(RankingType.Force)
|
||||
val theirCombatStrength = otherCiv.getStatForRanking(RankingType.Force)
|
||||
val ourAbsoluteAdvantage = ourCombatStrength - theirCombatStrength
|
||||
val percentageAdvantage = ourAbsoluteAdvantage / theirCombatStrength.toFloat()
|
||||
if (percentageAdvantage > 0.5) return false
|
||||
}
|
||||
|
||||
return true // Relationship is Afraid or greater
|
||||
}
|
||||
|
||||
fun wantsToOpenBorders(civInfo: Civilization, otherCiv: Civilization): Boolean {
|
||||
val diploManager = civInfo.getDiplomacyManager(otherCiv)!!
|
||||
if (diploManager.hasFlag(DiplomacyFlags.DeclinedOpenBorders)) return false
|
||||
if (diploManager.isRelationshipLevelLT(RelationshipLevel.Favorable)) return false
|
||||
val ourDiploManager = civInfo.getDiplomacyManager(otherCiv)!!
|
||||
if (ourDiploManager.hasFlag(DiplomacyFlags.DeclinedOpenBorders)) return false
|
||||
if (ourDiploManager.isRelationshipLevelLT(RelationshipLevel.Favorable)) return false
|
||||
// Don't accept if they are at war with our friends, they might use our land to attack them
|
||||
if (civInfo.diplomacy.values.any { it.isRelationshipLevelGE(RelationshipLevel.Friend) && it.otherCiv().isAtWarWith(otherCiv) })
|
||||
return false
|
||||
// Being able to see their cities can give us an advantage later on, especially with espionage enabled
|
||||
if (otherCiv.cities.count { !it.getCenterTile().isVisible(civInfo) } < otherCiv.cities.count() * .8f)
|
||||
return true
|
||||
if (hasAtLeastMotivationToAttack(civInfo, otherCiv,
|
||||
diploManager.opinionOfOtherCiv() * civInfo.getPersonality().modifierFocus(PersonalityValue.Commerce, .3f) / 2) > 0)
|
||||
if (hasAtLeastMotivationToAttack(civInfo, otherCiv,
|
||||
ourDiploManager.opinionOfOtherCiv() * civInfo.getPersonality().modifierFocus(PersonalityValue.Commerce, .3f) / 2) > 0)
|
||||
return false
|
||||
return true
|
||||
}
|
||||
|
||||
internal fun offerResearchAgreement(civInfo: Civilization) {
|
||||
if (!civInfo.diplomacyFunctions.canSignResearchAgreement()) return // don't waste your time
|
||||
|
||||
val civsThatWeCanSignResearchAgreementWith = civInfo.getKnownCivs().filter {
|
||||
civInfo.diplomacyFunctions.canSignResearchAgreementWith(it)
|
||||
&& !civInfo.getDiplomacyManager(it)!!.hasFlag(DiplomacyFlags.DeclinedResearchAgreement)
|
||||
&& !areWeOfferingTrade(civInfo, it, Constants.researchAgreement)
|
||||
}.sortedByDescending { it.stats.statsForNextTurn.science }
|
||||
|
||||
val canSignResearchAgreementCiv = civInfo.getKnownCivs()
|
||||
.filter {
|
||||
civInfo.diplomacyFunctions.canSignResearchAgreementsWith(it)
|
||||
&& !civInfo.getDiplomacyManager(it)!!.hasFlag(DiplomacyFlags.DeclinedResearchAgreement)
|
||||
&& !areWeOfferingTrade(civInfo, it, Constants.researchAgreement)
|
||||
}
|
||||
.sortedByDescending { it.stats.statsForNextTurn.science }
|
||||
|
||||
for (otherCiv in canSignResearchAgreementCiv) {
|
||||
for (otherCiv in civsThatWeCanSignResearchAgreementWith) {
|
||||
// Default setting is 5, this will be changed according to different civ.
|
||||
if ((1..10).random() <= 5 * civInfo.getPersonality().modifierFocus(PersonalityValue.Science, .3f)) continue
|
||||
val tradeLogic = TradeLogic(civInfo, otherCiv)
|
||||
val cost = civInfo.diplomacyFunctions.getResearchAgreementCost(otherCiv)
|
||||
tradeLogic.currentTrade.ourOffers.add(TradeOffer(Constants.researchAgreement, TradeOfferType.Treaty, cost, civInfo.gameInfo.speed))
|
||||
tradeLogic.currentTrade.theirOffers.add(TradeOffer(Constants.researchAgreement, TradeOfferType.Treaty, cost, civInfo.gameInfo.speed))
|
||||
val tradeOffer = TradeOffer(Constants.researchAgreement, TradeOfferType.Treaty, cost, civInfo.gameInfo.speed)
|
||||
|
||||
tradeLogic.currentTrade.ourOffers.add(tradeOffer)
|
||||
tradeLogic.currentTrade.theirOffers.add(tradeOffer)
|
||||
otherCiv.tradeRequests.add(TradeRequest(civInfo.civName, tradeLogic.currentTrade.reverse()))
|
||||
}
|
||||
}
|
||||
@ -178,23 +251,24 @@ object DiplomacyAutomation {
|
||||
internal fun offerDefensivePact(civInfo: Civilization) {
|
||||
if (!civInfo.diplomacyFunctions.canSignDefensivePact()) return // don't waste your time
|
||||
|
||||
val canSignDefensivePactCiv = civInfo.getKnownCivs()
|
||||
.filter {
|
||||
civInfo.diplomacyFunctions.canSignDefensivePactWith(it)
|
||||
&& !civInfo.getDiplomacyManager(it)!!.hasFlag(DiplomacyFlags.DeclinedDefensivePact)
|
||||
&& civInfo.getDiplomacyManager(it)!!.opinionOfOtherCiv() < 70f * civInfo.getPersonality().inverseModifierFocus(PersonalityValue.Aggressive, .2f)
|
||||
&& !areWeOfferingTrade(civInfo, it, Constants.defensivePact)
|
||||
}
|
||||
val civsThatWeCanSignDefensivePactWith = civInfo.getKnownCivs().filter {
|
||||
val ourDiploManager = civInfo.getDiplomacyManager(it)!!
|
||||
civInfo.diplomacyFunctions.canSignDefensivePactWith(it)
|
||||
&& !ourDiploManager.hasFlag(DiplomacyFlags.DeclinedDefensivePact)
|
||||
&& ourDiploManager.opinionOfOtherCiv() < 70f * civInfo.getPersonality().inverseModifierFocus(PersonalityValue.Aggressive, .2f)
|
||||
&& !areWeOfferingTrade(civInfo, it, Constants.defensivePact)
|
||||
}
|
||||
|
||||
for (otherCiv in canSignDefensivePactCiv) {
|
||||
for (otherCiv in civsThatWeCanSignDefensivePactWith) {
|
||||
// Default setting is 3, this will be changed according to different civ.
|
||||
if ((1..10).random() <= 7 * civInfo.getPersonality().inverseModifierFocus(PersonalityValue.Loyal, .3f)) continue
|
||||
if (wantsToSignDefensivePact(civInfo, otherCiv)) {
|
||||
//todo: Add more in depth evaluation here
|
||||
val tradeLogic = TradeLogic(civInfo, otherCiv)
|
||||
tradeLogic.currentTrade.ourOffers.add(TradeOffer(Constants.defensivePact, TradeOfferType.Treaty, speed = civInfo.gameInfo.speed))
|
||||
tradeLogic.currentTrade.theirOffers.add(TradeOffer(Constants.defensivePact, TradeOfferType.Treaty, speed = civInfo.gameInfo.speed))
|
||||
val tradeOffer = TradeOffer(Constants.defensivePact, TradeOfferType.Treaty, speed = civInfo.gameInfo.speed)
|
||||
|
||||
tradeLogic.currentTrade.ourOffers.add(tradeOffer)
|
||||
tradeLogic.currentTrade.theirOffers.add(tradeOffer)
|
||||
otherCiv.tradeRequests.add(TradeRequest(civInfo.civName, tradeLogic.currentTrade.reverse()))
|
||||
} else {
|
||||
// Remember this for a few turns to save computation power
|
||||
@ -204,10 +278,11 @@ object DiplomacyAutomation {
|
||||
}
|
||||
|
||||
fun wantsToSignDefensivePact(civInfo: Civilization, otherCiv: Civilization): Boolean {
|
||||
val diploManager = civInfo.getDiplomacyManager(otherCiv)!!
|
||||
if (diploManager.hasFlag(DiplomacyFlags.DeclinedDefensivePact)) return false
|
||||
if (diploManager.opinionOfOtherCiv() < 65f * civInfo.getPersonality().inverseModifierFocus(PersonalityValue.Aggressive, .3f)) return false
|
||||
val commonknownCivs = diploManager.getCommonKnownCivs()
|
||||
val ourDiploManager = civInfo.getDiplomacyManager(otherCiv)!!
|
||||
if (ourDiploManager.hasFlag(DiplomacyFlags.DeclinedDefensivePact)) return false
|
||||
if (ourDiploManager.opinionOfOtherCiv() < 65f * civInfo.getPersonality().inverseModifierFocus(PersonalityValue.Aggressive, .3f)) return false
|
||||
val commonknownCivs = ourDiploManager.getCommonKnownCivs()
|
||||
|
||||
for (thirdCiv in commonknownCivs) {
|
||||
// If they have bad relations with any of our friends, don't consider it
|
||||
if (civInfo.getDiplomacyManager(thirdCiv)!!.hasFlag(DiplomacyFlags.DeclarationOfFriendship)
|
||||
@ -230,11 +305,11 @@ object DiplomacyAutomation {
|
||||
val allAliveCivs = allCivs - deadCivs
|
||||
|
||||
// We have to already be at RelationshipLevel.Ally, so we must have 80 oppinion of them
|
||||
var motivation = diploManager.opinionOfOtherCiv() - 80
|
||||
var motivation = ourDiploManager.opinionOfOtherCiv() - 80
|
||||
|
||||
// Warmongerers don't make good allies
|
||||
if (diploManager.hasModifier(DiplomaticModifiers.WarMongerer)) {
|
||||
motivation -= diploManager.getModifier(DiplomaticModifiers.WarMongerer) * civInfo.getPersonality().modifierFocus(PersonalityValue.Diplomacy, .5f)
|
||||
if (ourDiploManager.hasModifier(DiplomaticModifiers.WarMongerer)) {
|
||||
motivation -= ourDiploManager.getModifier(DiplomaticModifiers.WarMongerer) * civInfo.getPersonality().modifierFocus(PersonalityValue.Diplomacy, .5f)
|
||||
}
|
||||
|
||||
// If they are stronger than us, then we value it a lot more
|
||||
@ -323,9 +398,10 @@ object DiplomacyAutomation {
|
||||
|
||||
// pay for peace
|
||||
val tradeLogic = TradeLogic(civInfo, enemy)
|
||||
val tradeOffer = TradeOffer(Constants.peaceTreaty, TradeOfferType.Treaty, speed = civInfo.gameInfo.speed)
|
||||
|
||||
tradeLogic.currentTrade.ourOffers.add(TradeOffer(Constants.peaceTreaty, TradeOfferType.Treaty, speed = civInfo.gameInfo.speed))
|
||||
tradeLogic.currentTrade.theirOffers.add(TradeOffer(Constants.peaceTreaty, TradeOfferType.Treaty, speed = civInfo.gameInfo.speed))
|
||||
tradeLogic.currentTrade.ourOffers.add(tradeOffer)
|
||||
tradeLogic.currentTrade.theirOffers.add(tradeOffer)
|
||||
|
||||
if (enemy.isMajorCiv()) {
|
||||
var moneyWeNeedToPay = -TradeEvaluation().evaluatePeaceCostForThem(civInfo, enemy)
|
||||
|
@ -50,7 +50,8 @@ object NextTurnAutomation {
|
||||
if (civInfo.gameInfo.isReligionEnabled()) {
|
||||
ReligionAutomation.spendFaithOnReligion(civInfo)
|
||||
}
|
||||
|
||||
|
||||
DiplomacyAutomation.offerToEstablishEmbassy(civInfo)
|
||||
DiplomacyAutomation.offerOpenBorders(civInfo)
|
||||
DiplomacyAutomation.offerResearchAgreement(civInfo)
|
||||
DiplomacyAutomation.offerDefensivePact(civInfo)
|
||||
|
@ -164,6 +164,9 @@ object DeclareWar {
|
||||
diplomacyManager.setFlag(DiplomacyFlags.DeclinedPeace, diplomacyManager.civInfo.gameInfo.ruleset.modOptions.constants.minimumWarDuration) // AI won't propose peace for 10 turns
|
||||
diplomacyManager.setFlag(DiplomacyFlags.DeclaredWar, diplomacyManager.civInfo.gameInfo.ruleset.modOptions.constants.minimumWarDuration) // AI won't agree to trade for 10 turns
|
||||
diplomacyManager.removeFlag(DiplomacyFlags.BorderConflict)
|
||||
|
||||
// War results in removal of embassies for both sides
|
||||
diplomacyManager.civInfo.diplomacyFunctions.removeEmbassies(civAtWarWith)
|
||||
}
|
||||
|
||||
private fun changeOpinions(diplomacyManager: DiplomacyManager, declareWarReason: DeclareWarReason) {
|
||||
|
@ -87,8 +87,78 @@ class DiplomacyFunctions(val civInfo: Civilization) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If denounciation happened this turn from either side, establishing embassy again is possible only from next turn.
|
||||
*/
|
||||
@Readonly
|
||||
private fun isDenouncedThisTurn(diploManager: DiplomacyManager): Boolean {
|
||||
return diploManager.getFlag(DiplomacyFlags.Denunciation) == 30
|
||||
|| diploManager.otherCivDiplomacy().getFlag(DiplomacyFlags.Denunciation) == 30
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic check if we can trade embassies, does not check all prerequisities
|
||||
* Use [canOfferEmbassyTo] and [canEstablishEmbassyWith] instead
|
||||
*/
|
||||
@Readonly
|
||||
private fun canTradeEmbassies(): Boolean {
|
||||
return civInfo.isMajorCiv()
|
||||
&& civInfo.hasUnique(UniqueType.EnablesEmbassies)
|
||||
&& civInfo.hasUnique(UniqueType.RequiresEmbassiesForDiplomacy)
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if we can offer our embassy to [otherCiv]
|
||||
*/
|
||||
@Readonly
|
||||
fun canOfferEmbassyTo(otherCiv: Civilization): Boolean {
|
||||
if (!canTradeEmbassies() || !otherCiv.isMajorCiv()) return false
|
||||
val theirDiploManager = otherCiv.getDiplomacyManager(civInfo)!!
|
||||
return !civInfo.isAtWarWith(otherCiv) && !isDenouncedThisTurn(theirDiploManager)
|
||||
&& !theirDiploManager.hasModifier(DiplomaticModifiers.EstablishedEmbassy)
|
||||
&& !theirDiploManager.hasModifier(DiplomaticModifiers.SharedEmbassies)
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if we can establish embassy in [otherCiv] capital
|
||||
*/
|
||||
@Readonly
|
||||
fun canEstablishEmbassyWith(otherCiv: Civilization): Boolean {
|
||||
if (!canTradeEmbassies() || !otherCiv.isMajorCiv()) return false
|
||||
val ourDiploManager = civInfo.getDiplomacyManager(otherCiv)!!
|
||||
return !civInfo.isAtWarWith(otherCiv) && !isDenouncedThisTurn(ourDiploManager)
|
||||
&& !ourDiploManager.hasModifier(DiplomaticModifiers.EstablishedEmbassy)
|
||||
&& !ourDiploManager.hasModifier(DiplomaticModifiers.SharedEmbassies)
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if both civs have embassies established in each others' capital
|
||||
* Returns true if base ruleset or mods don't enable embassies
|
||||
*/
|
||||
@Readonly
|
||||
fun hasMutualEmbassyWith(otherCiv: Civilization): Boolean {
|
||||
return if (civInfo.hasUnique(UniqueType.EnablesEmbassies)
|
||||
&& civInfo.hasUnique(UniqueType.RequiresEmbassiesForDiplomacy))
|
||||
civInfo.getDiplomacyManager(otherCiv)!!.hasModifier(DiplomaticModifiers.SharedEmbassies)
|
||||
else true // Embassies are not enabled
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove mutual embassies from both civs
|
||||
*/
|
||||
fun removeEmbassies(otherCiv: Civilization) {
|
||||
val ourDiploManager = civInfo.getDiplomacyManager(otherCiv)!!
|
||||
ourDiploManager.removeModifier(DiplomaticModifiers.EstablishedEmbassy)
|
||||
ourDiploManager.removeModifier(DiplomaticModifiers.ReceivedEmbassy)
|
||||
ourDiploManager.removeModifier(DiplomaticModifiers.SharedEmbassies)
|
||||
|
||||
val theirDiploManager = ourDiploManager.otherCivDiplomacy()
|
||||
theirDiploManager.removeModifier(DiplomaticModifiers.EstablishedEmbassy)
|
||||
theirDiploManager.removeModifier(DiplomaticModifiers.ReceivedEmbassy)
|
||||
theirDiploManager.removeModifier(DiplomaticModifiers.SharedEmbassies)
|
||||
}
|
||||
|
||||
fun canSignDeclarationOfFriendshipWith(otherCiv: Civilization): Boolean {
|
||||
return otherCiv.isMajorCiv() && !otherCiv.isAtWarWith(civInfo)
|
||||
&& !civInfo.getDiplomacyManager(otherCiv)!!.hasFlag(DiplomacyFlags.Denunciation)
|
||||
@ -105,15 +175,17 @@ class DiplomacyFunctions(val civInfo: Civilization) {
|
||||
|
||||
@Readonly
|
||||
fun canSignResearchAgreementNoCostWith (otherCiv: Civilization): Boolean {
|
||||
val diplomacyManager = civInfo.getDiplomacyManager(otherCiv)!!
|
||||
return canSignResearchAgreement() && otherCiv.diplomacyFunctions.canSignResearchAgreement()
|
||||
&& diplomacyManager.hasFlag(DiplomacyFlags.DeclarationOfFriendship)
|
||||
&& !diplomacyManager.hasFlag(DiplomacyFlags.ResearchAgreement)
|
||||
&& !diplomacyManager.otherCivDiplomacy().hasFlag(DiplomacyFlags.ResearchAgreement)
|
||||
val ourDiploManager = civInfo.getDiplomacyManager(otherCiv)!!
|
||||
return canSignResearchAgreement()
|
||||
&& otherCiv.diplomacyFunctions.canSignResearchAgreement()
|
||||
&& hasMutualEmbassyWith(otherCiv)
|
||||
&& ourDiploManager.hasFlag(DiplomacyFlags.DeclarationOfFriendship)
|
||||
&& !ourDiploManager.hasFlag(DiplomacyFlags.ResearchAgreement)
|
||||
&& !ourDiploManager.otherCivDiplomacy().hasFlag(DiplomacyFlags.ResearchAgreement)
|
||||
}
|
||||
|
||||
@Readonly
|
||||
fun canSignResearchAgreementsWith(otherCiv: Civilization): Boolean {
|
||||
fun canSignResearchAgreementWith(otherCiv: Civilization): Boolean {
|
||||
val cost = getResearchAgreementCost(otherCiv)
|
||||
return canSignResearchAgreementNoCostWith(otherCiv)
|
||||
&& civInfo.gold >= cost && otherCiv.gold >= cost
|
||||
@ -136,16 +208,16 @@ class DiplomacyFunctions(val civInfo: Civilization) {
|
||||
|
||||
@Readonly
|
||||
fun canSignDefensivePactWith(otherCiv: Civilization): Boolean {
|
||||
val diplomacyManager = civInfo.getDiplomacyManager(otherCiv)!!
|
||||
return canSignDefensivePact() && otherCiv.diplomacyFunctions.canSignDefensivePact()
|
||||
&& (diplomacyManager.hasFlag(DiplomacyFlags.DeclarationOfFriendship)
|
||||
|| diplomacyManager.otherCivDiplomacy().hasFlag(DiplomacyFlags.DeclarationOfFriendship))
|
||||
&& !diplomacyManager.hasFlag(DiplomacyFlags.DefensivePact)
|
||||
&& !diplomacyManager.otherCivDiplomacy().hasFlag(DiplomacyFlags.DefensivePact)
|
||||
&& diplomacyManager.diplomaticStatus != DiplomaticStatus.DefensivePact
|
||||
val ourDiplomacyManager = civInfo.getDiplomacyManager(otherCiv)!!
|
||||
return canSignDefensivePact()
|
||||
&& otherCiv.diplomacyFunctions.canSignDefensivePact()
|
||||
&& hasMutualEmbassyWith(otherCiv)
|
||||
&& ourDiplomacyManager.hasFlag(DiplomacyFlags.DeclarationOfFriendship)
|
||||
&& !ourDiplomacyManager.hasFlag(DiplomacyFlags.DefensivePact)
|
||||
&& !ourDiplomacyManager.otherCivDiplomacy().hasFlag(DiplomacyFlags.DefensivePact)
|
||||
&& ourDiplomacyManager.diplomaticStatus != DiplomaticStatus.DefensivePact
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @returns whether units of this civilization can pass through the tiles owned by [otherCiv],
|
||||
* considering only civ-wide filters.
|
||||
@ -167,7 +239,4 @@ class DiplomacyFunctions(val civInfo: Civilization) {
|
||||
if (!civInfo.isAIOrAutoPlaying() && otherCiv.isCityState) return true
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -46,6 +46,7 @@ enum class DiplomacyFlags {
|
||||
DeclinedLuxExchange,
|
||||
DeclinedPeace,
|
||||
DeclinedResearchAgreement,
|
||||
DeclinedEmbassy,
|
||||
DeclinedOpenBorders,
|
||||
DeclaredWar,
|
||||
DeclarationOfFriendship,
|
||||
@ -118,6 +119,9 @@ enum class DiplomaticModifiers(val text: String) {
|
||||
StoleOurAlly("You took the alliance we had with a City-State"),
|
||||
|
||||
// Positive
|
||||
EstablishedEmbassy("We have an embassy in your capital"),
|
||||
ReceivedEmbassy("You have an embassy in our capital"),
|
||||
SharedEmbassies("We have shared embassies"),
|
||||
YearsOfPeace("Years of peace have strengthened our relations."),
|
||||
SharedEnemy("Our mutual military struggle brings us closer together."),
|
||||
LiberatedCity("We applaud your liberation of conquered cities!"),
|
||||
@ -569,6 +573,11 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
|
||||
internal fun removeModifier(modifier: DiplomaticModifiers) = diplomaticModifiers.remove(modifier.name)
|
||||
@Readonly
|
||||
fun hasModifier(modifier: DiplomaticModifiers) = diplomaticModifiers.containsKey(modifier.name)
|
||||
|
||||
fun replaceModifier(oldModifier: DiplomaticModifiers, newModifier: DiplomaticModifiers, amount: Float) {
|
||||
removeModifier(oldModifier)
|
||||
addModifier(newModifier, amount)
|
||||
}
|
||||
|
||||
fun signDeclarationOfFriendship() {
|
||||
setModifier(DiplomaticModifiers.DeclarationOfFriendship, 35f)
|
||||
@ -679,6 +688,9 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
|
||||
setFlag(DiplomacyFlags.Denunciation, 30)
|
||||
otherCivDiplomacy().setFlag(DiplomacyFlags.Denunciation, 30)
|
||||
|
||||
// Denounciation results in removal of embasies for both sides
|
||||
civInfo.diplomacyFunctions.removeEmbassies(otherCiv())
|
||||
|
||||
otherCiv().addNotification("[${civInfo.civName}] has denounced us!",
|
||||
NotificationCategory.Diplomacy, NotificationIcon.Diplomacy, civInfo.civName)
|
||||
|
||||
|
@ -63,6 +63,9 @@ class TradeRequest : IsPartOfGameInfoSerialization {
|
||||
requestingCivDiploManager.setFlag(DiplomacyFlags.DeclinedDefensivePact,10)
|
||||
if (trade.ourOffers.any { it.name == Constants.openBorders })
|
||||
requestingCivDiploManager.setFlag(DiplomacyFlags.DeclinedOpenBorders, if (decliningCiv.isAI()) 5 else 10)
|
||||
if (trade.ourOffers.any { it.name == Constants.acceptEmbassy }
|
||||
|| trade.theirOffers.any { it.name == Constants.acceptEmbassy })
|
||||
requestingCivDiploManager.setFlag(DiplomacyFlags.DeclinedEmbassy, if (decliningCiv.isAI()) 5 else 10)
|
||||
if (trade.theirOffers.any { it.type == TradeOfferType.WarDeclaration })
|
||||
requestingCivDiploManager.setFlag(DiplomacyFlags.DeclinedJoinWarOffer, if (decliningCiv.isAI()) 5 else 10)
|
||||
if (trade.ourOffers.any { it.type == TradeOfferType.WarDeclaration })
|
||||
|
@ -7,6 +7,7 @@ import com.unciv.logic.automation.civilization.DeclareWarPlanEvaluator
|
||||
import com.unciv.logic.city.City
|
||||
import com.unciv.logic.civilization.Civilization
|
||||
import com.unciv.logic.civilization.diplomacy.DiplomacyFlags
|
||||
import com.unciv.logic.civilization.diplomacy.DiplomaticModifiers
|
||||
import com.unciv.logic.civilization.diplomacy.RelationshipLevel
|
||||
import com.unciv.logic.map.tile.Tile
|
||||
import com.unciv.models.ruleset.Ruleset
|
||||
@ -30,6 +31,23 @@ class TradeEvaluation {
|
||||
|| (tradePartner.hasEverOwnedOriginalCapital && trade.theirOffers.count { it.type == TradeOfferType.City } == tradePartner.cities.size)) {
|
||||
return false
|
||||
}
|
||||
|
||||
// No way to tell who offers what in isOfferValid()
|
||||
val embassyOffer = TradeOffer(Constants.acceptEmbassy, TradeOfferType.Embassy, speed = offerer.gameInfo.speed)
|
||||
val theirDiploManager = tradePartner.getDiplomacyManager(offerer)!!
|
||||
val ourDiploManager = offerer.getDiplomacyManager(tradePartner)!!
|
||||
|
||||
if (trade.ourOffers.contains(embassyOffer)
|
||||
&& (offerer.getCapital() == null
|
||||
|| theirDiploManager.hasModifier(DiplomaticModifiers.EstablishedEmbassy)
|
||||
|| theirDiploManager.hasModifier(DiplomaticModifiers.SharedEmbassies)))
|
||||
return false
|
||||
|
||||
if (trade.theirOffers.contains(embassyOffer)
|
||||
&& (tradePartner.getCapital() == null
|
||||
|| ourDiploManager.hasModifier(DiplomaticModifiers.EstablishedEmbassy)
|
||||
|| ourDiploManager.hasModifier(DiplomaticModifiers.SharedEmbassies)))
|
||||
return false
|
||||
|
||||
for (offer in trade.ourOffers)
|
||||
if (!isOfferValid(offer, offerer, tradePartner)) {
|
||||
@ -51,6 +69,7 @@ class TradeEvaluation {
|
||||
}
|
||||
|
||||
return when (tradeOffer.type) {
|
||||
TradeOfferType.Embassy -> true // Already checked
|
||||
// if they go a little negative it's okay, but don't allowing going overboard (promising same gold to many)
|
||||
TradeOfferType.Gold -> tradeOffer.amount * 0.9f < offerer.gold
|
||||
TradeOfferType.Gold_Per_Turn -> tradeOffer.amount * 0.9f < offerer.stats.statsForNextTurn.gold
|
||||
@ -122,6 +141,7 @@ class TradeEvaluation {
|
||||
*/
|
||||
private fun evaluateBuyCost(offer: TradeOffer, civInfo: Civilization, tradePartner: Civilization, trade: Trade): Int {
|
||||
when (offer.type) {
|
||||
TradeOfferType.Embassy -> return (30 * civInfo.gameInfo.speed.goldCostModifier).toInt()
|
||||
TradeOfferType.Gold -> return offer.amount
|
||||
// GPT loses value for each 'future' turn, meaning: gold now is more valuable than gold in the future
|
||||
// Empire-wide production tends to grow at roughly 2% per turn (quick speed), so let's take that as a base line
|
||||
@ -259,11 +279,9 @@ class TradeEvaluation {
|
||||
*/
|
||||
fun isPeaceProposalEnabled(thirdCiv: Civilization, civInfo: Civilization): Boolean {
|
||||
val diploManager = civInfo.getDiplomacyManager(thirdCiv)!!
|
||||
val warCountDown = if (diploManager.hasFlag(DiplomacyFlags.DeclaredWar))
|
||||
diploManager.getFlag(DiplomacyFlags.DeclaredWar) else 0
|
||||
|
||||
// On standard speed 10 turns must pass before peace can be proposed
|
||||
if (warCountDown > 0) return false
|
||||
if (diploManager.getFlag(DiplomacyFlags.DeclaredWar) > 0) return false
|
||||
|
||||
// TODO: We don't know if other human player would agree to peace
|
||||
if (thirdCiv.isHuman()) return false
|
||||
@ -322,6 +340,13 @@ class TradeEvaluation {
|
||||
*/
|
||||
private fun evaluateSellCost(offer: TradeOffer, civInfo: Civilization, tradePartner: Civilization, trade: Trade): Int {
|
||||
when (offer.type) {
|
||||
TradeOfferType.Embassy -> {
|
||||
val tradePartnerDiplo = civInfo.getDiplomacyManager(tradePartner)!!
|
||||
if (tradePartnerDiplo.isRelationshipLevelLE(RelationshipLevel.Enemy)) return Int.MIN_VALUE
|
||||
else if (tradePartnerDiplo.isRelationshipLevelLE(RelationshipLevel.Competitor))
|
||||
return (60 * civInfo.gameInfo.speed.goldCostModifier).toInt()
|
||||
return (30 * civInfo.gameInfo.speed.goldCostModifier).toInt() // 30 is Civ V default (on standard only?)
|
||||
}
|
||||
TradeOfferType.Gold -> return offer.amount
|
||||
TradeOfferType.Gold_Per_Turn -> return offer.amount * offer.duration
|
||||
TradeOfferType.Treaty -> {
|
||||
|
@ -7,6 +7,8 @@ import com.unciv.logic.civilization.Civilization
|
||||
import com.unciv.logic.civilization.PopupAlert
|
||||
import com.unciv.logic.civilization.diplomacy.DeclareWarReason
|
||||
import com.unciv.logic.civilization.diplomacy.DiplomacyFlags
|
||||
import com.unciv.logic.civilization.diplomacy.DiplomacyManager
|
||||
import com.unciv.logic.civilization.diplomacy.DiplomaticModifiers
|
||||
import com.unciv.logic.civilization.diplomacy.WarType
|
||||
import com.unciv.models.ruleset.tile.ResourceType
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
@ -14,28 +16,43 @@ import com.unciv.models.ruleset.unique.UniqueType
|
||||
class TradeLogic(val ourCivilization: Civilization, val otherCivilization: Civilization) {
|
||||
|
||||
/** 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)
|
||||
var ourAvailableOffers = TradeOffersList()
|
||||
var theirAvailableOffers = TradeOffersList()
|
||||
val currentTrade = Trade()
|
||||
|
||||
private fun getAvailableOffers(civInfo: Civilization, otherCivilization: Civilization): TradeOffersList {
|
||||
val offers = TradeOffersList()
|
||||
if (civInfo.isCityState && otherCivilization.isCityState) return offers
|
||||
if (civInfo.isAtWarWith(otherCivilization))
|
||||
offers.add(TradeOffer(Constants.peaceTreaty, TradeOfferType.Treaty, speed = civInfo.gameInfo.speed))
|
||||
init {
|
||||
// Embassy trade availability depends solely on our ability to trade it
|
||||
val embassyOffer = TradeOffer(Constants.acceptEmbassy, TradeOfferType.Embassy, speed = ourCivilization.gameInfo.speed)
|
||||
if (ourCivilization.diplomacyFunctions.canEstablishEmbassyWith(otherCivilization))
|
||||
theirAvailableOffers.add(embassyOffer)
|
||||
|
||||
if (!otherCivilization.getDiplomacyManager(civInfo)!!.hasOpenBorders
|
||||
&& !otherCivilization.isCityState
|
||||
&& civInfo.hasUnique(UniqueType.EnablesOpenBorders)
|
||||
&& otherCivilization.hasUnique(UniqueType.EnablesOpenBorders)) {
|
||||
if (ourCivilization.diplomacyFunctions.canOfferEmbassyTo(otherCivilization))
|
||||
ourAvailableOffers.add(embassyOffer)
|
||||
|
||||
// Other trade items are added as usual for both sides
|
||||
ourAvailableOffers += getAvailableOffers(ourCivilization, otherCivilization)
|
||||
theirAvailableOffers += getAvailableOffers(otherCivilization, ourCivilization)
|
||||
}
|
||||
|
||||
private fun getAvailableOffers(civInfo: Civilization, otherCiv: Civilization): TradeOffersList {
|
||||
val offers = TradeOffersList()
|
||||
if (civInfo.isCityState || otherCiv.isCityState) return offers
|
||||
|
||||
if (civInfo.isAtWarWith(otherCiv))
|
||||
offers.add(TradeOffer(Constants.peaceTreaty, TradeOfferType.Treaty, speed = civInfo.gameInfo.speed))
|
||||
|
||||
if (civInfo.diplomacyFunctions.hasMutualEmbassyWith(otherCiv)
|
||||
&& !otherCiv.getDiplomacyManager(civInfo)!!.hasOpenBorders
|
||||
&& civInfo.hasUnique(UniqueType.EnablesOpenBorders)
|
||||
&& otherCiv.hasUnique(UniqueType.EnablesOpenBorders)) {
|
||||
offers.add(TradeOffer(Constants.openBorders, TradeOfferType.Agreement, speed = civInfo.gameInfo.speed))
|
||||
}
|
||||
|
||||
if (civInfo.diplomacyFunctions.canSignResearchAgreementNoCostWith(otherCivilization))
|
||||
if (civInfo.diplomacyFunctions.canSignResearchAgreementNoCostWith(otherCiv))
|
||||
offers.add(TradeOffer(Constants.researchAgreement, TradeOfferType.Treaty,
|
||||
civInfo.diplomacyFunctions.getResearchAgreementCost(otherCivilization), civInfo.gameInfo.speed))
|
||||
civInfo.diplomacyFunctions.getResearchAgreementCost(otherCiv), civInfo.gameInfo.speed))
|
||||
|
||||
if (civInfo.diplomacyFunctions.canSignDefensivePactWith(otherCivilization))
|
||||
if (civInfo.diplomacyFunctions.canSignDefensivePactWith(otherCiv))
|
||||
offers.add(TradeOffer(Constants.defensivePact, TradeOfferType.Treaty, speed = civInfo.gameInfo.speed))
|
||||
|
||||
for (entry in civInfo.getPerTurnResourcesWithOriginsForTrade()
|
||||
@ -51,48 +68,43 @@ class TradeLogic(val ourCivilization: Civilization, val otherCivilization: Civil
|
||||
offers.add(TradeOffer(entry.resource.name, TradeOfferType.Stockpiled_Resource, entry.amount, speed = civInfo.gameInfo.speed))
|
||||
}
|
||||
|
||||
offers.add(TradeOffer("Gold", TradeOfferType.Gold, civInfo.gold, speed = civInfo.gameInfo.speed))
|
||||
offers.add(TradeOffer("Gold per turn", TradeOfferType.Gold_Per_Turn, civInfo.stats.statsForNextTurn.gold.toInt(), civInfo.gameInfo.speed))
|
||||
offers.add(TradeOffer(Constants.flatGold, TradeOfferType.Gold, civInfo.gold, speed = civInfo.gameInfo.speed))
|
||||
offers.add(TradeOffer(Constants.goldPerTurn, TradeOfferType.Gold_Per_Turn, civInfo.stats.statsForNextTurn.gold.toInt(), civInfo.gameInfo.speed))
|
||||
|
||||
if (!civInfo.isOneCityChallenger() && !otherCivilization.isOneCityChallenger()
|
||||
&& !civInfo.isCityState && !otherCivilization.isCityState
|
||||
) {
|
||||
if (!civInfo.isOneCityChallenger() && !otherCiv.isOneCityChallenger())
|
||||
for (city in civInfo.cities.filterNot { it.isCapital() || it.isInResistance() })
|
||||
offers.add(TradeOffer(city.id, TradeOfferType.City, speed = civInfo.gameInfo.speed))
|
||||
}
|
||||
|
||||
val otherCivsWeKnow = civInfo.getKnownCivs()
|
||||
.filter { it.civName != otherCivilization.civName && it.isMajorCiv() && !it.isDefeated() }
|
||||
.filter { it.civName != otherCiv.civName && it.isMajorCiv() && !it.isDefeated() }
|
||||
|
||||
if (civInfo.gameInfo.ruleset.modOptions.hasUnique(UniqueType.TradeCivIntroductions)) {
|
||||
val civsWeKnowAndTheyDont = otherCivsWeKnow
|
||||
.filter { !otherCivilization.diplomacy.containsKey(it.civName) && !it.isDefeated() }
|
||||
.filter { !otherCiv.diplomacy.containsKey(it.civName) && !it.isDefeated() }
|
||||
for (thirdCiv in civsWeKnowAndTheyDont) {
|
||||
offers.add(TradeOffer(thirdCiv.civName, TradeOfferType.Introduction, speed = civInfo.gameInfo.speed))
|
||||
}
|
||||
}
|
||||
|
||||
if (!civInfo.isCityState && !otherCivilization.isCityState
|
||||
&& !civInfo.gameInfo.ruleset.modOptions.hasUnique(UniqueType.DiplomaticRelationshipsCannotChange)) {
|
||||
if (!civInfo.gameInfo.ruleset.modOptions.hasUnique(UniqueType.DiplomaticRelationshipsCannotChange)) {
|
||||
val civsWeBothKnow = otherCivsWeKnow
|
||||
.filter { otherCivilization.diplomacy.containsKey(it.civName) }
|
||||
.filter { otherCiv.diplomacy.containsKey(it.civName) }
|
||||
val civsWeArentAtWarWith = civsWeBothKnow
|
||||
.filter { civInfo.getDiplomacyManager(it)!!.canDeclareWar() }
|
||||
for (thirdCiv in civsWeArentAtWarWith) {
|
||||
offers.add(TradeOffer(thirdCiv.civName, TradeOfferType.WarDeclaration, speed = civInfo.gameInfo.speed))
|
||||
}
|
||||
}
|
||||
|
||||
val thirdCivsAtWarTheyKnow = otherCiv.getKnownCivs().filter {
|
||||
it.isAtWarWith(civInfo) && !it.isDefeated()
|
||||
&& !it.gameInfo.ruleset.modOptions.hasUnique(UniqueType.DiplomaticRelationshipsCannotChange)
|
||||
}
|
||||
|
||||
if (!civInfo.isCityState && !otherCivilization.isCityState) {
|
||||
val thirdCivsAtWarTheyKnow = otherCivilization.getKnownCivs()
|
||||
.filter { it.isAtWarWith(civInfo) && !it.isDefeated()
|
||||
&& !it.gameInfo.ruleset.modOptions.hasUnique(UniqueType.DiplomaticRelationshipsCannotChange) }
|
||||
|
||||
for (thirdCiv in thirdCivsAtWarTheyKnow) {
|
||||
// Setting amount to 0 makes TradeOffer.isTradable() return false and also disables the button in trade window
|
||||
val amount = if (TradeEvaluation().isPeaceProposalEnabled(thirdCiv, civInfo)) 1 else 0
|
||||
offers.add(TradeOffer(thirdCiv.civName, TradeOfferType.PeaceProposal, amount, civInfo.gameInfo.speed))
|
||||
}
|
||||
for (thirdCiv in thirdCivsAtWarTheyKnow) {
|
||||
// Setting amount to 0 makes TradeOffer.isTradable() return false and also disables the button in trade window
|
||||
val amount = if (TradeEvaluation().isPeaceProposalEnabled(thirdCiv, civInfo)) 1 else 0
|
||||
offers.add(TradeOffer(thirdCiv.civName, TradeOfferType.PeaceProposal, amount, civInfo.gameInfo.speed))
|
||||
}
|
||||
|
||||
return offers
|
||||
@ -100,13 +112,13 @@ class TradeLogic(val ourCivilization: Civilization, val otherCivilization: Civil
|
||||
|
||||
fun acceptTrade(applyGifts: Boolean = true) {
|
||||
val ourDiploManager = ourCivilization.getDiplomacyManager(otherCivilization)!!
|
||||
val theirDiploManger = otherCivilization.getDiplomacyManager(ourCivilization)!!
|
||||
val theirDiploManager = otherCivilization.getDiplomacyManager(ourCivilization)!!
|
||||
|
||||
ourDiploManager.apply {
|
||||
trades.add(currentTrade)
|
||||
updateHasOpenBorders()
|
||||
}
|
||||
theirDiploManger.apply {
|
||||
theirDiploManager.apply {
|
||||
trades.add(currentTrade.reverse())
|
||||
updateHasOpenBorders()
|
||||
}
|
||||
@ -114,6 +126,10 @@ class TradeLogic(val ourCivilization: Civilization, val otherCivilization: Civil
|
||||
// instant transfers
|
||||
fun transferTrade(from: Civilization, to: Civilization, offer: TradeOffer) {
|
||||
when (offer.type) {
|
||||
TradeOfferType.Embassy -> {
|
||||
for (tile in from.getCapital()!!.getCenterTile().getTilesInDistance(2))
|
||||
tile.setExplored(to, true)
|
||||
}
|
||||
TradeOfferType.Gold -> {
|
||||
to.addGold(offer.amount)
|
||||
from.addGold(-offer.amount)
|
||||
@ -204,7 +220,7 @@ class TradeLogic(val ourCivilization: Civilization, val otherCivilization: Civil
|
||||
ourDiploManager.giftGold(ourGoldValueOfTrade - theirGoldValueOfTrade.coerceAtLeast(0), isPureGift)
|
||||
} else if (theirGoldValueOfTrade > ourGoldValueOfTrade) {
|
||||
val isPureGift = currentTrade.theirOffers.isEmpty()
|
||||
theirDiploManger.giftGold(theirGoldValueOfTrade - ourGoldValueOfTrade.coerceAtLeast(0), isPureGift)
|
||||
theirDiploManager.giftGold(theirGoldValueOfTrade - ourGoldValueOfTrade.coerceAtLeast(0), isPureGift)
|
||||
}
|
||||
}
|
||||
|
||||
@ -218,6 +234,23 @@ class TradeLogic(val ourCivilization: Civilization, val otherCivilization: Civil
|
||||
for (offer in currentTrade.theirOffers.filter { it.type == TradeOfferType.Treaty })
|
||||
transferTrade(otherCivilization, ourCivilization, offer)
|
||||
|
||||
fun applyEmbassyOffer(diploManager: DiplomacyManager) {
|
||||
if (diploManager.hasModifier(DiplomaticModifiers.EstablishedEmbassy)) {
|
||||
diploManager.replaceModifier(DiplomaticModifiers.EstablishedEmbassy, DiplomaticModifiers.SharedEmbassies, 3f)
|
||||
diploManager.otherCivDiplomacy().replaceModifier(DiplomaticModifiers.ReceivedEmbassy, DiplomaticModifiers.SharedEmbassies, 3f)
|
||||
}
|
||||
else {
|
||||
diploManager.addModifier(DiplomaticModifiers.ReceivedEmbassy, 1f)
|
||||
diploManager.otherCivDiplomacy().addModifier(DiplomaticModifiers.EstablishedEmbassy, 2f)
|
||||
}
|
||||
}
|
||||
|
||||
// Diplomatic modifiers for embassy depend on whether a civ gives its embassy, accepts it or both
|
||||
if (currentTrade.ourOffers.any { it.type == TradeOfferType.Embassy })
|
||||
applyEmbassyOffer(ourDiploManager)
|
||||
if (currentTrade.theirOffers.any { it.type == TradeOfferType.Embassy })
|
||||
applyEmbassyOffer(theirDiploManager)
|
||||
|
||||
ourCivilization.cache.updateCivResources()
|
||||
ourCivilization.updateStatsForNextTurn()
|
||||
|
||||
|
@ -6,6 +6,7 @@ package com.unciv.logic.trade
|
||||
*/
|
||||
@Suppress("EnumEntryName") // We do want the underscores in our names
|
||||
enum class TradeOfferType(val numberType: TradeTypeNumberType, val isImmediate: Boolean) {
|
||||
Embassy (TradeTypeNumberType.None, true),
|
||||
Gold (TradeTypeNumberType.Gold, true),
|
||||
Gold_Per_Turn (TradeTypeNumberType.Gold, false),
|
||||
/** Treaties are shared by both sides - like peace treaty and defensive pact */
|
||||
|
@ -215,6 +215,10 @@ enum class UniqueType(
|
||||
@Deprecated("As of 4.16.18", ReplaceWith("[+100]% [resource] resource production"))
|
||||
DoubleResourceProduced("Double quantity of [resource] produced", UniqueTarget.Global),
|
||||
|
||||
/// Diplomacy
|
||||
EnablesEmbassies("Enables establishment of embassies", UniqueTarget.Tech),
|
||||
RequiresEmbassiesForDiplomacy("Requires establishing embassies to conduct advanced diplomacy", UniqueTarget.Global),
|
||||
|
||||
/// Agreements
|
||||
EnablesOpenBorders("Enables Open Borders agreements", UniqueTarget.Global),
|
||||
// Should the 'R' in 'Research agreements' be capitalized?
|
||||
|
@ -57,7 +57,7 @@ class OffersListScroll(
|
||||
|
||||
for (offerType in TradeOfferType.entries) {
|
||||
val labelName = when(offerType) {
|
||||
Gold, Gold_Per_Turn, Treaty, Agreement, Introduction -> ""
|
||||
Embassy, Gold, Gold_Per_Turn, Treaty, Agreement, Introduction -> ""
|
||||
Luxury_Resource -> "Luxury resources"
|
||||
Strategic_Resource -> "Strategic resources"
|
||||
Stockpiled_Resource -> "Stockpiled resources"
|
||||
@ -89,6 +89,7 @@ class OffersListScroll(
|
||||
for (offer in offersOfType) {
|
||||
val tradeLabel = offer.getOfferText(untradableOffers.sumBy(offer.name))
|
||||
val tradeIcon = when (offer.type) {
|
||||
Embassy -> ImageGetter.getImage("OtherIcons/Star")
|
||||
Luxury_Resource, Strategic_Resource ->
|
||||
ImageGetter.getResourcePortrait(offer.name, 30f)
|
||||
WarDeclaration, PeaceProposal ->
|
||||
|
@ -808,6 +808,9 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
|
||||
|
||||
Applicable to: Global
|
||||
|
||||
??? example "Requires establishing embassies to conduct advanced diplomacy"
|
||||
Applicable to: Global
|
||||
|
||||
??? example "Enables Open Borders agreements"
|
||||
Applicable to: Global
|
||||
|
||||
@ -1148,6 +1151,9 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
|
||||
Applicable to: Era
|
||||
|
||||
## Tech uniques
|
||||
??? example "Enables establishment of embassies"
|
||||
Applicable to: Tech
|
||||
|
||||
??? example "Starting tech"
|
||||
Applicable to: Tech
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user