Research agreements with gold offer (#9933)

* Research agreements can now be offered when both civilizations combined have enough gold.

* Moved a OfferColumnsTable constructor parameter.

* Fixed the ordering of an argument in TradeTable.

* Added an extra comment to OffersListScroll.

* Refactored research pact trade balancing when offered.

* Research agreement cost now uses the highest era from both participants.
This commit is contained in:
Oskar Niesen 2023-08-24 02:10:12 -05:00 committed by GitHub
parent 12e3cfc5b3
commit 592304ba2f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 57 additions and 22 deletions

View File

@ -796,7 +796,7 @@ object NextTurnAutomation {
// Default setting is 5, this will be changed according to different civ.
if ((1..10).random() > 5) continue
val tradeLogic = TradeLogic(civInfo, otherCiv)
val cost = civInfo.diplomacyFunctions.getResearchAgreementCost()
val cost = civInfo.diplomacyFunctions.getResearchAgreementCost(otherCiv)
tradeLogic.currentTrade.ourOffers.add(TradeOffer(Constants.researchAgreement, TradeType.Treaty, cost))
tradeLogic.currentTrade.theirOffers.add(TradeOffer(Constants.researchAgreement, TradeType.Treaty, cost))

View File

@ -11,6 +11,7 @@ import com.unciv.logic.map.tile.Tile
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.stats.Stat
import com.unciv.models.stats.Stats
import kotlin.math.max
class DiplomacyFunctions(val civInfo: Civilization){
@ -93,22 +94,26 @@ class DiplomacyFunctions(val civInfo: Civilization){
.none { civInfo.tech.canBeResearched(it.name) && !civInfo.tech.isResearched(it.name) }) return false
return true
}
fun canSignResearchAgreementsWith(otherCiv: Civilization): Boolean {
fun canSignResearchAgreementNoCostWith (otherCiv: Civilization): Boolean {
val diplomacyManager = civInfo.getDiplomacyManager(otherCiv)
val cost = getResearchAgreementCost()
return canSignResearchAgreement() && otherCiv.diplomacyFunctions.canSignResearchAgreement()
&& diplomacyManager.hasFlag(DiplomacyFlags.DeclarationOfFriendship)
&& !diplomacyManager.hasFlag(DiplomacyFlags.ResearchAgreement)
&& !diplomacyManager.otherCivDiplomacy().hasFlag(DiplomacyFlags.ResearchAgreement)
&& civInfo.gold >= cost && otherCiv.gold >= cost
&& diplomacyManager.hasFlag(DiplomacyFlags.DeclarationOfFriendship)
&& !diplomacyManager.hasFlag(DiplomacyFlags.ResearchAgreement)
&& !diplomacyManager.otherCivDiplomacy().hasFlag(DiplomacyFlags.ResearchAgreement)
}
fun getResearchAgreementCost(): Int {
fun canSignResearchAgreementsWith(otherCiv: Civilization): Boolean {
val cost = getResearchAgreementCost(otherCiv)
return canSignResearchAgreementNoCostWith(otherCiv)
&& civInfo.gold >= cost && otherCiv.gold >= cost
}
fun getResearchAgreementCost(otherCiv: Civilization): Int {
// https://forums.civfanatics.com/resources/research-agreements-bnw.25568/
return (
civInfo.getEra().researchAgreementCost * civInfo.gameInfo.speed.goldCostModifier
).toInt()
return ( max(civInfo.getEra().researchAgreementCost, otherCiv.getEra().researchAgreementCost)
* civInfo.gameInfo.speed.goldCostModifier
).toInt()
}
fun canSignDefensivePact(): Boolean {

View File

@ -32,8 +32,8 @@ 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.canSignResearchAgreementNoCostWith(otherCivilization))
offers.add(TradeOffer(Constants.researchAgreement, TradeType.Treaty, civInfo.diplomacyFunctions.getResearchAgreementCost(otherCivilization)))
if (civInfo.diplomacyFunctions.canSignDefensivePactWith(otherCivilization))
offers.add(TradeOffer(Constants.defensivePact, TradeType.Treaty))

View File

@ -18,10 +18,12 @@ import com.unciv.ui.screens.basescreen.BaseScreen
class OfferColumnsTable(
private val tradeLogic: TradeLogic,
private val screen: DiplomacyScreen,
private val ourCiv: Civilization,
private val theirCiv: Civilization,
private val onChange: () -> Unit
): Table(BaseScreen.skin) {
private fun addOffer(offer: TradeOffer, offerList: TradeOffersList, correspondingOfferList: TradeOffersList) {
fun addOffer(offer: TradeOffer, offerList: TradeOffersList, correspondingOfferList: TradeOffersList) {
offerList.add(offer.copy())
if (offer.type == TradeType.Treaty) correspondingOfferList.add(offer.copy())
onChange()
@ -104,10 +106,10 @@ class OfferColumnsTable(
.removeAll(Constants.tradable)
val theirUntradables = tradeLogic.otherCivilization.getCivResourcesWithOriginsForTrade()
.removeAll(Constants.tradable)
ourAvailableOffersTable.update(ourFilteredOffers, tradeLogic.theirAvailableOffers, ourUntradables)
ourOffersTable.update(tradeLogic.currentTrade.ourOffers, tradeLogic.theirAvailableOffers)
theirOffersTable.update(tradeLogic.currentTrade.theirOffers, tradeLogic.ourAvailableOffers)
theirAvailableOffersTable.update(theirFilteredOffers, tradeLogic.ourAvailableOffers, theirUntradables)
ourAvailableOffersTable.update(ourFilteredOffers, tradeLogic.theirAvailableOffers, ourUntradables, ourCiv, theirCiv)
ourOffersTable.update(tradeLogic.currentTrade.ourOffers, tradeLogic.theirAvailableOffers, ourCiv = ourCiv, theirCiv = theirCiv)
theirOffersTable.update(tradeLogic.currentTrade.theirOffers, tradeLogic.ourAvailableOffers, ourCiv = ourCiv, theirCiv = theirCiv)
theirAvailableOffersTable.update(theirFilteredOffers, tradeLogic.ourAvailableOffers, theirUntradables, ourCiv, theirCiv)
}
private fun openGoldSelectionPopup(offer: TradeOffer, ourOffers: TradeOffersList, maxGold: Int) {

View File

@ -5,6 +5,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.utils.Align
import com.unciv.Constants
import com.unciv.UncivGame
import com.unciv.logic.civilization.Civilization
import com.unciv.logic.trade.TradeOffer
import com.unciv.logic.trade.TradeOffersList
import com.unciv.logic.trade.TradeType
@ -52,7 +53,9 @@ class OffersListScroll(
fun update(
offersToDisplay: TradeOffersList,
otherOffers: TradeOffersList,
untradableOffers: ResourceSupplyList = ResourceSupplyList.emptyList
untradableOffers: ResourceSupplyList = ResourceSupplyList.emptyList,
ourCiv: Civilization,
theirCiv: Civilization
) {
table.clear()
expanderTabs.clear()
@ -109,7 +112,10 @@ class OffersListScroll(
else -> 1
}
if (offer.isTradable() && offer.name != Constants.peaceTreaty) { // can't disable peace treaty!
if (offer.isTradable() && offer.name != Constants.peaceTreaty // can't disable peace treaty!
&& (offer.name != Constants.researchAgreement // If we have a research agreement make sure the total gold of both Civs is higher than the total cost
// If both civs combined can pay for the research agreement, don't disable it. One can offer the other it's gold.
|| (ourCiv.gold + theirCiv.gold > ourCiv.diplomacyFunctions.getResearchAgreementCost(theirCiv) * 2))) {
// highlight unique suggestions
if (offerType in listOf(Luxury_Resource, Strategic_Resource)

View File

@ -1,9 +1,11 @@
package com.unciv.ui.screens.diplomacyscreen
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.unciv.Constants
import com.unciv.logic.civilization.Civilization
import com.unciv.logic.trade.TradeLogic
import com.unciv.logic.trade.TradeRequest
import com.unciv.logic.trade.TradeType
import com.unciv.models.translations.tr
import com.unciv.ui.screens.basescreen.BaseScreen
import com.unciv.ui.components.extensions.isEnabled
@ -16,7 +18,7 @@ class TradeTable(
): Table(BaseScreen.skin) {
private val currentPlayerCiv = otherCivilization.gameInfo.getCurrentPlayerCivilization()
internal val tradeLogic = TradeLogic(currentPlayerCiv, otherCivilization)
internal val offerColumnsTable = OfferColumnsTable(tradeLogic, diplomacyScreen) { onChange() }
internal val offerColumnsTable = OfferColumnsTable(tradeLogic, diplomacyScreen , currentPlayerCiv, otherCivilization) { onChange() }
// This is so that after a trade has been traded, we can switch out the offersToDisplay to start anew - this is the easiest way
private val offerColumnsTableWrapper = Table()
private val offerButton = "Offer trade".toTextButton()
@ -49,6 +51,26 @@ class TradeTable(
retractOffer()
return@onClick
}
// If there is a research agreement trade, make sure both civilizations should be able to pay for it.
// If not lets add an extra gold offer to satisfy this.
// There must be enough gold to add to the offer to satisfy this, otherwise the research agreement button would be disabled
if (tradeLogic.currentTrade.ourOffers.any { it.name == Constants.researchAgreement}) {
val researchCost = currentPlayerCiv.diplomacyFunctions.getResearchAgreementCost(otherCivilization)
val currentPlayerOfferedGold = tradeLogic.currentTrade.ourOffers.firstOrNull { it.type == TradeType.Gold }?.amount ?: 0
val otherCivOfferedGold = tradeLogic.currentTrade.theirOffers.firstOrNull { it.type == TradeType.Gold }?.amount ?: 0
val newCurrentPlayerGold = currentPlayerCiv.gold + otherCivOfferedGold - researchCost
val newOtherCivGold = otherCivilization.gold + currentPlayerOfferedGold - researchCost
// Check if we require more gold from them
if (newCurrentPlayerGold < 0) {
offerColumnsTable.addOffer( tradeLogic.theirAvailableOffers.first { it.type == TradeType.Gold }
.copy(amount = -newCurrentPlayerGold), tradeLogic.currentTrade.theirOffers, tradeLogic.currentTrade.ourOffers)
}
// Check if they require more gold from us
if (newOtherCivGold < 0) {
offerColumnsTable.addOffer( tradeLogic.ourAvailableOffers.first { it.type == TradeType.Gold }
.copy(amount = -newOtherCivGold), tradeLogic.currentTrade.ourOffers, tradeLogic.currentTrade.theirOffers)
}
}
otherCivilization.tradeRequests.add(TradeRequest(currentPlayerCiv.civName, tradeLogic.currentTrade.reverse()))
currentPlayerCiv.cache.updateCivResources()