From c49a282a748724a157e2b62674ce41405abcc1e7 Mon Sep 17 00:00:00 2001 From: Yair Morgenstern Date: Mon, 2 Jul 2018 13:33:23 +0300 Subject: [PATCH] Added Trade and Diplomacy screens When the civilization is losing money, buiding gold buildings is prioritized --- .../com/unciv/logic/automation/Automation.kt | 9 +- core/src/com/unciv/logic/city/CityInfo.kt | 3 +- .../logic/civilization/CivilizationInfo.kt | 14 +- core/src/com/unciv/ui/DiplomacyScreen.kt | 69 +++++++++ core/src/com/unciv/ui/TradeScreen.kt | 143 ++++++++++++++++++ .../unciv/ui/utils/CameraStageBaseScreen.kt | 2 +- .../com/unciv/ui/worldscreen/WorldScreen.kt | 16 ++ 7 files changed, 244 insertions(+), 12 deletions(-) create mode 100644 core/src/com/unciv/ui/DiplomacyScreen.kt create mode 100644 core/src/com/unciv/ui/TradeScreen.kt diff --git a/core/src/com/unciv/logic/automation/Automation.kt b/core/src/com/unciv/logic/automation/Automation.kt index f7aef12f0a..f3bd907971 100644 --- a/core/src/com/unciv/logic/automation/Automation.kt +++ b/core/src/com/unciv/logic/automation/Automation.kt @@ -110,7 +110,11 @@ class Automation { val cities = cityInfo.civInfo.cities.size when { - !buildableNotWonders.isEmpty() -> currentConstruction = buildableNotWonders.first().name + buildableNotWonders.isNotEmpty() // if the civ is in the gold red-zone, build markets or somesuch + && cityInfo.civInfo.getStatsForNextTurn().values.map { it.gold }.sum()<0 + && buildableNotWonders.any { it.gold>0 } + -> currentConstruction = buildableNotWonders.first { it.gold>0 }.name + buildableNotWonders.isNotEmpty() -> currentConstruction = buildableNotWonders.first().name militaryUnits==0 -> trainCombatUnit(cityInfo) workers==0 -> currentConstruction = CityConstructions.Worker militaryUnits trainCombatUnit(cityInfo) @@ -119,8 +123,7 @@ class Automation { else -> trainCombatUnit(cityInfo) } - if (cityInfo.civInfo == cityInfo.civInfo.gameInfo.getPlayerCivilization()) - cityInfo.civInfo.addNotification("Work has started on [$currentConstruction]", cityInfo.location, Color.BROWN) + cityInfo.civInfo.addNotification("Work has started on [$currentConstruction]", cityInfo.location, Color.BROWN) } } diff --git a/core/src/com/unciv/logic/city/CityInfo.kt b/core/src/com/unciv/logic/city/CityInfo.kt index 0c779cecab..adf0ddd932 100644 --- a/core/src/com/unciv/logic/city/CityInfo.kt +++ b/core/src/com/unciv/logic/city/CityInfo.kt @@ -6,10 +6,10 @@ import com.unciv.logic.civilization.CivilizationInfo import com.unciv.logic.map.RoadStatus import com.unciv.logic.map.TileInfo import com.unciv.logic.map.TileMap +import com.unciv.models.Counter import com.unciv.models.gamebasics.GameBasics import com.unciv.models.gamebasics.tile.ResourceType import com.unciv.models.gamebasics.tile.TileResource -import com.unciv.models.Counter import com.unciv.models.stats.Stats import kotlin.math.min @@ -43,6 +43,7 @@ class CityInfo { for (tileInfo in getTiles().filter { it.resource != null }) { val resource = tileInfo.tileResource + if(resource.revealedBy!=null && !civInfo.tech.isResearched(resource.revealedBy!!)) continue if (resource.improvement == tileInfo.improvement || tileInfo.isCityCenter()){ if(resource.resourceType == ResourceType.Strategic) cityResources.add(resource, 2) else cityResources.add(resource, 1) diff --git a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt index f0eaf7a6cf..4ccc1d4c01 100644 --- a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt +++ b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt @@ -33,7 +33,7 @@ class CivilizationInfo { var goldenAges = GoldenAgeManager() var greatPeople = GreatPersonManager() var scienceVictory = ScienceVictoryManager() - //@Transient var diplomacy = HashMap() +// @Transient var diplomacy = HashMap() var cities = ArrayList() var exploredTiles = HashSet() @@ -246,11 +246,11 @@ class CivilizationInfo { } } -//enum class DiplomaticStatus{ -// Peace, -// War -//} -// +enum class DiplomaticStatus{ + Peace, + War +} + //class DiplomacyManager { // @Transient lateinit var civInfo:CivilizationInfo // lateinit var otherCivName:String @@ -261,4 +261,4 @@ class CivilizationInfo { // status = DiplomaticStatus.War // otherCiv().diplomacy[civInfo.civName]!!.status = DiplomaticStatus.War // } -//} \ No newline at end of file +//} diff --git a/core/src/com/unciv/ui/DiplomacyScreen.kt b/core/src/com/unciv/ui/DiplomacyScreen.kt new file mode 100644 index 0000000000..61ebc3fb47 --- /dev/null +++ b/core/src/com/unciv/ui/DiplomacyScreen.kt @@ -0,0 +1,69 @@ +//package com.unciv.ui +// +//import com.badlogic.gdx.scenes.scene2d.ui.SplitPane +//import com.badlogic.gdx.scenes.scene2d.ui.Table +//import com.badlogic.gdx.scenes.scene2d.ui.TextButton +//import com.unciv.UnCivGame +//import com.unciv.logic.civilization.CivilizationInfo +//import com.unciv.logic.civilization.DiplomaticStatus +//import com.unciv.ui.utils.CameraStageBaseScreen +//import com.unciv.ui.utils.addClickListener +//import com.unciv.ui.utils.tr +// +// +//class DiplomacyScreen : CameraStageBaseScreen(){ +// +// val civInfo = UnCivGame.Current.gameInfo.getPlayerCivilization() +// var otherCivilization: CivilizationInfo? = null +// val diplomacyTable = Table() +// +// init { +// val closeButton = TextButton("Close".tr(), skin) +// closeButton.addClickListener { UnCivGame.Current.setWorldScreen() } +// closeButton.y = stage.height - closeButton.height - 5 +// stage.addActor(closeButton) +// +// +// val civPickerTable = Table().apply { defaults().pad(5f) } +// for(otherCivName in civInfo.diplomacy.keys){ +// val chooseCiv = TextButton(otherCivName,skin) +// chooseCiv.addClickListener { +// otherCivilization = civInfo.gameInfo.civilizations.first{it.civName==otherCivName} +// updateDiplomacyTable() +// } +// civPickerTable.add().row() +// } +// +// val splitPane = SplitPane(diplomacyTable,civPickerTable,true, skin) +// splitPane.setSplitAmount(0.8f) +// stage.addActor(splitPane) +// } +// +// private fun updateDiplomacyTable() { +// diplomacyTable.clear() +// if(otherCivilization==null) return +// val otherCivDiplomacyManager = civInfo.diplomacy[otherCivilization!!.civName]!! +// +// if(otherCivDiplomacyManager.status==DiplomaticStatus.Peace) { +// val tradeButton = TextButton("Trade".tr(), skin) +// tradeButton .addClickListener { +// UnCivGame.Current.screen = TradeScreen(otherCivilization!!) +// } +// +// val declareWarButton = TextButton("Declare War".tr(), skin) +// declareWarButton.addClickListener { +// civInfo.diplomacy[otherCivilization!!.civName]!!.declareWar() +// updateDiplomacyTable() +// } +// } +// +// else{ +// val declareWarButton = TextButton("Negotiate Peace".tr(), skin) +// declareWarButton.addClickListener { +// UnCivGame.Current.screen = TradeScreen(otherCivilization!!) +// } +// } +// diplomacyTable.add() +// } +// +//} diff --git a/core/src/com/unciv/ui/TradeScreen.kt b/core/src/com/unciv/ui/TradeScreen.kt new file mode 100644 index 0000000000..f924f45211 --- /dev/null +++ b/core/src/com/unciv/ui/TradeScreen.kt @@ -0,0 +1,143 @@ +package com.unciv.ui + +import com.badlogic.gdx.scenes.scene2d.ui.Label +import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane +import com.badlogic.gdx.scenes.scene2d.ui.Table +import com.badlogic.gdx.scenes.scene2d.ui.TextButton +import com.unciv.UnCivGame +import com.unciv.logic.civilization.CivilizationInfo +import com.unciv.models.Counter +import com.unciv.models.gamebasics.tile.ResourceType +import com.unciv.ui.utils.* +import kotlin.math.min + + +enum class TradeType{ + Luxury_Resource, + Strategic_Resource, + Gold, + Gold_Per_Turn, + City +} + +data class TradeOffer(val name:String, val type:TradeType, val duration:Int) { + fun getText(): String { + var text = "{$name}" + if(duration>0) text += " ($duration {turns})" + return text.tr() + } +} + +class TradeOffersList():Counter(){} + +class Trade(){ + val theirOffers = TradeOffersList() + val ourOffers = TradeOffersList() +} + + +class TradeScreen(val otherCivilization: CivilizationInfo) : CameraStageBaseScreen(){ + + val civInfo = UnCivGame.Current.gameInfo.getPlayerCivilization() + val ourAvailableOffers = getAvailableOffers(civInfo) + val theirAvailableOffers = getAvailableOffers(otherCivilization) + val currentTrade = Trade() + + val table = Table(skin) + val tradeText = Label("What do you have in mind?",skin) + + init { + val closeButton = TextButton("Close".tr(), skin) + closeButton.addClickListener { UnCivGame.Current.setWorldScreen() } + closeButton.y = stage.height - closeButton.height - 5 + stage.addActor(closeButton) + stage.addActor(table) + + val lowerTable = Table().apply { defaults().pad(10f) } + + lowerTable.add(tradeText).row() + val offerButton = TextButton("Offer trade",skin) + offerButton.addClickListener { + if(isTradeAcceptable(currentTrade)) tradeText.setText("That is acceptable.") + else tradeText.setText("I think not.") + } + lowerTable.add(offerButton) + + lowerTable.pack() + lowerTable.centerX(stage) + lowerTable.y = 10f + stage.addActor(lowerTable) + + + update() + } + + fun update(){ + table.clear() + val ourAvailableOffersTable = ScrollPane(getTableOfOffers(ourAvailableOffers, currentTrade.ourOffers)) + val ourOffersTable = ScrollPane(getTableOfOffers(currentTrade.ourOffers, ourAvailableOffers)) + val theirOffersTable = ScrollPane(getTableOfOffers(currentTrade.theirOffers, theirAvailableOffers)) + val theirAvailableOffersTable = ScrollPane(getTableOfOffers(theirAvailableOffers, currentTrade.theirOffers)) + table.add("Our items") + table.add("Our trade offer") + table.add(otherCivilization.civName+"'s trade offer") + table.add(otherCivilization.civName+"'s items").row() + table.add(ourAvailableOffersTable).width(stage.width/4) + table.add(ourOffersTable).width(stage.width/4) + table.add(theirOffersTable).width(stage.width/4) + table.add(theirAvailableOffersTable).width(stage.width/4) + table.pack() + table.center(stage) + } + + fun getTableOfOffers(offers: TradeOffersList, correspondingOffers: TradeOffersList): Table { + val table= Table(skin).apply { defaults().pad(5f) } + for(offer in offers) { + val tb = TextButton(offer.key.name+" ("+offer.value+")",skin) + val amountPerClick = + if(offer.key.type==TradeType.Gold) 50 + else 1 + if(offer.value>0) // for instance we have negative gold + tb.addClickListener { + val amountTransfered = min(amountPerClick, offer.value) + offers.add(offer.key,-amountTransfered) + correspondingOffers.add(offer.key,amountTransfered) + update() + } + else tb.disable() + table.add(tb).row() + } + return table + } + + fun getAvailableOffers(civInfo: CivilizationInfo): TradeOffersList { + val offers = TradeOffersList() + 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 + offers.add(TradeOffer(entry.key.name, resourceTradeType, 30), entry.value) + } + offers.add(TradeOffer("Gold",TradeType.Gold,0),civInfo.gold) + return offers + } + + fun isTradeAcceptable(trade:Trade): Boolean { + val sumOfTheirOffers = trade.theirOffers.map { evaluateOffer(it.key,false)*it.value }.sum() + val sumOfOurOffers = trade.ourOffers.map { evaluateOffer(it.key,true)*it.value }.sum() + return sumOfOurOffers >= sumOfTheirOffers + } + + fun evaluateOffer(offer:TradeOffer, otherCivIsRecieving:Boolean): Int { + if(offer.type==TradeType.Gold) return 1 + if(offer.type == TradeType.Luxury_Resource){ + if(!theirAvailableOffers.containsKey(offer)) // We want to take away their last luxury or give them one they don't have + return 250 + if(!otherCivIsRecieving && !ourAvailableOffers.containsKey(offer)) return 250 // they're giving us a luxury we don't have yet + return 100 // this is useful only as a barter trade to other civs + } + if(offer.type == TradeType.Strategic_Resource){ + return 50 + } + return 1000 // Dunno what this is? + } +} \ No newline at end of file diff --git a/core/src/com/unciv/ui/utils/CameraStageBaseScreen.kt b/core/src/com/unciv/ui/utils/CameraStageBaseScreen.kt index fcce9dff8b..952b7560c8 100644 --- a/core/src/com/unciv/ui/utils/CameraStageBaseScreen.kt +++ b/core/src/com/unciv/ui/utils/CameraStageBaseScreen.kt @@ -184,7 +184,7 @@ fun getFont(size: Int): BitmapFont { // parameter.genMipMaps = true parameter.minFilter = Texture.TextureFilter.Linear parameter.magFilter = Texture.TextureFilter.Linear - parameter.characters = "ABCČĆDĐEFGHIJKLMNOPQRSŠTUVWXYZŽaäàâăbcčćdđeéfghiîjklmnoöpqrsșštțuüvwxyzžАБВГҐДЂЕЁЄЖЗЅИІЇЙЈКЛЉМНЊОПРСТЋУЎФХЦЧЏШЩЪЫЬЭЮЯабвгґдђеёєжзѕиіїйјклљмнњопрстћуўфхцчџшщъыьэюяΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩαβγδεζηθικλμνξοπρστυφχψωάΆέΈέΉίϊΐΊόΌύΰϋΎΫΏĂÂÊÔƠƯăâêôơư1234567890‘?’“!”(%)[#]{@}/&\\<-+÷×=>®©\$€£¥¢:;,.*|" + parameter.characters = "ABCČĆDĐEFGHIJKLMNOPQRSŠTUVWXYZŽaäàâăbcčćdđeéfghiîjklmnoöpqrsșštțuüvwxyzžАБВГҐДЂЕЁЄЖЗЅИІЇЙЈКЛЉМНЊОПРСТЋУЎФХЦЧЏШЩЪЫЬЭЮЯабвгґдђеёєжзѕиіїйјклљмнњопрстћуўфхцчџшщъыьэюяΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩαβγδεζηθικλμνξοπρστυφχψωάΆέΈέΉίϊΐΊόΌύΰϋΎΫΏĂÂÊÔƠƯăâêôơư1234567890‘?’'“!”(%)[#]{@}/&\\<-+÷×=>®©\$€£¥¢:;,.*|" //generator.scaleForPixelHeight(size) diff --git a/core/src/com/unciv/ui/worldscreen/WorldScreen.kt b/core/src/com/unciv/ui/worldscreen/WorldScreen.kt index 3c574311c5..1d55f82204 100644 --- a/core/src/com/unciv/ui/worldscreen/WorldScreen.kt +++ b/core/src/com/unciv/ui/worldscreen/WorldScreen.kt @@ -2,9 +2,12 @@ package com.unciv.ui.worldscreen import com.badlogic.gdx.Gdx import com.badlogic.gdx.math.Vector2 +import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.scenes.scene2d.ui.TextButton +import com.unciv.UnCivGame import com.unciv.logic.GameSaver import com.unciv.logic.civilization.CivilizationInfo +import com.unciv.ui.TradeScreen import com.unciv.ui.pickerscreens.GreatPersonPickerScreen import com.unciv.ui.pickerscreens.PolicyPickerScreen import com.unciv.ui.pickerscreens.TechPickerScreen @@ -25,6 +28,7 @@ class WorldScreen : CameraStageBaseScreen() { val unitActionsTable = UnitActionsTable(this) private val techButton = TextButton("", CameraStageBaseScreen.skin) + val tradeButtons = Table() private val nextTurnButton = createNextTurnButton() private val notificationsScroll: NotificationsScroll @@ -53,6 +57,16 @@ class WorldScreen : CameraStageBaseScreen() { stage.addActor(techButton) stage.addActor(notificationsScroll) + + tradeButtons.defaults().pad(5f) + for(civ in gameInfo.civilizations.filterNot { it.isPlayerCivilization()||it.isBarbarianCivilization() }){ + val tb = TextButton(civ.civName,skin) + tb.addClickListener { UnCivGame.Current.screen = TradeScreen(civ) } + tradeButtons.add(tb) + } + tradeButtons.pack() + stage.addActor(tradeButtons) + bottomBar.width = stage.width stage.addActor(bottomBar) stage.addActor(unitActionsTable) @@ -100,6 +114,8 @@ class WorldScreen : CameraStageBaseScreen() { techButton.setSize(techButton.prefWidth, techButton.prefHeight) techButton.setPosition(10f, topBar.y - techButton.height - 5f) + + tradeButtons.y = techButton.y - tradeButtons.height } private fun createNextTurnButton(): TextButton {