mirror of
https://github.com/yairm210/Unciv.git
synced 2025-01-05 21:11:35 +07:00
Add Defensive pact (#9900)
* Defensive Pacts can now be offered. * Signing a defensive pact now makes the Civs join all defensive wars. Any future defensive wars will force the other civ to join. * Removed Popup Alert Defensive Pact. * Defensive pact and Research pact now are only on the trade screen. * AI now offers defensive pacts. * Added AI evaluating sending and receiving Defensive Pact offers. * Reverted some temporary changes * Reduced the chance an AI offers a defensive pact * Starting an offensive war now cancels all Defensive Pacts with other civilisations. * Removed extra requirements before an AI will sign or offer a defensive pact. * Added Defensive Pacts to the Civilopedia. * Fixed the AI counter offering with treaties. * Fixed a test using the old method of checking if a civ is at war. * Fixed a previous refactor error. * Deleted commented out Research Agreement button code. * Fixed some spelling errors and remnant debugging code. * Removed signing a defensive pact brings both Civ's into each others previous defensive wars. * Refactored setFriendshipBasedModifier to look better * Starting an offensive war now removes the defensive pact form both sides. * Reverted changes to DiplomaticStatus * Removed extra technology check to sign a defensive pact. * Removed DiplomacyManager.isAtWar() completely. * Moved setting defensivePact flags from TradeLogic.transferTrade() to DiplomacyManager.signDefensivePact. * Changed diplomatic modifiers related to Defensive Pacts to be less extreme. * Fixed canceling Defensive Pacts when declaring war and notifying other Civs. * Updated the Defensive Pact entry in the Civilopedia and fixed some spelling. * Fixed Defensive Pact behavior while attacking and defending. * Changed a variable to a more readable name. * Improved readability of setFriendshipBasedModifier(). * Moved the important onWarDeclared functionality to their own functions. * Added a notification for the attacking Civ when a Civ joins war through a Defensive Pact. * Refactored setDefensivePactBasedModifier() to be more readable. * Increased DeclinedDefensivePact time. * Deleted old commented code that removed the research agreement button. * Fixed having reverting changes errors in UnitMovementTests. * Refactored breaking treaties when declaring war. * Removed unnecessary semicolons.
This commit is contained in:
parent
65f884cb54
commit
548b536818
@ -234,7 +234,8 @@
|
||||
"name": "Chivalry",
|
||||
"row": 6,
|
||||
"prerequisites": ["Civil Service","Guilds"],
|
||||
"quote": "'Whoso pulleth out this sword of this stone and anvil, is rightwise king born of all England.' - Malory"
|
||||
"uniques": ["Enables Defensive Pacts"],
|
||||
"quote": "'Whoso pulleth out this sword of this stone and anvil, is rightwise king born of all England.' - Malory"
|
||||
},
|
||||
{
|
||||
"name": "Machinery",
|
||||
|
@ -214,8 +214,9 @@
|
||||
"name": "Chivalry",
|
||||
"row": 5,
|
||||
"prerequisites": ["Civil Service","Currency","Horseback Riding"],
|
||||
"uniques": ["Enables Defensive Pacts"],
|
||||
"quote": "'Whoso pulleth out this sword of this stone and anvil, is rightwise king born of all England.' - Malory"
|
||||
}, // Allows for defensive pacts
|
||||
},
|
||||
{
|
||||
"name": "Machinery",
|
||||
"row": 8,
|
||||
|
@ -198,6 +198,14 @@
|
||||
"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!"
|
||||
]
|
||||
},
|
||||
{
|
||||
"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 attitude."
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "City-States",
|
||||
"steps": [
|
||||
|
@ -43,6 +43,7 @@ object Constants {
|
||||
const val peaceTreaty = "Peace Treaty"
|
||||
const val researchAgreement = "Research Agreement"
|
||||
const val openBorders = "Open Borders"
|
||||
const val defensivePact = "Defensive Pact"
|
||||
/** Used as origin in StatMap or ResourceSupplyList, or the toggle button in DiplomacyOverviewTab */
|
||||
const val cityStates = "City-States"
|
||||
/** Used as origin in ResourceSupplyList */
|
||||
|
@ -69,6 +69,7 @@ object NextTurnAutomation {
|
||||
ReligionAutomation.spendFaithOnReligion(civInfo)
|
||||
}
|
||||
offerResearchAgreement(civInfo)
|
||||
offerDefensivePact(civInfo)
|
||||
exchangeLuxuries(civInfo)
|
||||
issueRequests(civInfo)
|
||||
adoptPolicy(civInfo) // todo can take a second - why?
|
||||
@ -172,6 +173,8 @@ object NextTurnAutomation {
|
||||
|
||||
if (tradeLogic.currentTrade.theirOffers.any { it.type == offer.type && it.name == offer.name })
|
||||
continue // So you don't get double offers of open borders declarations of war etc.
|
||||
if (offer.type == TradeType.Treaty)
|
||||
continue // Don't try to counter with a defensive pact or research pact
|
||||
|
||||
val value = evaluation.evaluateBuyCost(offer, civInfo, otherCiv)
|
||||
if (value > 0)
|
||||
@ -801,6 +804,29 @@ object NextTurnAutomation {
|
||||
}
|
||||
}
|
||||
|
||||
private 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).relationshipIgnoreAfraid() == RelationshipLevel.Ally
|
||||
}
|
||||
.sortedByDescending { it.stats.statsForNextTurn.science }
|
||||
|
||||
for (otherCiv in canSignDefensivePactCiv) {
|
||||
// Default setting is 1, this will be changed according to different civ.
|
||||
if ((1..10).random() > 1) continue
|
||||
//todo: Add more in depth evaluation here
|
||||
val tradeLogic = TradeLogic(civInfo, otherCiv)
|
||||
tradeLogic.currentTrade.ourOffers.add(TradeOffer(Constants.defensivePact, TradeType.Treaty))
|
||||
tradeLogic.currentTrade.theirOffers.add(TradeOffer(Constants.defensivePact, TradeType.Treaty))
|
||||
|
||||
otherCiv.tradeRequests.add(TradeRequest(civInfo.civName, tradeLogic.currentTrade.reverse()))
|
||||
}
|
||||
}
|
||||
|
||||
private fun declareWar(civInfo: Civilization) {
|
||||
if (civInfo.wantsToFocusOn(Victory.Focus.Culture)) return
|
||||
if (civInfo.cities.isEmpty() || civInfo.diplomacy.isEmpty()) return
|
||||
|
@ -87,7 +87,6 @@ class DiplomacyFunctions(val civInfo: Civilization){
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun canSignResearchAgreement(): Boolean {
|
||||
if (!civInfo.isMajorCiv()) return false
|
||||
if (!civInfo.hasUnique(UniqueType.EnablesResearchAgreements)) return false
|
||||
@ -113,6 +112,21 @@ class DiplomacyFunctions(val civInfo: Civilization){
|
||||
).toInt()
|
||||
}
|
||||
|
||||
fun canSignDefensivePact(): Boolean {
|
||||
if (!civInfo.isMajorCiv()) return false
|
||||
if (!civInfo.hasUnique(UniqueType.EnablesDefensivePacts)) return false
|
||||
return true
|
||||
}
|
||||
|
||||
fun canSignDefensivePactWith(otherCiv: Civilization): Boolean {
|
||||
val diplomacyManager = civInfo.getDiplomacyManager(otherCiv)
|
||||
return canSignDefensivePact() && otherCiv.diplomacyFunctions.canSignDefensivePact()
|
||||
&& diplomacyManager.hasFlag(DiplomacyFlags.DeclarationOfFriendship)
|
||||
&& !diplomacyManager.hasFlag(DiplomacyFlags.DefensivePact)
|
||||
&& !diplomacyManager.otherCivDiplomacy().hasFlag(DiplomacyFlags.DefensivePact)
|
||||
&& diplomacyManager.diplomaticStatus != DiplomaticStatus.DefensivePact
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @returns whether units of this civilization can pass through the tiles owned by [otherCiv],
|
||||
|
@ -44,6 +44,8 @@ enum class DiplomacyFlags {
|
||||
DeclinedResearchAgreement,
|
||||
DeclaredWar,
|
||||
DeclarationOfFriendship,
|
||||
DefensivePact,
|
||||
DeclinedDefensivePact,
|
||||
ResearchAgreement,
|
||||
BorderConflict,
|
||||
SettledCitiesNearUs,
|
||||
@ -72,6 +74,8 @@ enum class DiplomaticModifiers(val text:String) {
|
||||
CapturedOurCities("You have captured our cities!"),
|
||||
DeclaredFriendshipWithOurEnemies("You have declared friendship with our enemies!"),
|
||||
BetrayedDeclarationOfFriendship("Your so-called 'friendship' is worth nothing."),
|
||||
SignedDefensivePactWithOurEnemies("You have declared a defensive pact with our enemies!"),
|
||||
BetrayedDefensivePact("Your so-called 'defensive pact' is worth nothing."),
|
||||
Denunciation("You have publicly denounced us!"),
|
||||
DenouncedOurAllies("You have denounced our allies"),
|
||||
RefusedToNotSettleCitiesNearUs("You refused to stop settling cities near us"),
|
||||
@ -90,6 +94,8 @@ enum class DiplomaticModifiers(val text:String) {
|
||||
LiberatedCity("We applaud your liberation of conquered cities!"),
|
||||
DeclarationOfFriendship("We have signed a public declaration of friendship"),
|
||||
DeclaredFriendshipWithOurAllies("You have declared friendship with our allies"),
|
||||
DefensivePact("We have signed a promise to protect each other."),
|
||||
SignedDefensivePactWithOurAllies("You have declared a defensive pact with our allies"),
|
||||
DenouncedOurEnemies("You have denounced our enemies"),
|
||||
OpenBorders("Our open borders have brought us closer together."),
|
||||
FulfilledPromiseToNotSettleCitiesNearUs("You fulfilled your promise to stop settling cities near us!"),
|
||||
@ -376,7 +382,7 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
|
||||
|
||||
return max(0f, increment) * max(0f, modifierPercent).toPercent()
|
||||
}
|
||||
|
||||
|
||||
fun canDeclareWar() = turnsToPeaceTreaty() == 0 && diplomaticStatus != DiplomaticStatus.War
|
||||
|
||||
//Used for nuke
|
||||
@ -591,6 +597,9 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
|
||||
if (!otherCivDiplomacy().hasFlag(DiplomacyFlags.ResearchAgreement))
|
||||
scienceFromResearchAgreement()
|
||||
}
|
||||
DiplomacyFlags.DefensivePact.name -> {
|
||||
diplomaticStatus = DiplomaticStatus.Peace
|
||||
}
|
||||
// This is confusingly named - in fact, the civ that has the flag set is the MAJOR civ
|
||||
DiplomacyFlags.ProvideMilitaryUnit.name -> {
|
||||
// Do not unset the flag - they may return soon, and we'll continue from that point on
|
||||
@ -673,6 +682,7 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
|
||||
revertToZero(DiplomaticModifiers.WarMongerer, 1 / 2f) // warmongering gives a big negative boost when it happens but they're forgotten relatively quickly, like WWII amirite
|
||||
revertToZero(DiplomaticModifiers.CapturedOurCities, 1 / 4f) // if you captured our cities, though, that's harder to forget
|
||||
revertToZero(DiplomaticModifiers.BetrayedDeclarationOfFriendship, 1 / 8f) // That's a bastardly thing to do
|
||||
revertToZero(DiplomaticModifiers.BetrayedDefensivePact, 1 / 16f) // That's an outrageous thing to do
|
||||
revertToZero(DiplomaticModifiers.RefusedToNotSettleCitiesNearUs, 1 / 4f)
|
||||
revertToZero(DiplomaticModifiers.BetrayedPromiseToNotSettleCitiesNearUs, 1 / 8f) // That's a bastardly thing to do
|
||||
revertToZero(DiplomaticModifiers.UnacceptableDemands, 1 / 4f)
|
||||
@ -688,9 +698,14 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
|
||||
|
||||
setFriendshipBasedModifier()
|
||||
|
||||
setDefensivePactBasedModifier()
|
||||
|
||||
if (!hasFlag(DiplomacyFlags.DeclarationOfFriendship))
|
||||
revertToZero(DiplomaticModifiers.DeclarationOfFriendship, 1 / 2f) //decreases slowly and will revert to full if it is declared later
|
||||
|
||||
if (!hasFlag(DiplomacyFlags.DefensivePact))
|
||||
revertToZero(DiplomaticModifiers.DefensivePact, 1f)
|
||||
|
||||
if (!otherCiv().isCityState()) return
|
||||
|
||||
if (isRelationshipLevelLT(RelationshipLevel.Friend)) {
|
||||
@ -714,41 +729,101 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
|
||||
}
|
||||
|
||||
/** Everything that happens to both sides equally when war is declared by one side on the other */
|
||||
private fun onWarDeclared() {
|
||||
private fun onWarDeclared(isOffensiveWar: Boolean) {
|
||||
// Cancel all trades.
|
||||
for (trade in trades)
|
||||
for (offer in trade.theirOffers.filter { it.duration > 0 })
|
||||
for (offer in trade.theirOffers.filter { it.duration > 0 && it.name != Constants.defensivePact})
|
||||
civInfo.addNotification("[${offer.name}] from [$otherCivName] has ended",
|
||||
NotificationCategory.Trade, otherCivName, NotificationIcon.Trade)
|
||||
trades.clear()
|
||||
updateHasOpenBorders()
|
||||
|
||||
val civAtWarWith = otherCiv()
|
||||
|
||||
if (civInfo.isCityState() && civInfo.cityStateFunctions.getProtectorCivs().contains(civAtWarWith)) {
|
||||
civInfo.cityStateFunctions.removeProtectorCiv(civAtWarWith, forced = true)
|
||||
|
||||
// If we attacked, then we need to end all of our defensive pacts acording to Civ 5
|
||||
if (isOffensiveWar) {
|
||||
removeDefensivePacts()
|
||||
}
|
||||
|
||||
diplomaticStatus = DiplomaticStatus.War
|
||||
|
||||
if (civInfo.isMajorCiv()) {
|
||||
if (!isOffensiveWar) callInDefensivePactAllies()
|
||||
callInCityStateAllies()
|
||||
}
|
||||
|
||||
if (civInfo.isCityState() && civInfo.cityStateFunctions.getProtectorCivs().contains(civAtWarWith)) {
|
||||
civInfo.cityStateFunctions.removeProtectorCiv(civAtWarWith, forced = true)
|
||||
}
|
||||
|
||||
updateHasOpenBorders()
|
||||
|
||||
removeModifier(DiplomaticModifiers.YearsOfPeace)
|
||||
setFlag(DiplomacyFlags.DeclinedPeace, 10)/// AI won't propose peace for 10 turns
|
||||
setFlag(DiplomacyFlags.DeclaredWar, 10) // AI won't agree to trade for 10 turns
|
||||
removeFlag(DiplomacyFlags.BorderConflict)
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all defensive Pacts and trades. Notifies other civs.
|
||||
* Note: Does not remove the flags and modifiers of the otherCiv if there is a defensive pact.
|
||||
* This is so that we can apply more negative modifiers later.
|
||||
*/
|
||||
private fun removeDefensivePacts() {
|
||||
val civAtWarWith = otherCiv()
|
||||
civInfo.diplomacy.values.filter { it.diplomaticStatus == DiplomaticStatus.DefensivePact }.forEach {
|
||||
// We already removed the trades and we don't want to remove the flags yet.
|
||||
if (it.otherCiv() != civAtWarWith) {
|
||||
// Trades with defensive pact are now invalid
|
||||
val defensivePactOffer = it.trades.firstOrNull { trade -> trade.ourOffers.any { offer -> offer.name == Constants.defensivePact } }
|
||||
it.trades.remove(defensivePactOffer)
|
||||
val theirDefensivePactOffer = it.otherCivDiplomacy().trades.firstOrNull { trade -> trade.ourOffers.any { offer -> offer.name == Constants.defensivePact } }
|
||||
it.otherCivDiplomacy().trades.remove(theirDefensivePactOffer)
|
||||
it.removeFlag(DiplomacyFlags.DefensivePact)
|
||||
it.otherCivDiplomacy().removeFlag(DiplomacyFlags.DefensivePact)
|
||||
it.diplomaticStatus = DiplomaticStatus.Peace
|
||||
it.otherCivDiplomacy().diplomaticStatus = DiplomaticStatus.Peace
|
||||
}
|
||||
for (civ in getCommonKnownCivs().filter { civ -> civ.isMajorCiv() }) {
|
||||
civ.addNotification("[${civInfo.civName}] canceled their Defensive Pact with [${it.otherCivName}]!",
|
||||
NotificationCategory.Diplomacy, civInfo.civName, NotificationIcon.Diplomacy, it.otherCivName)
|
||||
}
|
||||
civInfo.addNotification("We have canceled our Defensive Pact with [${it.otherCivName}]!",
|
||||
NotificationCategory.Diplomacy, NotificationIcon.Diplomacy, it.otherCivName)
|
||||
it.otherCiv().addNotification("[${civInfo.civName}] has canceled our Defensive Pact with us!",
|
||||
NotificationCategory.Diplomacy, civInfo.civName, NotificationIcon.Diplomacy)
|
||||
}
|
||||
}
|
||||
|
||||
// Go through city state allies.
|
||||
if (!civInfo.isCityState()) {
|
||||
for (thirdCiv in civInfo.getKnownCivs()
|
||||
.filter { it.isCityState() && it.getAllyCiv() == civInfo.civName }) {
|
||||
/**
|
||||
* Goes through each DiplomacyManager with a defensive pact that is not already in the war.
|
||||
* The civ that we are calling them in against should no longer have a defensive pact with us.
|
||||
*/
|
||||
private fun callInDefensivePactAllies() {
|
||||
val civAtWarWith = otherCiv()
|
||||
for (ourDefensivePact in civInfo.diplomacy.values.filter { ourDipManager ->
|
||||
ourDipManager.diplomaticStatus == DiplomaticStatus.DefensivePact
|
||||
&& !ourDipManager.otherCiv().isDefeated()
|
||||
&& !ourDipManager.otherCiv().isAtWarWith(civAtWarWith)
|
||||
}) {
|
||||
val ally = ourDefensivePact.otherCiv()
|
||||
// Have the aggressor declare war on the ally.
|
||||
civAtWarWith.getDiplomacyManager(ally).declareWar(true)
|
||||
// Notify the aggressor
|
||||
civAtWarWith.addNotification("[${ally.civName}] has joined the defensive war with [${civInfo.civName}]!",
|
||||
NotificationCategory.Diplomacy, ally.civName, NotificationIcon.Diplomacy, civInfo.civName)
|
||||
}
|
||||
}
|
||||
|
||||
private fun callInCityStateAllies() {
|
||||
val civAtWarWith = otherCiv()
|
||||
for (thirdCiv in civInfo.getKnownCivs()
|
||||
.filter { it.isCityState() && it.getAllyCiv() == civInfo.civName }) {
|
||||
|
||||
if (thirdCiv.knows(civAtWarWith) && !thirdCiv.isAtWarWith(civAtWarWith))
|
||||
thirdCiv.getDiplomacyManager(civAtWarWith).declareWar(true)
|
||||
else if (!thirdCiv.knows(civAtWarWith)) {
|
||||
// Our city state ally has not met them yet, so they have to meet first
|
||||
thirdCiv.diplomacyFunctions.makeCivilizationsMeet(civAtWarWith, warOnContact = true)
|
||||
thirdCiv.getDiplomacyManager(civAtWarWith).declareWar(true)
|
||||
}
|
||||
if (thirdCiv.knows(civAtWarWith) && !thirdCiv.isAtWarWith(civAtWarWith))
|
||||
thirdCiv.getDiplomacyManager(civAtWarWith).declareWar(true)
|
||||
else if (!thirdCiv.knows(civAtWarWith)) {
|
||||
// Our city state ally has not met them yet, so they have to meet first
|
||||
thirdCiv.diplomacyFunctions.makeCivilizationsMeet(civAtWarWith, warOnContact = true)
|
||||
thirdCiv.getDiplomacyManager(civAtWarWith).declareWar(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -780,8 +855,8 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
|
||||
}
|
||||
}
|
||||
|
||||
onWarDeclared()
|
||||
otherCivDiplomacy.onWarDeclared()
|
||||
onWarDeclared(true)
|
||||
otherCivDiplomacy.onWarDeclared(false)
|
||||
|
||||
otherCiv.addNotification("[${civInfo.civName}] has declared war on us!",
|
||||
NotificationCategory.Diplomacy, NotificationIcon.War, civInfo.civName)
|
||||
@ -801,29 +876,57 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
|
||||
else thirdCiv.getDiplomacyManager(civInfo).addModifier(DiplomaticModifiers.SharedEnemy, 5f)
|
||||
} else thirdCiv.getDiplomacyManager(civInfo).addModifier(DiplomaticModifiers.WarMongerer, -5f)
|
||||
}
|
||||
|
||||
breakTreaties()
|
||||
|
||||
if (otherCiv.isMajorCiv())
|
||||
for (unique in civInfo.getTriggeredUniques(UniqueType.TriggerUponDeclaringWar))
|
||||
UniqueTriggerActivation.triggerCivwideUnique(unique, civInfo)
|
||||
}
|
||||
|
||||
private fun breakTreaties() {
|
||||
val otherCiv = otherCiv()
|
||||
val otherCivDiplomacy = otherCivDiplomacy()
|
||||
|
||||
var betrayedFriendship = false
|
||||
var betrayedDefensivePact = false
|
||||
if (hasFlag(DiplomacyFlags.DeclarationOfFriendship)) {
|
||||
betrayedFriendship = true
|
||||
removeFlag(DiplomacyFlags.DeclarationOfFriendship)
|
||||
otherCivDiplomacy.removeModifier(DiplomaticModifiers.DeclarationOfFriendship)
|
||||
for (knownCiv in civInfo.getKnownCivs()) {
|
||||
val amount = if (knownCiv == otherCiv) -40f else -20f
|
||||
val diploManager = knownCiv.getDiplomacyManager(civInfo)
|
||||
diploManager.addModifier(DiplomaticModifiers.BetrayedDeclarationOfFriendship, amount)
|
||||
diploManager.removeModifier(DiplomaticModifiers.DeclaredFriendshipWithOurAllies) // obviously this guy's declarations of friendship aren't worth much.
|
||||
}
|
||||
}
|
||||
otherCivDiplomacy.removeFlag(DiplomacyFlags.DeclarationOfFriendship)
|
||||
|
||||
if (hasFlag(DiplomacyFlags.DefensivePact)) {
|
||||
betrayedDefensivePact = true
|
||||
removeFlag(DiplomacyFlags.DefensivePact)
|
||||
otherCivDiplomacy.removeModifier(DiplomaticModifiers.DefensivePact)
|
||||
}
|
||||
otherCivDiplomacy.removeFlag(DiplomacyFlags.DefensivePact)
|
||||
|
||||
if (betrayedFriendship || betrayedDefensivePact) {
|
||||
for (knownCiv in civInfo.getKnownCivs()) {
|
||||
val diploManager = knownCiv.getDiplomacyManager(civInfo)
|
||||
if (betrayedFriendship) {
|
||||
val amount = if (knownCiv == otherCiv) -40f else -20f
|
||||
diploManager.addModifier(DiplomaticModifiers.BetrayedDeclarationOfFriendship, amount)
|
||||
}
|
||||
if (betrayedDefensivePact) {
|
||||
//Note: this stacks with Declaration of Friendship
|
||||
val amount = if (knownCiv == otherCiv) -20f else -10f
|
||||
diploManager.addModifier(DiplomaticModifiers.BetrayedDefensivePact, amount)
|
||||
}
|
||||
diploManager.removeModifier(DiplomaticModifiers.DeclaredFriendshipWithOurAllies) // obviously this guy's declarations of friendship aren't worth much.
|
||||
diploManager.removeModifier(DiplomaticModifiers.SignedDefensivePactWithOurAllies)
|
||||
}
|
||||
}
|
||||
|
||||
if (hasFlag(DiplomacyFlags.ResearchAgreement)) {
|
||||
removeFlag(DiplomacyFlags.ResearchAgreement)
|
||||
totalOfScienceDuringRA = 0
|
||||
otherCivDiplomacy.totalOfScienceDuringRA = 0
|
||||
}
|
||||
otherCivDiplomacy.removeFlag(DiplomacyFlags.ResearchAgreement)
|
||||
|
||||
if (otherCiv.isMajorCiv())
|
||||
for (unique in civInfo.getTriggeredUniques(UniqueType.TriggerUponDeclaringWar))
|
||||
UniqueTriggerActivation.triggerCivwideUnique(unique, civInfo)
|
||||
}
|
||||
|
||||
/** Should only be called from makePeace */
|
||||
@ -919,16 +1022,70 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
|
||||
removeModifier(DiplomaticModifiers.DeclaredFriendshipWithOurEnemies)
|
||||
for (thirdCiv in getCommonKnownCivs()
|
||||
.filter { it.getDiplomacyManager(civInfo).hasFlag(DiplomacyFlags.DeclarationOfFriendship) }) {
|
||||
when (otherCiv().getDiplomacyManager(thirdCiv).relationshipIgnoreAfraid()) {
|
||||
RelationshipLevel.Unforgivable -> addModifier(DiplomaticModifiers.DeclaredFriendshipWithOurEnemies, -15f)
|
||||
RelationshipLevel.Enemy -> addModifier(DiplomaticModifiers.DeclaredFriendshipWithOurEnemies, -5f)
|
||||
RelationshipLevel.Friend -> addModifier(DiplomaticModifiers.DeclaredFriendshipWithOurAllies, 5f)
|
||||
RelationshipLevel.Ally -> addModifier(DiplomaticModifiers.DeclaredFriendshipWithOurAllies, 15f)
|
||||
else -> {}
|
||||
|
||||
val relationshipLevel = otherCiv().getDiplomacyManager(thirdCiv).relationshipIgnoreAfraid()
|
||||
val modifierType = when (relationshipLevel) {
|
||||
RelationshipLevel.Unforgivable, RelationshipLevel.Enemy -> DiplomaticModifiers.DeclaredFriendshipWithOurEnemies
|
||||
else -> DiplomaticModifiers.DeclaredFriendshipWithOurAllies
|
||||
}
|
||||
val modifierValue = when (relationshipLevel) {
|
||||
RelationshipLevel.Unforgivable -> -15f
|
||||
RelationshipLevel.Enemy -> -5f
|
||||
RelationshipLevel.Friend -> 5f
|
||||
RelationshipLevel.Ally -> 15f
|
||||
else -> 0f
|
||||
}
|
||||
addModifier(modifierType, modifierValue)
|
||||
}
|
||||
}
|
||||
|
||||
fun signDefensivePact(duration: Int) {
|
||||
//Note: These modifiers are additive to the friendship modifiers
|
||||
setModifier(DiplomaticModifiers.DefensivePact, 10f)
|
||||
otherCivDiplomacy().setModifier(DiplomaticModifiers.DefensivePact, 10f)
|
||||
setFlag(DiplomacyFlags.DefensivePact, duration)
|
||||
otherCivDiplomacy().setFlag(DiplomacyFlags.DefensivePact, duration)
|
||||
diplomaticStatus = DiplomaticStatus.DefensivePact
|
||||
otherCivDiplomacy().diplomaticStatus = DiplomaticStatus.DefensivePact
|
||||
|
||||
|
||||
for (thirdCiv in getCommonKnownCivs().filter { it.isMajorCiv() }) {
|
||||
thirdCiv.addNotification("[${civInfo.civName}] and [$otherCivName] have signed the Defensive Pact!",
|
||||
NotificationCategory.Diplomacy, civInfo.civName, NotificationIcon.Diplomacy, otherCivName)
|
||||
thirdCiv.getDiplomacyManager(civInfo).setDefensivePactBasedModifier()
|
||||
}
|
||||
|
||||
// Ignore contitionals as triggerCivwideUnique will check again, and that would break
|
||||
// UniqueType.ConditionalChance - 25% declared chance would work as 6% actual chance
|
||||
for (unique in civInfo.getTriggeredUniques(UniqueType.TriggerUponSigningDefensivePact, StateForConditionals.IgnoreConditionals))
|
||||
UniqueTriggerActivation.triggerCivwideUnique(unique, civInfo)
|
||||
for (unique in otherCiv().getTriggeredUniques(UniqueType.TriggerUponSigningDefensivePact, StateForConditionals.IgnoreConditionals))
|
||||
UniqueTriggerActivation.triggerCivwideUnique(unique, otherCiv())
|
||||
}
|
||||
|
||||
private fun setDefensivePactBasedModifier() {
|
||||
removeModifier(DiplomaticModifiers.SignedDefensivePactWithOurAllies)
|
||||
removeModifier(DiplomaticModifiers.SignedDefensivePactWithOurEnemies)
|
||||
for (thirdCiv in getCommonKnownCivs()
|
||||
.filter { it.getDiplomacyManager(civInfo).hasFlag(DiplomacyFlags.DefensivePact) }) {
|
||||
//Note: These modifiers are additive to the friendship modifiers
|
||||
val relationshipLevel = otherCiv().getDiplomacyManager(thirdCiv).relationshipIgnoreAfraid()
|
||||
val modifierType = when (relationshipLevel) {
|
||||
RelationshipLevel.Unforgivable, RelationshipLevel.Enemy -> DiplomaticModifiers.SignedDefensivePactWithOurEnemies
|
||||
else -> DiplomaticModifiers.SignedDefensivePactWithOurAllies
|
||||
}
|
||||
val modifierValue = when (relationshipLevel) {
|
||||
RelationshipLevel.Unforgivable -> -15f
|
||||
RelationshipLevel.Enemy -> -10f
|
||||
RelationshipLevel.Friend -> 2f
|
||||
RelationshipLevel.Ally -> 5f
|
||||
else -> 0f
|
||||
}
|
||||
addModifier(modifierType, modifierValue)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun denounce() {
|
||||
setModifier(DiplomaticModifiers.Denunciation, -35f)
|
||||
otherCivDiplomacy().setModifier(DiplomaticModifiers.Denunciation, -35f)
|
||||
|
@ -5,5 +5,6 @@ import com.unciv.logic.IsPartOfGameInfoSerialization
|
||||
enum class DiplomaticStatus : IsPartOfGameInfoSerialization {
|
||||
Peace,
|
||||
Protector, //city state's diplomacy for major civ can be marked as Protector, not vice versa.
|
||||
War
|
||||
War,
|
||||
DefensivePact,
|
||||
}
|
||||
|
@ -60,6 +60,9 @@ class TradeRequest : IsPartOfGameInfoSerialization {
|
||||
diplomacyManager.setFlag(DiplomacyFlags.DeclinedLuxExchange,20)
|
||||
if (trade.ourOffers.any { it.name == Constants.researchAgreement })
|
||||
diplomacyManager.setFlag(DiplomacyFlags.DeclinedResearchAgreement,20)
|
||||
if (trade.ourOffers.any { it.name == Constants.defensivePact })
|
||||
diplomacyManager.setFlag(DiplomacyFlags.DeclinedDefensivePact,10)
|
||||
|
||||
if (trade.isPeaceTreaty()) diplomacyManager.setFlag(DiplomacyFlags.DeclinedPeace, 5)
|
||||
|
||||
requestingCivInfo.addNotification("[${decliningCiv.civName}] has denied your trade request",
|
||||
|
@ -5,6 +5,7 @@ import com.unciv.logic.automation.Automation
|
||||
import com.unciv.logic.automation.ThreatLevel
|
||||
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.RelationshipLevel
|
||||
import com.unciv.logic.map.tile.Tile
|
||||
import com.unciv.models.ruleset.ModOptionsConstants
|
||||
@ -74,13 +75,20 @@ class TradeEvaluation {
|
||||
|
||||
var sumOfOurOffers = trade.ourOffers.sumOf { evaluateSellCost(it, evaluator, tradePartner) }
|
||||
|
||||
val relationshipLevel = evaluator.getDiplomacyManager(tradePartner).relationshipIgnoreAfraid()
|
||||
// If we're making a peace treaty, don't try to up the bargain for people you don't like.
|
||||
// Leads to spartan behaviour where you demand more, the more you hate the enemy...unhelpful
|
||||
if (trade.ourOffers.none { it.name == Constants.peaceTreaty || it.name == Constants.researchAgreement }) {
|
||||
val relationshipLevel = evaluator.getDiplomacyManager(tradePartner).relationshipIgnoreAfraid()
|
||||
if (trade.ourOffers.none { it.name == Constants.peaceTreaty || it.name == Constants.researchAgreement}) {
|
||||
if (relationshipLevel == RelationshipLevel.Enemy) sumOfOurOffers = (sumOfOurOffers * 1.5).toInt()
|
||||
else if (relationshipLevel == RelationshipLevel.Unforgivable) sumOfOurOffers *= 2
|
||||
}
|
||||
if (trade.ourOffers.firstOrNull { it.name == Constants.defensivePact } != null) {
|
||||
if (relationshipLevel == RelationshipLevel.Ally) {
|
||||
//todo: Add more in depth evaluation here
|
||||
} else {
|
||||
return Int.MIN_VALUE
|
||||
}
|
||||
}
|
||||
|
||||
return sumOfTheirOffers - sumOfOurOffers
|
||||
}
|
||||
@ -195,6 +203,7 @@ class TradeEvaluation {
|
||||
Constants.peaceTreaty -> evaluatePeaceCostForThem(civInfo, tradePartner)
|
||||
Constants.researchAgreement -> -offer.amount
|
||||
else -> 1000
|
||||
//Todo:AddDefensiveTreatyHere
|
||||
}
|
||||
}
|
||||
TradeType.Luxury_Resource -> {
|
||||
|
@ -7,6 +7,7 @@ import com.unciv.logic.civilization.PopupAlert
|
||||
import com.unciv.logic.civilization.diplomacy.CityStateFunctions
|
||||
import com.unciv.logic.civilization.diplomacy.DiplomacyFlags
|
||||
import com.unciv.logic.civilization.diplomacy.DiplomaticModifiers
|
||||
import com.unciv.logic.civilization.diplomacy.DiplomaticStatus
|
||||
import com.unciv.models.ruleset.ModOptionsConstants
|
||||
import com.unciv.models.ruleset.tile.ResourceType
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
@ -31,6 +32,12 @@ class TradeLogic(val ourCivilization:Civilization, val otherCivilization: Civili
|
||||
offers.add(TradeOffer(Constants.openBorders, TradeType.Agreement))
|
||||
}
|
||||
|
||||
if (civInfo.diplomacyFunctions.canSignResearchAgreementsWith(otherCivilization))
|
||||
offers.add(TradeOffer(Constants.researchAgreement, TradeType.Treaty, civInfo.diplomacyFunctions.getResearchAgreementCost()))
|
||||
|
||||
if (civInfo.diplomacyFunctions.canSignDefensivePactWith(otherCivilization))
|
||||
offers.add(TradeOffer(Constants.defensivePact, TradeType.Treaty))
|
||||
|
||||
for (entry in civInfo.getCivResourcesWithOriginsForTrade()
|
||||
.filterNot { it.resource.resourceType == ResourceType.Bonus }
|
||||
.filter { it.origin == Constants.tradable }
|
||||
@ -123,6 +130,7 @@ class TradeLogic(val ourCivilization:Civilization, val otherCivilization: Civili
|
||||
to.getDiplomacyManager(from)
|
||||
.setFlag(DiplomacyFlags.ResearchAgreement, offer.duration)
|
||||
}
|
||||
if (offer.name == Constants.defensivePact) from.getDiplomacyManager(to).signDefensivePact(offer.duration);
|
||||
}
|
||||
TradeType.Introduction -> to.diplomacyFunctions.makeCivilizationsMeet(to.gameInfo.getCivilization(offer.name))
|
||||
TradeType.WarDeclaration -> {
|
||||
|
@ -197,6 +197,7 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
|
||||
// Should the 'R' in 'Research agreements' be capitalized?
|
||||
EnablesResearchAgreements("Enables Research agreements", UniqueTarget.Global),
|
||||
ScienceFromResearchAgreements("Science gained from research agreements [relativeAmount]%", UniqueTarget.Global),
|
||||
EnablesDefensivePacts("Enables Defensive Pacts", UniqueTarget.Global),
|
||||
GreatPersonBoostWithFriendship("When declaring friendship, both parties gain a [relativeAmount]% boost to great person generation", UniqueTarget.Global),
|
||||
|
||||
/// City State Influence
|
||||
@ -730,6 +731,7 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
|
||||
TriggerUponAdoptingPolicyOrBelief("upon adopting [policy/belief]", UniqueTarget.TriggerCondition),
|
||||
TriggerUponDeclaringWar("upon declaring war with a major Civilization", UniqueTarget.TriggerCondition),
|
||||
TriggerUponDeclaringFriendship("upon declaring friendship", UniqueTarget.TriggerCondition),
|
||||
TriggerUponSigningDefensivePact("upon declaring a defensive pact", UniqueTarget.TriggerCondition),
|
||||
TriggerUponEnteringGoldenAge("upon entering a Golden Age", UniqueTarget.TriggerCondition),
|
||||
/** Can be placed upon both units and as global */
|
||||
TriggerUponConqueringCity("upon conquering a city", UniqueTarget.TriggerCondition, UniqueTarget.UnitTriggerCondition),
|
||||
|
@ -658,10 +658,6 @@ class DiplomacyScreen(
|
||||
if (!diplomacyManager.hasFlag(DiplomacyFlags.DeclarationOfFriendship))
|
||||
diplomacyTable.add(getDeclareFriendshipButton(otherCiv)).row()
|
||||
|
||||
|
||||
if (viewingCiv.diplomacyFunctions.canSignResearchAgreementsWith(otherCiv))
|
||||
diplomacyTable.add(getResearchAgreementButton(otherCiv)).row()
|
||||
|
||||
if (!diplomacyManager.hasFlag(DiplomacyFlags.Denunciation)
|
||||
&& !diplomacyManager.hasFlag(DiplomacyFlags.DeclarationOfFriendship)
|
||||
) diplomacyTable.add(getDenounceButton(otherCiv, diplomacyManager)).row()
|
||||
@ -744,30 +740,7 @@ class DiplomacyScreen(
|
||||
if (isNotPlayersTurn()) denounceButton.disable()
|
||||
return denounceButton
|
||||
}
|
||||
|
||||
private fun getResearchAgreementButton(otherCiv: Civilization): TextButton {
|
||||
val researchAgreementButton = "Research Agreement".toTextButton()
|
||||
|
||||
val requiredGold = viewingCiv.diplomacyFunctions.getResearchAgreementCost()
|
||||
researchAgreementButton.onClick {
|
||||
val tradeTable = setTrade(otherCiv)
|
||||
val researchAgreement =
|
||||
TradeOffer(Constants.researchAgreement, TradeType.Treaty, requiredGold)
|
||||
val goldCostOfSignResearchAgreement =
|
||||
TradeOffer("Gold".tr(), TradeType.Gold, -requiredGold)
|
||||
tradeTable.tradeLogic.currentTrade.theirOffers.add(researchAgreement)
|
||||
tradeTable.tradeLogic.ourAvailableOffers.add(researchAgreement)
|
||||
tradeTable.tradeLogic.ourAvailableOffers.add(goldCostOfSignResearchAgreement)
|
||||
tradeTable.tradeLogic.currentTrade.ourOffers.add(researchAgreement)
|
||||
tradeTable.tradeLogic.theirAvailableOffers.add(researchAgreement)
|
||||
tradeTable.tradeLogic.theirAvailableOffers.add(goldCostOfSignResearchAgreement)
|
||||
tradeTable.offerColumnsTable.update()
|
||||
tradeTable.enableOfferButton(true)
|
||||
}
|
||||
if (isNotPlayersTurn()) researchAgreementButton.disable()
|
||||
return researchAgreementButton
|
||||
}
|
||||
|
||||
|
||||
private fun getDeclareFriendshipButton(otherCiv: Civilization): TextButton {
|
||||
val declareFriendshipButton =
|
||||
"Offer Declaration of Friendship ([30] turns)".toTextButton()
|
||||
@ -791,8 +764,6 @@ class DiplomacyScreen(
|
||||
val tradeButton = "Trade".toTextButton()
|
||||
tradeButton.onClick {
|
||||
setTrade(otherCiv).apply {
|
||||
tradeLogic.ourAvailableOffers.apply { remove(firstOrNull { it.type == TradeType.Treaty }) }
|
||||
tradeLogic.theirAvailableOffers.apply { remove(firstOrNull { it.type == TradeType.Treaty }) }
|
||||
offerColumnsTable.update()
|
||||
}
|
||||
}
|
||||
|
@ -103,11 +103,13 @@ class OffersListScroll(
|
||||
}
|
||||
|
||||
val amountPerClick =
|
||||
if (offer.type == Gold) 50
|
||||
else 1
|
||||
when (offer.type) {
|
||||
Gold -> 50
|
||||
Treaty -> Int.MAX_VALUE
|
||||
else -> 1
|
||||
}
|
||||
|
||||
if (offer.isTradable() && offer.name != Constants.peaceTreaty && // can't disable peace treaty!
|
||||
offer.name != Constants.researchAgreement) {
|
||||
if (offer.isTradable() && offer.name != Constants.peaceTreaty) { // can't disable peace treaty!
|
||||
|
||||
// highlight unique suggestions
|
||||
if (offerType in listOf(Luxury_Resource, Strategic_Resource)
|
||||
|
@ -629,6 +629,9 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
|
||||
|
||||
Applicable to: Global
|
||||
|
||||
??? example "Enables Defensive Pacts"
|
||||
Applicable to: Global
|
||||
|
||||
??? example "When declaring friendship, both parties gain a [relativeAmount]% boost to great person generation"
|
||||
Example: "When declaring friendship, both parties gain a [+20]% boost to great person generation"
|
||||
|
||||
@ -2022,6 +2025,9 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
|
||||
??? example "<upon declaring friendship>"
|
||||
Applicable to: TriggerCondition
|
||||
|
||||
??? example "<upon declaring a defensive pact>"
|
||||
Applicable to: TriggerCondition
|
||||
|
||||
??? example "<upon entering a Golden Age>"
|
||||
Applicable to: TriggerCondition
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user