Resolved #525 - Added Open Borders agreement

This commit is contained in:
Yair Morgenstern
2019-04-24 10:19:47 +03:00
parent d902db0af0
commit c81c81fe8f
11 changed files with 51 additions and 28 deletions

View File

@ -11,7 +11,6 @@ import com.unciv.logic.map.TileMap
import com.unciv.models.gamebasics.GameBasics
import java.util.*
import kotlin.collections.ArrayList
import kotlin.math.min
class GameParameters{
var difficulty="Prince"
@ -91,7 +90,7 @@ class GameStarter{
for(minimumDistanceBetweenStartingLocations in tileMap.tileMatrix.size/2 downTo 0){
val freeTiles = landTilesInBigEnoughGroup
.filter { vectorIsWithinNTilesOfEdge(it.position,min(3,minimumDistanceBetweenStartingLocations),tileMap)}
.filter { vectorIsAtLeastNTilesAwayFromEdge(it.position,minimumDistanceBetweenStartingLocations,tileMap)}
.toMutableList()
val startingLocations = ArrayList<TileInfo>()
@ -109,7 +108,7 @@ class GameStarter{
throw Exception("Didn't manage to get starting locations even with distance of 1?")
}
fun vectorIsWithinNTilesOfEdge(vector: Vector2,n:Int, tileMap: TileMap): Boolean {
fun vectorIsAtLeastNTilesAwayFromEdge(vector: Vector2, n:Int, tileMap: TileMap): Boolean {
val arrayXIndex = vector.x.toInt()-tileMap.leftX
val arrayYIndex = vector.y.toInt()-tileMap.bottomY

View File

@ -41,9 +41,9 @@ class NextTurnAutomation{
}
private fun exchangeTechs(civInfo: CivilizationInfo) {
val otherCivList = civInfo.diplomacy.values.map { it.otherCiv() }.
filter { it.playerType == PlayerType.AI && !it.isBarbarianCivilization() }.
sortedBy { it.tech.techsResearched.size }
val otherCivList = civInfo.getKnownCivs()
.filter { it.playerType == PlayerType.AI && !it.isBarbarianCivilization() }
.sortedBy { it.tech.techsResearched.size }
for (otherCiv in otherCivList) {
val tradeLogic = TradeLogic(civInfo, otherCiv)
@ -141,7 +141,7 @@ class NextTurnAutomation{
}
private fun exchangeLuxuries(civInfo: CivilizationInfo) {
val knownCivs = civInfo.diplomacy.values.map { it.otherCiv() }
val knownCivs = civInfo.getKnownCivs()
// Player trades are... more complicated.
// When the AI offers a trade, it's not immediately accepted,
@ -151,7 +151,7 @@ class NextTurnAutomation{
// B. have a way for the AI to keep track of the "pending offers" - see DiplomacyManager.resourcesFromTrade
for (otherCiv in knownCivs.filter { it.isPlayerCivilization() && !it.isAtWarWith(civInfo)
&& !civInfo.diplomacy[it.civName]!!.flagsCountdown.containsKey(DiplomacyFlags.DeclinedLuxExchange)}) {
&& !civInfo.getDiplomacyManager(it).flagsCountdown.containsKey(DiplomacyFlags.DeclinedLuxExchange)}) {
val trades = potentialLuxuryTrades(civInfo,otherCiv)
for(trade in trades){
val tradeRequest = TradeRequest(civInfo.civName, trade.reverse())
@ -185,7 +185,7 @@ class NextTurnAutomation{
val enemiesCiv = civInfo.diplomacy.filter{ it.value.diplomaticStatus == DiplomaticStatus.War }
.map{ it.value.otherCiv() }
.filterNot{ it == civInfo || it.isBarbarianCivilization() || it.cities.isEmpty() }
.filter { !civInfo.diplomacy[it.civName]!!.flagsCountdown.containsKey(DiplomacyFlags.DeclinedPeace) }
.filter { !civInfo.getDiplomacyManager(it).flagsCountdown.containsKey(DiplomacyFlags.DeclinedPeace) }
for (enemy in enemiesCiv) {
val enemiesStrength = Automation().evaluteCombatStrength(enemy)
@ -228,8 +228,8 @@ class NextTurnAutomation{
if (!civInfo.isAtWar() && civInfo.happiness > 0
&& ourMilitaryUnits >= civInfo.cities.size) { //evaluate war
val ourCombatStrength = Automation().evaluteCombatStrength(civInfo)
val enemyCivsByDistanceToOurs = civInfo.diplomacy.values.map { it.otherCiv() }
.filterNot { it == civInfo || it.cities.isEmpty() || !civInfo.diplomacy[it.civName]!!.canDeclareWar() }
val enemyCivsByDistanceToOurs = civInfo.getKnownCivs()
.filterNot { it == civInfo || it.cities.isEmpty() || !civInfo.getDiplomacyManager(it).canDeclareWar() }
.groupBy { getMinDistanceBetweenCities(civInfo, it) }
.toSortedMap()
@ -237,7 +237,7 @@ class NextTurnAutomation{
if (group.key > 7) break
for (otherCiv in group.value) {
if (Automation().evaluteCombatStrength(otherCiv) * 2 < ourCombatStrength) {
civInfo.diplomacy[otherCiv.civName]!!.declareWar()
civInfo.getDiplomacyManager(otherCiv).declareWar()
return
}
}

View File

@ -94,7 +94,7 @@ class CivilizationInfo {
toReturn.goldenAges = goldenAges.clone()
toReturn.greatPeople = greatPeople.clone()
toReturn.victoryManager = victoryManager.clone()
toReturn.diplomacy.putAll(diplomacy.values.map { it.clone() }.associateBy { it.otherCivName })
toReturn.diplomacy.putAll(diplomacy)
toReturn.cities = cities.map { it.clone() }
toReturn.exploredTiles.addAll(exploredTiles)
toReturn.notifications.addAll(notifications)
@ -119,6 +119,9 @@ class CivilizationInfo {
return translatedNation
}
fun getDiplomacyManager(civInfo: CivilizationInfo) = diplomacy[civInfo.civName]!!
fun getKnownCivs() = diplomacy.values.map { it.otherCiv() }
fun getCapital()=cities.first { it.isCapital() }
fun isPlayerCivilization() = playerType==PlayerType.Human
fun isCurrentPlayer() = gameInfo.getCurrentPlayerCivilization()==this
@ -323,7 +326,7 @@ class CivilizationInfo {
if(otherCiv.isBarbarianCivilization() || isBarbarianCivilization()) return true
if(!diplomacy.containsKey(otherCiv.civName)) // not encountered yet
return false
return diplomacy[otherCiv.civName]!!.diplomaticStatus == DiplomaticStatus.War
return getDiplomacyManager(otherCiv).diplomaticStatus == DiplomaticStatus.War
}
fun isAtWar() = diplomacy.values.any { it.diplomaticStatus== DiplomaticStatus.War && !it.otherCiv().isDefeated() }
@ -425,6 +428,7 @@ class CivilizationInfo {
fun canEnterTiles(otherCiv: CivilizationInfo): Boolean {
if(otherCiv==this) return true
if(isAtWarWith(otherCiv)) return true
if(getDiplomacyManager(otherCiv).hasOpenBorders()) return true
return false
}

View File

@ -45,6 +45,13 @@ class DiplomacyManager() {
return 0
}
fun hasOpenBorders(): Boolean {
for(trade in trades)
for(offer in trade.theirOffers)
if(offer.name=="Open Borders" && offer.duration > 0) return true
return false
}
fun canDeclareWar() = (turnsToPeaceTreaty()==0 && diplomaticStatus != DiplomaticStatus.War)
fun otherCiv() = civInfo.gameInfo.getCivilization(otherCivName)
@ -87,7 +94,7 @@ class DiplomacyManager() {
if (offer.type in listOf(TradeType.Luxury_Resource, TradeType.Strategic_Resource)
&& offer.name in negativeCivResources){
trades.remove(trade)
val otherCivTrades = otherCiv().diplomacy[civInfo.civName]!!.trades
val otherCivTrades = otherCiv().getDiplomacyManager(civInfo).trades
otherCivTrades.removeAll{ it.equals(trade.reverse()) }
civInfo.addNotification("One of our trades with [$otherCivName] has been cut short!".tr(),null, Color.GOLD)
otherCiv().addNotification("One of our trades with [${civInfo.civName}] has been cut short!".tr(),null, Color.GOLD)
@ -119,13 +126,13 @@ class DiplomacyManager() {
diplomaticStatus = DiplomaticStatus.War
val otherCiv = otherCiv()
otherCiv.diplomacy[civInfo.civName]!!.diplomaticStatus = DiplomaticStatus.War
otherCiv.getDiplomacyManager(civInfo).diplomaticStatus = DiplomaticStatus.War
otherCiv.addNotification("[${civInfo.civName}] has declared war on us!",null, Color.RED)
otherCiv.popupAlerts.add(PopupAlert(AlertType.WarDeclaration,civInfo.civName))
/// AI won't propose peace for 10 turns
flagsCountdown[DiplomacyFlags.DeclinedPeace]=10
otherCiv.diplomacy[civInfo.civName]!!.flagsCountdown[DiplomacyFlags.DeclinedPeace]=10
otherCiv.getDiplomacyManager(civInfo).flagsCountdown[DiplomacyFlags.DeclinedPeace]=10
}
//endregion
}

View File

@ -82,7 +82,7 @@ class TradeEvaluation{
val civToDeclareWarOn = civInfo.gameInfo.getCivilization(nameOfCivToDeclareWarOn)
val threatToThem = Automation().threatAssessment(civInfo,civToDeclareWarOn)
if(civInfo.diplomacy[nameOfCivToDeclareWarOn]!!.diplomaticStatus== DiplomaticStatus.War){
if(civInfo.getDiplomacyManager(civToDeclareWarOn).diplomaticStatus== DiplomaticStatus.War){
when (threatToThem) {
ThreatLevel.VeryLow -> return 0
ThreatLevel.Low -> return 0
@ -101,6 +101,10 @@ class TradeEvaluation{
val sumOfStats = stats.culture+stats.gold+stats.science+stats.production+stats.happiness+stats.food
return sumOfStats.toInt() * 100
}
TradeType.Agreement -> {
if(offer.name=="Open Borders") return 100
throw Exception("Invalid agreement type!")
}
}
}
@ -141,6 +145,10 @@ class TradeEvaluation{
val sumOfStats = stats.culture+stats.gold+stats.science+stats.production+stats.happiness+stats.food
return sumOfStats.toInt() * 100
}
TradeType.Agreement -> {
if(offer.name=="Open Borders") return 100
throw Exception("Invalid agreement type!")
}
}
}

View File

@ -1,7 +1,6 @@
package com.unciv.logic.trade
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.civilization.diplomacy.DiplomacyFlags
import com.unciv.logic.civilization.diplomacy.DiplomaticStatus
import com.unciv.models.gamebasics.tile.ResourceType
import com.unciv.models.gamebasics.tr
@ -17,6 +16,8 @@ class TradeLogic(val ourCivilization:CivilizationInfo, val otherCivilization: Ci
val offers = TradeOffersList()
if(civInfo.isAtWarWith(otherCivilization))
offers.add(TradeOffer("Peace Treaty", TradeType.Treaty, 20))
if(!otherCivilization.getDiplomacyManager(civInfo).hasOpenBorders())
offers.add(TradeOffer("Open Borders", TradeType.Agreement, 30))
for(entry in civInfo.getCivResources().filterNot { it.key.resourceType == ResourceType.Bonus }) {
val resourceTradeType = if(entry.key.resourceType== ResourceType.Luxury) TradeType.Luxury_Resource
else TradeType.Strategic_Resource
@ -32,7 +33,7 @@ class TradeLogic(val ourCivilization:CivilizationInfo, val otherCivilization: Ci
for(city in civInfo.cities.filterNot { it.isCapital() })
offers.add(TradeOffer(city.name, TradeType.City, 0))
val otherCivsWeKnow = civInfo.diplomacy.values.map { it.otherCiv() }
val otherCivsWeKnow = civInfo.getKnownCivs()
.filter { it != otherCivilization && !it.isBarbarianCivilization() && !it.isDefeated() }
val civsWeKnowAndTheyDont = otherCivsWeKnow
.filter { !otherCivilization.diplomacy.containsKey(it.civName) && !it.isDefeated() }
@ -43,7 +44,7 @@ class TradeLogic(val ourCivilization:CivilizationInfo, val otherCivilization: Ci
val civsWeBothKnow = otherCivsWeKnow
.filter { otherCivilization.diplomacy.containsKey(it.civName) }
val civsWeArentAtWarWith = civsWeBothKnow
.filter { civInfo.diplomacy[it.civName]!!.diplomaticStatus== DiplomaticStatus.Peace }
.filter { civInfo.getDiplomacyManager(it).diplomaticStatus== DiplomaticStatus.Peace }
for(thirdCiv in civsWeArentAtWarWith){
offers.add(TradeOffer("Declare war on "+thirdCiv.civName,TradeType.WarDeclaration,0))
}
@ -52,8 +53,8 @@ class TradeLogic(val ourCivilization:CivilizationInfo, val otherCivilization: Ci
}
fun acceptTrade() {
ourCivilization.diplomacy[otherCivilization.civName]!!.trades.add(currentTrade)
otherCivilization.diplomacy[ourCivilization.civName]!!.trades.add(currentTrade.reverse())
ourCivilization.getDiplomacyManager(otherCivilization).trades.add(currentTrade)
otherCivilization.getDiplomacyManager(ourCivilization).trades.add(currentTrade.reverse())
// instant transfers
fun transferTrade(to: CivilizationInfo, from: CivilizationInfo, trade: Trade) {
@ -74,7 +75,7 @@ class TradeLogic(val ourCivilization:CivilizationInfo, val otherCivilization: Ci
}
if(offer.type== TradeType.Treaty){
if(offer.name=="Peace Treaty"){
to.diplomacy[from.civName]!!.diplomaticStatus= DiplomaticStatus.Peace
to.getDiplomacyManager(from).diplomaticStatus= DiplomaticStatus.Peace
for(unit in to.getCivUnits().filter { it.getTile().getOwner()==from })
unit.movementAlgs().teleportToClosestMoveableTile()
}

View File

@ -3,7 +3,10 @@ package com.unciv.logic.trade
enum class TradeType{
Gold,
Gold_Per_Turn,
/** Treaties are shared by both sides - like peace treaty and defensive pact */
Treaty,
/** Agreements are one-sided, like open borders */
Agreement,
Luxury_Resource,
Strategic_Resource,
Technology,

View File

@ -79,7 +79,7 @@ class DiplomacyScreen:CameraStageBaseScreen() {
diplomacyTable.add(tradeButton).row()
val currentPlayerCiv = UnCivGame.Current.gameInfo.getCurrentPlayerCivilization()
val civDiplomacy = currentPlayerCiv.diplomacy[civ.civName]!!
val civDiplomacy = currentPlayerCiv.getDiplomacyManager(civ)
if (!currentPlayerCiv.isAtWarWith(civ)) {
val declareWarButton = TextButton("Declare war".tr(), skin)

View File

@ -31,6 +31,7 @@ class OffersListScroll(val onOfferClicked: (TradeOffer) -> Unit) : ScrollPane(nu
Technology -> "Technologies"
WarDeclaration -> "Declarations of war"
City -> "Cities"
Agreement -> "Agreements"
}
val offersOfType = offersToDisplay.filter { it.type == offertype }
if (labelName!="" && offersOfType.any()) {

View File

@ -59,10 +59,10 @@ class TradePopup(worldScreen: WorldScreen): PopupTable(worldScreen){
currentPlayerCiv.tradeRequests.remove(tradeRequest)
if(trade.ourOffers.all { it.type==TradeType.Luxury_Resource } && trade.theirOffers.all { it.type==TradeType.Luxury_Resource })
requestingCiv.diplomacy[currentPlayerCiv.civName]!!.flagsCountdown[DiplomacyFlags.DeclinedLuxExchange]=20 // offer again in 20 turns
requestingCiv.getDiplomacyManager(currentPlayerCiv).flagsCountdown[DiplomacyFlags.DeclinedLuxExchange]=20 // offer again in 20 turns
if(trade.ourOffers.any{ it.type==TradeType.Treaty && it.name=="Peace Treaty" })
requestingCiv.diplomacy[currentPlayerCiv.civName]!!.flagsCountdown[DiplomacyFlags.DeclinedPeace]=5 // offer again in 20 turns
requestingCiv.getDiplomacyManager(currentPlayerCiv).flagsCountdown[DiplomacyFlags.DeclinedPeace]=5 // offer again in 20 turns
remove()
worldScreen.shouldUpdate=true

View File

@ -178,7 +178,7 @@ class WorldScreen : CameraStageBaseScreen() {
private fun updateDiplomacyButton(civInfo: CivilizationInfo) {
diplomacyButtonWrapper.clear()
if(civInfo.diplomacy.values.map { it.otherCiv() }
if(civInfo.getKnownCivs()
.filterNot { it.isDefeated() || it.isPlayerCivilization() || it.isBarbarianCivilization() }
.any()) {
displayTutorials("OtherCivEncountered")