mirror of
https://github.com/yairm210/Unciv.git
synced 2025-07-12 16:59:11 +07:00
Resolved #525 - Added Open Borders agreement
This commit is contained in:
@ -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
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
@ -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!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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()) {
|
||||
|
@ -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
|
||||
|
@ -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")
|
||||
|
Reference in New Issue
Block a user