From ef5483e9d57581d3feca765ad1933c9e3f3f08c4 Mon Sep 17 00:00:00 2001 From: Arthur van der Staaij <32672293+avdstaaij@users.noreply.github.com> Date: Thu, 19 Aug 2021 08:45:03 +0200 Subject: [PATCH] Removed the civ introduction trade option (#4888) * Removed the civ introduction trade option Left in the minimum amount of code to ensure that saves with a pending introduction trade do not break (any such pending trades are cancelled). The left-in introduction trade code can be fully removed in a later version. * Added back civ introduction trades as a mod option Also made the gold value of introducation trades moddable. * Made civ introduction trade invalid if receiver already knows the civ This prevents players from sending two AI civs introduction trades for each other in the same turn and profiting from both. This therefore fixes #4272. * Applied requested changes * Removed a spurious space --- .../com/unciv/logic/trade/TradeEvaluation.kt | 45 +++++++++++-------- core/src/com/unciv/logic/trade/TradeLogic.kt | 15 ++++--- core/src/com/unciv/models/ruleset/Ruleset.kt | 9 +++- .../com/unciv/ui/trade/OffersListScroll.kt | 2 +- 4 files changed, 42 insertions(+), 29 deletions(-) diff --git a/core/src/com/unciv/logic/trade/TradeEvaluation.kt b/core/src/com/unciv/logic/trade/TradeEvaluation.kt index 402f779bb9..c7363af8a7 100644 --- a/core/src/com/unciv/logic/trade/TradeEvaluation.kt +++ b/core/src/com/unciv/logic/trade/TradeEvaluation.kt @@ -6,6 +6,8 @@ import com.unciv.logic.automation.ThreatLevel import com.unciv.logic.city.CityInfo import com.unciv.logic.civilization.CivilizationInfo import com.unciv.logic.civilization.diplomacy.RelationshipLevel +import com.unciv.models.ruleset.ModOptionsConstants +import com.unciv.models.ruleset.Ruleset import com.unciv.models.ruleset.tile.ResourceType import kotlin.math.min import kotlin.math.sqrt @@ -21,32 +23,32 @@ class TradeEvaluation { return false for (offer in trade.ourOffers) - if (!isOfferValid(offer, offerer)) + if (!isOfferValid(offer, offerer, tradePartner)) return false for (offer in trade.theirOffers) - if (!isOfferValid(offer, tradePartner)) + if (!isOfferValid(offer, tradePartner, offerer)) return false return true } - private fun isOfferValid(tradeOffer: TradeOffer, offerer: CivilizationInfo): Boolean { + private fun isOfferValid(tradeOffer: TradeOffer, offerer: CivilizationInfo, tradePartner: CivilizationInfo): Boolean { fun hasResource(tradeOffer: TradeOffer): Boolean { val resourcesByName = offerer.getCivResourcesByName() return resourcesByName.containsKey(tradeOffer.name) && resourcesByName[tradeOffer.name]!! >= 0 } - when (tradeOffer.type) { - TradeType.Gold -> return true // even if they go negative it's okay - TradeType.Gold_Per_Turn -> return true // even if they go negative it's okay - TradeType.Treaty -> return true - TradeType.Agreement -> return true - TradeType.Luxury_Resource -> return hasResource(tradeOffer) - TradeType.Strategic_Resource -> return hasResource(tradeOffer) - TradeType.Technology -> return true - TradeType.Introduction -> return true - TradeType.WarDeclaration -> return true - TradeType.City -> return offerer.cities.any { it.id == tradeOffer.name } + return when (tradeOffer.type) { + TradeType.Gold -> true // even if they go negative it's okay + TradeType.Gold_Per_Turn -> true // even if they go negative it's okay + TradeType.Treaty -> true + TradeType.Agreement -> true + TradeType.Luxury_Resource -> hasResource(tradeOffer) + TradeType.Strategic_Resource -> hasResource(tradeOffer) + TradeType.Technology -> true + TradeType.Introduction -> !tradePartner.knows(tradeOffer.name) // You can't introduce them to someone they already know! + TradeType.WarDeclaration -> true + TradeType.City -> offerer.cities.any { it.id == tradeOffer.name } } } @@ -68,7 +70,7 @@ class TradeEvaluation { return sumOfOurOffers <= sumOfTheirOffers } - fun evaluateBuyCost(offer: TradeOffer, civInfo: CivilizationInfo, tradePartner: CivilizationInfo): Int { + private fun evaluateBuyCost(offer: TradeOffer, civInfo: CivilizationInfo, tradePartner: CivilizationInfo): Int { when (offer.type) { TradeType.Gold -> return offer.amount TradeType.Gold_Per_Turn -> return offer.amount * offer.duration @@ -131,7 +133,7 @@ class TradeEvaluation { TradeType.Technology -> return (sqrt(civInfo.gameInfo.ruleSet.technologies[offer.name]!!.cost.toDouble()) * civInfo.gameInfo.gameParameters.gameSpeed.modifier).toInt() * 20 - TradeType.Introduction -> return 250 + TradeType.Introduction -> return introductionValue(civInfo.gameInfo.ruleSet) TradeType.WarDeclaration -> { val civToDeclareWarOn = civInfo.gameInfo.getCivilization(offer.name) val threatToThem = Automation.threatAssessment(civInfo, civToDeclareWarOn) @@ -160,7 +162,7 @@ class TradeEvaluation { } } } - fun surroundedByOurCities(city: CityInfo, civInfo: CivilizationInfo): Int{ + private fun surroundedByOurCities(city: CityInfo, civInfo: CivilizationInfo): Int{ val borderingCivs: List = city.getNeighbouringCivs() if (borderingCivs.size == 1 && borderingCivs.contains(civInfo.civName)){ return 10*civInfo.getEraNumber() // if the city is surrounded only by trading civ @@ -171,7 +173,7 @@ class TradeEvaluation { } - fun evaluateSellCost(offer: TradeOffer, civInfo: CivilizationInfo, tradePartner: CivilizationInfo): Int { + private fun evaluateSellCost(offer: TradeOffer, civInfo: CivilizationInfo, tradePartner: CivilizationInfo): Int { when (offer.type) { TradeType.Gold -> return offer.amount TradeType.Gold_Per_Turn -> return offer.amount * offer.duration @@ -213,7 +215,7 @@ class TradeEvaluation { return totalCost } TradeType.Technology -> return sqrt(civInfo.gameInfo.ruleSet.technologies[offer.name]!!.cost.toDouble()).toInt() * 20 - TradeType.Introduction -> return 250 + TradeType.Introduction -> return introductionValue(civInfo.gameInfo.ruleSet) TradeType.WarDeclaration -> { val civToDeclareWarOn = civInfo.gameInfo.getCivilization(offer.name) val threatToUs = Automation.threatAssessment(civInfo, civToDeclareWarOn) @@ -274,4 +276,9 @@ class TradeEvaluation { } } + private fun introductionValue(ruleSet: Ruleset): Int { + val unique = ruleSet.modOptions.uniqueObjects.firstOrNull{ it.placeholderText == ModOptionsConstants.tradeCivIntroductions } + if (unique == null) return 0 + return unique.params[0].toInt() + } } \ No newline at end of file diff --git a/core/src/com/unciv/logic/trade/TradeLogic.kt b/core/src/com/unciv/logic/trade/TradeLogic.kt index bb4aa8959a..39f99db8fc 100644 --- a/core/src/com/unciv/logic/trade/TradeLogic.kt +++ b/core/src/com/unciv/logic/trade/TradeLogic.kt @@ -13,7 +13,7 @@ class TradeLogic(val ourCivilization:CivilizationInfo, val otherCivilization: Ci val theirAvailableOffers = getAvailableOffers(otherCivilization, ourCivilization) val currentTrade = Trade() - fun getAvailableOffers(civInfo: CivilizationInfo, otherCivilization: CivilizationInfo): TradeOffersList { + private fun getAvailableOffers(civInfo: CivilizationInfo, otherCivilization: CivilizationInfo): TradeOffersList { val offers = TradeOffersList() if (civInfo.isCityState() && otherCivilization.isCityState()) return offers if (civInfo.isAtWarWith(otherCivilization)) @@ -43,12 +43,14 @@ class TradeLogic(val ourCivilization:CivilizationInfo, val otherCivilization: Ci } val otherCivsWeKnow = civInfo.getKnownCivs() - .filter { it.civName != otherCivilization.civName && it.isMajorCiv() && !it.isDefeated() } - val civsWeKnowAndTheyDont = otherCivsWeKnow - .filter { !otherCivilization.diplomacy.containsKey(it.civName) && !it.isDefeated() } + .filter { it.civName != otherCivilization.civName && it.isMajorCiv() && !it.isDefeated() } - for (thirdCiv in civsWeKnowAndTheyDont) { - offers.add(TradeOffer(thirdCiv.civName, TradeType.Introduction)) + if (civInfo.gameInfo.ruleSet.modOptions.uniqueObjects.any{ it.placeholderText == ModOptionsConstants.tradeCivIntroductions }) { + val civsWeKnowAndTheyDont = otherCivsWeKnow + .filter { !otherCivilization.diplomacy.containsKey(it.civName) && !it.isDefeated() } + for (thirdCiv in civsWeKnowAndTheyDont) { + offers.add(TradeOffer(thirdCiv.civName, TradeType.Introduction)) + } } if (!civInfo.isCityState() && !otherCivilization.isCityState() @@ -106,7 +108,6 @@ class TradeLogic(val ourCivilization:CivilizationInfo, val otherCivilization: Ci } if (offer.type == TradeType.Introduction) to.makeCivilizationsMeet(to.gameInfo.getCivilization(offer.name)) - if (offer.type == TradeType.WarDeclaration) { val nameOfCivToDeclareWarOn = offer.name from.getDiplomacyManager(nameOfCivToDeclareWarOn).declareWar() diff --git a/core/src/com/unciv/models/ruleset/Ruleset.kt b/core/src/com/unciv/models/ruleset/Ruleset.kt index 525da72c69..9b145defd9 100644 --- a/core/src/com/unciv/models/ruleset/Ruleset.kt +++ b/core/src/com/unciv/models/ruleset/Ruleset.kt @@ -25,9 +25,10 @@ object ModOptionsConstants { const val diplomaticRelationshipsCannotChange = "Diplomatic relationships cannot change" const val convertGoldToScience = "Can convert gold to science with sliders" const val allowCityStatesSpawnUnits = "Allow City States to spawn with additional units" + const val tradeCivIntroductions = "Can trade civilization introductions for [] Gold" } -class ModOptions { +class ModOptions : IHasUniques { var isBaseRuleset = false var techsToRemove = HashSet() var buildingsToRemove = HashSet() @@ -41,7 +42,10 @@ class ModOptions { var modSize = 0 val maxXPfromBarbarians = 30 - var uniques = HashSet() // No reason for now to use IHasUniques here, in that case needs to change to ArrayList + + override var uniques = ArrayList() + // If this is delegated with "by lazy", the mod download process crashes and burns + override var uniqueObjects: List = listOf() } class Ruleset { @@ -145,6 +149,7 @@ class Ruleset { try { modOptions = jsonParser.getFromJson(ModOptions::class.java, modOptionsFile) } catch (ex: Exception) {} + modOptions.uniqueObjects = modOptions.uniques.map { Unique(it) } } val techFile = folderHandle.child("Techs.json") diff --git a/core/src/com/unciv/ui/trade/OffersListScroll.kt b/core/src/com/unciv/ui/trade/OffersListScroll.kt index c402355a6f..10de655ff4 100644 --- a/core/src/com/unciv/ui/trade/OffersListScroll.kt +++ b/core/src/com/unciv/ui/trade/OffersListScroll.kt @@ -29,7 +29,7 @@ class OffersListScroll(val onOfferClicked: (TradeOffer) -> Unit) : ScrollPane(nu for (offerType in values()) { val labelName = when(offerType){ - Gold, Gold_Per_Turn, Treaty,Agreement,Introduction -> "" + Gold, Gold_Per_Turn, Treaty, Agreement, Introduction -> "" Luxury_Resource -> "Luxury resources" Strategic_Resource -> "Strategic resources" Technology -> "Technologies"