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
This commit is contained in:
Arthur van der Staaij 2021-08-19 08:45:03 +02:00 committed by GitHub
parent 4114296cbe
commit ef5483e9d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 42 additions and 29 deletions

View File

@ -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<String> = 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()
}
}

View File

@ -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()

View File

@ -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<String>()
var buildingsToRemove = HashSet<String>()
@ -41,7 +42,10 @@ class ModOptions {
var modSize = 0
val maxXPfromBarbarians = 30
var uniques = HashSet<String>() // No reason for now to use IHasUniques here, in that case needs to change to ArrayList
override var uniques = ArrayList<String>()
// If this is delegated with "by lazy", the mod download process crashes and burns
override var uniqueObjects: List<Unique> = 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")

View File

@ -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"